diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 97975404f..54b3bc36e 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -815,64 +815,6 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab } } -bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, ModelInstanceEPrintVolumeState *out_state) const -{ - const Model& model = GUI::wxGetApp().plater()->model(); - auto volume_below = [](GLVolume& volume) -> bool - { return volume.object_idx() != -1 && volume.volume_idx() != -1 && volume.is_below_printbed(); }; - // Volume is partially below the print bed, thus a pre-calculated convex hull cannot be used. - auto volume_sinking = [](GLVolume& volume) -> bool - { return volume.object_idx() != -1 && volume.volume_idx() != -1 && volume.is_sinking(); }; - // Cached bounding box of a volume above the print bed. - auto volume_bbox = [volume_sinking](GLVolume& volume) -> BoundingBoxf3 - { return volume_sinking(volume) ? volume.transformed_non_sinking_bounding_box() : volume.transformed_convex_hull_bounding_box(); }; - // Cached 3D convex hull of a volume above the print bed. - auto volume_convex_mesh = [volume_sinking, &model](GLVolume& volume) -> const TriangleMesh& - { return volume_sinking(volume) ? model.objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh() : *volume.convex_hull(); }; - - ModelInstanceEPrintVolumeState overall_state = ModelInstancePVS_Inside; - bool contained_min_one = false; - - for (GLVolume* volume : this->volumes) - if (! volume->is_modifier && (volume->shader_outside_printer_detection_enabled || (! volume->is_wipe_tower && volume->composite_id.volume_id >= 0))) { - BuildVolume::ObjectState state; - if (volume_below(*volume)) - state = BuildVolume::ObjectState::Below; - else { - switch (build_volume.type()) { - case BuildVolume::Type::Rectangle: - //FIXME this test does not evaluate collision of a build volume bounding box with non-convex objects. - state = build_volume.volume_state_bbox(volume_bbox(*volume)); - break; - case BuildVolume::Type::Circle: - case BuildVolume::Type::Convex: - //FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently. - case BuildVolume::Type::Custom: - state = build_volume.object_state(volume_convex_mesh(*volume).its, volume->world_matrix().cast(), volume_sinking(*volume)); - break; - default: - // Ignore, don't produce any collision. - state = BuildVolume::ObjectState::Inside; - break; - } - assert(state != BuildVolume::ObjectState::Below); - } - volume->is_outside = state != BuildVolume::ObjectState::Inside; - if (volume->printable) { - if (overall_state == ModelInstancePVS_Inside && volume->is_outside) - overall_state = ModelInstancePVS_Fully_Outside; - if (overall_state == ModelInstancePVS_Fully_Outside && volume->is_outside && state == BuildVolume::ObjectState::Colliding) - overall_state = ModelInstancePVS_Partly_Outside; - contained_min_one |= !volume->is_outside; - } - } - - if (out_state != nullptr) - *out_state = overall_state; - - return contained_min_one; -} - void GLVolumeCollection::reset_outside_state() { for (GLVolume* volume : this->volumes) { diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 2f7e0a767..805972ce7 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -450,9 +450,6 @@ public: void set_show_sinking_contours(bool show) { m_show_sinking_contours = show; } void set_show_non_manifold_edges(bool show) { m_show_non_manifold_edges = show; } - // returns true if all the volumes are completely contained in the print volume - // returns the containment state in the given out_state, if non-null - bool check_outside_state(const Slic3r::BuildVolume& build_volume, ModelInstanceEPrintVolumeState* out_state) const; void reset_outside_state(); void update_colors_by_extruder(const DynamicPrintConfig* config); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 4db4c1c2a..854c712e8 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1265,11 +1265,85 @@ void GLCanvas3D::reset_volumes() ModelInstanceEPrintVolumeState GLCanvas3D::check_volumes_outside_state() const { ModelInstanceEPrintVolumeState state = ModelInstanceEPrintVolumeState::ModelInstancePVS_Inside; - if (m_initialized) - m_volumes.check_outside_state(m_bed.build_volume(), &state); + if (m_initialized && !m_volumes.empty()) + check_volumes_outside_state(m_bed.build_volume(), &state); return state; } +bool GLCanvas3D::check_volumes_outside_state(const Slic3r::BuildVolume& build_volume, ModelInstanceEPrintVolumeState* out_state) const +{ + auto volume_below = [](GLVolume& volume) -> bool + { return volume.object_idx() != -1 && volume.volume_idx() != -1 && volume.is_below_printbed(); }; + // Volume is partially below the print bed, thus a pre-calculated convex hull cannot be used. + auto volume_sinking = [](GLVolume& volume) -> bool + { return volume.object_idx() != -1 && volume.volume_idx() != -1 && volume.is_sinking(); }; + // Cached bounding box of a volume above the print bed. + auto volume_bbox = [volume_sinking](GLVolume& volume) -> BoundingBoxf3 + { return volume_sinking(volume) ? volume.transformed_non_sinking_bounding_box() : volume.transformed_convex_hull_bounding_box(); }; + // Cached 3D convex hull of a volume above the print bed. + auto volume_convex_mesh = [this, volume_sinking](GLVolume& volume) -> const TriangleMesh& + { return volume_sinking(volume) ? m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh() : *volume.convex_hull(); }; + + auto volumes_to_process_idxs = [this]() { + std::vector ret; + if (m_selection.is_empty()) { + ret = std::vector(m_volumes.volumes.size()); + std::iota(ret.begin(), ret.end(), 0); + } + else { + const GUI::Selection::IndicesList& selected_volume_idxs = m_selection.get_volume_idxs(); + ret.assign(selected_volume_idxs.begin(), selected_volume_idxs.end()); + } + return ret; + }; + + ModelInstanceEPrintVolumeState overall_state = ModelInstancePVS_Inside; + bool contained_min_one = false; + + const std::vector volumes_idxs = volumes_to_process_idxs(); + + for (unsigned int vol_idx : volumes_idxs) { + GLVolume* volume = m_volumes.volumes[vol_idx]; + if (!volume->is_modifier && (volume->shader_outside_printer_detection_enabled || (!volume->is_wipe_tower && volume->composite_id.volume_id >= 0))) { + BuildVolume::ObjectState state; + if (volume_below(*volume)) + state = BuildVolume::ObjectState::Below; + else { + switch (build_volume.type()) { + case BuildVolume::Type::Rectangle: + //FIXME this test does not evaluate collision of a build volume bounding box with non-convex objects. + state = build_volume.volume_state_bbox(volume_bbox(*volume)); + break; + case BuildVolume::Type::Circle: + case BuildVolume::Type::Convex: + //FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently. + case BuildVolume::Type::Custom: + state = build_volume.object_state(volume_convex_mesh(*volume).its, volume->world_matrix().cast(), volume_sinking(*volume)); + break; + default: + // Ignore, don't produce any collision. + state = BuildVolume::ObjectState::Inside; + break; + } + assert(state != BuildVolume::ObjectState::Below); + } + volume->is_outside = state != BuildVolume::ObjectState::Inside; + if (volume->printable) { + if (overall_state == ModelInstancePVS_Inside && volume->is_outside) + overall_state = ModelInstancePVS_Fully_Outside; + if (overall_state == ModelInstancePVS_Fully_Outside && volume->is_outside && state == BuildVolume::ObjectState::Colliding) + overall_state = ModelInstancePVS_Partly_Outside; + contained_min_one |= !volume->is_outside; + } + } + } + + if (out_state != nullptr) + *out_state = overall_state; + + return contained_min_one; +} + void GLCanvas3D::toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo, int instance_idx) { if (current_printer_technology() != ptSLA) @@ -2235,13 +2309,13 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re 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()) { ModelInstanceEPrintVolumeState state; - const bool contained_min_one = m_volumes.check_outside_state(m_bed.build_volume(), &state); + const bool contained_min_one = check_volumes_outside_state(m_bed.build_volume(), &state); const bool partlyOut = (state == ModelInstanceEPrintVolumeState::ModelInstancePVS_Partly_Outside); const bool fullyOut = (state == ModelInstanceEPrintVolumeState::ModelInstancePVS_Fully_Outside); @@ -5694,7 +5768,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type) } } if (m_requires_check_outside_state) { - m_volumes.check_outside_state(build_volume, nullptr); + check_volumes_outside_state(build_volume, nullptr); m_requires_check_outside_state = false; } } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index e94b6742f..04ab92dfb 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -705,6 +705,9 @@ public: const GLVolumeCollection& get_volumes() const { return m_volumes; } void reset_volumes(); ModelInstanceEPrintVolumeState check_volumes_outside_state() const; + // returns true if all the volumes are completely contained in the print volume + // returns the containment state in the given out_state, if non-null + bool check_volumes_outside_state(const Slic3r::BuildVolume& build_volume, ModelInstanceEPrintVolumeState* out_state) const; void init_gcode_viewer() { m_gcode_viewer.init(); } void reset_gcode_toolpaths() { m_gcode_viewer.reset(); }