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.
This commit is contained in:
Lukas Matena 2024-10-09 12:33:59 +02:00
parent 87a1fe8c65
commit cc73ff8f4f
8 changed files with 116 additions and 43 deletions

View File

@ -9,6 +9,7 @@ namespace Slic3r {
MultipleBeds s_multiple_beds;
bool s_reload_preview_after_switching_beds = false;
bool s_beds_just_switched = false;

View File

@ -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:

View File

@ -102,10 +102,10 @@ std::pair<std::string, bool> 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)

View File

@ -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; }

View File

@ -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());

View File

@ -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();
});
}

View File

@ -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(); }

View File

@ -2119,11 +2119,23 @@ void Plater::priv::process_validation_warning(const std::vector<std::string>& 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<PrintStep>(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<PrintStep>(warning_step)) :
//this->sla_print.step_state_with_warnings(static_cast<SLAPrintStep>(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<PrintObjectStep>(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<SLAPrintObjectStep>(warning_step));
std::vector<ObjectID> object_ids = { evt.status.warning_object_id };
std::vector<int> warning_steps = { evt.status.warning_step };
std::vector<int> 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<PrintStep>(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<PrintStep>(warning_step)) :
q->active_sla_print().step_state_with_warnings(static_cast<SLAPrintStep>(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<PrintObjectStep>(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<SLAPrintObjectStep>(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);
}
}
}
}