diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index f87d7d309..3732697ed 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -837,6 +837,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co enum Status { Unknown, Deleted, + Reused, New }; PrintObjectStatus(PrintObject *print_object, Status status = Unknown) : @@ -931,6 +932,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co { std::vector print_objects_new; print_objects_new.reserve(std::max(m_objects.size(), m_model.objects.size())); + bool new_objects = false; // Walk over all new model objects and check, whether there are matching PrintObjects. for (ModelObject *model_object : m_model.objects) { auto range = print_object_status.equal_range(PrintObjectStatus(model_object->id())); @@ -953,7 +955,8 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co print_object->set_copies(print_instances.copies); print_object->config_apply(config); print_objects_new.emplace_back(print_object); - print_object_status.emplace(PrintObjectStatus(print_object, PrintObjectStatus::New)); + // print_object_status.emplace(PrintObjectStatus(print_object, PrintObjectStatus::New)); + new_objects = true; } continue; } @@ -971,7 +974,10 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co print_object->set_copies(new_instances.copies); print_object->config_apply(config); print_objects_new.emplace_back(print_object); - print_object_status.emplace(PrintObjectStatus(print_object, PrintObjectStatus::New)); + // print_object_status.emplace(PrintObjectStatus(print_object, PrintObjectStatus::New)); + new_objects = true; + if (it_old != old.end()) + const_cast(*it_old)->status = PrintObjectStatus::Deleted; } else if ((*it_old)->print_object->copies() != new_instances.copies) { // The PrintObject already exists and the copies differ. if ((*it_old)->print_object->copies().size() != new_instances.copies.size()) @@ -979,14 +985,26 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co update_apply_status(this->invalidate_step(psSkirt) || this->invalidate_step(psBrim) || this->invalidate_step(psGCodeExport)); (*it_old)->print_object->set_copies(new_instances.copies); print_objects_new.emplace_back((*it_old)->print_object); + const_cast(*it_old)->status = PrintObjectStatus::Reused; } } } if (m_objects != print_objects_new) { m_cancel_callback(); m_objects = print_objects_new; - update_apply_status(false); + // Delete the PrintObjects marked as Unknown or Deleted. + bool deleted_objects = false; + for (auto &pos : print_object_status) + if (pos.status == PrintObjectStatus::Unknown || pos.status == PrintObjectStatus::Deleted) { + // update_apply_status(pos.print_object->invalidate_all_steps()); + delete pos.print_object; + deleted_objects = true; + } + if (deleted_objects) + update_apply_status(this->invalidate_step(psSkirt) || this->invalidate_step(psBrim) || this->invalidate_step(psWipeTower) || this->invalidate_step(psGCodeExport)); + update_apply_status(new_objects); } + print_object_status.clear(); } // 5) Synchronize configs of ModelVolumes, synchronize AMF / 3MF materials (and their configs), refresh PrintRegions. diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 767106336..514cc0e0f 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -485,11 +485,22 @@ public: // the state of the finished or running calculations. void set_cancel_callback(cancel_callback_type cancel_callback) { m_cancel_callback = cancel_callback; } // Has the calculation been canceled? - bool canceled() const { return m_canceled; } + enum CancelStatus { + // No cancelation, background processing should run. + NOT_CANCELED = 0, + // Canceled by user from the user interface (user pressed the "Cancel" button or user closed the application). + CANCELED_BY_USER = 1, + // Canceled internally from Print::apply() through the Print/PrintObject::invalidate_step() or ::invalidate_all_steps(). + CANCELED_INTERNAL = 2 + }; + CancelStatus cancel_status() const { return m_cancel_status; } + // Has the calculation been canceled? + bool canceled() const { return m_cancel_status; } // Cancel the running computation. Stop execution of all the background threads. - void cancel() { m_canceled = true; } + void cancel() { m_cancel_status = CANCELED_BY_USER; } + void cancel_internal() { m_cancel_status = CANCELED_INTERNAL; } // Cancel the running computation. Stop execution of all the background threads. - void restart() { m_canceled = false; } + void restart() { m_cancel_status = NOT_CANCELED; } // Accessed by SupportMaterial const PrintRegion* get_region(size_t idx) const { return m_regions[idx]; } @@ -513,7 +524,7 @@ private: // If the background processing stop was requested, throw CanceledException. // To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly. - void throw_if_canceled() const { if (m_canceled) throw CanceledException(); } + void throw_if_canceled() const { if (m_cancel_status) throw CanceledException(); } void _make_skirt(); void _make_brim(); @@ -526,8 +537,7 @@ private: // while the data influencing the stage is modified. mutable tbb::mutex m_mutex; - // Has the calculation been canceled? - tbb::atomic m_canceled; + tbb::atomic m_cancel_status; // Callback to be evoked regularly to update state of the UI thread. status_callback_type m_status_callback; diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 17d290db7..ce65acd5f 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -84,10 +84,14 @@ void BackgroundSlicingProcess::thread_proc() } lck.lock(); m_state = m_print->canceled() ? STATE_CANCELED : STATE_FINISHED; - wxCommandEvent evt(m_event_finished_id); - evt.SetString(error); - evt.SetInt(m_print->canceled() ? -1 : (error.empty() ? 1 : 0)); - wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, evt.Clone()); + if (m_print->cancel_status() != Print::CANCELED_INTERNAL) { + // Only post the canceled event, if canceled by user. + // Don't post the canceled event, if canceled from Print::apply(). + wxCommandEvent evt(m_event_finished_id); + evt.SetString(error); + evt.SetInt(m_print->canceled() ? -1 : (error.empty() ? 1 : 0)); + wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, evt.Clone()); + } m_print->restart(); lck.unlock(); // Let the UI thread wake up if it is waiting for the background task to finish. @@ -134,7 +138,7 @@ bool BackgroundSlicingProcess::start() if (! this->idle()) throw std::runtime_error("Cannot start a background task, the worker thread is not idle."); m_state = STATE_STARTED; - m_print->set_cancel_callback([this](){ this->stop(); }); + m_print->set_cancel_callback([this](){ this->stop_internal(); }); lck.unlock(); m_condition.notify_one(); return true; @@ -164,6 +168,23 @@ bool BackgroundSlicingProcess::stop() return true; } +// To be called by Print::apply() through the Print::m_cancel_callback to stop the background +// processing before changing any data of running or finalized milestones. +// This function shall not trigger any UI update through the wxWidgets event. +void BackgroundSlicingProcess::stop_internal() +{ + std::unique_lock lck(m_mutex); + assert(m_state == STATE_STARTED || m_state == STATE_RUNNING || m_state == STATE_FINISHED || m_state == STATE_CANCELED); + if (m_state == STATE_STARTED || m_state == STATE_RUNNING) { + m_print->cancel_internal(); + // Wait until the background processing stops by being canceled. + m_condition.wait(lck, [this](){ return m_state == STATE_CANCELED; }); + } + // In the "Canceled" state. Reset the state to "Idle". + m_state = STATE_IDLE; + m_print->set_cancel_callback([](){}); +} + // Apply config over the print. Returns false, if the new config values caused any of the already // processed steps to be invalidated, therefore the task will need to be restarted. bool BackgroundSlicingProcess::apply_config(const DynamicPrintConfig &config) diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index dab40d3a8..f00668299 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -81,6 +81,10 @@ public: private: void thread_proc(); void join_background_thread(); + // To be called by Print::apply() through the Print::m_cancel_callback to stop the background + // processing before changing any data of running or finalized milestones. + // This function shall not trigger any UI update through the wxWidgets event. + void stop_internal(); Print *m_print = nullptr; // Data structure, to which the G-code export writes its annotations.