Multiple beds: Fixed behaviour with empty beds and non-printable instances

This commit is contained in:
Lukas Matena 2024-11-20 13:24:07 +01:00
parent 4f7366045e
commit 1a608da2ae
6 changed files with 61 additions and 28 deletions

View File

@ -1661,7 +1661,7 @@ unsigned int ModelObject::update_instances_print_volume_state(const BuildVolume
if (inside_outside == INSIDE) if (inside_outside == INSIDE)
++num_printable; ++num_printable;
if (bed_idx != -1) if (bed_idx != -1)
s_multiple_beds.set_instance_bed(model_instance->id(), bed_idx); s_multiple_beds.set_instance_bed(model_instance->id(), model_instance->printable, bed_idx);
} }
return num_printable; return num_printable;
} }

View File

@ -115,12 +115,16 @@ Vec3d MultipleBeds::get_bed_translation(int id) const
void MultipleBeds::clear_inst_map() void MultipleBeds::clear_inst_map()
{ {
m_inst_to_bed.clear(); m_inst_to_bed.clear();
m_occupied_beds_cache.fill(false);
} }
void MultipleBeds::set_instance_bed(ObjectID id, int bed_idx) void MultipleBeds::set_instance_bed(ObjectID id, bool printable, int bed_idx)
{ {
assert(bed_idx < get_max_beds()); assert(bed_idx < get_max_beds());
m_inst_to_bed[id] = bed_idx; m_inst_to_bed[id] = bed_idx;
if (printable)
m_occupied_beds_cache[bed_idx] = true;
} }
void MultipleBeds::inst_map_updated() void MultipleBeds::inst_map_updated()
@ -298,6 +302,11 @@ Vec2d MultipleBeds::bed_gap() const
return Vec2d::Ones() * gap; return Vec2d::Ones() * gap;
} }
bool MultipleBeds::is_bed_occupied(int i) const
{
return m_occupied_beds_cache[i];
}
Vec2crd MultipleBeds::get_bed_gap() const { Vec2crd MultipleBeds::get_bed_gap() const {
return scaled(Vec2d{bed_gap() / 2.0}); return scaled(Vec2d{bed_gap() / 2.0});

View File

@ -32,9 +32,10 @@ public:
Vec3d get_bed_translation(int id) const; Vec3d get_bed_translation(int id) const;
void clear_inst_map(); void clear_inst_map();
void set_instance_bed(ObjectID id, int bed_idx); void set_instance_bed(ObjectID id, bool printable, int bed_idx);
void inst_map_updated(); void inst_map_updated();
const std::map<ObjectID, int> &get_inst_map() const { return m_inst_to_bed; } const std::map<ObjectID, int> &get_inst_map() const { return m_inst_to_bed; }
bool is_bed_occupied(int bed_idx) const;
int get_number_of_beds() const { return m_number_of_beds; } int get_number_of_beds() const { return m_number_of_beds; }
bool should_show_next_bed() const { return m_show_next_bed; } bool should_show_next_bed() const { return m_show_next_bed; }
@ -78,6 +79,7 @@ private:
bool m_show_next_bed = false; bool m_show_next_bed = false;
std::map<ObjectID, int> m_inst_to_bed; std::map<ObjectID, int> m_inst_to_bed;
std::map<PrintBase*, size_t> m_printbase_to_texture; std::map<PrintBase*, size_t> m_printbase_to_texture;
std::array<int, MAX_NUMBER_OF_BEDS> m_occupied_beds_cache;
int m_last_hovered_bed = -1; int m_last_hovered_bed = -1;
BoundingBoxf m_build_volume_bb; BoundingBoxf m_build_volume_bb;
bool m_legacy_layout = false; bool m_legacy_layout = false;

View File

@ -139,6 +139,7 @@ void GLCanvas3D::select_bed(int i, bool triggered_by_user)
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();
wxGetApp().plater()->object_list_changed(); // Updates Slice Now / Export buttons.
if (s_multiple_beds.is_autoslicing() && triggered_by_user) if (s_multiple_beds.is_autoslicing() && triggered_by_user)
s_multiple_beds.stop_autoslice(false); s_multiple_beds.stop_autoslice(false);
}); });
@ -6314,7 +6315,7 @@ void GLCanvas3D::_render_overlays()
void Slic3r::GUI::GLCanvas3D::_render_bed_selector() void Slic3r::GUI::GLCanvas3D::_render_bed_selector()
{ {
static float btn_side = 80.f; static float btn_side = 80.f;
static float btn_border = 4.f; static float btn_border = 2.f;
static bool hide_title = true; static bool hide_title = true;
ImVec2 btn_size = ImVec2(btn_side, btn_side); ImVec2 btn_size = ImVec2(btn_side, btn_side);
@ -6325,27 +6326,38 @@ void Slic3r::GUI::GLCanvas3D::_render_bed_selector()
//ImGui::Text("%d", i); //ImGui::Text("%d", i);
//ImGui::SameLine(); //ImGui::SameLine();
bool empty = ! s_multiple_beds.is_bed_occupied(i);
bool inactive = i != s_multiple_beds.get_active_bed() || s_multiple_beds.is_autoslicing(); 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)); ImGui::PushStyleColor(ImGuiCol_Button, ImGuiPureWrap::COL_GREY_DARK);
if (bool clicked = (i >= int(s_th_tex_id.size())) ImGui::PushStyleColor(ImGuiCol_Border, inactive ? ImGuiPureWrap::COL_GREY_DARK : ImGuiPureWrap::COL_BUTTON_ACTIVE);
? ImGui::Button(std::to_string(i).c_str(), btn_size)
: ImGui::ImageButton((void*)(int64_t)s_th_tex_id[i], btn_size, ImVec2(0, 1), ImVec2(1, 0)); if (empty)
clicked) ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
bool clicked = false;
ImVec2 btn_padding = ImVec2(btn_border, btn_border);
if (i >= int(s_th_tex_id.size()) || empty)
clicked = ImGui::Button(empty ? "empty" : std::to_string(i + 1).c_str(), btn_size + btn_padding);
else
clicked = ImGui::ImageButton((void*)(int64_t)s_th_tex_id[i], btn_size - btn_padding, ImVec2(0, 1), ImVec2(1, 0), btn_border);
if (clicked && ! empty)
select_bed(i, true); select_bed(i, true);
if (inactive) ImGui::PopStyleColor(2);
ImGui::PopStyleColor(); if (empty)
ImGui::PopItemFlag();
std::string status_text; //std::string status_text;
if (wxGetApp().plater()->get_fff_prints()[i]->finished()) //if (wxGetApp().plater()->get_fff_prints()[i]->finished())
status_text = "Finished"; // status_text = "Finished";
else if (m_process->fff_print() == wxGetApp().plater()->get_fff_prints()[i].get() && m_process->running()) //else if (m_process->fff_print() == wxGetApp().plater()->get_fff_prints()[i].get() && m_process->running())
status_text = "Running"; // status_text = "Running";
else //else
status_text = "Idle"; // status_text = "Idle";
if (ImGui::IsItemHovered()) //if (ImGui::IsItemHovered())
ImGui::SetTooltip(status_text.c_str()); // ImGui::SetTooltip(status_text.c_str());
}; };
ImGuiWrapper& imgui = *wxGetApp().imgui(); ImGuiWrapper& imgui = *wxGetApp().imgui();
@ -6365,9 +6377,8 @@ void Slic3r::GUI::GLCanvas3D::_render_bed_selector()
#endif #endif
ImGui::Begin("Bed selector", 0, ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar); ImGui::Begin("Bed selector", 0, ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.f);
ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2()); ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2());
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(btn_border, btn_border)); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2());
// Disable for now. // Disable for now.
//if (imgui.image_button(ImGui::SliceAllBtnIcon, "Slice All")) { //if (imgui.image_button(ImGui::SliceAllBtnIcon, "Slice All")) {
@ -6386,7 +6397,7 @@ void Slic3r::GUI::GLCanvas3D::_render_bed_selector()
ImGui::SameLine(); ImGui::SameLine();
} }
ImGui::PopStyleVar(4); ImGui::PopStyleVar(3);
#if use_scrolling #if use_scrolling
bool extra_frame{ false }; bool extra_frame{ false };

View File

@ -1874,7 +1874,7 @@ void Plater::priv::object_list_changed()
// XXX: is this right? // XXX: is this right?
const bool model_fits = view3D->get_canvas3d()->check_volumes_outside_state() == ModelInstancePVS_Inside; const bool model_fits = view3D->get_canvas3d()->check_volumes_outside_state() == ModelInstancePVS_Inside;
sidebar->enable_buttons(!model.objects.empty() && !export_in_progress && model_fits); sidebar->enable_buttons(s_multiple_beds.is_bed_occupied(s_multiple_beds.get_active_bed()) && !model.objects.empty() && !export_in_progress && model_fits);
} }
void Plater::priv::select_all() void Plater::priv::select_all()
@ -2979,13 +2979,17 @@ void Plater::priv::set_current_panel(wxPanel* panel)
// FIXME: it may be better to have a single function making this check and let it be called wherever needed // FIXME: it may be better to have a single function making this check and let it be called wherever needed
bool export_in_progress = this->background_process.is_export_scheduled(); bool export_in_progress = this->background_process.is_export_scheduled();
bool model_fits = view3D->get_canvas3d()->check_volumes_outside_state() != ModelInstancePVS_Partly_Outside; bool model_fits = view3D->get_canvas3d()->check_volumes_outside_state() != ModelInstancePVS_Partly_Outside;
if (!model.objects.empty() && !export_in_progress && model_fits) { if (s_multiple_beds.is_bed_occupied(s_multiple_beds.get_active_bed()) && !model.objects.empty() && !export_in_progress && model_fits) {
preview->get_canvas3d()->init_gcode_viewer(); preview->get_canvas3d()->init_gcode_viewer();
preview->load_gcode_shells(); preview->load_gcode_shells();
q->reslice(); q->reslice();
} }
// keeps current gcode preview, if any // keeps current gcode preview, if any
preview->reload_print(); preview->reload_print();
if (! s_multiple_beds.is_bed_occupied(s_multiple_beds.get_active_bed()))
preview->get_canvas3d()->reset_gcode_toolpaths();
} }
preview->set_as_dirty(); preview->set_as_dirty();
@ -4564,6 +4568,11 @@ void Plater::reload_print()
p->preview->reload_print(); p->preview->reload_print();
} }
void Plater::object_list_changed()
{
p->object_list_changed();
}
std::vector<size_t> Plater::load_files(const std::vector<fs::path>& input_files, bool load_model, bool load_config, bool imperial_units /*= false*/) { return p->load_files(input_files, load_model, load_config, imperial_units); } std::vector<size_t> Plater::load_files(const std::vector<fs::path>& input_files, bool load_model, bool load_config, bool imperial_units /*= false*/) { return p->load_files(input_files, load_model, load_config, imperial_units); }
// To be called when providing a list of files to the GUI slic3r on command line. // To be called when providing a list of files to the GUI slic3r on command line.
@ -5535,8 +5544,9 @@ void Plater::apply_cut_object_to_model(size_t obj_idx, const ModelObjectPtrs& ne
size_t last_id = p->model.objects.size() - 1; size_t last_id = p->model.objects.size() - 1;
for (size_t i = 0; i < new_objects.size(); ++i) { for (size_t i = 0; i < new_objects.size(); ++i) {
selection.add_object((unsigned int)(last_id - i), i == 0); selection.add_object((unsigned int)(last_id - i), i == 0);
const ObjectID instance_id{p->model.objects[last_id - i]->instances.front()->id().id}; const ModelInstance* mi = p->model.objects[last_id - i]->instances.front();
s_multiple_beds.set_instance_bed(instance_id, s_multiple_beds.get_active_bed()); const ObjectID instance_id{mi->id().id};
s_multiple_beds.set_instance_bed(instance_id, mi->printable, s_multiple_beds.get_active_bed());
} }
UIThreadWorker w; UIThreadWorker w;

View File

@ -117,6 +117,7 @@ public:
void convert_gcode_to_ascii(); void convert_gcode_to_ascii();
void convert_gcode_to_binary(); void convert_gcode_to_binary();
void reload_print(); void reload_print();
void object_list_changed();
std::vector<size_t> load_files(const std::vector<boost::filesystem::path>& input_files, bool load_model = true, bool load_config = true, bool imperial_units = false); std::vector<size_t> load_files(const std::vector<boost::filesystem::path>& input_files, bool load_model = true, bool load_config = true, bool imperial_units = false);
// To be called when providing a list of files to the GUI slic3r on command line. // To be called when providing a list of files to the GUI slic3r on command line.