Autoslice (part 1)

This commit is contained in:
Lukas Matena 2024-11-06 09:06:38 +01:00
parent 0bd37e6b08
commit e1be0f041c
6 changed files with 166 additions and 60 deletions

View File

@ -318,6 +318,44 @@ void MultipleBeds::ensure_wipe_towers_on_beds(Model& model, const std::vector<st
} }
} }
#ifdef SLIC3R_GUI
void MultipleBeds::start_autoslice(std::function<void(int, bool)> select_bed_fn)
{
if (is_autoslicing())
return;
m_select_bed_fn = select_bed_fn;
m_autoslicing_original_bed = get_active_bed();
m_autoslicing = true;
}
void MultipleBeds::stop_autoslice(bool restore_original)
{
if (! is_autoslicing())
return;
m_autoslicing = false;
if (restore_original)
m_select_bed_fn(m_autoslicing_original_bed, false);
}
void MultipleBeds::autoslice_next_bed()
{
if (! is_autoslicing())
return;
int next_bed = s_multiple_beds.get_active_bed() + 1;
if (next_bed >= s_multiple_beds.get_number_of_beds())
next_bed = 0;
m_select_bed_fn(next_bed, false);
}
#endif // SLIC3R_GUI
} }

View File

@ -64,6 +64,11 @@ public:
Vec2crd get_bed_gap() const; Vec2crd get_bed_gap() const;
void ensure_wipe_towers_on_beds(Model& model, const std::vector<std::unique_ptr<Print>>& prints); void ensure_wipe_towers_on_beds(Model& model, const std::vector<std::unique_ptr<Print>>& prints);
void start_autoslice(std::function<void(int,bool)>);
void stop_autoslice(bool restore_original);
bool is_autoslicing() const { return m_autoslicing; }
void autoslice_next_bed();
private: private:
bool is_instance_on_active_bed(ObjectID id) const; bool is_instance_on_active_bed(ObjectID id) const;
@ -78,6 +83,9 @@ private:
bool m_legacy_layout = false; bool m_legacy_layout = false;
bool m_loading_project = false; bool m_loading_project = false;
bool m_autoslicing = false;
int m_autoslicing_original_bed = 0;
std::function<void(int, bool)> m_select_bed_fn;
}; };
extern MultipleBeds s_multiple_beds; extern MultipleBeds s_multiple_beds;

View File

@ -102,10 +102,10 @@ static bool show_imgui_demo_window = false;
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
void GLCanvas3D::select_bed(int i) void GLCanvas3D::select_bed(int i, bool triggered_by_user)
{ {
int old_bed = s_multiple_beds.get_active_bed(); int old_bed = s_multiple_beds.get_active_bed();
if (i == old_bed || i == -1) if ((i == old_bed && !s_multiple_beds.is_autoslicing()) || i == -1)
return; return;
wxGetApp().plater()->canvas3D()->m_process->stop(); wxGetApp().plater()->canvas3D()->m_process->stop();
m_sequential_print_clearance.m_evaluating = true; m_sequential_print_clearance.m_evaluating = true;
@ -115,7 +115,7 @@ void GLCanvas3D::select_bed(int i)
// Among else, on_process_completed would be called, which would stop slicing of // 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 // the new bed. We need to stop the process, pump all the events out of the queue
// and then switch the beds. // and then switch the beds.
wxGetApp().CallAfter([i, old_bed]() { wxGetApp().CallAfter([i, old_bed, triggered_by_user]() {
wxYield(); wxYield();
s_multiple_beds.set_active_bed(i); s_multiple_beds.set_active_bed(i);
s_beds_just_switched = true; s_beds_just_switched = true;
@ -125,6 +125,8 @@ void GLCanvas3D::select_bed(int i)
wxGetApp().plater()->get_camera().translate_world(s_multiple_beds.get_bed_translation(i) - s_multiple_beds.get_bed_translation(old_bed)); 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(); wxGetApp().plater()->schedule_background_process();
if (s_multiple_beds.is_autoslicing() && triggered_by_user)
s_multiple_beds.stop_autoslice(false);
}); });
} }
@ -1899,21 +1901,7 @@ void GLCanvas3D::render()
#endif // SHOW_IMGUI_DEMO_WINDOW #endif // SHOW_IMGUI_DEMO_WINDOW
{
if (s_multiple_beds.get_number_of_beds() != 1 && wxGetApp().plater()->is_preview_shown()) {
ImGui::Begin("Bed selector", 0, ImGuiWindowFlags_NoResize);
for (int i = 0; i < s_multiple_beds.get_number_of_beds(); ++i) {
bool inactive = i != s_multiple_beds.get_active_bed();
if (inactive)
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0., 0., 0., .5));
if (ImGui::ImageButton((void*)(int64_t)s_th_tex_id[i], ImVec2(100, 100), ImVec2(0, 1), ImVec2(1, 0)))
select_bed(i);
if (inactive)
ImGui::PopStyleColor();
}
ImGui::End();
}
}
const bool is_looking_downward = camera.is_looking_downward(); const bool is_looking_downward = camera.is_looking_downward();
@ -1922,6 +1910,7 @@ void GLCanvas3D::render()
glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
_render_background(); _render_background();
if (! s_multiple_beds.is_autoslicing()) {
_render_objects(GLVolumeCollection::ERenderType::Opaque); _render_objects(GLVolumeCollection::ERenderType::Opaque);
_render_sla_slices(); _render_sla_slices();
_render_selection(); _render_selection();
@ -1965,10 +1954,73 @@ void GLCanvas3D::render()
if (m_picking_enabled && m_rectangle_selection.is_dragging()) if (m_picking_enabled && m_rectangle_selection.is_dragging())
m_rectangle_selection.render(*this); m_rectangle_selection.render(*this);
} else {
// Autoslicing.
// Render the combined statistics if all is ready.
bool valid = true;
double total_g = 0;
for (size_t i=0; i<s_multiple_beds.get_number_of_beds(); ++i) {
const Print* print = wxGetApp().plater()->get_fff_prints()[i].get();
if (!print->finished()) {
// TODO: Only active bed invalidation can be detected here.
valid = false;
break;
}
total_g += print->print_statistics().total_used_filament;
}
ImGui::Begin("Total stats");
if (valid)
ImGui::Text("%s", std::to_string(total_g).c_str());
else
ImGui::Text("Wait until all beds are sliced...");
ImGui::End();
if (!valid) {
if (fff_print()->finished())
s_multiple_beds.autoslice_next_bed();
else
wxGetApp().plater()->schedule_background_process();
}
}
// draw overlays // draw overlays
_render_overlays(); _render_overlays();
{
if (s_multiple_beds.get_number_of_beds() != 1 && wxGetApp().plater()->is_preview_shown()) {
ImGui::Begin("Bed selector", 0, ImGuiWindowFlags_NoResize);
for (int i = 0; i < s_multiple_beds.get_number_of_beds(); ++i) {
bool inactive = i != s_multiple_beds.get_active_bed() || s_multiple_beds.is_autoslicing();
if (inactive)
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0., 0., 0., .5));
if (bool clicked = (i >= int(s_th_tex_id.size()))
? ImGui::Button(std::to_string(i).c_str(), ImVec2(100,100))
: ImGui::ImageButton((void*)(int64_t)s_th_tex_id[i], ImVec2(100, 100), ImVec2(0, 1), ImVec2(1, 0));
clicked)
select_bed(i, true);
if (inactive)
ImGui::PopStyleColor();
std::string status_text;
if (wxGetApp().plater()->get_fff_prints()[i]->finished())
status_text = "finished";
else if (m_process->fff_print() == wxGetApp().plater()->get_fff_prints()[i].get() && m_process->running())
status_text = "running";
else
status_text = "idle";
ImGui::SameLine();
ImGui::Text("%s", status_text.c_str());
}
if (ImGui::Button("ALL", ImVec2(105, 105))) {
if (! s_multiple_beds.is_autoslicing())
s_multiple_beds.start_autoslice([this](int i, bool user) { this->select_bed(i, user); });
}
ImGui::End();
}
}
if (wxGetApp().plater()->is_render_statistic_dialog_visible()) { if (wxGetApp().plater()->is_render_statistic_dialog_visible()) {
ImGuiPureWrap::begin(std::string("Render statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); ImGuiPureWrap::begin(std::string("Render statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
ImGuiPureWrap::text("FPS (SwapBuffers() calls per second):"); ImGuiPureWrap::text("FPS (SwapBuffers() calls per second):");
@ -2046,6 +2098,7 @@ void GLCanvas3D::render()
wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width()); wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width());
if (! s_multiple_beds.is_autoslicing())
wxGetApp().plater()->render_sliders(*this); wxGetApp().plater()->render_sliders(*this);
wxGetApp().imgui()->render(); wxGetApp().imgui()->render();
@ -3696,7 +3749,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_dirty = true; m_dirty = true;
} }
} else if (evt.LeftDown()) { } else if (evt.LeftDown()) {
select_bed(s_multiple_beds.get_last_hovered_bed()); select_bed(s_multiple_beds.get_last_hovered_bed(), true);
} }
} }

View File

@ -526,9 +526,13 @@ private:
Selection m_selection; Selection m_selection;
const DynamicPrintConfig* m_config; const DynamicPrintConfig* m_config;
Model* m_model; Model* m_model;
public:
BackgroundSlicingProcess *m_process; BackgroundSlicingProcess *m_process;
private:
bool m_requires_check_outside_state{ false }; bool m_requires_check_outside_state{ false };
void select_bed(int i, bool triggered_by_user);
std::array<unsigned int, 2> m_old_size{ 0, 0 }; std::array<unsigned int, 2> m_old_size{ 0, 0 };
// Screen is only refreshed from the OnIdle handler if it is dirty. // Screen is only refreshed from the OnIdle handler if it is dirty.
@ -742,8 +746,6 @@ private:
// returns the containment state in the given out_state, if non-null // 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; bool check_volumes_outside_state(GLVolumeCollection& volumes, ModelInstanceEPrintVolumeState* out_state, bool selection_only = true) const;
void select_bed(int i);
public: public:
void init_gcode_viewer() { m_gcode_viewer.init(); } void init_gcode_viewer() { m_gcode_viewer.init(); }
void reset_gcode_toolpaths() { m_gcode_viewer.reset(); } void reset_gcode_toolpaths() { m_gcode_viewer.reset(); }

View File

@ -2228,10 +2228,6 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
glsafe(glPixelStorei(GL_UNPACK_ALIGNMENT, curr_unpack_alignment)); glsafe(glPixelStorei(GL_UNPACK_ALIGNMENT, curr_unpack_alignment));
} }
// Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile. // Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile.
if (view3D->is_layers_editing_enabled()) if (view3D->is_layers_editing_enabled())
view3D->get_wxglcanvas()->Refresh(); view3D->get_wxglcanvas()->Refresh();
@ -2945,6 +2941,9 @@ void Plater::priv::set_current_panel(wxPanel* panel)
panel_sizer->Layout(); panel_sizer->Layout();
if (current_panel == view3D) { if (current_panel == view3D) {
s_multiple_beds.stop_autoslice(true);
if (old_panel == preview) if (old_panel == preview)
preview->get_canvas3d()->unbind_event_handlers(); preview->get_canvas3d()->unbind_event_handlers();
@ -7314,6 +7313,11 @@ std::vector<std::unique_ptr<Print>>& Plater::get_fff_prints()
return p->fff_prints; return p->fff_prints;
} }
const std::vector<GCodeProcessorResult>& Plater::get_gcode_results() const
{
return p->gcode_results;
}
wxMenu* Plater::object_menu() { return p->menus.object_menu(); } wxMenu* Plater::object_menu() { return p->menus.object_menu(); }
wxMenu* Plater::part_menu() { return p->menus.part_menu(); } wxMenu* Plater::part_menu() { return p->menus.part_menu(); }
wxMenu* Plater::text_part_menu() { return p->menus.text_part_menu(); } wxMenu* Plater::text_part_menu() { return p->menus.text_part_menu(); }

View File

@ -102,6 +102,7 @@ public:
SLAPrint& active_sla_print(); SLAPrint& active_sla_print();
std::vector<std::unique_ptr<Print>>& get_fff_prints(); std::vector<std::unique_ptr<Print>>& get_fff_prints();
const std::vector<GCodeProcessorResult>& get_gcode_results() const;
void new_project(); void new_project();
void load_project(); void load_project();