Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/xs
diff options
context:
space:
mode:
authorbubnikv <bubnikv@gmail.com>2018-09-14 10:28:00 +0300
committerbubnikv <bubnikv@gmail.com>2018-09-14 10:28:00 +0300
commit9d9e4a0f7b2d9d3440c2a05bc65b2cab707d148a (patch)
treee57a7cb171afe5efa6381a73ad02dcbce3050826 /xs
parentbb70ad609025a259f35f4f21e2fc9587c7a3fc2d (diff)
WIP: Background processing.
Diffstat (limited to 'xs')
-rw-r--r--xs/CMakeLists.txt12
-rw-r--r--xs/src/libslic3r/GCode.cpp18
-rw-r--r--xs/src/libslic3r/GCodeTimeEstimator.cpp4
-rw-r--r--xs/src/libslic3r/Model.cpp1
-rw-r--r--xs/src/libslic3r/Model.hpp1
-rw-r--r--xs/src/libslic3r/Print.cpp23
-rw-r--r--xs/src/libslic3r/Print.hpp19
-rw-r--r--xs/src/libslic3r/PrintObject.cpp13
-rw-r--r--xs/src/libslic3r/Utils.hpp8
-rw-r--r--xs/src/libslic3r/utils.cpp82
-rw-r--r--xs/src/slic3r/GUI/BackgroundSlicingProcess.cpp27
-rw-r--r--xs/src/slic3r/GUI/BackgroundSlicingProcess.hpp9
-rw-r--r--xs/src/slic3r/GUI/GLCanvas3D.cpp4
-rw-r--r--xs/src/slic3r/GUI/GUI_ObjectParts.cpp9
-rw-r--r--xs/src/slic3r/GUI/ProgressIndicator.hpp72
-rw-r--r--xs/xsp/GUI_BackgroundSlicingProcess.xsp1
16 files changed, 260 insertions, 43 deletions
diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt
index 272a1ad71..7e35a27b1 100644
--- a/xs/CMakeLists.txt
+++ b/xs/CMakeLists.txt
@@ -602,12 +602,12 @@ if (WIN32 AND ";${PerlEmbed_CCFLAGS};" MATCHES ";[-/]Od;")
message("Old CMAKE_CXX_FLAGS_RELEASE: ${CMAKE_CXX_FLAGS_RELEASE}")
message("Old CMAKE_CXX_FLAGS_RELWITHDEBINFO: ${CMAKE_CXX_FLAGS_RELEASE}")
message("Old CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS_RELEASE}")
- set(CMAKE_CXX_FLAGS_RELEASE "/MD /Od /Zi /EHsc /DNDEBUG /DWIN32")
- set(CMAKE_C_FLAGS_RELEASE "/MD /Od /Zi /DNDEBUG /DWIN32")
- set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /EHsc /DNDEBUG /DWIN32")
- set(CMAKE_C_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /DNDEBUG /DWIN32")
- set(CMAKE_CXX_FLAGS "/MD /Od /Zi /EHsc /DNDEBUG /DWIN32")
- set(CMAKE_C_FLAGS "/MD /Od /Zi /DNDEBUG /DWIN32")
+ set(CMAKE_CXX_FLAGS_RELEASE "/MD /Od /Zi /EHsc /DNDEBUG /DWIN32 /DTBB_USE_ASSERT")
+ set(CMAKE_C_FLAGS_RELEASE "/MD /Od /Zi /DNDEBUG /DWIN32 /DTBB_USE_ASSERT")
+ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /EHsc /DNDEBUG /DWIN32 /DTBB_USE_ASSERT")
+ set(CMAKE_C_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /DNDEBUG /DWIN32 /DTBB_USE_ASSERT")
+ set(CMAKE_CXX_FLAGS "/MD /Od /Zi /EHsc /DNDEBUG /DWIN32 /DTBB_USE_ASSERT")
+ set(CMAKE_C_FLAGS "/MD /Od /Zi /DNDEBUG /DWIN32 /DTBB_USE_ASSERT")
endif()
# The following line will add -fPIC on Linux to make the XS.so rellocable.
add_definitions(${PerlEmbed_CCCDLFLAGS})
diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp
index 0ade0de61..91c9d6b0f 100644
--- a/xs/src/libslic3r/GCode.cpp
+++ b/xs/src/libslic3r/GCode.cpp
@@ -418,6 +418,17 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
{
PROFILE_CLEAR();
+ if (print->is_step_done(psGCodeExport)) {
+ // Does the file exist? If so, we hope that it is still valid.
+ FILE *f = boost::nowide::fopen(path, "r");
+ if (f != nullptr) {
+ ::fclose(f);
+ return;
+ }
+ }
+
+ print->set_started(psGCodeExport);
+
BOOST_LOG_TRIVIAL(info) << "Exporting G-code...";
// Remove the old g-code if it exists.
@@ -467,12 +478,13 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
throw std::runtime_error(msg);
}
- if (boost::nowide::rename(path_tmp.c_str(), path) != 0)
+ if (rename_file(path_tmp, path) != 0)
throw std::runtime_error(
std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + path + '\n' +
"Is " + path_tmp + " locked?" + '\n');
BOOST_LOG_TRIVIAL(info) << "Exporting G-code finished";
+ print->set_done(psGCodeExport);
// Write the profiler measurements to file
PROFILE_UPDATE();
@@ -483,8 +495,6 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
{
PROFILE_FUNC();
- print.set_started(psGCodeExport);
-
// resets time estimators
m_normal_time_estimator.reset();
m_normal_time_estimator.set_dialect(print.config().gcode_flavor);
@@ -1029,8 +1039,6 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
// starts analizer calculations
if (preview_data != nullptr)
m_analyzer.calc_gcode_preview_data(*preview_data);
-
- print.set_done(psGCodeExport);
}
std::string GCode::placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override)
diff --git a/xs/src/libslic3r/GCodeTimeEstimator.cpp b/xs/src/libslic3r/GCodeTimeEstimator.cpp
index 7471367fe..f97265ee3 100644
--- a/xs/src/libslic3r/GCodeTimeEstimator.cpp
+++ b/xs/src/libslic3r/GCodeTimeEstimator.cpp
@@ -1,4 +1,5 @@
#include "GCodeTimeEstimator.hpp"
+#include "Utils.hpp"
#include <boost/bind.hpp>
#include <cmath>
@@ -367,8 +368,7 @@ namespace Slic3r {
fclose(out);
in.close();
- boost::nowide::remove(filename.c_str());
- if (boost::nowide::rename(path_tmp.c_str(), filename.c_str()) != 0)
+ if (rename_file(path_tmp, filename) != 0)
throw std::runtime_error(std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + filename + '\n' +
"Is " + path_tmp + " locked?" + '\n');
diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp
index 19c474cad..dc21ab4ae 100644
--- a/xs/src/libslic3r/Model.cpp
+++ b/xs/src/libslic3r/Model.cpp
@@ -849,6 +849,7 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
return;
}
+// Called by Print::validate() from the UI thread.
void ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume)
{
for (const ModelVolume* vol : this->volumes)
diff --git a/xs/src/libslic3r/Model.hpp b/xs/src/libslic3r/Model.hpp
index 8a8af481c..8ca1d8ea9 100644
--- a/xs/src/libslic3r/Model.hpp
+++ b/xs/src/libslic3r/Model.hpp
@@ -129,6 +129,7 @@ public:
void cut(coordf_t z, Model* model) const;
void split(ModelObjectPtrs* new_objects);
+ // Called by Print::validate() from the UI thread.
void check_instances_print_volume_state(const BoundingBoxf3& print_volume);
// Print object statistics to console.
diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp
index c8a50a6bb..a677d9e5a 100644
--- a/xs/src/libslic3r/Print.cpp
+++ b/xs/src/libslic3r/Print.cpp
@@ -72,6 +72,7 @@ void Print::reload_object(size_t /* idx */)
// Returns true if the brim or skirt have been invalidated.
bool Print::reload_model_instances()
{
+ tbb::mutex::scoped_lock lock(m_mutex);
bool invalidated = false;
for (PrintObject *object : m_objects)
invalidated |= object->reload_model_instances();
@@ -370,6 +371,7 @@ double Print::max_allowed_layer_height() const
// and have explicit instance positions.
void Print::add_model_object(ModelObject* model_object, int idx)
{
+ tbb::mutex::scoped_lock lock(m_mutex);
// Initialize a new print object and store it at the given position.
PrintObject *object = new PrintObject(this, model_object, model_object->raw_bounding_box());
if (idx != -1) {
@@ -378,6 +380,7 @@ void Print::add_model_object(ModelObject* model_object, int idx)
} else
m_objects.emplace_back(object);
// Invalidate all print steps.
+ //FIXME lock mutex!
this->invalidate_all_steps();
for (size_t volume_id = 0; volume_id < model_object->volumes.size(); ++ volume_id) {
@@ -434,6 +437,8 @@ void Print::add_model_object(ModelObject* model_object, int idx)
bool Print::apply_config(DynamicPrintConfig config)
{
+ tbb::mutex::scoped_lock lock(m_mutex);
+
// we get a copy of the config object so we can modify it safely
config.normalize();
@@ -564,13 +569,17 @@ std::string Print::validate() const
BoundingBoxf3 print_volume(unscale(bed_box_2D.min(0), bed_box_2D.min(1), 0.0), unscale(bed_box_2D.max(0), bed_box_2D.max(1), scale_(m_config.max_print_height)));
// Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced.
print_volume.min(2) = -1e10;
- unsigned int printable_count = 0;
- for (PrintObject *po : m_objects) {
- po->model_object()->check_instances_print_volume_state(print_volume);
- po->reload_model_instances();
- if (po->is_printable())
- ++printable_count;
- }
+ unsigned int printable_count = 0;
+ {
+ // Lock due to the po->reload_model_instances()
+ tbb::mutex::scoped_lock lock(m_mutex);
+ for (PrintObject *po : m_objects) {
+ po->model_object()->check_instances_print_volume_state(print_volume);
+ po->reload_model_instances();
+ if (po->is_printable())
+ ++ printable_count;
+ }
+ }
if (printable_count == 0)
return L("All objects are outside of the print volume.");
diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp
index d72c1fef5..106640c4d 100644
--- a/xs/src/libslic3r/Print.hpp
+++ b/xs/src/libslic3r/Print.hpp
@@ -88,6 +88,11 @@ public:
bool invalidate(StepType step, tbb::mutex &mtx, CancelationCallback &cancel) {
bool invalidated = m_state[step].load(std::memory_order_relaxed) != INVALID;
if (invalidated) {
+#if 0
+ if (mtx.state != mtx.HELD) {
+ printf("Not held!\n");
+ }
+#endif
mtx.unlock();
cancel();
mtx.lock();
@@ -283,18 +288,14 @@ private:
SupportLayerPtrs m_support_layers;
PrintState<PrintObjectStep, posCount> m_state;
- // Mutex used for synchronization of the worker thread with the UI thread:
- // The mutex will be used to guard the worker thread against entering a stage
- // while the data influencing the stage is modified.
- tbb::mutex m_mutex;
// TODO: call model_object->get_bounding_box() instead of accepting
// parameter
PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox);
~PrintObject() {}
- void set_started(PrintObjectStep step) { m_state.set_started(step, m_mutex); }
- void set_done(PrintObjectStep step) { m_state.set_done(step, m_mutex); }
+ void set_started(PrintObjectStep step);
+ void set_done(PrintObjectStep step);
std::vector<ExPolygons> _slice_region(size_t region_id, const std::vector<float> &z, bool modifier);
};
@@ -446,8 +447,8 @@ public:
const PrintRegion* get_region(size_t idx) const { return m_regions[idx]; }
protected:
- void set_started(PrintStep step) { m_state.set_started(step, m_mutex); }
- void set_done(PrintStep step) { m_state.set_done(step, m_mutex); }
+ void set_started(PrintStep step) { m_state.set_started(step, m_mutex); throw_if_canceled(); }
+ void set_done(PrintStep step) { m_state.set_done(step, m_mutex); throw_if_canceled(); }
bool invalidate_step(PrintStep step);
bool invalidate_all_steps() { return m_state.invalidate_all(m_mutex, m_cancel_callback); }
@@ -473,7 +474,7 @@ private:
// Mutex used for synchronization of the worker thread with the UI thread:
// The mutex will be used to guard the worker thread against entering a stage
// while the data influencing the stage is modified.
- tbb::mutex m_mutex;
+ mutable tbb::mutex m_mutex;
// Has the calculation been canceled?
tbb::atomic<bool> m_canceled;
diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp
index 96c831157..7882c58a8 100644
--- a/xs/src/libslic3r/PrintObject.cpp
+++ b/xs/src/libslic3r/PrintObject.cpp
@@ -59,8 +59,19 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Bounding
this->layer_height_profile = model_object->layer_height_profile;
}
+void PrintObject::set_started(PrintObjectStep step)
+{
+ m_state.set_started(step, m_print->m_mutex);
+}
+
+void PrintObject::set_done(PrintObjectStep step)
+{
+ m_state.set_done(step, m_print->m_mutex);
+}
+
bool PrintObject::add_copy(const Vec2d &point)
{
+ tbb::mutex::scoped_lock lock(m_print->m_mutex);
Points points = m_copies;
points.push_back(Point::new_scale(point(0), point(1)));
return this->set_copies(points);
@@ -68,6 +79,7 @@ bool PrintObject::add_copy(const Vec2d &point)
bool PrintObject::delete_last_copy()
{
+ tbb::mutex::scoped_lock lock(m_print->m_mutex);
Points points = m_copies;
points.pop_back();
return this->set_copies(points);
@@ -158,7 +170,6 @@ void PrintObject::make_perimeters()
m_print->throw_if_canceled();
}
this->typed_slices = false;
-// m_state.invalidate(posPrepareInfill);
}
// compare each layer to the one below, and mark those slices needing
diff --git a/xs/src/libslic3r/Utils.hpp b/xs/src/libslic3r/Utils.hpp
index f1390b8a2..dd05891dd 100644
--- a/xs/src/libslic3r/Utils.hpp
+++ b/xs/src/libslic3r/Utils.hpp
@@ -43,6 +43,14 @@ extern local_encoded_string encode_path(const char *src);
extern std::string decode_path(const char *src);
extern std::string normalize_utf8_nfc(const char *src);
+// Safely rename a file even if the target exists.
+// On Windows, the file explorer (or anti-virus or whatever else) often locks the file
+// for a short while, so the file may not be movable. Retry while we see recoverable errors.
+extern int rename_file(const std::string &from, const std::string &to);
+
+// Copy a file, adjust the access attributes, so that the target is writable.
+extern int copy_file(const std::string &from, const std::string &to);
+
// File path / name / extension splitting utilities, working with UTF-8,
// to be published to Perl.
namespace PerlUtils {
diff --git a/xs/src/libslic3r/utils.cpp b/xs/src/libslic3r/utils.cpp
index 95aaf5453..4c2d65605 100644
--- a/xs/src/libslic3r/utils.cpp
+++ b/xs/src/libslic3r/utils.cpp
@@ -23,6 +23,7 @@
#include <boost/nowide/fstream.hpp>
#include <boost/nowide/integration/filesystem.hpp>
#include <boost/nowide/convert.hpp>
+#include <boost/nowide/cstdio.hpp>
namespace Slic3r {
@@ -139,6 +140,87 @@ const std::string& data_dir()
return g_data_dir;
}
+
+// borrowed from LVVM lib/Support/Windows/Path.inc
+int rename_file(const std::string &from, const std::string &to)
+{
+ int ec = 0;
+
+#ifdef _WIN32
+
+ // Convert to utf-16.
+ std::wstring wide_from = boost::nowide::widen(from);
+ std::wstring wide_to = boost::nowide::widen(to);
+
+ // Retry while we see recoverable errors.
+ // System scanners (eg. indexer) might open the source file when it is written
+ // and closed.
+ bool TryReplace = true;
+
+ // This loop may take more than 2000 x 1ms to finish.
+ for (int i = 0; i < 2000; ++ i) {
+ if (i > 0)
+ // Sleep 1ms
+ ::Sleep(1);
+ if (TryReplace) {
+ // Try ReplaceFile first, as it is able to associate a new data stream
+ // with the destination even if the destination file is currently open.
+ if (::ReplaceFileW(wide_to.data(), wide_from.data(), NULL, 0, NULL, NULL))
+ return 0;
+ DWORD ReplaceError = ::GetLastError();
+ ec = -1; // ReplaceError
+ // If ReplaceFileW returned ERROR_UNABLE_TO_MOVE_REPLACEMENT or
+ // ERROR_UNABLE_TO_MOVE_REPLACEMENT_2, retry but only use MoveFileExW().
+ if (ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT ||
+ ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT_2) {
+ TryReplace = false;
+ continue;
+ }
+ // If ReplaceFileW returned ERROR_UNABLE_TO_REMOVE_REPLACED, retry
+ // using ReplaceFileW().
+ if (ReplaceError == ERROR_UNABLE_TO_REMOVE_REPLACED)
+ continue;
+ // We get ERROR_FILE_NOT_FOUND if the destination file is missing.
+ // MoveFileEx can handle this case.
+ if (ReplaceError != ERROR_ACCESS_DENIED && ReplaceError != ERROR_FILE_NOT_FOUND && ReplaceError != ERROR_SHARING_VIOLATION)
+ break;
+ }
+ if (::MoveFileExW(wide_from.c_str(), wide_to.c_str(), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING))
+ return 0;
+ DWORD MoveError = ::GetLastError();
+ ec = -1; // MoveError
+ if (MoveError != ERROR_ACCESS_DENIED && MoveError != ERROR_SHARING_VIOLATION)
+ break;
+ }
+
+#else
+
+ boost::nowide::remove(from.c_str());
+ ec = boost::nowide::rename(from.c_str(), to.c_str());
+
+#endif
+
+ return ec;
+}
+
+int copy_file(const std::string &from, const std::string &to)
+{
+ const boost::filesystem::path source(from);
+ const boost::filesystem::path target(to);
+ static const auto perms = boost::filesystem::owner_read | boost::filesystem::owner_write | boost::filesystem::group_read | boost::filesystem::others_read; // aka 644
+
+ // Make sure the file has correct permission both before and after we copy over it.
+ try {
+ if (boost::filesystem::exists(target))
+ boost::filesystem::permissions(target, perms);
+ boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists);
+ boost::filesystem::permissions(target, perms);
+ } catch (std::exception & /* ex */) {
+ return -1;
+ }
+ return 0;
+}
+
} // namespace Slic3r
#include <xsinit.h>
diff --git a/xs/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/xs/src/slic3r/GUI/BackgroundSlicingProcess.cpp
index 47da3367c..2f88b25ca 100644
--- a/xs/src/slic3r/GUI/BackgroundSlicingProcess.cpp
+++ b/xs/src/slic3r/GUI/BackgroundSlicingProcess.cpp
@@ -3,6 +3,7 @@
#include <wx/event.h>
#include <wx/panel.h>
+#include <wx/stdpaths.h>
// Print now includes tbb, and tbb includes Windows. This breaks compilation of wxWidgets if included before wx.
#include "../../libslic3r/Print.hpp"
@@ -11,12 +12,28 @@
#include <cassert>
#include <stdexcept>
+#include <boost/format.hpp>
+#include <boost/nowide/cstdio.hpp>
+
namespace Slic3r {
namespace GUI {
extern wxPanel *g_wxPlater;
};
+BackgroundSlicingProcess::BackgroundSlicingProcess()
+{
+ m_temp_output_path = wxStandardPaths::Get().GetTempDir().utf8_str().data();
+ m_temp_output_path += (boost::format(".%1%.gcode") % get_current_pid()).str();
+}
+
+BackgroundSlicingProcess::~BackgroundSlicingProcess()
+{
+ this->stop();
+ this->join_background_thread();
+ boost::nowide::remove(m_temp_output_path.c_str());
+}
+
void BackgroundSlicingProcess::thread_proc()
{
std::unique_lock<std::mutex> lck(m_mutex);
@@ -41,7 +58,10 @@ void BackgroundSlicingProcess::thread_proc()
m_print->process();
if (! m_print->canceled()) {
wxQueueEvent(GUI::g_wxPlater, new wxCommandEvent(m_event_sliced_id));
- m_print->export_gcode(m_output_path, m_gcode_preview_data);
+ m_print->export_gcode(m_temp_output_path, m_gcode_preview_data);
+ if (! m_print->canceled() && ! m_output_path.empty() &&
+ copy_file(m_temp_output_path, m_output_path) != 0)
+ throw std::runtime_error("Copying of the temporary G-code to the output G-code failed");
}
} catch (CanceledException &ex) {
// Canceled, this is all right.
@@ -111,8 +131,10 @@ bool BackgroundSlicingProcess::start()
bool BackgroundSlicingProcess::stop()
{
std::unique_lock<std::mutex> lck(m_mutex);
- if (m_state == STATE_INITIAL)
+ if (m_state == STATE_INITIAL) {
+ this->m_output_path.clear();
return false;
+ }
assert(this->running());
if (m_state == STATE_STARTED || m_state == STATE_RUNNING) {
m_print->cancel();
@@ -124,6 +146,7 @@ bool BackgroundSlicingProcess::stop()
// In the "Finished" or "Canceled" state. Reset the state to "Idle".
m_state = STATE_IDLE;
}
+ this->m_output_path.clear();
return true;
}
diff --git a/xs/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/xs/src/slic3r/GUI/BackgroundSlicingProcess.hpp
index 358e00ca9..cc7a6db30 100644
--- a/xs/src/slic3r/GUI/BackgroundSlicingProcess.hpp
+++ b/xs/src/slic3r/GUI/BackgroundSlicingProcess.hpp
@@ -17,9 +17,9 @@ class Print;
class BackgroundSlicingProcess
{
public:
- BackgroundSlicingProcess() {}
- // Stop the background processing and finalize the bacgkround processing thread.
- ~BackgroundSlicingProcess() { this->stop(); this->join_background_thread(); }
+ BackgroundSlicingProcess();
+ // Stop the background processing and finalize the bacgkround processing thread, remove temp files.
+ ~BackgroundSlicingProcess();
void set_print(Print *print) { m_print = print; }
void set_gcode_preview_data(GCodePreviewData *gpd) { m_gcode_preview_data = gpd; }
@@ -31,6 +31,8 @@ public:
// The wxCommandEvent is sent to the UI thread asynchronously without waiting for the event to be processed.
void set_finished_event(int event_id) { m_event_finished_id = event_id; }
+ // Set the output path of the G-code.
+ void set_output_path(const std::string &path) { m_output_path = path; }
// Start the background processing. Returns false if the background processing was already running.
bool start();
// Cancel the background processing. Returns false if the background processing was not running.
@@ -68,6 +70,7 @@ private:
Print *m_print = nullptr;
// Data structure, to which the G-code export writes its annotations.
GCodePreviewData *m_gcode_preview_data = nullptr;
+ std::string m_temp_output_path;
std::string m_output_path;
// Thread, on which the background processing is executed. The thread will always be present
// and ready to execute the slicing process.
diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp
index 2aaa4aed9..ae42f014b 100644
--- a/xs/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp
@@ -5208,9 +5208,9 @@ void GLCanvas3D::_load_shells()
// adds objects' volumes
unsigned int object_id = 0;
- for (PrintObject* obj : m_print->objects())
+ for (const PrintObject* obj : m_print->objects())
{
- ModelObject* model_obj = obj->model_object();
+ const ModelObject* model_obj = obj->model_object();
std::vector<int> instance_ids(model_obj->instances.size());
for (int i = 0; i < (int)model_obj->instances.size(); ++i)
diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index af57db8ed..0c7b7a5d8 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -383,13 +383,10 @@ void update_after_moving()
if (volume_id < 0)
return;
- Vec3d m = m_move_options;
- Vec3d l = m_last_coords;
-
- auto d = Vec3d(m(0) - l(0), m(1) - l(1), m(2) - l(2));
- auto volume = (*m_objects)[m_selected_object_id]->volumes[volume_id];
+ auto d = m_move_options - m_last_coords;
+ auto volume = (*m_objects)[m_selected_object_id]->volumes[volume_id];
volume->mesh.translate(d(0), d(1), d(2));
- m_last_coords = m;
+ m_last_coords = m_move_options;
m_parts_changed = true;
parts_changed(m_selected_object_id);
diff --git a/xs/src/slic3r/GUI/ProgressIndicator.hpp b/xs/src/slic3r/GUI/ProgressIndicator.hpp
new file mode 100644
index 000000000..106f5e7ea
--- /dev/null
+++ b/xs/src/slic3r/GUI/ProgressIndicator.hpp
@@ -0,0 +1,72 @@
+#ifndef IPROGRESSINDICATOR_HPP
+#define IPROGRESSINDICATOR_HPP
+
+#include <string>
+#include <functional>
+
+#include <wx/string.h>
+
+namespace Slic3r {
+
+/**
+ * @brief Generic progress indication interface.
+ */
+class ProgressIndicator {
+public:
+ using CancelFn = std::function<void(void)>; // Cancel function signature.
+
+private:
+ float state_ = .0f, max_ = 1.f, step_;
+ CancelFn cancelfunc_ = [](){};
+
+public:
+
+ inline virtual ~ProgressIndicator() {}
+
+ /// Get the maximum of the progress range.
+ float max() const { return max_; }
+
+ /// Get the current progress state
+ float state() const { return state_; }
+
+ /// Set the maximum of the progress range
+ virtual void max(float maxval) { max_ = maxval; }
+
+ /// Set the current state of the progress.
+ virtual void state(float val) { state_ = val; }
+
+ /**
+ * @brief Number of states int the progress. Can be used instead of giving a
+ * maximum value.
+ */
+ virtual void states(unsigned statenum) {
+ step_ = max_ / statenum;
+ }
+
+ /// Message shown on the next status update.
+ virtual void message(const wxString&) = 0;
+
+ /// Title of the operation.
+ virtual void title(const wxString&) = 0;
+
+ /// Formatted message for the next status update. Works just like sprintf.
+ virtual void message_fmt(const wxString& fmt, ...);
+
+ /// Set up a cancel callback for the operation if feasible.
+ virtual void on_cancel(CancelFn func = CancelFn()) { cancelfunc_ = func; }
+
+ /**
+ * Explicitly shut down the progress indicator and call the associated
+ * callback.
+ */
+ virtual void cancel() { cancelfunc_(); }
+
+ /// Convenience function to call message and status update in one function.
+ void update(float st, const wxString& msg) {
+ message(msg); state(st);
+ }
+};
+
+}
+
+#endif // IPROGRESSINDICATOR_HPP
diff --git a/xs/xsp/GUI_BackgroundSlicingProcess.xsp b/xs/xsp/GUI_BackgroundSlicingProcess.xsp
index cef9f6d58..8452b8c31 100644
--- a/xs/xsp/GUI_BackgroundSlicingProcess.xsp
+++ b/xs/xsp/GUI_BackgroundSlicingProcess.xsp
@@ -15,6 +15,7 @@
void set_sliced_event(int event_id);
void set_finished_event(int event_id);
+ void set_output_path(const char *path);
bool start();
bool stop();
bool apply_config(DynamicPrintConfig *config)