From cc73ff8f4f413067875924263adfab57301128bb Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 9 Oct 2024 12:33:59 +0200 Subject: [PATCH] Multiple beds (part 7): This is where it really gets nasty: - Switch background_process.m_temp_output_path is now updated when beds are switched, so each Print writes to a different file. - When switching beds in Preview, there is a cache in GCodeViewer which would mistakenly not load the other preview (happens in case when switching to a bed which is not sliced and back). Bypass this cache when beds are being switched. - Added a CallAfter logic into GLCanvas3D::select_bed (the central function where beds are switched). It now does the following: 1. Stops the background process 2. Schedules a callafter which then 3. wxYields the event queue (so all events generated as a result of (1) are consumed before active bed is switched. 4. switches active bed 5. fires couple of update functions and events, schedules background process - When BSProcess is switched to the new bed, it now calls on_slicing_update (in sync). This is to regenerate all slicing error/warning notifications. The on_slicing_update function was updated to be able to process all print(object)steps and objects. - Sliced info in sidebar did not properly show when switching beds in 3D scene. Added explicit refresh into update_background_process. --- src/libslic3r/MultipleBeds.cpp | 1 + src/libslic3r/MultipleBeds.hpp | 1 + src/slic3r/GUI/BackgroundSlicingProcess.cpp | 18 +++- src/slic3r/GUI/BackgroundSlicingProcess.hpp | 2 +- src/slic3r/GUI/GCodeViewer.cpp | 2 +- src/slic3r/GUI/GLCanvas3D.cpp | 25 +++-- src/slic3r/GUI/GLCanvas3D.hpp | 2 + src/slic3r/GUI/Plater.cpp | 108 ++++++++++++++------ 8 files changed, 116 insertions(+), 43 deletions(-) diff --git a/src/libslic3r/MultipleBeds.cpp b/src/libslic3r/MultipleBeds.cpp index cca72e2483..b42fb01887 100644 --- a/src/libslic3r/MultipleBeds.cpp +++ b/src/libslic3r/MultipleBeds.cpp @@ -9,6 +9,7 @@ namespace Slic3r { MultipleBeds s_multiple_beds; bool s_reload_preview_after_switching_beds = false; +bool s_beds_just_switched = false; diff --git a/src/libslic3r/MultipleBeds.hpp b/src/libslic3r/MultipleBeds.hpp index 5527b8f65a..49c9b2b4ba 100644 --- a/src/libslic3r/MultipleBeds.hpp +++ b/src/libslic3r/MultipleBeds.hpp @@ -14,6 +14,7 @@ class BuildVolume; class PrintBase; extern bool s_reload_preview_after_switching_beds; +extern bool s_beds_just_switched; class MultipleBeds { public: diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 8beb7e195c..67df537d5c 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -102,10 +102,10 @@ std::pair SlicingProcessCompletedEvent::format_error_message( return std::make_pair(std::move(error), monospace); } -BackgroundSlicingProcess::BackgroundSlicingProcess() +void BackgroundSlicingProcess::set_temp_output_path(int bed_idx) { boost::filesystem::path temp_path(wxStandardPaths::Get().GetTempDir().utf8_str().data()); - temp_path /= (boost::format(".%1%.gcode") % get_current_pid()).str(); + temp_path /= (boost::format(".%1%_%2%.gcode") % get_current_pid() % bed_idx).str(); m_temp_output_path = temp_path.string(); } @@ -113,7 +113,19 @@ BackgroundSlicingProcess::~BackgroundSlicingProcess() { this->stop(); this->join_background_thread(); - boost::nowide::remove(m_temp_output_path.c_str()); + + // Current m_temp_output_path corresponds to the last selected bed. Remove everything + // in the same directory that starts the same (see set_temp_output_path). + const auto temp_dir = boost::filesystem::path(m_temp_output_path).parent_path(); + std::string prefix = boost::filesystem::path(m_temp_output_path).filename().string(); + prefix = prefix.substr(0, prefix.find('_')); + for (const auto& entry : boost::filesystem::directory_iterator(temp_dir)) { + if (entry.is_regular_file()) { + const std::string filename = entry.path().filename().string(); + if (boost::starts_with(filename, prefix) && boost::ends_with(filename, ".gcode")) + boost::filesystem::remove(entry); + } + } } bool BackgroundSlicingProcess::select_technology(PrinterTechnology tech) diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index 1c0a73631f..7a8e53cfeb 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -83,10 +83,10 @@ enum BackgroundSlicingProcessStep { class BackgroundSlicingProcess { public: - BackgroundSlicingProcess(); // Stop the background processing and finalize the bacgkround processing thread, remove temp files. ~BackgroundSlicingProcess(); + void set_temp_output_path(int bed_idx); void set_fff_print(Print* print) { if (m_fff_print != print) stop(); m_fff_print = print; } void set_sla_print(SLAPrint *print) { if (m_sla_print != print) stop(); m_sla_print = print; } void set_thumbnail_cb(ThumbnailsGeneratorCallback cb) { m_thumbnail_cb = cb; } diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 679d43ad34..1405912910 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -870,7 +870,7 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const m_viewer.toggle_top_layer_only_view_range(); // avoid processing if called with the same gcode_result - if (m_last_result_id == gcode_result.id && wxGetApp().is_editor()) { + if (m_last_result_id == gcode_result.id && wxGetApp().is_editor() && ! s_reload_preview_after_switching_beds) { // collect tool colors libvgcode::Palette tools_colors; tools_colors.reserve(str_tool_colors.size()); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 42a05135bf..6fe4e233ef 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -102,19 +102,28 @@ static bool show_imgui_demo_window = false; namespace Slic3r { namespace GUI { -static void select_bed(int i) +void GLCanvas3D::select_bed(int i) { int old_bed = s_multiple_beds.get_active_bed(); if (i == old_bed || i == -1) return; + wxGetApp().plater()->canvas3D()->m_process->stop(); - s_multiple_beds.set_active_bed(i); - if (wxGetApp().plater()->is_preview_shown()) { - s_reload_preview_after_switching_beds = true; - wxPostEvent(wxGetApp().plater(), SimpleEvent(EVT_GLVIEWTOOLBAR_PREVIEW)); - wxGetApp().plater()->get_camera().translate_world(s_multiple_beds.get_bed_translation(i) - s_multiple_beds.get_bed_translation(old_bed)); - } - wxGetApp().plater()->sidebar().update_sliced_info_sizer(); + // The stop call above schedules some events that would be processed after the switch. + // Among else, on_process_completed would be called, which would stop slicing of + // the new bed. We need to stop the process, pump all the events out of the queue + // and then switch the beds. + wxGetApp().CallAfter([i, old_bed]() { + wxYield(); + s_multiple_beds.set_active_bed(i); + s_beds_just_switched = true; + if (wxGetApp().plater()->is_preview_shown()) { + s_reload_preview_after_switching_beds = true; + wxPostEvent(wxGetApp().plater(), SimpleEvent(EVT_GLVIEWTOOLBAR_PREVIEW)); + wxGetApp().plater()->get_camera().translate_world(s_multiple_beds.get_bed_translation(i) - s_multiple_beds.get_bed_translation(old_bed)); + } + wxGetApp().plater()->schedule_background_process(); + }); } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index f96a958991..bae830f9e2 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -732,6 +732,8 @@ private: // returns the containment state in the given out_state, if non-null bool check_volumes_outside_state(GLVolumeCollection& volumes, ModelInstanceEPrintVolumeState* out_state, bool selection_only = true) const; + void select_bed(int i); + public: void init_gcode_viewer() { m_gcode_viewer.init(); } void reset_gcode_toolpaths() { m_gcode_viewer.reset(); } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index a7e64a77e0..e8442a811a 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2119,11 +2119,23 @@ void Plater::priv::process_validation_warning(const std::vector& wa // Returns a bitmask of UpdateBackgroundProcessReturnState. unsigned int Plater::priv::update_background_process(bool force_validation, bool postpone_error_messages) { + assert(! s_beds_just_switched || background_process.idle()); + int active_bed = s_multiple_beds.get_active_bed(); + background_process.set_temp_output_path(active_bed); background_process.set_fff_print(fff_prints[active_bed].get()); background_process.set_sla_print(sla_prints[active_bed].get()); background_process.set_gcode_result(&gcode_results[active_bed]); background_process.select_technology(this->printer_technology); + + if (s_beds_just_switched) { + PrintBase::SlicingStatus status(q->active_fff_print(), -1); + SlicingStatusEvent evt(EVT_SLICING_UPDATE, 0, status); + on_slicing_update(evt); + s_beds_just_switched = false; + notification_manager->close_notification_of_type(NotificationType::ExportOngoing); + q->sidebar().show_sliced_info_sizer(background_process.finished()); + } // bitmap of enum UpdateBackgroundProcessReturnState @@ -2884,11 +2896,12 @@ void Plater::priv::set_current_panel(wxPanel* panel) bool force_render = (current_panel != nullptr); #endif // __WXMAC__ + ScopeGuard guard([]() { s_reload_preview_after_switching_beds = false; }); if (current_panel == panel) { if (! s_reload_preview_after_switching_beds) return; else - s_reload_preview_after_switching_beds = false; + update_background_process(); } wxPanel* old_panel = current_panel; @@ -3036,36 +3049,71 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) this->preview->reload_print(); } - if ((evt.status.flags & PrintBase::SlicingStatus::UPDATE_PRINT_STEP_WARNINGS) && - static_cast(evt.status.warning_step) == psAlertWhenSupportsNeeded && - !get_app_config()->get_bool("alert_when_supports_needed")) { - // This alerts are from psAlertWhenSupportsNeeded and the respective app settings is not Enabled, so discard the alerts. - } else if (evt.status.flags & - (PrintBase::SlicingStatus::UPDATE_PRINT_STEP_WARNINGS | PrintBase::SlicingStatus::UPDATE_PRINT_OBJECT_STEP_WARNINGS)) { - // Update notification center with warnings of object_id and its warning_step. - ObjectID object_id = evt.status.warning_object_id; - int warning_step = evt.status.warning_step; - PrintStateBase::StateWithWarnings state; - if (evt.status.flags & PrintBase::SlicingStatus::UPDATE_PRINT_STEP_WARNINGS) { - // LUKAS state = this->printer_technology == ptFFF ? - //this->fff_print.step_state_with_warnings(static_cast(warning_step)) : - //this->sla_print.step_state_with_warnings(static_cast(warning_step)); - } else if (this->printer_technology == ptFFF) { - //LUKAS const PrintObject *print_object = this->fff_print.get_object(object_id); - //if (print_object) - // state = print_object->step_state_with_warnings(static_cast(warning_step)); - } else { - // LUKAS const SLAPrintObject *print_object = this->sla_print.get_object(object_id); - // if (print_object) - // state = print_object->step_state_with_warnings(static_cast(warning_step)); + + std::vector object_ids = { evt.status.warning_object_id }; + std::vector warning_steps = { evt.status.warning_step }; + std::vector flagss = { int(evt.status.flags) }; + + if (warning_steps.front() == -1) { + flagss = { PrintBase::SlicingStatus::UPDATE_PRINT_STEP_WARNINGS, PrintBase::SlicingStatus::UPDATE_PRINT_OBJECT_STEP_WARNINGS }; + notification_manager->close_slicing_errors_and_warnings(); + } + + for (int flags : flagss ) { + if (warning_steps.front() == -1) { + warning_steps.clear(); + if (flags == PrintBase::SlicingStatus::UPDATE_PRINT_STEP_WARNINGS) { + int i = 0; + while (i < int(psCount)) { warning_steps.push_back(i); ++i; } + } else { + int i = 0; + while (i < int(posCount)) { warning_steps.push_back(i); ++i; } + for (const PrintObject* po : wxGetApp().plater()->active_fff_print().objects()) + object_ids.push_back(po->id()); + } + } + + + + + + for (int warning_step : warning_steps) { + for (ObjectID object_id : object_ids) { + if ((flags & PrintBase::SlicingStatus::UPDATE_PRINT_STEP_WARNINGS) && + static_cast(warning_step) == psAlertWhenSupportsNeeded && + !get_app_config()->get_bool("alert_when_supports_needed")) { + // This alerts are from psAlertWhenSupportsNeeded and the respective app settings is not Enabled, so discard the alerts. + } + else if (flags & + (PrintBase::SlicingStatus::UPDATE_PRINT_STEP_WARNINGS | PrintBase::SlicingStatus::UPDATE_PRINT_OBJECT_STEP_WARNINGS)) { + // Update notification center with warnings of object_id and its warning_step. + + PrintStateBase::StateWithWarnings state; + if (flags & PrintBase::SlicingStatus::UPDATE_PRINT_STEP_WARNINGS) { + state = this->printer_technology == ptFFF ? + q->active_fff_print().step_state_with_warnings(static_cast(warning_step)) : + q->active_sla_print().step_state_with_warnings(static_cast(warning_step)); + } + else if (this->printer_technology == ptFFF) { + const PrintObject* print_object = q->active_fff_print().get_object(object_id); + if (print_object) + state = print_object->step_state_with_warnings(static_cast(warning_step)); + } + else { + const SLAPrintObject* print_object = q->active_sla_print().get_object(object_id); + if (print_object) + state = print_object->step_state_with_warnings(static_cast(warning_step)); + } + // Now process state.warnings. + for (auto const& warning : state.warnings) { + if (warning.current) { + notification_manager->push_slicing_warning_notification(warning.message, false, object_id, warning_step); + add_warning(warning, object_id.id); + } + } + } + } } - // Now process state.warnings. - for (auto const& warning : state.warnings) { - if (warning.current) { - notification_manager->push_slicing_warning_notification(warning.message, false, object_id, warning_step); - add_warning(warning, object_id.id); - } - } } }