From 4e74e4ecc06daa71869ddd1c48914ffb29e87761 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 3 Aug 2023 10:01:23 +0200 Subject: [PATCH] CutGizmo: Implemented validation of groove size/position --- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 103 +++++++++++++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoCut.hpp | 8 ++- 2 files changed, 79 insertions(+), 32 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 8c27a96f0c..7effe33107 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -509,10 +509,8 @@ bool GLGizmoCut3D::render_cut_mode_combo() m_contour_width = CutMode(m_mode) == CutMode::cutTongueAndGroove ? 0.f : 0.4f; oc->set_behavior(m_connectors_editing, m_connectors_editing, double(m_contour_width)); } - if (m_use_TAG_mesh) { - m_plane.reset(); - on_unregister_raycasters_for_picking(); - } + if (m_use_TAG_mesh) + update_plane_model(); reset_cut_by_contours(); update_clipper(); check_and_update_connectors_state(); @@ -921,6 +919,23 @@ indexed_triangle_set GLGizmoCut3D::its_make_groove_plane() const float cut_plane_thiknes = 0.02f;// 0.02f * (float)get_grabber_mean_size(m_bounding_box); // cut_plane_thiknes + // Vertices of the groove used to detection if groove is valid + // They are written as: + // {left_ext_lower, left_nar_lower, left_ext_upper, left_nar_upper, + // right_ext_lower, right_nar_lower, right_ext_upper, right_nar_upper } + { + m_groove_vertices.clear(); + m_groove_vertices.reserve(8); + + m_groove_vertices.emplace_back(Vec3f(-ext_lower_x, -y, z_lower).cast()); + m_groove_vertices.emplace_back(Vec3f(-nar_lower_x, y, z_lower).cast()); + m_groove_vertices.emplace_back(Vec3f(-ext_upper_x, -y, z_upper).cast()); + m_groove_vertices.emplace_back(Vec3f(-nar_upper_x, y, z_upper).cast()); + m_groove_vertices.emplace_back(Vec3f( ext_lower_x, -y, z_lower).cast()); + m_groove_vertices.emplace_back(Vec3f( nar_lower_x, y, z_lower).cast()); + m_groove_vertices.emplace_back(Vec3f( ext_upper_x, -y, z_upper).cast()); + m_groove_vertices.emplace_back(Vec3f( nar_upper_x, y, z_upper).cast()); + } // Different cases of groove plane: @@ -1211,7 +1226,7 @@ void GLGizmoCut3D::render_cut_plane() shader->set_uniform("projection_matrix", camera.get_projection_matrix()); if (m_use_TAG_mesh) { - ColorRGBA cp_clr = can_perform_cut() && has_valid_contour() ? CUT_PLANE_DEF_COLOR : CUT_PLANE_ERR_COLOR; + ColorRGBA cp_clr = can_perform_cut() && has_valid_groove() ? CUT_PLANE_DEF_COLOR : CUT_PLANE_ERR_COLOR; if (m_mode == size_t(CutMode::cutTongueAndGroove)) cp_clr.a(cp_clr.a() - 0.1f); m_plane.model.set_color(cp_clr); @@ -1718,6 +1733,14 @@ void GLGizmoCut3D::update_raycasters_for_picking_transform() } } +void GLGizmoCut3D::update_plane_model() +{ + m_plane.reset(); + on_unregister_raycasters_for_picking(); + + init_picking_models(); +} + void GLGizmoCut3D::on_set_hover_id() { } @@ -2415,10 +2438,7 @@ void GLGizmoCut3D::render_debug_input_window(float x) is_changed |= m_imgui->checkbox(("Render Cut plane as a full mesh"), m_use_TAG_mesh_full); if (is_changed) - { - m_plane.reset(); - on_unregister_raycasters_for_picking(); - } + update_plane_model(); m_imgui->end(); return; @@ -2710,14 +2730,12 @@ void GLGizmoCut3D::reset_cut_by_contours() m_part_selection = PartSelection(); if (CutMode(m_mode) == CutMode::cutTongueAndGroove) { - if (m_optimaze_groove_rendering && m_dragging) + if (m_optimaze_groove_rendering && m_dragging || !has_valid_groove()) return; process_contours(); } - else { - m_invalid_groove = false; + else toggle_model_objects_visibility(); - } } void GLGizmoCut3D::process_contours() @@ -2734,10 +2752,8 @@ void GLGizmoCut3D::process_contours() if (CutMode(m_mode) == CutMode::cutTongueAndGroove) { ModelObjectPtrs cut_objects = perform_cut_with_groove(model_objects[object_idx], true); - if (!cut_objects.empty() && !m_invalid_groove) + if (!cut_objects.empty()) m_part_selection = PartSelection(cut_objects.front(), instance_idx); - else - m_invalid_groove = true; } else { reset_cut_by_contours(); @@ -2808,10 +2824,8 @@ void GLGizmoCut3D::render_groove_float_input(const std::string& label, float& in m_imgui->disabled_end(); if (is_changed) { - if (m_use_TAG_mesh) { - m_plane.reset(); - on_unregister_raycasters_for_picking(); - } + if (m_use_TAG_mesh) + update_plane_model(); reset_cut_by_contours(); // Plater::TakeSnapshot snapshot(wxGetApp().plater(), format_wxstr("%1%: %2%", _L("Groove change"), label), UndoRedo::SnapshotType::GizmoAction); } @@ -2848,10 +2862,8 @@ void GLGizmoCut3D::render_groove_angle_input(const std::string& label, float& in m_imgui->disabled_end(); if (is_changed) { - if (m_use_TAG_mesh) { - m_plane.reset(); - on_unregister_raycasters_for_picking(); - } + if (m_use_TAG_mesh) + update_plane_model(); reset_cut_by_contours(); // Plater::TakeSnapshot snapshot(wxGetApp().plater(), format_wxstr("%1%: %2%", _L("Groove change"), label), UndoRedo::SnapshotType::GizmoAction); } @@ -3129,7 +3141,7 @@ void GLGizmoCut3D::render_input_window_warning() const m_imgui->text(wxString(ImGui::WarningMarkerSmall) + _L("Select at least one object to keep after cutting.")); if (!has_valid_contour()) m_imgui->text(wxString(ImGui::WarningMarkerSmall) + _L("Cut plane is placed out of object")); - if (m_invalid_groove) + else if (!has_valid_groove()) m_imgui->text(wxString(ImGui::WarningMarkerSmall) + _L("Cut plane with groove is invalid")); } @@ -3362,7 +3374,7 @@ bool GLGizmoCut3D::can_perform_cut() const if (CutMode(m_mode) == CutMode::cutTongueAndGroove) { const float flaps_width = -2.f * m_groove_depth / tan(m_groove_flaps_angle); - return flaps_width < m_groove_width && !m_invalid_groove && has_valid_contour(); + return flaps_width < m_groove_width && has_valid_groove(); } if (m_part_selection.valid()) @@ -3371,6 +3383,39 @@ bool GLGizmoCut3D::can_perform_cut() const return true; } +bool GLGizmoCut3D::has_valid_groove() const +{ + if (CutMode(m_mode) != CutMode::cutTongueAndGroove) + return true; + + const Selection& selection = m_parent.get_selection(); + const auto&list = selection.get_volume_idxs(); + // is more volumes selected? + if (list.empty()) + return false; + + const Transform3d cp_matrix = translation_transform(m_plane_center) * m_rotation_m; + + for (size_t id = 0; id < m_groove_vertices.size(); id += 2) { + const Vec3d beg = cp_matrix * m_groove_vertices[id]; + const Vec3d end = cp_matrix * m_groove_vertices[id + 1]; + + bool intersection = false; + for (const unsigned int volume_idx : list) { + const GLVolume* glvol = selection.get_volume(volume_idx); + if (!glvol->is_modifier && + glvol->mesh_raycaster->intersects_line(beg, end - beg, glvol->world_matrix())) { + intersection = true; + break; + } + } + if (!intersection) + return false; + } + + return true; +} + bool GLGizmoCut3D::has_valid_contour() const { const auto clipper = m_c->object_clipper(); @@ -3569,7 +3614,8 @@ ModelObjectPtrs GLGizmoCut3D::perform_cut_by_contour(ModelObject* cut_mo, const ModelObjectPtrs GLGizmoCut3D::perform_cut_with_groove(ModelObject* cut_mo, bool keep_as_parts/* = false*/) { - m_invalid_groove = false; + if (!has_valid_groove()) + return {}; const Selection& selection = m_parent.get_selection(); const int instance_idx = selection.get_instance_idx(); @@ -3684,9 +3730,6 @@ ModelObjectPtrs GLGizmoCut3D::perform_cut_with_groove(ModelObject* cut_mo, bool invalid_added_volumes |= !add_volumes_from_cut(upper, ModelObjectCutAttribute::KeepLower, cut_part_ptrs); if (keep_as_parts) { - if (!m_invalid_groove) - m_invalid_groove = upper->volumes.empty() || lower->volumes.empty() || invalid_added_volumes; - // add volumes from lower object to the upper, but mark them as a lower const auto& volumes = lower->volumes; for (const ModelVolume* volume : volumes) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index db62cacdd1..c8bf50c29c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -109,8 +109,6 @@ class GLGizmoCut3D : public GLGizmoBase } } m_info_stats; - bool m_invalid_groove{ false }; - bool m_keep_upper{ true }; bool m_keep_lower{ true }; bool m_keep_as_parts{ false }; @@ -163,6 +161,9 @@ class GLGizmoCut3D : public GLGizmoBase bool m_was_cut_plane_dragged { false }; bool m_was_contour_selected { false }; + // Vertices of the groove used to detection if groove is valid + std::vector m_groove_vertices; + class PartSelection { public: PartSelection() = default; @@ -323,6 +324,8 @@ protected: void set_volumes_picking_state(bool state); void update_raycasters_for_picking_transform(); + void update_plane_model(); + void on_render_input_window(float x, float y, float bottom_limit) override; bool wants_enter_leave_snapshots() const override { return true; } @@ -348,6 +351,7 @@ private: void render_connectors(); bool can_perform_cut() const; + bool has_valid_groove() const; bool has_valid_contour() const; void apply_connectors_in_model(ModelObject* mo, int &dowels_count); bool cut_line_processing() const;