From 797dd1197e2be640b00d74b46387f151d09ab9d5 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 3 Apr 2023 08:54:04 +0200 Subject: [PATCH 01/10] Allow the user to switch between visualizing original or processed volumes in 3D scene after slicing using SLA printers --- src/slic3r/GUI/3DScene.cpp | 26 ++++- src/slic3r/GUI/GLCanvas3D.cpp | 115 +++++++++++++++++++ src/slic3r/GUI/GLCanvas3D.hpp | 44 ++++++- src/slic3r/GUI/GUI_ObjectList.cpp | 4 + src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 3 +- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 + src/slic3r/GUI/Plater.cpp | 4 +- src/slic3r/GUI/Selection.cpp | 37 ++++++ src/slic3r/GUI/Selection.hpp | 3 + 9 files changed, 231 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 71361e68f..cfd457151 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -613,10 +613,28 @@ void GLVolumeCollection::load_object_auxiliary( if (convex_hull.has_value()) v.set_convex_hull(*convex_hull); v.is_modifier = false; - v.shader_outside_printer_detection_enabled = (step == slaposSupportTree); + v.shader_outside_printer_detection_enabled = (step == slaposSupportTree || step == slaposDrillHoles); v.set_instance_transformation(model_instance.get_transformation()); }; + if (milestone == SLAPrintObjectStep::slaposDrillHoles) { + if (print_object->get_parts_to_slice().size() > 1) { + // Get the mesh. + TriangleMesh backend_mesh; + std::shared_ptr preview_mesh_ptr = print_object->get_mesh_to_print(); + if (preview_mesh_ptr != nullptr) + backend_mesh = TriangleMesh(*preview_mesh_ptr); + if (!backend_mesh.empty()) { + backend_mesh.transform(mesh_trafo_inv); + TriangleMesh convex_hull = backend_mesh.convex_hull_3d(); + for (const std::pair& instance_idx : instances) { + const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first]; + add_volume(obj_idx, (int)instance_idx.first, model_instance, slaposDrillHoles, backend_mesh, GLVolume::MODEL_COLOR[0], convex_hull); + } + } + } + } + // Get the support mesh. if (milestone == SLAPrintObjectStep::slaposSupportTree) { TriangleMesh supports_mesh = print_object->support_mesh(); @@ -624,8 +642,8 @@ void GLVolumeCollection::load_object_auxiliary( supports_mesh.transform(mesh_trafo_inv); TriangleMesh convex_hull = supports_mesh.convex_hull_3d(); for (const std::pair& instance_idx : instances) { - const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first]; - add_volume(obj_idx, (int)instance_idx.first, model_instance, slaposSupportTree, supports_mesh, GLVolume::SLA_SUPPORT_COLOR, convex_hull); + const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first]; + add_volume(obj_idx, (int)instance_idx.first, model_instance, slaposSupportTree, supports_mesh, GLVolume::SLA_SUPPORT_COLOR, convex_hull); } } } @@ -924,7 +942,7 @@ void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* con } for (GLVolume* volume : volumes) { - if (volume == nullptr || volume->is_modifier || volume->is_wipe_tower || volume->volume_idx() < 0) + if (volume == nullptr || volume->is_modifier || volume->is_wipe_tower || volume->is_sla_pad() || volume->is_sla_support()) continue; int extruder_id = volume->extruder_id - 1; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 958346849..69bcd6ab5 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1072,6 +1072,107 @@ void GLCanvas3D::load_arrange_settings() m_arrange_settings_fff_seq_print.alignment = arr_alignment ; } +static int processed_object_idx(const Model& model, const SLAPrint& sla_print, const GLVolumePtrs& volumes) +{ + for (const GLVolume* v : volumes) { + if (v->volume_idx() == -(int)slaposDrillHoles) { + const int mo_idx = v->object_idx(); + const ModelObject* model_object = (mo_idx < (int)model.objects.size()) ? model.objects[mo_idx] : nullptr; + if (model_object != nullptr && model_object->instances[v->instance_idx()]->is_printable()) { + const SLAPrintObject* print_object = sla_print.get_print_object_by_model_object_id(model_object->id()); + if (print_object != nullptr && print_object->get_parts_to_slice().size() > 1) + return mo_idx; + } + } + } + + return -1; +}; + +GLCanvas3D::ESLAViewType GLCanvas3D::SLAView::detect_type(const GLVolumePtrs& volumes) +{ + m_type = ESLAViewType::Original; + if (m_allow_type_detection) { + for (const GLVolume* v : volumes) { + if (v->volume_idx() == -(int)slaposDrillHoles) { + m_type = ESLAViewType::Processed; + break; + } + } + } + + m_parent.set_sla_view_type(m_type); + m_allow_type_detection = false; + return m_type; +} + +bool GLCanvas3D::SLAView::set_type(ESLAViewType type) { + if (m_type != type) { + m_type = type; + return true; + } + return false; +} + +void GLCanvas3D::SLAView::update_volumes(GLVolumePtrs& volumes) +{ + const SLAPrint* sla_print = m_parent.sla_print(); + const int mo_idx = (sla_print != nullptr) ? processed_object_idx(*m_parent.get_model(), *sla_print, volumes) : -1; + const bool show_processed = m_type == ESLAViewType::Processed && mo_idx != -1; + + auto show = [show_processed](const GLVolume& v) { + return show_processed ? v.volume_idx() < 0 : v.volume_idx() != -(int)slaposDrillHoles; + }; + + std::vector>* raycasters = m_parent.get_raycasters_for_picking(SceneRaycaster::EType::Volume); + + for (GLVolume* v : volumes) { + v->is_active = v->object_idx() != mo_idx || show(*v); + auto it = std::find_if(raycasters->begin(), raycasters->end(), [v](std::shared_ptr item) { return item->get_raycaster() == v->mesh_raycaster.get(); }); + if (it != raycasters->end()) + (*it)->set_active(v->is_active); + } +} + +void GLCanvas3D::SLAView::render_switch_button() +{ + const SLAPrint* sla_print = m_parent.sla_print(); + const int mo_idx = (sla_print != nullptr) ? processed_object_idx(*m_parent.get_model(), *sla_print, m_parent.get_volumes().volumes) : -1; + if (mo_idx == -1) + return; + + const BoundingBoxf ss_box = m_parent.get_selection().get_screen_space_bounding_box(); + if (ss_box.defined) { + ImGuiWrapper& imgui = *wxGetApp().imgui(); + ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); + ImGui::SetNextWindowPos(ImVec2((float)ss_box.max.x(), (float)ss_box.center().y()), ImGuiCond_Always, ImVec2(0.0, 0.5)); + imgui.begin(std::string("SLAViewSwitch"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration); + const wxString btn_text = (m_type == ESLAViewType::Original) ? _L("Processed") : _L("Original"); + if (imgui.button(btn_text)) { + switch (m_type) + { + case ESLAViewType::Original: { m_parent.set_sla_view_type(ESLAViewType::Processed); break; } + case ESLAViewType::Processed: { m_parent.set_sla_view_type(ESLAViewType::Original); break; } + default: { assert(false); break; } + } + } + imgui.end(); + ImGui::PopStyleColor(2); + } +} + +//void GLCanvas3D::SLAView::render_debug_window() +//{ +// ImGuiWrapper& imgui = *wxGetApp().imgui(); +// imgui.begin(std::string("SLAView"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize); +// imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Type:"); +// ImGui::SameLine(); +// const std::string text = (m_type == ESLAViewType::Original) ? "Original" : "Processed"; +// imgui.text_colored(ImGui::GetStyleColorVec4(ImGuiCol_Text), text); +// imgui.end(); +//} + PrinterTechnology GLCanvas3D::current_printer_technology() const { return m_process->current_printer_technology(); @@ -1113,6 +1214,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed) , m_render_sla_auxiliaries(true) , m_labels(*this) , m_slope(m_volumes) + , m_sla_view(*this) { if (m_canvas != nullptr) { m_timer.SetOwner(m_canvas); @@ -1642,6 +1744,13 @@ void GLCanvas3D::render() GLModel::render_statistics(); #endif // ENABLE_GLMODEL_STATISTICS + if (wxGetApp().plater()->is_view3D_shown() && current_printer_technology() == ptSLA) { + const GLGizmosManager::EType type = m_gizmos.get_current_type(); + if (type == GLGizmosManager::EType::Undefined) + m_sla_view.render_switch_button(); +// m_sla_view.render_debug_window(); + } + std::string tooltip; // Negative coordinate means out of the window, likely because the window was deactivated. @@ -2114,6 +2223,9 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re if (!instances[istep].empty()) m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp); } + + if (m_sla_view.detect_type(m_volumes.volumes) == ESLAViewType::Processed) + update_object_list = true; } // Shift-up all volumes of the object so that it has the right elevation with respect to the print bed @@ -2169,6 +2281,9 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re else m_selection.volumes_changed(map_glvolume_old_to_new); + if (printer_technology == ptSLA) + m_sla_view.update_volumes(m_volumes.volumes); + m_gizmos.update_data(); m_gizmos.refresh_on_off_state(); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index a79bcff2e..cb76a79e9 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -468,6 +468,12 @@ public: int alignment = 0; }; + enum class ESLAViewType + { + Original, + Processed + }; + private: wxGLCanvas* m_canvas; wxGLContext* m_context; @@ -547,6 +553,26 @@ private: bool m_tooltip_enabled{ true }; Slope m_slope; + class SLAView + { + public: + explicit SLAView(GLCanvas3D& parent) : m_parent(parent) {} + void allow_type_detection(bool allow) { m_allow_type_detection = allow; } + ESLAViewType detect_type(const GLVolumePtrs& volumes); + ESLAViewType get_type() const { return m_type; } + bool set_type(ESLAViewType type); + void update_volumes(GLVolumePtrs& volumes); + void render_switch_button(); +// void render_debug_window(); + + private: + GLCanvas3D& m_parent; + ESLAViewType m_type{ ESLAViewType::Original }; + bool m_allow_type_detection{ false }; + }; + + SLAView m_sla_view; + ArrangeSettings m_arrange_settings_fff, m_arrange_settings_sla, m_arrange_settings_fff_seq_print; @@ -656,7 +682,7 @@ private: GLModel m_background; public: - explicit GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed); + GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed); ~GLCanvas3D(); bool is_initialized() const { return m_initialized; } @@ -962,6 +988,22 @@ public: std::pair> get_layers_height_data(int object_id); + void set_sla_view_type(ESLAViewType type) { + if (type == ESLAViewType::Processed) { + assert(!m_selection.is_empty()); + const GLVolume* v = m_selection.get_first_volume(); + m_selection.add_instance(v->object_idx(), v->instance_idx()); + post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); + } + + m_dirty = type != m_sla_view.get_type(); + + if (m_sla_view.set_type(type)) + m_sla_view.update_volumes(m_volumes.volumes); + } + + void allow_sla_view_type_detection(bool allow) { m_sla_view.allow_type_detection(allow); } + private: bool _is_shown_on_screen() const; diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 5f8b9a75b..c1536da0b 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -747,6 +747,10 @@ void ObjectList::selection_changed() wxGetApp().obj_layers()->update_scene_from_editor_selection(); } } + else if (type & itVolume) { + if (printer_technology() == ptSLA) + wxGetApp().plater()->canvas3D()->set_sla_view_type(GLCanvas3D::ESLAViewType::Original); + } } part_selection_changed(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index fe7e1b4ea..5998d5b11 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -64,7 +64,6 @@ void GLGizmoSlaSupports::data_changed() // If we triggered autogeneration before, check backend and fetch results if they are there if (mo) { - m_c->instances_hider()->set_hide_full_scene(true); const SLAPrintObject* po = m_c->selection_info()->print_object(); const int required_step = get_min_sla_print_object_step(); auto last_comp_step = static_cast(po->last_completed_step()); @@ -83,6 +82,8 @@ void GLGizmoSlaSupports::data_changed() register_point_raycasters_for_picking(); else update_point_raycasters_for_picking_transform(); + + m_c->instances_hider()->set_hide_full_scene(true); } // m_parent.toggle_model_objects_visibility(false); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index af93c07df..20444586d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -969,6 +969,8 @@ bool GLGizmosManager::activate_gizmo(EType type) return false; // gizmo refused to be turned on. } + m_parent.set_sla_view_type(GLCanvas3D::ESLAViewType::Original); + new_gizmo.register_raycasters_for_picking(); // sucessful activation of gizmo diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 159a9693d..a2ed0bef4 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3448,8 +3448,10 @@ unsigned int Plater::priv::update_restart_background_process(bool force_update_s { // bitmask of UpdateBackgroundProcessReturnState unsigned int state = this->update_background_process(false); - if (force_update_scene || (state & UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) != 0) + if (force_update_scene || (state & UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) != 0) { + view3D->get_canvas3d()->allow_sla_view_type_detection(true); view3D->reload_scene(false); + } if (force_update_preview) this->preview->reload_print(); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 28cf367fd..b10a45928 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -890,6 +890,43 @@ std::pair Selection::get_bounding_box_in_reference_s } #endif // ENABLE_WORLD_COORDINATE +BoundingBoxf Selection::get_screen_space_bounding_box() +{ + BoundingBoxf ss_box; + if (!is_empty()) { + const auto& [box, box_trafo] = get_bounding_box_in_current_reference_system(); + + // vertices + std::vector vertices = { + { box.min.x(), box.min.y(), box.min.z() }, + { box.max.x(), box.min.y(), box.min.z() }, + { box.max.x(), box.max.y(), box.min.z() }, + { box.min.x(), box.max.y(), box.min.z() }, + { box.min.x(), box.min.y(), box.max.z() }, + { box.max.x(), box.min.y(), box.max.z() }, + { box.max.x(), box.max.y(), box.max.z() }, + { box.min.x(), box.max.y(), box.max.z() } + }; + + const Camera& camera = wxGetApp().plater()->get_camera(); + const Matrix4d projection_view_matrix = camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix(); + const std::array& viewport = camera.get_viewport(); + + const double half_w = 0.5 * double(viewport[2]); + const double h = double(viewport[3]); + const double half_h = 0.5 * h; + for (const Vec3d& v : vertices) { + const Vec3d world = box_trafo * v; + const Vec4d clip = projection_view_matrix * Vec4d(world.x(), world.y(), world.z(), 1.0); + const Vec3d ndc = Vec3d(clip.x(), clip.y(), clip.z()) / clip.w(); + const Vec2d ss = Vec2d(half_w * ndc.x() + double(viewport[0]) + half_w, h - (half_h * ndc.y() + double(viewport[1]) + half_h)); + ss_box.merge(ss); + } + } + + return ss_box; +} + void Selection::setup_cache() { if (!m_valid) diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index d3f456702..0657a8d8a 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -400,6 +400,9 @@ public: std::pair get_bounding_box_in_reference_system(ECoordinatesType type) const; #endif // ENABLE_WORLD_COORDINATE + // Returns the screen space bounding box + BoundingBoxf get_screen_space_bounding_box(); + void setup_cache(); #if ENABLE_WORLD_COORDINATE From d1c959529c80a086bce84b301bc685805963c530 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 3 Apr 2023 11:39:53 +0200 Subject: [PATCH 02/10] Fixed assert showing up after merge with master --- src/slic3r/GUI/Selection.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 3f0deab40..cbd61a1dd 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1742,18 +1742,11 @@ std::vector Selection::get_volume_idxs_from_object(unsigned int ob std::vector Selection::get_volume_idxs_from_instance(unsigned int object_idx, unsigned int instance_idx) const { std::vector idxs; - - const PrinterTechnology pt = wxGetApp().plater()->printer_technology(); - for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) { const GLVolume* v = (*m_volumes)[i]; - const ModelVolume *mv = get_model_volume(*v, *m_model); - if (pt == ptSLA && v->is_modifier && mv && mv->is_modifier()) - continue; if (v->object_idx() == (int)object_idx && v->instance_idx() == (int)instance_idx) idxs.push_back(i); } - return idxs; } @@ -1761,8 +1754,7 @@ std::vector Selection::get_volume_idxs_from_volume(unsigned int ob { std::vector idxs; - for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) - { + for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) { const GLVolume* v = (*m_volumes)[i]; if (v->object_idx() == (int)object_idx && v->volume_idx() == (int)volume_idx) { if ((int)instance_idx != -1 && v->instance_idx() == (int)instance_idx) From 799e44f155ac1008d9611b63531a52ff29041174 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 4 Apr 2023 09:47:22 +0200 Subject: [PATCH 03/10] Show an icon button, in place of a plain imgui button, in the 3D scene as switch between view types of an object sliced with sla printer --- resources/icons/sla_view_original.svg | 72 ++++++++++++++++++++++++++ resources/icons/sla_view_processed.svg | 56 ++++++++++++++++++++ src/imgui/imconfig.h | 2 + src/slic3r/GUI/GCodeViewer.cpp | 59 +++++++++------------ src/slic3r/GUI/GLCanvas3D.cpp | 32 ++++++++++-- src/slic3r/GUI/ImGuiWrapper.cpp | 14 +++++ src/slic3r/GUI/ImGuiWrapper.hpp | 3 +- 7 files changed, 199 insertions(+), 39 deletions(-) create mode 100644 resources/icons/sla_view_original.svg create mode 100644 resources/icons/sla_view_processed.svg diff --git a/resources/icons/sla_view_original.svg b/resources/icons/sla_view_original.svg new file mode 100644 index 000000000..4691721c8 --- /dev/null +++ b/resources/icons/sla_view_original.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + diff --git a/resources/icons/sla_view_processed.svg b/resources/icons/sla_view_processed.svg new file mode 100644 index 000000000..a26a0db2f --- /dev/null +++ b/resources/icons/sla_view_processed.svg @@ -0,0 +1,56 @@ + + + + + + + + + + + diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h index dff8aea9f..5aed97842 100644 --- a/src/imgui/imconfig.h +++ b/src/imgui/imconfig.h @@ -166,6 +166,8 @@ namespace ImGui const wchar_t PauseHoverButton = 0x261B; const wchar_t OpenButton = 0x261C; const wchar_t OpenHoverButton = 0x261D; + const wchar_t SlaViewOriginal = 0x261E; + const wchar_t SlaViewProcessed = 0x261F; const wchar_t LegendTravel = 0x2701; const wchar_t LegendWipe = 0x2702; diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 62d4314db..20ba4a216 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -4049,69 +4049,58 @@ void GCodeViewer::render_legend(float& legend_height) } }; - auto image_icon = [&imgui](ImGuiWindow& window, const ImVec2& pos, float size, const wchar_t& icon_id) { - ImGuiIO& io = ImGui::GetIO(); - const ImTextureID tex_id = io.Fonts->TexID; - const float tex_w = static_cast(io.Fonts->TexWidth); - const float tex_h = static_cast(io.Fonts->TexHeight); - const ImFontAtlas::CustomRect* const rect = imgui.GetTextureCustomRect(icon_id); - const ImVec2 uv0 = { static_cast(rect->X) / tex_w, static_cast(rect->Y) / tex_h }; - const ImVec2 uv1 = { static_cast(rect->X + rect->Width) / tex_w, static_cast(rect->Y + rect->Height) / tex_h }; - window.DrawList->AddImage(tex_id, pos, { pos.x + size, pos.y + size }, uv0, uv1, ImGuiWrapper::to_ImU32({ 1.0f, 1.0f, 1.0f, 1.0f })); - }; - ImGui::Spacing(); ImGui::Separator(); ImGui::Spacing(); ImGui::Spacing(); - toggle_button(Preview::OptionType::Travel, _u8L("Travel"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - image_icon(window, pos, size, ImGui::LegendTravel); + toggle_button(Preview::OptionType::Travel, _u8L("Travel"), [&imgui](ImGuiWindow& window, const ImVec2& pos, float size) { + imgui.draw_icon(window, pos, size, ImGui::LegendTravel); }); ImGui::SameLine(); - toggle_button(Preview::OptionType::Wipe, _u8L("Wipe"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - image_icon(window, pos, size, ImGui::LegendWipe); + toggle_button(Preview::OptionType::Wipe, _u8L("Wipe"), [&imgui](ImGuiWindow& window, const ImVec2& pos, float size) { + imgui.draw_icon(window, pos, size, ImGui::LegendWipe); }); ImGui::SameLine(); - toggle_button(Preview::OptionType::Retractions, _u8L("Retractions"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - image_icon(window, pos, size, ImGui::LegendRetract); + toggle_button(Preview::OptionType::Retractions, _u8L("Retractions"), [&imgui](ImGuiWindow& window, const ImVec2& pos, float size) { + imgui.draw_icon(window, pos, size, ImGui::LegendRetract); }); ImGui::SameLine(); - toggle_button(Preview::OptionType::Unretractions, _u8L("Deretractions"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - image_icon(window, pos, size, ImGui::LegendDeretract); + toggle_button(Preview::OptionType::Unretractions, _u8L("Deretractions"), [&imgui](ImGuiWindow& window, const ImVec2& pos, float size) { + imgui.draw_icon(window, pos, size, ImGui::LegendDeretract); }); ImGui::SameLine(); - toggle_button(Preview::OptionType::Seams, _u8L("Seams"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - image_icon(window, pos, size, ImGui::LegendSeams); + toggle_button(Preview::OptionType::Seams, _u8L("Seams"), [&imgui](ImGuiWindow& window, const ImVec2& pos, float size) { + imgui.draw_icon(window, pos, size, ImGui::LegendSeams); }); ImGui::SameLine(); - toggle_button(Preview::OptionType::ToolChanges, _u8L("Tool changes"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - image_icon(window, pos, size, ImGui::LegendToolChanges); + toggle_button(Preview::OptionType::ToolChanges, _u8L("Tool changes"), [&imgui](ImGuiWindow& window, const ImVec2& pos, float size) { + imgui.draw_icon(window, pos, size, ImGui::LegendToolChanges); }); ImGui::SameLine(); - toggle_button(Preview::OptionType::ColorChanges, _u8L("Color changes"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - image_icon(window, pos, size, ImGui::LegendColorChanges); + toggle_button(Preview::OptionType::ColorChanges, _u8L("Color changes"), [&imgui](ImGuiWindow& window, const ImVec2& pos, float size) { + imgui.draw_icon(window, pos, size, ImGui::LegendColorChanges); }); ImGui::SameLine(); - toggle_button(Preview::OptionType::PausePrints, _u8L("Print pauses"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - image_icon(window, pos, size, ImGui::LegendPausePrints); + toggle_button(Preview::OptionType::PausePrints, _u8L("Print pauses"), [&imgui](ImGuiWindow& window, const ImVec2& pos, float size) { + imgui.draw_icon(window, pos, size, ImGui::LegendPausePrints); }); ImGui::SameLine(); - toggle_button(Preview::OptionType::CustomGCodes, _u8L("Custom G-codes"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - image_icon(window, pos, size, ImGui::LegendCustomGCodes); + toggle_button(Preview::OptionType::CustomGCodes, _u8L("Custom G-codes"), [&imgui](ImGuiWindow& window, const ImVec2& pos, float size) { + imgui.draw_icon(window, pos, size, ImGui::LegendCustomGCodes); }); ImGui::SameLine(); - toggle_button(Preview::OptionType::CenterOfGravity, _u8L("Center of gravity"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - image_icon(window, pos, size, ImGui::LegendCOG); + toggle_button(Preview::OptionType::CenterOfGravity, _u8L("Center of gravity"), [&imgui](ImGuiWindow& window, const ImVec2& pos, float size) { + imgui.draw_icon(window, pos, size, ImGui::LegendCOG); }); ImGui::SameLine(); if (!wxGetApp().is_gcode_viewer()) { - toggle_button(Preview::OptionType::Shells, _u8L("Shells"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - image_icon(window, pos, size, ImGui::LegendShells); + toggle_button(Preview::OptionType::Shells, _u8L("Shells"), [&imgui](ImGuiWindow& window, const ImVec2& pos, float size) { + imgui.draw_icon(window, pos, size, ImGui::LegendShells); }); ImGui::SameLine(); } - toggle_button(Preview::OptionType::ToolMarker, _u8L("Tool marker"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - image_icon(window, pos, size, ImGui::LegendToolMarker); + toggle_button(Preview::OptionType::ToolMarker, _u8L("Tool marker"), [&imgui](ImGuiWindow& window, const ImVec2& pos, float size) { + imgui.draw_icon(window, pos, size, ImGui::LegendToolMarker); }); bool size_dirty = !ImGui::GetCurrentWindow()->ScrollbarY && ImGui::CalcWindowNextAutoFitSize(ImGui::GetCurrentWindow()).x != ImGui::GetWindowWidth(); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 4decbdab9..fe0a7b724 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1146,15 +1146,41 @@ void GLCanvas3D::SLAView::render_switch_button() ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); ImGui::SetNextWindowPos(ImVec2((float)ss_box.max.x(), (float)ss_box.center().y()), ImGuiCond_Always, ImVec2(0.0, 0.5)); imgui.begin(std::string("SLAViewSwitch"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration); - const wxString btn_text = (m_type == ESLAViewType::Original) ? _L("Processed") : _L("Original"); - if (imgui.button(btn_text)) { + const float icon_size = 1.5 * ImGui::GetTextLineHeight(); + if (imgui.draw_radio_button(_u8L("SLA view"), 1.5f * icon_size, true, [this, &imgui](ImGuiWindow& window, const ImVec2& pos, float size) { + wchar_t icon_id; + switch (m_type) + { + case ESLAViewType::Original: { icon_id = ImGui::SlaViewProcessed; break; } + case ESLAViewType::Processed: { icon_id = ImGui::SlaViewOriginal; break; } + default: { assert(false); break; } + } + imgui.draw_icon(window, pos, size, icon_id); + + })) { switch (m_type) { case ESLAViewType::Original: { m_parent.set_sla_view_type(ESLAViewType::Processed); break; } case ESLAViewType::Processed: { m_parent.set_sla_view_type(ESLAViewType::Original); break; } - default: { assert(false); break; } + default: { assert(false); break; } } } + + if (ImGui::IsItemHovered()) { + ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND); + ImGui::BeginTooltip(); + wxString tooltip; + switch (m_type) + { + case ESLAViewType::Original: { tooltip = _L("Show as processed"); break; } + case ESLAViewType::Processed: { tooltip = _L("Show as original"); break; } + default: { assert(false); break; } + } + + imgui.text(tooltip); + ImGui::EndTooltip(); + ImGui::PopStyleColor(); + } imgui.end(); ImGui::PopStyleColor(2); } diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 55bf57602..3d2b92610 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -104,6 +104,8 @@ static const std::map font_icons_large = { {ImGui::PauseHoverButton , "notification_pause_hover" }, {ImGui::OpenButton , "notification_open" }, {ImGui::OpenHoverButton , "notification_open_hover" }, + {ImGui::SlaViewOriginal , "sla_view_original" }, + {ImGui::SlaViewProcessed , "sla_view_processed" }, }; static const std::map font_icons_extra_large = { @@ -490,6 +492,18 @@ bool ImGuiWrapper::radio_button(const wxString &label, bool active) return ImGui::RadioButton(label_utf8.c_str(), active); } +void ImGuiWrapper::draw_icon(ImGuiWindow& window, const ImVec2& pos, float size, wchar_t icon_id) +{ + ImGuiIO& io = ImGui::GetIO(); + const ImTextureID tex_id = io.Fonts->TexID; + const float tex_w = static_cast(io.Fonts->TexWidth); + const float tex_h = static_cast(io.Fonts->TexHeight); + const ImFontAtlas::CustomRect* const rect = GetTextureCustomRect(icon_id); + const ImVec2 uv0 = { static_cast(rect->X) / tex_w, static_cast(rect->Y) / tex_h }; + const ImVec2 uv1 = { static_cast(rect->X + rect->Width) / tex_w, static_cast(rect->Y + rect->Height) / tex_h }; + window.DrawList->AddImage(tex_id, pos, { pos.x + size, pos.y + size }, uv0, uv1, ImGuiWrapper::to_ImU32({ 1.0f, 1.0f, 1.0f, 1.0f })); +} + bool ImGuiWrapper::draw_radio_button(const std::string& name, float size, bool active, std::function draw_callback) { diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 077bf568d..d95b934f1 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -92,9 +92,10 @@ public: void end(); bool button(const wxString &label, const wxString& tooltip = {}); - bool button(const wxString& label, float width, float height); + bool button(const wxString& label, float width, float height); bool button(const wxString& label, const ImVec2 &size, bool enable); // default size = ImVec2(0.f, 0.f) bool radio_button(const wxString &label, bool active); + void draw_icon(ImGuiWindow& window, const ImVec2& pos, float size, wchar_t icon_id); bool draw_radio_button(const std::string& name, float size, bool active, std::function draw_callback); bool checkbox(const wxString &label, bool &value); static void text(const char *label); From 1835e52842ad850326ccb509a44e0bd87ae204d7 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 4 Apr 2023 09:58:14 +0200 Subject: [PATCH 04/10] Fixed visibility of volumes when switching to FFF printer after slicing an object with SLA printer --- src/slic3r/GUI/Plater.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 8da6d0d26..75963a250 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -6922,6 +6922,7 @@ void Plater::on_config_change(const DynamicPrintConfig &config) p->sidebar->show_sliced_info_sizer(false); p->reset_gcode_toolpaths(); p->view3D->get_canvas3d()->reset_sequential_print_clearance(); + p->view3D->get_canvas3d()->set_sla_view_type(GLCanvas3D::ESLAViewType::Original); } else if (opt_key == "bed_shape" || opt_key == "bed_custom_texture" || opt_key == "bed_custom_model") { bed_shape_changed = true; From d9dde32b78f4f2b518ae0de49e7ed6e1fe136aaf Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 3 May 2023 13:45:15 +0200 Subject: [PATCH 05/10] SPE-1606 - Fixed a bunch of bugs/crashes related to visualizing original or processed volumes in 3D scene after slicing using SLA printers when multiple objects are on the printbed --- src/libslic3r/Technologies.hpp | 2 + src/slic3r/GUI/GLCanvas3D.cpp | 362 +++++++++++++++------- src/slic3r/GUI/GLCanvas3D.hpp | 46 ++- src/slic3r/GUI/GUI_ObjectList.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 3 +- src/slic3r/GUI/Plater.cpp | 14 +- 6 files changed, 289 insertions(+), 140 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 60d89c9e9..adfcda664 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -36,6 +36,8 @@ #define ENABLE_MATRICES_DEBUG 0 // Shows an imgui dialog containing data from class ObjectManipulation #define ENABLE_OBJECT_MANIPULATION_DEBUG 0 +// Shows an imgui dialog containing data for class GLCanvas3D::SLAView +#define ENABLE_SLA_VIEW_DEBUG_WINDOW 1 // Enable rendering of objects using environment map diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 98bf2e03c..d6765a046 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1070,132 +1070,246 @@ void GLCanvas3D::load_arrange_settings() m_arrange_settings_fff_seq_print.alignment = arr_alignment ; } -static int processed_object_idx(const Model& model, const SLAPrint& sla_print, const GLVolumePtrs& volumes) +static std::vector processed_objects_idxs(const Model& model, const SLAPrint& sla_print, const GLVolumePtrs& volumes) { - for (const GLVolume* v : volumes) { - if (v->volume_idx() == -(int)slaposDrillHoles) { - const int mo_idx = v->object_idx(); - const ModelObject* model_object = (mo_idx < (int)model.objects.size()) ? model.objects[mo_idx] : nullptr; - if (model_object != nullptr && model_object->instances[v->instance_idx()]->is_printable()) { - const SLAPrintObject* print_object = sla_print.get_print_object_by_model_object_id(model_object->id()); - if (print_object != nullptr && print_object->get_parts_to_slice().size() > 1) - return mo_idx; - } + std::vector ret; + GLVolumePtrs matching_volumes; + std::copy_if(volumes.begin(), volumes.end(), std::back_inserter(matching_volumes), [](GLVolume* v) { + return v->volume_idx() == -(int)slaposDrillHoles; }); + for (const GLVolume* v : matching_volumes) { + const int mo_idx = v->object_idx(); + const ModelObject* model_object = (mo_idx < (int)model.objects.size()) ? model.objects[mo_idx] : nullptr; + if (model_object != nullptr && model_object->instances[v->instance_idx()]->is_printable()) { + const SLAPrintObject* print_object = sla_print.get_print_object_by_model_object_id(model_object->id()); + if (print_object != nullptr && print_object->get_parts_to_slice().size() > 1) + ret.push_back(mo_idx); } } - - return -1; + std::sort(ret.begin(), ret.end()); + ret.erase(std::unique(ret.begin(), ret.end()), ret.end()); + return ret; }; -GLCanvas3D::ESLAViewType GLCanvas3D::SLAView::detect_type(const GLVolumePtrs& volumes) +static bool composite_id_match(const GLVolume::CompositeID& id1, const GLVolume::CompositeID& id2) { - m_type = ESLAViewType::Original; - if (m_allow_type_detection) { - for (const GLVolume* v : volumes) { - if (v->volume_idx() == -(int)slaposDrillHoles) { - m_type = ESLAViewType::Processed; - break; - } + return id1.object_id == id2.object_id && id1.instance_id == id2.instance_id; +} + +void GLCanvas3D::SLAView::detect_type_from_volumes(const GLVolumePtrs& volumes) +{ + for (auto& [id, type] : m_instances_cache) { + type = ESLAViewType::Original; + } + + for (const GLVolume* v : volumes) { + if (v->volume_idx() == -(int)slaposDrillHoles) { + const InstancesCacheItem* instance = find_instance_item(v->composite_id); + assert(instance != nullptr); + set_type(instance->first, ESLAViewType::Processed); } } - - m_parent.set_sla_view_type(m_type); - m_allow_type_detection = false; - return m_type; } -bool GLCanvas3D::SLAView::set_type(ESLAViewType type) { - if (m_type != type) { - m_type = type; - return true; +void GLCanvas3D::SLAView::set_type(ESLAViewType new_type) +{ + for (auto& [id, type] : m_instances_cache) { + type = new_type; + if (new_type == ESLAViewType::Processed) + select_full_instance(id); } - return false; } -void GLCanvas3D::SLAView::update_volumes(GLVolumePtrs& volumes) +void GLCanvas3D::SLAView::set_type(const GLVolume::CompositeID& id, ESLAViewType new_type) +{ + InstancesCacheItem* instance = find_instance_item(id); + assert(instance != nullptr); + instance->second = new_type; + if (new_type == ESLAViewType::Processed) + select_full_instance(id); +} + +void GLCanvas3D::SLAView::update_volumes_visibility(GLVolumePtrs& volumes) { const SLAPrint* sla_print = m_parent.sla_print(); - const int mo_idx = (sla_print != nullptr) ? processed_object_idx(*m_parent.get_model(), *sla_print, volumes) : -1; - const bool show_processed = m_type == ESLAViewType::Processed && mo_idx != -1; - - auto show = [show_processed](const GLVolume& v) { - return show_processed ? v.volume_idx() < 0 : v.volume_idx() != -(int)slaposDrillHoles; - }; + const std::vector mo_idxs = (sla_print != nullptr) ? processed_objects_idxs(*m_parent.get_model(), *sla_print, volumes) : std::vector(); std::vector>* raycasters = m_parent.get_raycasters_for_picking(SceneRaycaster::EType::Volume); for (GLVolume* v : volumes) { - v->is_active = v->object_idx() != mo_idx || show(*v); + const int obj_idx = v->object_idx(); + bool active = std::find(mo_idxs.begin(), mo_idxs.end(), obj_idx) == mo_idxs.end(); + if (!active) { + const InstancesCacheItem* instance = find_instance_item(v->composite_id); + assert(instance != nullptr); + active = (instance->second == ESLAViewType::Processed) ? v->volume_idx() < 0 : v->volume_idx() != -(int)slaposDrillHoles; + } + v->is_active = active; auto it = std::find_if(raycasters->begin(), raycasters->end(), [v](std::shared_ptr item) { return item->get_raycaster() == v->mesh_raycaster.get(); }); if (it != raycasters->end()) (*it)->set_active(v->is_active); } } +void GLCanvas3D::SLAView::update_instances_cache(const std::vector>& new_to_old_ids_map) +{ + // First, extract current instances list from the volumes + const GLVolumePtrs& volumes = m_parent.get_volumes().volumes; + std::vector new_instances_cache; + for (const GLVolume* v : volumes) { + new_instances_cache.emplace_back(v->composite_id, ESLAViewType::Original); + } + + std::sort(new_instances_cache.begin(), new_instances_cache.end(), + [](const InstancesCacheItem& i1, const InstancesCacheItem& i2) { + return i1.first.object_id < i2.first.object_id || (i1.first.object_id == i2.first.object_id && i1.first.instance_id < i2.first.instance_id); }); + + new_instances_cache.erase(std::unique(new_instances_cache.begin(), new_instances_cache.end(), + [](const InstancesCacheItem& i1, const InstancesCacheItem& i2) { + return composite_id_match(i1.first, i2.first); }), new_instances_cache.end()); + + // Second, update instances type from previous state + for (auto& inst_type : new_instances_cache) { + const auto map_to_old_it = std::find_if(new_to_old_ids_map.begin(), new_to_old_ids_map.end(), [&inst_type](const std::pair& item) { + return composite_id_match(inst_type.first, item.first); }); + + const GLVolume::CompositeID old_inst_id = (map_to_old_it != new_to_old_ids_map.end()) ? map_to_old_it->second : inst_type.first; + const InstancesCacheItem* old_instance = find_instance_item(old_inst_id); + if (old_instance != nullptr) + inst_type.second = old_instance->second; + } + + m_instances_cache = new_instances_cache; +} + void GLCanvas3D::SLAView::render_switch_button() { const SLAPrint* sla_print = m_parent.sla_print(); - const int mo_idx = (sla_print != nullptr) ? processed_object_idx(*m_parent.get_model(), *sla_print, m_parent.get_volumes().volumes) : -1; - if (mo_idx == -1) + if (sla_print == nullptr) return; - const BoundingBoxf ss_box = m_parent.get_selection().get_screen_space_bounding_box(); - if (ss_box.defined) { - ImGuiWrapper& imgui = *wxGetApp().imgui(); - ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); - ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); - ImGui::SetNextWindowPos(ImVec2((float)ss_box.max.x(), (float)ss_box.center().y()), ImGuiCond_Always, ImVec2(0.0, 0.5)); - imgui.begin(std::string("SLAViewSwitch"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration); - const float icon_size = 1.5 * ImGui::GetTextLineHeight(); - if (imgui.draw_radio_button(_u8L("SLA view"), 1.5f * icon_size, true, [this, &imgui](ImGuiWindow& window, const ImVec2& pos, float size) { + const std::vector mo_idxs = processed_objects_idxs(*m_parent.get_model(), *sla_print, m_parent.get_volumes().volumes); + if (mo_idxs.empty()) + return; + + Selection& selection = m_parent.get_selection(); + const int obj_idx = selection.get_object_idx(); + if (std::find(mo_idxs.begin(), mo_idxs.end(), obj_idx) == mo_idxs.end()) + return; + + const int inst_idx = selection.get_instance_idx(); + if (inst_idx < 0) + return; + + const GLVolume::CompositeID composite_id(obj_idx, 0, inst_idx); + const InstancesCacheItem* sel_instance = find_instance_item(composite_id); + if (sel_instance == nullptr) + return; + + const ESLAViewType type = sel_instance->second; + + BoundingBoxf ss_box; + if (m_use_instance_bbox) { + const Selection::EMode mode = selection.get_mode(); + if (obj_idx >= 0 && inst_idx >= 0) { + const Selection::IndicesList selected_idxs = selection.get_volume_idxs(); + std::vector idxs_as_vector; + idxs_as_vector.assign(selected_idxs.begin(), selected_idxs.end()); + selection.add_instance(obj_idx, inst_idx, true); + ss_box = selection.get_screen_space_bounding_box(); + selection.add_volumes(mode, idxs_as_vector, true); + } + } + + if (!ss_box.defined) + ss_box = selection.get_screen_space_bounding_box(); + assert(ss_box.defined); + + ImGuiWrapper& imgui = *wxGetApp().imgui(); + ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); + ImGui::SetNextWindowPos(ImVec2((float)ss_box.max.x(), (float)ss_box.center().y()), ImGuiCond_Always, ImVec2(0.0, 0.5)); + imgui.begin(std::string("SLAViewSwitch"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration); + const float icon_size = 1.5 * ImGui::GetTextLineHeight(); + if (imgui.draw_radio_button(_u8L("SLA view"), 1.5f * icon_size, true, + [this, &imgui, sel_instance](ImGuiWindow& window, const ImVec2& pos, float size) { wchar_t icon_id; - switch (m_type) + switch (sel_instance->second) { case ESLAViewType::Original: { icon_id = ImGui::SlaViewProcessed; break; } case ESLAViewType::Processed: { icon_id = ImGui::SlaViewOriginal; break; } default: { assert(false); break; } } imgui.draw_icon(window, pos, size, icon_id); - - })) { - switch (m_type) - { - case ESLAViewType::Original: { m_parent.set_sla_view_type(ESLAViewType::Processed); break; } - case ESLAViewType::Processed: { m_parent.set_sla_view_type(ESLAViewType::Original); break; } - default: { assert(false); break; } - } + })) { + switch (sel_instance->second) + { + case ESLAViewType::Original: { m_parent.set_sla_view_type(sel_instance->first, ESLAViewType::Processed); break; } + case ESLAViewType::Processed: { m_parent.set_sla_view_type(sel_instance->first, ESLAViewType::Original); break; } + default: { assert(false); break; } } - - if (ImGui::IsItemHovered()) { - ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND); - ImGui::BeginTooltip(); - wxString tooltip; - switch (m_type) - { - case ESLAViewType::Original: { tooltip = _L("Show as processed"); break; } - case ESLAViewType::Processed: { tooltip = _L("Show as original"); break; } - default: { assert(false); break; } - } - - imgui.text(tooltip); - ImGui::EndTooltip(); - ImGui::PopStyleColor(); - } - imgui.end(); - ImGui::PopStyleColor(2); } + + if (ImGui::IsItemHovered()) { + ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND); + ImGui::BeginTooltip(); + wxString tooltip; + switch (type) + { + case ESLAViewType::Original: { tooltip = _L("Show as processed"); break; } + case ESLAViewType::Processed: { tooltip = _L("Show as original"); break; } + default: { assert(false); break; } + } + + imgui.text(tooltip); + ImGui::EndTooltip(); + ImGui::PopStyleColor(); + } + imgui.end(); + ImGui::PopStyleColor(2); } -//void GLCanvas3D::SLAView::render_debug_window() -//{ -// ImGuiWrapper& imgui = *wxGetApp().imgui(); -// imgui.begin(std::string("SLAView"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize); -// imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Type:"); -// ImGui::SameLine(); -// const std::string text = (m_type == ESLAViewType::Original) ? "Original" : "Processed"; -// imgui.text_colored(ImGui::GetStyleColorVec4(ImGuiCol_Text), text); -// imgui.end(); -//} +#if ENABLE_SLA_VIEW_DEBUG_WINDOW +void GLCanvas3D::SLAView::render_debug_window() +{ + ImGuiWrapper& imgui = *wxGetApp().imgui(); + imgui.begin(std::string("SLAView"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize); + for (const auto& [id, type] : m_instances_cache) { + imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "(" + std::to_string(id.object_id) + ", " + std::to_string(id.instance_id) + ")"); + ImGui::SameLine(); + imgui.text_colored(ImGui::GetStyleColorVec4(ImGuiCol_Text), (type == ESLAViewType::Original) ? "Original" : "Processed"); + } + if (!m_instances_cache.empty()) + ImGui::Separator(); + + imgui.checkbox("Use instance bounding box", m_use_instance_bbox); + imgui.end(); +} +#endif // ENABLE_SLA_VIEW_DEBUG_WINDOW + +GLCanvas3D::SLAView::InstancesCacheItem* GLCanvas3D::SLAView::find_instance_item(const GLVolume::CompositeID& id) +{ + auto it = std::find_if(m_instances_cache.begin(), m_instances_cache.end(), + [&id](const InstancesCacheItem& item) { return composite_id_match(item.first, id); }); + return (it == m_instances_cache.end()) ? nullptr : &(*it); +} + +void GLCanvas3D::SLAView::select_full_instance(const GLVolume::CompositeID& id) +{ + bool extended_selection = false; + Selection& selection = m_parent.get_selection(); + const Selection::ObjectIdxsToInstanceIdxsMap& sel_cache = selection.get_content(); + auto obj_it = sel_cache.find(id.object_id); + if (obj_it != sel_cache.end()) { + auto inst_it = std::find(obj_it->second.begin(), obj_it->second.end(), id.instance_id); + if (inst_it != obj_it->second.end()) { + selection.add_instance(id.object_id, id.instance_id); + extended_selection = true; + } + } + + if (extended_selection) + m_parent.post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); +} PrinterTechnology GLCanvas3D::current_printer_technology() const { @@ -1775,7 +1889,9 @@ void GLCanvas3D::render() const GLGizmosManager::EType type = m_gizmos.get_current_type(); if (type == GLGizmosManager::EType::Undefined) m_sla_view.render_switch_button(); -// m_sla_view.render_debug_window(); +#if ENABLE_SLA_VIEW_DEBUG_WINDOW + m_sla_view.render_debug_window(); +#endif // ENABLE_SLA_VIEW_DEBUG_WINDOW } std::string tooltip; @@ -2017,6 +2133,8 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re size_t volume_idx; }; + std::vector> new_to_old_ids_map; + // SLA steps to pull the preview meshes for. typedef std::array SLASteps; SLASteps sla_steps = { slaposDrillHoles, slaposSupportTree, slaposPad }; @@ -2164,12 +2282,12 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re for (unsigned int obj_idx = 0; obj_idx < (unsigned int)m_model->objects.size(); ++ obj_idx) { const ModelObject &model_object = *m_model->objects[obj_idx]; for (int volume_idx = 0; volume_idx < (int)model_object.volumes.size(); ++ volume_idx) { - const ModelVolume &model_volume = *model_object.volumes[volume_idx]; + const ModelVolume &model_volume = *model_object.volumes[volume_idx]; for (int instance_idx = 0; instance_idx < (int)model_object.instances.size(); ++ instance_idx) { - const ModelInstance &model_instance = *model_object.instances[instance_idx]; - ModelVolumeState key(model_volume.id(), model_instance.id()); - auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower); - assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id); + const ModelInstance &model_instance = *model_object.instances[instance_idx]; + ModelVolumeState key(model_volume.id(), model_instance.id()); + auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower); + assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id); if (it->new_geometry()) { // New volume. auto it_old_volume = std::lower_bound(deleted_volumes.begin(), deleted_volumes.end(), GLVolumeState(it->composite_id), deleted_volumes_lower); @@ -2182,15 +2300,17 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx); m_volumes.volumes.back()->geometry_id = key.geometry_id; update_object_list = true; - } else { - // Recycling an old GLVolume. - GLVolume &existing_volume = *m_volumes.volumes[it->volume_idx]; + } + else { + // Recycling an old GLVolume. + GLVolume &existing_volume = *m_volumes.volumes[it->volume_idx]; assert(existing_volume.geometry_id == key.geometry_id); - // Update the Object/Volume/Instance indices into the current Model. - if (existing_volume.composite_id != it->composite_id) { - existing_volume.composite_id = it->composite_id; - update_object_list = true; - } + // Update the Object/Volume/Instance indices into the current Model. + if (existing_volume.composite_id != it->composite_id) { + new_to_old_ids_map.push_back(std::make_pair(it->composite_id, existing_volume.composite_id)); + existing_volume.composite_id = it->composite_id; + update_object_list = true; + } } } } @@ -2241,7 +2361,9 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re } else { // Recycling an old GLVolume. Update the Object/Instance indices into the current Model. - m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx); + const GLVolume::CompositeID new_id(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx); + new_to_old_ids_map.push_back(std::make_pair(new_id, m_volumes.volumes[it->volume_idx]->composite_id)); + m_volumes.volumes[it->volume_idx]->composite_id = new_id; m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation()); } } @@ -2252,9 +2374,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re if (!instances[istep].empty()) m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp); } - - if (m_sla_view.detect_type(m_volumes.volumes) == ESLAViewType::Processed) - update_object_list = true; } // Shift-up all volumes of the object so that it has the right elevation with respect to the print bed @@ -2312,15 +2431,30 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re else m_selection.volumes_changed(map_glvolume_old_to_new); - if (printer_technology == ptSLA) - m_sla_view.update_volumes(m_volumes.volumes); + if (printer_technology == ptSLA) { + std::sort(new_to_old_ids_map.begin(), new_to_old_ids_map.end(), + [](const std::pair& i1, const std::pair& i2) { + return i1.first.object_id < i2.first.object_id || (i1.first.object_id == i2.first.object_id && i1.first.instance_id < i2.first.instance_id); }); + + new_to_old_ids_map.erase(std::unique(new_to_old_ids_map.begin(), new_to_old_ids_map.end(), + [](const std::pair& i1, const std::pair& i2) { + return composite_id_match(i1.first, i2.first); }), new_to_old_ids_map.end()); + + m_sla_view.update_instances_cache(new_to_old_ids_map); + if (m_sla_view_type_detection_active) { + m_sla_view.detect_type_from_volumes(m_volumes.volumes); + m_sla_view_type_detection_active = false; + } + m_sla_view.update_volumes_visibility(m_volumes.volumes); + update_object_list = true; + } m_gizmos.update_data(); m_gizmos.refresh_on_off_state(); // Update the toolbar - if (update_object_list) - post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); + if (update_object_list) + post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); // checks for geometry outside the print volume to render it accordingly if (!m_volumes.empty()) { @@ -4324,6 +4458,20 @@ std::pair> GLCanvas3D::get_layers_h return ret; } +void GLCanvas3D::set_sla_view_type(ESLAViewType type) +{ + m_sla_view.set_type(type); + m_sla_view.update_volumes_visibility(m_volumes.volumes); + m_dirty = true; +} + +void GLCanvas3D::set_sla_view_type(const GLVolume::CompositeID& id, ESLAViewType type) +{ + m_sla_view.set_type(id, type); + m_sla_view.update_volumes_visibility(m_volumes.volumes); + m_dirty = true; +} + bool GLCanvas3D::_is_shown_on_screen() const { return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false; diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 201a86fa0..a0e4df88f 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -555,27 +555,33 @@ private: { public: explicit SLAView(GLCanvas3D& parent) : m_parent(parent) {} - void allow_type_detection(bool allow) { m_allow_type_detection = allow; } - ESLAViewType detect_type(const GLVolumePtrs& volumes); - ESLAViewType get_type() const { return m_type; } - bool set_type(ESLAViewType type); - void update_volumes(GLVolumePtrs& volumes); + void detect_type_from_volumes(const GLVolumePtrs& volumes); + void set_type(ESLAViewType type); + void set_type(const GLVolume::CompositeID& id, ESLAViewType type); + void update_volumes_visibility(GLVolumePtrs& volumes); + void update_instances_cache(const std::vector>& new_to_old_ids_map); void render_switch_button(); -// void render_debug_window(); + +#if ENABLE_SLA_VIEW_DEBUG_WINDOW + void render_debug_window(); +#endif // ENABLE_SLA_VIEW_DEBUG_WINDOW private: GLCanvas3D& m_parent; - ESLAViewType m_type{ ESLAViewType::Original }; - bool m_allow_type_detection{ false }; + typedef std::pair InstancesCacheItem; + std::vector m_instances_cache; + bool m_use_instance_bbox{ false }; + + InstancesCacheItem* find_instance_item(const GLVolume::CompositeID& id); + void select_full_instance(const GLVolume::CompositeID& id); }; SLAView m_sla_view; + bool m_sla_view_type_detection_active{ false }; ArrangeSettings m_arrange_settings_fff, m_arrange_settings_sla, m_arrange_settings_fff_seq_print; - PrinterTechnology current_printer_technology() const; - bool is_arrange_alignment_enabled() const; template @@ -793,6 +799,8 @@ public: void zoom_to_gcode(); void select_view(const std::string& direction); + PrinterTechnology current_printer_technology() const; + void update_volumes_colors_by_extruder(); bool is_dragging() const { return m_gizmos.is_dragging() || (m_moving && !m_mouse.scene_position.isApprox(m_mouse.drag.start_position_3D)); } @@ -980,21 +988,9 @@ public: std::pair> get_layers_height_data(int object_id); - void set_sla_view_type(ESLAViewType type) { - if (type == ESLAViewType::Processed) { - assert(!m_selection.is_empty()); - const GLVolume* v = m_selection.get_first_volume(); - m_selection.add_instance(v->object_idx(), v->instance_idx()); - post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); - } - - m_dirty = type != m_sla_view.get_type(); - - if (m_sla_view.set_type(type)) - m_sla_view.update_volumes(m_volumes.volumes); - } - - void allow_sla_view_type_detection(bool allow) { m_sla_view.allow_type_detection(allow); } + void set_sla_view_type(ESLAViewType type); + void set_sla_view_type(const GLVolume::CompositeID& id, ESLAViewType type); + void enable_sla_view_type_detection() { m_sla_view_type_detection_active = true; } private: bool _is_shown_on_screen() const; diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index c2e573f97..bb8eafd1c 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -749,7 +749,7 @@ void ObjectList::selection_changed() } else if (type & itVolume) { if (printer_technology() == ptSLA) - wxGetApp().plater()->canvas3D()->set_sla_view_type(GLCanvas3D::ESLAViewType::Original); + wxGetApp().plater()->canvas3D()->set_sla_view_type(scene_selection().get_first_volume()->composite_id, GLCanvas3D::ESLAViewType::Original); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 09211b805..657235511 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -978,7 +978,8 @@ bool GLGizmosManager::activate_gizmo(EType type) return false; // gizmo refused to be turned on. } - m_parent.set_sla_view_type(GLCanvas3D::ESLAViewType::Original); + if (m_parent.current_printer_technology() == ptSLA) + m_parent.set_sla_view_type(GLCanvas3D::ESLAViewType::Original); new_gizmo.register_raycasters_for_picking(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 133167fe4..5bc90293d 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3454,10 +3454,8 @@ unsigned int Plater::priv::update_restart_background_process(bool force_update_s { // bitmask of UpdateBackgroundProcessReturnState unsigned int state = this->update_background_process(false); - if (force_update_scene || (state & UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) != 0) { - view3D->get_canvas3d()->allow_sla_view_type_detection(true); + if (force_update_scene || (state & UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) != 0) view3D->reload_scene(false); - } if (force_update_preview) this->preview->reload_print(); @@ -4082,8 +4080,10 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) // If RELOAD_SLA_SUPPORT_POINTS, then the SLA gizmo is updated (reload_scene calls update_gizmos_data) if (view3D->is_dragging()) delayed_scene_refresh = true; - else + else { + view3D->get_canvas3d()->enable_sla_view_type_detection(); this->update_sla_scene(); + } break; default: break; } @@ -6946,11 +6946,13 @@ void Plater::on_config_change(const DynamicPrintConfig &config) p->config->set_key_value(opt_key, config.option(opt_key)->clone()); if (opt_key == "printer_technology") { - this->set_printer_technology(config.opt_enum(opt_key)); + const PrinterTechnology printer_technology = config.opt_enum(opt_key); + this->set_printer_technology(printer_technology); p->sidebar->show_sliced_info_sizer(false); p->reset_gcode_toolpaths(); p->view3D->get_canvas3d()->reset_sequential_print_clearance(); - p->view3D->get_canvas3d()->set_sla_view_type(GLCanvas3D::ESLAViewType::Original); + if (printer_technology == ptSLA) + p->view3D->get_canvas3d()->set_sla_view_type(GLCanvas3D::ESLAViewType::Original); } else if (opt_key == "bed_shape" || opt_key == "bed_custom_texture" || opt_key == "bed_custom_model") { bed_shape_changed = true; From 35f4993ec2440e4c47ba20b985ee3e80ddccdc0d Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 10 May 2023 10:13:20 +0200 Subject: [PATCH 06/10] SPE-1606 - Fixed geometry not rendered in the 3D scene after switching from SLA to FFF printer --- src/slic3r/GUI/Plater.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 5bc90293d..b657616f0 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -6951,8 +6951,7 @@ void Plater::on_config_change(const DynamicPrintConfig &config) p->sidebar->show_sliced_info_sizer(false); p->reset_gcode_toolpaths(); p->view3D->get_canvas3d()->reset_sequential_print_clearance(); - if (printer_technology == ptSLA) - p->view3D->get_canvas3d()->set_sla_view_type(GLCanvas3D::ESLAViewType::Original); + p->view3D->get_canvas3d()->set_sla_view_type(GLCanvas3D::ESLAViewType::Original); } else if (opt_key == "bed_shape" || opt_key == "bed_custom_texture" || opt_key == "bed_custom_model") { bed_shape_changed = true; From a4605a5e9ed378c0687789abfd636bb2826d9fce Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 10 May 2023 10:20:31 +0200 Subject: [PATCH 07/10] SPE-1606 - Do no show the switch view type icon in the 3D scene if the object does not contain negative volumes --- src/slic3r/GUI/GLCanvas3D.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 804f6058d..3859372b6 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1095,6 +1095,19 @@ static bool composite_id_match(const GLVolume::CompositeID& id1, const GLVolume: return id1.object_id == id2.object_id && id1.instance_id == id2.instance_id; } +static bool object_contains_negative_volumes(const Model& model, int obj_id) { + bool ret = false; + if (0 <= obj_id && obj_id < model.objects.size()) { + for (const ModelVolume* v : model.objects[obj_id]->volumes) { + if (v->is_negative_volume()) { + ret = true; + break; + } + } + } + return ret; +} + void GLCanvas3D::SLAView::detect_type_from_volumes(const GLVolumePtrs& volumes) { for (auto& [id, type] : m_instances_cache) { @@ -1103,9 +1116,11 @@ void GLCanvas3D::SLAView::detect_type_from_volumes(const GLVolumePtrs& volumes) for (const GLVolume* v : volumes) { if (v->volume_idx() == -(int)slaposDrillHoles) { - const InstancesCacheItem* instance = find_instance_item(v->composite_id); - assert(instance != nullptr); - set_type(instance->first, ESLAViewType::Processed); + if (object_contains_negative_volumes(*m_parent.get_model(), v->composite_id.object_id)) { + const InstancesCacheItem* instance = find_instance_item(v->composite_id); + assert(instance != nullptr); + set_type(instance->first, ESLAViewType::Processed); + } } } } @@ -1196,6 +1211,9 @@ void GLCanvas3D::SLAView::render_switch_button() if (std::find(mo_idxs.begin(), mo_idxs.end(), obj_idx) == mo_idxs.end()) return; + if (!object_contains_negative_volumes(*m_parent.get_model(), obj_idx)) + return; + const int inst_idx = selection.get_instance_idx(); if (inst_idx < 0) return; From 5984111388f796858393cb05104f09ba015b39ae Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 10 May 2023 10:37:05 +0200 Subject: [PATCH 08/10] SPE-1606 - Placement of switch view type icon in the 3D scene by the current selected instance bounding box --- src/libslic3r/Technologies.hpp | 2 +- src/slic3r/GUI/GLCanvas3D.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index adfcda664..602654633 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -37,7 +37,7 @@ // Shows an imgui dialog containing data from class ObjectManipulation #define ENABLE_OBJECT_MANIPULATION_DEBUG 0 // Shows an imgui dialog containing data for class GLCanvas3D::SLAView -#define ENABLE_SLA_VIEW_DEBUG_WINDOW 1 +#define ENABLE_SLA_VIEW_DEBUG_WINDOW 0 // Enable rendering of objects using environment map diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index a0e4df88f..38dcdb8b8 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -570,7 +570,7 @@ private: GLCanvas3D& m_parent; typedef std::pair InstancesCacheItem; std::vector m_instances_cache; - bool m_use_instance_bbox{ false }; + bool m_use_instance_bbox{ true }; InstancesCacheItem* find_instance_item(const GLVolume::CompositeID& id); void select_full_instance(const GLVolume::CompositeID& id); From 662c3da65b2c44cc42768d5c036ba9fb0ee51a76 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 10 May 2023 11:01:50 +0200 Subject: [PATCH 09/10] Fixed warnings --- src/slic3r/GUI/GLCanvas3D.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 3859372b6..610f3bdec 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1097,7 +1097,7 @@ static bool composite_id_match(const GLVolume::CompositeID& id1, const GLVolume: static bool object_contains_negative_volumes(const Model& model, int obj_id) { bool ret = false; - if (0 <= obj_id && obj_id < model.objects.size()) { + if (0 <= obj_id && obj_id < (int)model.objects.size()) { for (const ModelVolume* v : model.objects[obj_id]->volumes) { if (v->is_negative_volume()) { ret = true; @@ -1250,13 +1250,7 @@ void GLCanvas3D::SLAView::render_switch_button() const float icon_size = 1.5 * ImGui::GetTextLineHeight(); if (imgui.draw_radio_button(_u8L("SLA view"), 1.5f * icon_size, true, [this, &imgui, sel_instance](ImGuiWindow& window, const ImVec2& pos, float size) { - wchar_t icon_id; - switch (sel_instance->second) - { - case ESLAViewType::Original: { icon_id = ImGui::SlaViewProcessed; break; } - case ESLAViewType::Processed: { icon_id = ImGui::SlaViewOriginal; break; } - default: { assert(false); break; } - } + const wchar_t icon_id = (sel_instance->second == ESLAViewType::Original) ? ImGui::SlaViewProcessed : ImGui::SlaViewOriginal; imgui.draw_icon(window, pos, size, icon_id); })) { switch (sel_instance->second) From 663465299ba0665698c37bb7017b41c9990284fd Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 10 May 2023 11:15:39 +0200 Subject: [PATCH 10/10] Small refactoring --- src/libslic3r/Model.cpp | 8 ++++++++ src/libslic3r/Model.hpp | 2 ++ src/slic3r/GUI/GLCanvas3D.cpp | 11 +---------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 837f32479..f2a1db3c9 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -2097,6 +2097,14 @@ bool ModelObject::has_solid_mesh() const return false; } +bool ModelObject::has_negative_volume_mesh() const +{ + for (const ModelVolume* volume : volumes) + if (volume->is_negative_volume()) + return true; + return false; +} + void ModelVolume::set_material_id(t_model_material_id material_id) { m_material_id = material_id; diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index ea22b968d..359e1fbbd 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -503,6 +503,8 @@ public: // Detect if object has at least one solid mash bool has_solid_mesh() const; + // Detect if object has at least one negative volume mash + bool has_negative_volume_mesh() const; bool is_cut() const { return cut_id.id().valid(); } bool has_connectors() const; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 610f3bdec..fc2e04d5a 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1096,16 +1096,7 @@ static bool composite_id_match(const GLVolume::CompositeID& id1, const GLVolume: } static bool object_contains_negative_volumes(const Model& model, int obj_id) { - bool ret = false; - if (0 <= obj_id && obj_id < (int)model.objects.size()) { - for (const ModelVolume* v : model.objects[obj_id]->volumes) { - if (v->is_negative_volume()) { - ret = true; - break; - } - } - } - return ret; + return (0 <= obj_id && obj_id < (int)model.objects.size()) ? model.objects[obj_id]->has_negative_volume_mesh() : false; } void GLCanvas3D::SLAView::detect_type_from_volumes(const GLVolumePtrs& volumes)