From d7f55253cd636c228adee9a54468ef52d8f377b0 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 16 Aug 2022 13:24:57 +0200 Subject: [PATCH] Cut: allow enabling/disabling an island --- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 45 +++--- src/slic3r/GUI/Gizmos/GLGizmoCut.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 10 ++ src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 4 + src/slic3r/GUI/MeshUtils.cpp | 177 ++++++++++++----------- src/slic3r/GUI/MeshUtils.hpp | 22 ++- 6 files changed, 150 insertions(+), 110 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 7b6c729f8..905e39db3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -1117,7 +1117,8 @@ void GLGizmoCut3D::on_dragging(const UpdateData& data) else if (m_hover_id >= m_connectors_group_id && m_connector_mode == CutConnectorMode::Manual) { std::pair pos_and_normal; - if (!unproject_on_cut_plane(data.mouse_pos.cast(), pos_and_normal)) + Vec3d pos_world; + if (!unproject_on_cut_plane(data.mouse_pos.cast(), pos_and_normal, pos_world)) return; connectors[m_hover_id - m_connectors_group_id].pos = pos_and_normal.first; update_raycasters_for_picking_transform(); @@ -1773,7 +1774,7 @@ void GLGizmoCut3D::perform_cut(const Selection& selection) // Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal // Return false if no intersection was found, true otherwise. -bool GLGizmoCut3D::unproject_on_cut_plane(const Vec2d& mouse_position, std::pair& pos_and_normal) +bool GLGizmoCut3D::unproject_on_cut_plane(const Vec2d& mouse_position, std::pair& pos_and_normal, Vec3d& pos_world) { const float sla_shift = m_c->selection_info()->get_sla_shift(); @@ -1788,8 +1789,8 @@ bool GLGizmoCut3D::unproject_on_cut_plane(const Vec2d& mouse_position, std::pair ++mesh_id; if (!mv->is_model_part()) continue; - Vec3f hit; Vec3f normal; + Vec3f hit; bool clipping_plane_was_hit = false; // const Transform3d volume_trafo = get_volume_transformation(mv); @@ -1806,6 +1807,7 @@ bool GLGizmoCut3D::unproject_on_cut_plane(const Vec2d& mouse_position, std::pair // Return both the point and the facet normal. pos_and_normal = std::make_pair(hit_d, normal.cast()); + pos_world = hit.cast(); return true; } } @@ -1916,27 +1918,32 @@ bool GLGizmoCut3D::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_posi CutConnectors& connectors = m_c->selection_info()->model_object()->cut_connectors; - if (action == SLAGizmoEventType::LeftDown && !shift_down && m_connectors_editing) { + if (action == SLAGizmoEventType::LeftDown && !shift_down) { // If there is no selection and no hovering, add new point if (m_hover_id == -1 && !control_down && !alt_down) { std::pair pos_and_normal; - if (unproject_on_cut_plane(mouse_position.cast(), pos_and_normal)) { + Vec3d pos_world; + if (unproject_on_cut_plane(mouse_position.cast(), pos_and_normal, pos_world)) { const Vec3d& hit = pos_and_normal.first; - // The clipping plane was clicked, hit containts coordinates of the hit in world coords. - //std::cout << hit.x() << "\t" << hit.y() << "\t" << hit.z() << std::endl; - Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Add connector"), UndoRedo::SnapshotType::GizmoAction); - connectors.emplace_back(hit, Geometry::Transformation(m_rotation_m).get_rotation(), - float(m_connector_size * 0.5), float(m_connector_depth_ratio), - float(0.01f * m_connector_size_tolerance), float(0.01f * m_connector_depth_ratio_tolerance), - CutConnectorAttributes( CutConnectorType(m_connector_type), - CutConnectorStyle(m_connector_style), - CutConnectorShape(m_connector_shape_id))); - std::fill(m_selected.begin(), m_selected.end(), false); - m_selected.push_back(true); - assert(m_selected.size() == connectors.size()); - update_model_object(); - m_parent.set_as_dirty(); + if (m_connectors_editing) { + + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Add connector"), UndoRedo::SnapshotType::GizmoAction); + + connectors.emplace_back(hit, Geometry::Transformation(m_rotation_m).get_rotation(), + float(m_connector_size * 0.5), float(m_connector_depth_ratio), + float(0.01f * m_connector_size_tolerance), float(0.01f * m_connector_depth_ratio_tolerance), + CutConnectorAttributes( CutConnectorType(m_connector_type), + CutConnectorStyle(m_connector_style), + CutConnectorShape(m_connector_shape_id))); + std::fill(m_selected.begin(), m_selected.end(), false); + m_selected.push_back(true); + assert(m_selected.size() == connectors.size()); + update_model_object(); + m_parent.set_as_dirty(); + } else { + m_c->object_clipper()->pass_mouse_click(pos_world); + } return true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index 81a69e425..a7892a9cd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -139,7 +139,7 @@ public: GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); std::string get_tooltip() const override; - bool unproject_on_cut_plane(const Vec2d& mouse_pos, std::pair& pos_and_normal); + bool unproject_on_cut_plane(const Vec2d& mouse_pos, std::pair& pos_and_normal, Vec3d& pos_world); bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); /// diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 97f3cb9a8..a08836c28 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -494,6 +494,16 @@ void ObjectClipper::set_behavior(bool hide_clipped, bool fill_cut, double contou clipper->set_behaviour(fill_cut, contour_width); } +void ObjectClipper::pass_mouse_click(const Vec3d& pt) +{ + for (auto& clipper : m_clippers) + clipper->pass_mouse_click(pt); +} + +std::vector ObjectClipper::get_disabled_contours() const +{ + return std::vector(); +} void SupportsClipper::on_update() { diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index 925408008..7c41a64b9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -262,6 +262,10 @@ public: void set_position_by_ratio(double pos, bool keep_normal); void set_range_and_pos(const Vec3d& cpl_normal, double cpl_offset, double pos); void set_behavior(bool hide_clipped, bool fill_cut, double contour_width); + + void pass_mouse_click(const Vec3d& pt); + std::vector get_disabled_contours() const; + protected: diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index bbf1f7652..74fe82494 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -23,7 +23,7 @@ namespace GUI { void MeshClipper::set_behaviour(bool fill_cut, double contour_width) { if (fill_cut != m_fill_cut || contour_width != m_contour_width) - m_triangles_valid = false; + m_result.reset(); m_fill_cut = fill_cut; m_contour_width = contour_width; } @@ -34,7 +34,7 @@ void MeshClipper::set_plane(const ClippingPlane& plane) { if (m_plane != plane) { m_plane = plane; - m_triangles_valid = false; + m_result.reset(); } } @@ -43,7 +43,7 @@ void MeshClipper::set_limiting_plane(const ClippingPlane& plane) { if (m_limiting_plane != plane) { m_limiting_plane = plane; - m_triangles_valid = false; + m_result.reset(); } } @@ -53,7 +53,7 @@ void MeshClipper::set_mesh(const TriangleMesh& mesh) { if (m_mesh != &mesh) { m_mesh = &mesh; - m_triangles_valid = false; + m_result.reset(); } } @@ -61,7 +61,7 @@ void MeshClipper::set_negative_mesh(const TriangleMesh& mesh) { if (m_negative_mesh != &mesh) { m_negative_mesh = &mesh; - m_triangles_valid = false; + m_result.reset(); } } @@ -71,7 +71,7 @@ void MeshClipper::set_transformation(const Geometry::Transformation& trafo) { if (! m_trafo.get_matrix().isApprox(trafo.get_matrix())) { m_trafo = trafo; - m_triangles_valid = false; + m_result.reset(); } } @@ -81,12 +81,9 @@ void MeshClipper::render_cut(const ColorRGBA& color) void MeshClipper::render_cut() #endif // ENABLE_LEGACY_OPENGL_REMOVAL { - if (! m_triangles_valid) + if (! m_result) recalculate_triangles(); #if ENABLE_LEGACY_OPENGL_REMOVAL - if (m_model.vertices_count() == 0 || m_model.indices_count() == 0) - return; - GLShaderProgram* curr_shader = wxGetApp().get_current_shader(); if (curr_shader != nullptr) curr_shader->stop_using(); @@ -97,8 +94,10 @@ void MeshClipper::render_cut() const Camera& camera = wxGetApp().plater()->get_camera(); shader->set_uniform("view_model_matrix", camera.get_view_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - m_model.set_color(color); - m_model.render(); + for (CutIsland& isl : m_result->cut_islands) { + isl.model.set_color(isl.disabled ? ColorRGBA(1.f, 0.f, 0.f, 1.f) : color); + isl.model.render(); + } shader->stop_using(); } @@ -117,7 +116,7 @@ void MeshClipper::render_contour(const ColorRGBA& color) void MeshClipper::render_contour() #endif // ENABLE_LEGACY_OPENGL_REMOVAL { - if (! m_triangles_valid) + if (! m_result) recalculate_triangles(); #if ENABLE_LEGACY_OPENGL_REMOVAL GLShaderProgram* curr_shader = wxGetApp().get_current_shader(); @@ -130,8 +129,10 @@ void MeshClipper::render_contour() const Camera& camera = wxGetApp().plater()->get_camera(); shader->set_uniform("view_model_matrix", camera.get_view_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - m_model_expanded.set_color(color); - m_model_expanded.render(); + for (CutIsland& isl : m_result->cut_islands) { + isl.model_expanded.set_color(color); + isl.model_expanded.render(); + } shader->stop_using(); } @@ -145,8 +146,24 @@ void MeshClipper::render_contour() +void MeshClipper::pass_mouse_click(const Vec3d& point_in) +{ + if (! m_result || m_result->cut_islands.empty()) + return; + Vec3d point = m_result->trafo.inverse() * point_in; + Point pt_2d = Point::new_scale(Vec2d(point.x(), point.y())); + + for (CutIsland& isl : m_result->cut_islands) { + if (isl.expoly_bb.contains(pt_2d) && isl.expoly.contains(pt_2d)) + isl.disabled = ! isl.disabled; + } +} + void MeshClipper::recalculate_triangles() { + m_result = ClipResult(); + + #if ENABLE_WORLD_COORDINATE const Transform3f instance_matrix_no_translation_no_scaling = m_trafo.get_rotation_matrix().cast(); #else @@ -176,6 +193,8 @@ void MeshClipper::recalculate_triangles() tr.rotate(q); tr = m_trafo.get_matrix() * tr; + m_result->trafo = tr; + if (m_limiting_plane != ClippingPlane::ClipsNothing()) { // Now remove whatever ended up below the limiting plane (e.g. sinking objects). @@ -231,88 +250,72 @@ void MeshClipper::recalculate_triangles() tr.pretranslate(0.001 * m_plane.get_normal().normalized()); // to avoid z-fighting - std::vector triangles2d = m_fill_cut - ? triangulate_expolygons_2f(expolys, m_trafo.get_matrix().matrix().determinant() < 0.) - : std::vector(); #if ENABLE_LEGACY_OPENGL_REMOVAL - m_model.reset(); + std::vector triangles2d; - GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; - init_data.reserve_vertices(triangles2d.size()); - init_data.reserve_indices(triangles2d.size()); + for (const ExPolygon& exp : expolys) { + triangles2d.clear(); - // vertices + indices - for (auto it = triangles2d.cbegin(); it != triangles2d.cend(); it = it + 3) { - init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast(), (Vec3f)up.cast()); - init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast(), (Vec3f)up.cast()); - init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast(), (Vec3f)up.cast()); - const size_t idx = it - triangles2d.cbegin(); - init_data.add_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2); + m_result->cut_islands.push_back(CutIsland()); + CutIsland& isl = m_result->cut_islands.back(); + + if (m_fill_cut) { + triangles2d = triangulate_expolygon_2f(exp, m_trafo.get_matrix().matrix().determinant() < 0.); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + init_data.reserve_vertices(triangles2d.size()); + init_data.reserve_indices(triangles2d.size()); + + // vertices + indices + for (auto it = triangles2d.cbegin(); it != triangles2d.cend(); it = it + 3) { + init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + const size_t idx = it - triangles2d.cbegin(); + init_data.add_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2); + } + + if (!init_data.is_empty()) + isl.model.init_from(std::move(init_data)); + } + + if (m_contour_width != 0.) { + triangles2d.clear(); + ExPolygons expolys_exp = offset_ex(exp, scale_(m_contour_width)); + expolys_exp = diff_ex(expolys_exp, ExPolygons({exp})); + triangles2d = triangulate_expolygons_2f(expolys_exp, m_trafo.get_matrix().matrix().determinant() < 0.); + GLModel::Geometry init_data = GLModel::Geometry(); + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + init_data.reserve_vertices(triangles2d.size()); + init_data.reserve_indices(triangles2d.size()); + + // vertices + indices + for (auto it = triangles2d.cbegin(); it != triangles2d.cend(); it = it + 3) { + init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast(), (Vec3f)up.cast()); + const size_t idx = it - triangles2d.cbegin(); + init_data.add_triangle((unsigned short)idx, (unsigned short)idx + 1, (unsigned short)idx + 2); + } + + if (!init_data.is_empty()) + isl.model_expanded.init_from(std::move(init_data)); + } + + isl.expoly = std::move(exp); + isl.expoly_bb = get_extents(exp); } - - if (!init_data.is_empty()) - m_model.init_from(std::move(init_data)); #else - m_vertex_array.release_geometry(); - for (auto it=triangles2d.cbegin(); it != triangles2d.cend(); it=it+3) { - m_vertex_array.push_geometry(tr * Vec3d((*(it+0))(0), (*(it+0))(1), height_mesh), up); - m_vertex_array.push_geometry(tr * Vec3d((*(it+1))(0), (*(it+1))(1), height_mesh), up); - m_vertex_array.push_geometry(tr * Vec3d((*(it+2))(0), (*(it+2))(1), height_mesh), up); - const size_t idx = it - triangles2d.cbegin(); - m_vertex_array.push_triangle(idx, idx+1, idx+2); - } - m_vertex_array.finalize_geometry(true); -#endif // ENABLE_LEGACY_OPENGL_REMOVAL - - - triangles2d = {}; - if (m_contour_width != 0.) { - ExPolygons expolys_exp = offset_ex(expolys, scale_(m_contour_width)); - expolys_exp = diff_ex(expolys_exp, expolys); - triangles2d = triangulate_expolygons_2f(expolys_exp, m_trafo.get_matrix().matrix().determinant() < 0.); - } - - -#if ENABLE_LEGACY_OPENGL_REMOVAL - m_model_expanded.reset(); - - init_data = GLModel::Geometry(); - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; - init_data.reserve_vertices(triangles2d.size()); - init_data.reserve_indices(triangles2d.size()); - - // vertices + indices - for (auto it = triangles2d.cbegin(); it != triangles2d.cend(); it = it + 3) { - init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast(), (Vec3f)up.cast()); - init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast(), (Vec3f)up.cast()); - init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast(), (Vec3f)up.cast()); - const size_t idx = it - triangles2d.cbegin(); - init_data.add_triangle((unsigned short)idx, (unsigned short)idx + 1, (unsigned short)idx + 2); - //if (init_data./*format.*/index_type == GLModel::Geometry::EIndexType::USHORT) - // init_data.add_ushort_triangle((unsigned short)idx, (unsigned short)idx + 1, (unsigned short)idx + 2); - //else - // init_data.add_uint_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2); - } - - if (!init_data.is_empty()) - m_model_expanded.init_from(std::move(init_data)); -#else - m_vertex_array_expanded.release_geometry(); - for (auto it=triangles2d.cbegin(); it != triangles2d.cend(); it=it+3) { - m_vertex_array_expanded.push_geometry(tr * Vec3d((*(it+0))(0), (*(it+0))(1), height_mesh), up); - m_vertex_array_expanded.push_geometry(tr * Vec3d((*(it+1))(0), (*(it+1))(1), height_mesh), up); - m_vertex_array_expanded.push_geometry(tr * Vec3d((*(it+2))(0), (*(it+2))(1), height_mesh), up); - const size_t idx = it - triangles2d.cbegin(); - m_vertex_array_expanded.push_triangle(idx, idx+1, idx+2); - } - m_vertex_array_expanded.finalize_geometry(true); + #error NOT IMPLEMENTED #endif // ENABLE_LEGACY_OPENGL_REMOVAL - m_triangles_valid = true; +#if ENABLE_LEGACY_OPENGL_REMOVAL +#else + #error NOT IMPLEMENTED +#endif // ENABLE_LEGACY_OPENGL_REMOVAL } diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index 5df4236a6..726f228ca 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -14,6 +14,7 @@ #endif // ENABLE_LEGACY_OPENGL_REMOVAL #include +#include #if ENABLE_RAYCAST_PICKING #include #endif // ENABLE_RAYCAST_PICKING @@ -112,6 +113,9 @@ public: void render_cut(); #endif // ENABLE_LEGACY_OPENGL_REMOVAL + void pass_mouse_click(const Vec3d& pt); + + private: void recalculate_triangles(); @@ -121,12 +125,24 @@ private: ClippingPlane m_plane; ClippingPlane m_limiting_plane = ClippingPlane::ClipsNothing(); #if ENABLE_LEGACY_OPENGL_REMOVAL - GLModel m_model; - GLModel m_model_expanded; + + struct CutIsland { + GLModel model; + GLModel model_expanded; + ExPolygon expoly; + BoundingBox expoly_bb; + bool disabled = false; + }; + struct ClipResult { + std::vector cut_islands; + Transform3d trafo; // this rotates the cut into world coords + }; + std::optional m_result; + #else + #error NOT IMLEMENTED GLIndexedVertexArray m_vertex_array; #endif // ENABLE_LEGACY_OPENGL_REMOVAL - bool m_triangles_valid = false; bool m_fill_cut = true; double m_contour_width = 0.; };