From 46da54ffaf6c1877de0710f5fcd4a20cda1932ac Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 3 Jun 2022 12:53:02 +0200 Subject: [PATCH 001/250] First implementation of SurfaceMesh --- src/libslic3r/CMakeLists.txt | 1 + src/libslic3r/SurfaceMesh.hpp | 151 ++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 src/libslic3r/SurfaceMesh.hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index e637b1402f..396494a181 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -249,6 +249,7 @@ set(SLIC3R_SOURCES Surface.hpp SurfaceCollection.cpp SurfaceCollection.hpp + SurfaceMesh.hpp SVG.cpp SVG.hpp Technologies.hpp diff --git a/src/libslic3r/SurfaceMesh.hpp b/src/libslic3r/SurfaceMesh.hpp new file mode 100644 index 0000000000..47d5ed0dcc --- /dev/null +++ b/src/libslic3r/SurfaceMesh.hpp @@ -0,0 +1,151 @@ +#ifndef slic3r_SurfaceMesh_hpp_ +#define slic3r_SurfaceMesh_hpp_ + +#include + +namespace Slic3r { + +class TriangleMesh; + + + +enum Face_index : int; + +class Halfedge_index { + friend class SurfaceMesh; + +public: + Halfedge_index() : m_face(Face_index(-1)), m_side(0) {} + Face_index face() const { return m_face; } + bool is_invalid() const { return int(m_face) < 0; } + bool operator!=(const Halfedge_index& rhs) const { return ! ((*this) == rhs); } + bool operator==(const Halfedge_index& rhs) const { return m_face == rhs.m_face && m_side == rhs.m_side; } + +private: + Halfedge_index(int face_idx, unsigned char side_idx) : m_face(Face_index(face_idx)), m_side(side_idx) {} + + Face_index m_face; + unsigned char m_side; +}; + + + +class Vertex_index { + friend class SurfaceMesh; + +public: + Vertex_index() : m_face(Face_index(-1)), m_vertex_idx(0) {} + bool is_invalid() const { return int(m_face) < 0; } + bool operator==(const Vertex_index& rhs) const = delete; // Use SurfaceMesh::is_same_vertex. + +private: + Vertex_index(int face_idx, unsigned char vertex_idx) : m_face(Face_index(face_idx)), m_vertex_idx(vertex_idx) {} + + Face_index m_face; + unsigned char m_vertex_idx; +}; + + + +class SurfaceMesh { +public: + explicit SurfaceMesh(const indexed_triangle_set& its) + : m_its(its), + m_face_neighbors(its_face_neighbors_par(its)) + {} + SurfaceMesh(const SurfaceMesh&) = delete; + SurfaceMesh& operator=(const SurfaceMesh&) = delete; + + Vertex_index source(Halfedge_index h) const { assert(! h.is_invalid()); return Vertex_index(h.m_face, h.m_side); } + Vertex_index target(Halfedge_index h) const { assert(! h.is_invalid()); return Vertex_index(h.m_face, h.m_side == 2 ? 0 : h.m_side + 1); } + Face_index face(Halfedge_index h) const { assert(! h.is_invalid()); return h.m_face; } + + Halfedge_index next(Halfedge_index h) const { assert(! h.is_invalid()); h.m_side = (h.m_side + 1) % 3; return h; } + Halfedge_index prev(Halfedge_index h) const { assert(! h.is_invalid()); h.m_side = (h.m_side == 0 ? 2 : h.m_side - 1); return h; } + Halfedge_index halfedge(Vertex_index v) const { return Halfedge_index(v.m_face, (v.m_vertex_idx == 0 ? 2 : v.m_vertex_idx - 1)); } + Halfedge_index halfedge(Face_index f) const { return Halfedge_index(f, 0); } + Halfedge_index opposite(Halfedge_index h) const { + if (h.is_invalid()) + return h; + + int face_idx = m_face_neighbors[h.m_face][h.m_side]; + Halfedge_index h_candidate = halfedge(Face_index(face_idx)); + + if (h_candidate.is_invalid()) + return Halfedge_index(); // invalid + + for (int i=0; i<3; ++i) { + if (is_same_vertex(source(h_candidate), target(h))) { + // Meshes in PrusaSlicer should be fixed enough for the following not to happen. + assert(is_same_vertex(target(h_candidate), source(h))); + return h_candidate; + } + h_candidate = next(h_candidate); + } + return Halfedge_index(); // invalid + } + + Halfedge_index next_around_target(Halfedge_index h) const { return opposite(next(h)); } + Halfedge_index prev_around_target(Halfedge_index h) const { Halfedge_index op = opposite(h); return (op.is_invalid() ? Halfedge_index() : prev(op)); } + Halfedge_index next_around_source(Halfedge_index h) const { Halfedge_index op = opposite(h); return (op.is_invalid() ? Halfedge_index() : next(op)); } + Halfedge_index prev_around_source(Halfedge_index h) const { return opposite(prev(h)); } + Halfedge_index halfedge(Vertex_index source, Vertex_index target) const + { + Halfedge_index hi(source.m_face, source.m_vertex_idx); + assert(! hi.is_invalid()); + + const Vertex_index orig_target = this->target(hi); + Vertex_index current_target = orig_target; + + while (! is_same_vertex(current_target, target)) { + hi = next_around_source(hi); + if (hi.is_invalid()) + break; + current_target = this->target(hi); + if (is_same_vertex(current_target, orig_target)) + return Halfedge_index(); // invalid + } + + return hi; + } + + const stl_vertex& point(Vertex_index v) const { return m_its.vertices[m_its.indices[v.m_face][v.m_vertex_idx]]; } + + size_t degree(Vertex_index v) const + { + Halfedge_index h_first = halfedge(v); + Halfedge_index h = next_around_target(h_first); + size_t degree = 2; + while (! h.is_invalid() && h != h_first) { + h = next_around_target(h); + ++degree; + } + return h.is_invalid() ? 0 : degree - 1; + } + + size_t degree(Face_index f) const { + size_t total = 0; + for (unsigned char i=0; i<3; ++i) { + size_t d = degree(Vertex_index(f, i)); + if (d == 0) + return 0; + total += d; + } + assert(total - 6 >= 0); + return total - 6; // we counted 3 halfedges from f, and one more for each neighbor + } + + bool is_border(Halfedge_index h) const { return m_face_neighbors[h.m_face][h.m_side] == -1; } + + bool is_same_vertex(const Vertex_index& a, const Vertex_index& b) const { return m_its.indices[a.m_face][a.m_vertex_idx] == m_its.indices[b.m_face][b.m_vertex_idx]; } + + + +private: + const std::vector m_face_neighbors; + const indexed_triangle_set& m_its; +}; + +} //namespace Slic3r + +#endif // slic3r_SurfaceMesh_hpp_ From 9a163c356b713a00600ece17f76fa5805e205198 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 3 Jun 2022 12:53:34 +0200 Subject: [PATCH 002/250] Added some unit tests (SurfaceMesh) --- tests/libslic3r/CMakeLists.txt | 1 + tests/libslic3r/test_surface_mesh.cpp | 122 ++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 tests/libslic3r/test_surface_mesh.cpp diff --git a/tests/libslic3r/CMakeLists.txt b/tests/libslic3r/CMakeLists.txt index cf89b2246f..3622ac2b8e 100644 --- a/tests/libslic3r/CMakeLists.txt +++ b/tests/libslic3r/CMakeLists.txt @@ -24,6 +24,7 @@ add_executable(${_TEST_NAME}_tests test_voronoi.cpp test_optimizers.cpp test_png_io.cpp + test_surface_mesh.cpp test_timeutils.cpp test_indexed_triangle_set.cpp test_astar.cpp diff --git a/tests/libslic3r/test_surface_mesh.cpp b/tests/libslic3r/test_surface_mesh.cpp new file mode 100644 index 0000000000..34ff356679 --- /dev/null +++ b/tests/libslic3r/test_surface_mesh.cpp @@ -0,0 +1,122 @@ +#include +#include + + +#include + +using namespace Slic3r; + + +// Generate a broken cube mesh. Face 8 is inverted, face 11 is missing. +indexed_triangle_set its_make_cube_broken(double xd, double yd, double zd) +{ + auto x = float(xd), y = float(yd), z = float(zd); + return { + { {0, 1, 2}, {0, 2, 3}, {4, 5, 6}, {4, 6, 7}, + {0, 4, 7}, {0, 7, 1}, {1, 7, 6}, {1, 6, 2}, + {2, 5, 6}, {2, 5, 3}, {4, 0, 3} /*missing face*/ }, + { {x, y, 0}, {x, 0, 0}, {0, 0, 0}, {0, y, 0}, + {x, y, z}, {0, y, z}, {0, 0, z}, {x, 0, z} } + }; +} + + + +TEST_CASE("SurfaceMesh on a cube", "[SurfaceMesh]") { + indexed_triangle_set cube = its_make_cube(1., 1., 1.); + SurfaceMesh sm(cube); + const Halfedge_index hi_first = sm.halfedge(Face_index(0)); + Halfedge_index hi = hi_first; + + REQUIRE(! hi_first.is_invalid()); + + SECTION("next / prev halfedge") { + hi = sm.next(hi); + REQUIRE(hi != hi_first); + hi = sm.next(hi); + hi = sm.next(hi); + REQUIRE(hi == hi_first); + hi = sm.prev(hi); + REQUIRE(hi != hi_first); + hi = sm.prev(hi); + hi = sm.prev(hi); + REQUIRE(hi == hi_first); + } + + SECTION("next_around_target") { + // Check that we get to the same halfedge after applying next_around_target + // four times. + const Vertex_index target_vert = sm.target(hi_first); + for (int i=0; i<4;++i) { + hi = sm.next_around_target(hi); + REQUIRE((hi == hi_first) == (i == 3)); + REQUIRE(sm.is_same_vertex(sm.target(hi), target_vert)); + REQUIRE(! sm.is_border(hi)); + } + } + + SECTION("iterate around target and source") { + hi = sm.next_around_target(hi); + hi = sm.prev_around_target(hi); + hi = sm.prev_around_source(hi); + hi = sm.next_around_source(hi); + REQUIRE(hi == hi_first); + } + + SECTION("opposite") { + const Vertex_index target = sm.target(hi); + const Vertex_index source = sm.source(hi); + hi = sm.opposite(hi); + REQUIRE(sm.is_same_vertex(target, sm.source(hi))); + REQUIRE(sm.is_same_vertex(source, sm.target(hi))); + hi = sm.opposite(hi); + REQUIRE(hi == hi_first); + } + + SECTION("halfedges walk") { + for (int i=0; i<4; ++i) { + hi = sm.next(hi); + hi = sm.opposite(hi); + } + REQUIRE(hi == hi_first); + } + + SECTION("point accessor") { + Halfedge_index hi = sm.halfedge(Face_index(0)); + hi = sm.opposite(hi); + hi = sm.prev(hi); + hi = sm.opposite(hi); + REQUIRE(hi.face() == Face_index(6)); + REQUIRE(sm.point(sm.target(hi)).isApprox(cube.vertices[7])); + } +} + + + + +TEST_CASE("SurfaceMesh on a broken cube", "[SurfaceMesh]") { + indexed_triangle_set cube = its_make_cube_broken(1., 1., 1.); + SurfaceMesh sm(cube); + + SECTION("Check inverted face") { + Halfedge_index hi = sm.halfedge(Face_index(8)); + for (int i=0; i<3; ++i) { + REQUIRE(! hi.is_invalid()); + REQUIRE(sm.is_border(hi)); + } + REQUIRE(hi == sm.halfedge(Face_index(8))); + hi = sm.opposite(hi); + REQUIRE(hi.is_invalid()); + } + + SECTION("missing face") { + Halfedge_index hi = sm.halfedge(Face_index(0)); + for (int i=0; i<3; ++i) + hi = sm.next_around_source(hi); + hi = sm.next(hi); + REQUIRE(sm.is_border(hi)); + REQUIRE(! hi.is_invalid()); + hi = sm.opposite(hi); + REQUIRE(hi.is_invalid()); + } +} From 1e494e30af62b36c6e6a1ad1196ee1a20ee07957 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 17 Jun 2022 12:19:47 +0200 Subject: [PATCH 003/250] SurfaceMesh testing (to be reverted later) --- src/libslic3r/TriangleMesh.cpp | 11 +- src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | 253 ++++++++++++----------- src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp | 2 + 3 files changed, 149 insertions(+), 117 deletions(-) diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 0dffdaab0e..8dc87c6fb1 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -877,13 +877,20 @@ Polygon its_convex_hull_2d_above(const indexed_triangle_set &its, const Transfor indexed_triangle_set its_make_cube(double xd, double yd, double zd) { auto x = float(xd), y = float(yd), z = float(zd); - return { + /*return { { {0, 1, 2}, {0, 2, 3}, {4, 5, 6}, {4, 6, 7}, {0, 4, 7}, {0, 7, 1}, {1, 7, 6}, {1, 6, 2}, {2, 6, 5}, {2, 5, 3}, {4, 0, 3}, {4, 3, 5} }, { {x, y, 0}, {x, 0, 0}, {0, 0, 0}, {0, y, 0}, {x, y, z}, {0, y, z}, {0, 0, z}, {x, 0, z} } - }; + };*/ + return { + { {0, 1, 2}, {0, 2, 3}, {4, 5, 6}, {4, 6, 7}, + {0, 4, 7}, {0, 7, 1}, {1, 7, 6}, {1, 6, 2}, + {2, 5, 6}, {2, 5, 3}, {4, 0, 3}, /*{4, 3, 5}*/ }, + { {x, y, 0}, {x, 0, 0}, {0, 0, 0}, {0, y, 0}, + {x, y, z}, {0, y, z}, {0, 0, z}, {x, 0, z} } + }; } indexed_triangle_set its_make_prism(float width, float length, float height) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index f854edb817..f8d6abad98 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -12,20 +12,45 @@ #include "libslic3r/Geometry/ConvexHull.hpp" #include "libslic3r/Model.hpp" +#include "libslic3r/SurfaceMesh.hpp" #include #include + + namespace Slic3r { namespace GUI { static const Slic3r::ColorRGBA DEFAULT_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.5f }; static const Slic3r::ColorRGBA DEFAULT_HOVER_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.75f }; + + + +// TESTING: +static Halfedge_index hi; +static bool hi_initialized = false; +static std::unique_ptr sm_ptr; +static Vertex_index src; +static Vertex_index tgt; + + + + + + GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) -{} +{ + indexed_triangle_set a = its_make_cone(0.05, .2); + its_rotate_x(a, M_PI); + its_translate(a, stl_vertex(0., 0., .8)); + indexed_triangle_set b = its_make_cylinder(.02, 0.8); + its_merge(a, b); + arrow.init_from(a); +} bool GLGizmoFlatten::on_mouse(const wxMouseEvent &mouse_event) { @@ -39,9 +64,7 @@ bool GLGizmoFlatten::on_mouse(const wxMouseEvent &mouse_event) m_mouse_left_down = true; Selection &selection = m_parent.get_selection(); if (selection.is_single_full_instance()) { - // Rotate the object so the normal points downward: - selection.flattening_rotate(m_planes[m_hover_id].normal); - m_parent.do_rotate(L("Gizmo-Place on Face")); + hi = sm_ptr->halfedge(Face_index(m_hover_id)); } return true; } @@ -105,6 +128,19 @@ void GLGizmoFlatten::on_render() const Selection& selection = m_parent.get_selection(); #if ENABLE_LEGACY_OPENGL_REMOVAL + + + + if (! hi_initialized) { + const indexed_triangle_set& its = m_c->selection_info()->model_object()->volumes.front()->mesh().its; + sm_ptr.reset(new SurfaceMesh(its)); + hi = sm_ptr->halfedge(Face_index(0)); + hi_initialized = true; + } + SurfaceMesh& sm = *sm_ptr; + + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader == nullptr) return; @@ -135,8 +171,12 @@ void GLGizmoFlatten::on_render() update_planes(); for (int i = 0; i < (int)m_planes.size(); ++i) { #if ENABLE_LEGACY_OPENGL_REMOVAL + int cur_face = hi.is_invalid() ? 1000000 : sm.face(hi); + for (int i=0; i < m_planes.size(); ++i) { m_planes[i].vbo.set_color(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); - m_planes[i].vbo.render(); + if (i == cur_face) + m_planes[i].vbo.set_color(i == m_hover_id ? ColorRGBA(.5f, 0.f, 0.f, 1.f) : ColorRGBA(1.f, 0.f, 0.f, 1.f)); + m_planes[i].vbo.render(); #else glsafe(::glColor4fv(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR.data() : DEFAULT_PLANE_COLOR.data())); if (m_planes[i].vbo.has_VBOs()) @@ -146,8 +186,92 @@ void GLGizmoFlatten::on_render() #if !ENABLE_GL_SHADERS_ATTRIBUTES glsafe(::glPopMatrix()); #endif // !ENABLE_GL_SHADERS_ATTRIBUTES + } } + + + + ///////////////// + //////////////// + ////////////////// + + auto draw_arrow = [&](const Vec3d& from, const Vec3d& to) -> void { + Vec3d desired_pos = from; + Vec3d desired_dir = to - from; + double desired_len = desired_dir.norm(); + desired_dir.normalize(); + + Transform3d m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); + m.translate(desired_pos); + Eigen::Quaterniond q; + Transform3d rot = Transform3d::Identity(); + rot.matrix().block(0, 0, 3, 3) = q.setFromTwoVectors(Vec3d::UnitZ(), desired_dir).toRotationMatrix(); + Transform3d sc = Transform3d::Identity(); + sc.scale(desired_len); + m = m*sc*rot; + + const Camera& camera = wxGetApp().plater()->get_camera(); + Transform3d view_model_matrix = camera.get_view_matrix() * + Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m; + + shader->set_uniform("view_model_matrix", view_model_matrix); + arrow.render(); + }; + + m_imgui->begin(std::string("DEBUG")); + bool invalid = hi.is_invalid(); + if (invalid) { + if (m_imgui->button(std::string("HALFEDGE INVALID (Click to reset)"))) + hi = sm.halfedge(Face_index(0)); + } else { + m_imgui->text(sm.is_border(hi) ? "BORDER HALFEDGE !" : "Halfedge is not border"); + m_imgui->text((std::string("Face: ") + std::to_string(int(hi.face()))).c_str()); + m_imgui->text(std::string("Target degree:" + std::to_string(sm.degree(sm.target(hi))))); + m_imgui->text(std::string("Face degree:" + std::to_string(sm.degree(sm.face(hi))))); + } + m_imgui->disabled_begin(invalid); + if (m_imgui->button(std::string("next"))) + hi = sm.next(hi); + if (m_imgui->button(std::string("prev"))) + hi = sm.prev(hi); + if (m_imgui->button(std::string("opposite"))) + hi = sm.opposite(hi); + if (m_imgui->button(std::string("next_around_target"))) + hi = sm.next_around_target(hi); + if (m_imgui->button(std::string("prev_around_target"))) + hi = sm.prev_around_target(hi); + if (m_imgui->button(std::string("next_around_source"))) + hi = sm.next_around_source(hi); + if (m_imgui->button(std::string("prev_around_source"))) + hi = sm.prev_around_source(hi); + if (m_imgui->button(std::string("remember one"))) + src = sm.target(hi); + if (m_imgui->button(std::string("switch to halfedge"))) { + tgt = sm.target(hi); + hi = sm.halfedge(src, tgt); + } + + if (invalid) + m_imgui->disabled_end(); + m_imgui->end(); + + if (! hi.is_invalid()) { + Vec3d a = sm.point(sm.source(hi)).cast(); + Vec3d b = sm.point(sm.target(hi)).cast(); + draw_arrow(a, b); + } + + + ///////////////// + //////////////// + ////////////////// + + + + + + glsafe(::glEnable(GL_CULL_FACE)); glsafe(::glDisable(GL_BLEND)); @@ -222,11 +346,11 @@ void GLGizmoFlatten::update_planes() for (const ModelVolume* vol : mo->volumes) { if (vol->type() != ModelVolumeType::MODEL_PART) continue; - TriangleMesh vol_ch = vol->get_convex_hull(); + TriangleMesh vol_ch = vol->mesh(); //vol->get_convex_hull(); vol_ch.transform(vol->get_matrix()); ch.merge(vol_ch); } - ch = ch.convex_hull_3d(); + //ch = ch.convex_hull_3d(); m_planes.clear(); #if ENABLE_WORLD_COORDINATE const Transform3d inst_matrix = mo->instances.front()->get_matrix_no_offset(); @@ -247,47 +371,18 @@ void GLGizmoFlatten::update_planes() std::vector facet_visited(num_of_facets, false); int facet_queue_cnt = 0; const stl_normal* normal_ptr = nullptr; - int facet_idx = 0; - while (1) { - // Find next unvisited triangle: - for (; facet_idx < num_of_facets; ++ facet_idx) - if (!facet_visited[facet_idx]) { - facet_queue[facet_queue_cnt ++] = facet_idx; - facet_visited[facet_idx] = true; - normal_ptr = &face_normals[facet_idx]; - m_planes.emplace_back(); - break; - } - if (facet_idx == num_of_facets) - break; // Everything was visited already - - while (facet_queue_cnt > 0) { - int facet_idx = facet_queue[-- facet_queue_cnt]; - const stl_normal& this_normal = face_normals[facet_idx]; - if (std::abs(this_normal(0) - (*normal_ptr)(0)) < 0.001 && std::abs(this_normal(1) - (*normal_ptr)(1)) < 0.001 && std::abs(this_normal(2) - (*normal_ptr)(2)) < 0.001) { - const Vec3i face = ch.its.indices[facet_idx]; - for (int j=0; j<3; ++j) - m_planes.back().vertices.emplace_back(ch.its.vertices[face[j]].cast()); - - facet_visited[facet_idx] = true; - for (int j = 0; j < 3; ++ j) - if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && ! facet_visited[neighbor_idx]) - facet_queue[facet_queue_cnt ++] = neighbor_idx; - } - } - m_planes.back().normal = normal_ptr->cast(); + + for (size_t i=0; i()); + m_planes.back().normal = face_normals[i].cast(); Pointf3s& verts = m_planes.back().vertices; // Now we'll transform all the points into world coordinates, so that the areas, angles and distances // make real sense. verts = transform(verts, inst_matrix); - - // if this is a just a very small triangle, remove it to speed up further calculations (it would be rejected later anyway): - if (verts.size() == 3 && - ((verts[0] - verts[1]).norm() < minimal_side - || (verts[0] - verts[2]).norm() < minimal_side - || (verts[1] - verts[2]).norm() < minimal_side)) - m_planes.pop_back(); } // Let's prepare transformation of the normal vector from mesh to instance coordinates. @@ -319,84 +414,12 @@ void GLGizmoFlatten::update_planes() polygon = Slic3r::Geometry::convex_hull(polygon); polygon = transform(polygon, tr.inverse()); - // Calculate area of the polygons and discard ones that are too small - float& area = m_planes[polygon_id].area; - area = 0.f; - for (unsigned int i = 0; i < polygon.size(); i++) // Shoelace formula - area += polygon[i](0)*polygon[i + 1 < polygon.size() ? i + 1 : 0](1) - polygon[i + 1 < polygon.size() ? i + 1 : 0](0)*polygon[i](1); - area = 0.5f * std::abs(area); - - bool discard = false; - if (area < minimal_area) - discard = true; - else { - // We also check the inner angles and discard polygons with angles smaller than the following threshold - const double angle_threshold = ::cos(10.0 * (double)PI / 180.0); - - for (unsigned int i = 0; i < polygon.size(); ++i) { - const Vec3d& prec = polygon[(i == 0) ? polygon.size() - 1 : i - 1]; - const Vec3d& curr = polygon[i]; - const Vec3d& next = polygon[(i == polygon.size() - 1) ? 0 : i + 1]; - - if ((prec - curr).normalized().dot((next - curr).normalized()) > angle_threshold) { - discard = true; - break; - } - } - } - - if (discard) { - m_planes[polygon_id--] = std::move(m_planes.back()); - m_planes.pop_back(); - continue; - } - // We will shrink the polygon a little bit so it does not touch the object edges: Vec3d centroid = std::accumulate(polygon.begin(), polygon.end(), Vec3d(0.0, 0.0, 0.0)); centroid /= (double)polygon.size(); for (auto& vertex : polygon) vertex = 0.9f*vertex + 0.1f*centroid; - // Polygon is now simple and convex, we'll round the corners to make them look nicer. - // The algorithm takes a vertex, calculates middles of respective sides and moves the vertex - // towards their average (controlled by 'aggressivity'). This is repeated k times. - // In next iterations, the neighbours are not always taken at the middle (to increase the - // rounding effect at the corners, where we need it most). - const unsigned int k = 10; // number of iterations - const float aggressivity = 0.2f; // agressivity - const unsigned int N = polygon.size(); - std::vector> neighbours; - if (k != 0) { - Pointf3s points_out(2*k*N); // vector long enough to store the future vertices - for (unsigned int j=0; j vertices; // should be in fact local in update_planes() #if ENABLE_LEGACY_OPENGL_REMOVAL From f0cf420a8457e1355181ba0e22efcb8f4856dcf8 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 3 Jun 2022 15:37:11 +0200 Subject: [PATCH 004/250] Measuring: separated another gizmo --- resources/icons/measure.svg | 13 + src/libslic3r/SurfaceMesh.hpp | 1 + src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 388 ++++++++++++++++++++++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 75 +++++ src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 + src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 1 + 7 files changed, 482 insertions(+) create mode 100644 resources/icons/measure.svg create mode 100644 src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp create mode 100644 src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp diff --git a/resources/icons/measure.svg b/resources/icons/measure.svg new file mode 100644 index 0000000000..275c522251 --- /dev/null +++ b/resources/icons/measure.svg @@ -0,0 +1,13 @@ + + + Layer 1 + + + + + + + + + + \ No newline at end of file diff --git a/src/libslic3r/SurfaceMesh.hpp b/src/libslic3r/SurfaceMesh.hpp index 47d5ed0dcc..e8ada4cd80 100644 --- a/src/libslic3r/SurfaceMesh.hpp +++ b/src/libslic3r/SurfaceMesh.hpp @@ -138,6 +138,7 @@ public: bool is_border(Halfedge_index h) const { return m_face_neighbors[h.m_face][h.m_side] == -1; } bool is_same_vertex(const Vertex_index& a, const Vertex_index& b) const { return m_its.indices[a.m_face][a.m_vertex_idx] == m_its.indices[b.m_face][b.m_vertex_idx]; } + Vec3i get_face_neighbors(Face_index face_id) const { assert(int(face_id) < int(m_face_neighbors.size())); return m_face_neighbors[face_id]; } diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 29b8b7e736..a56556baa5 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -61,6 +61,8 @@ set(SLIC3R_GUI_SOURCES GUI/Gizmos/GLGizmoSimplify.hpp GUI/Gizmos/GLGizmoMmuSegmentation.cpp GUI/Gizmos/GLGizmoMmuSegmentation.hpp + GUI/Gizmos/GLGizmoMeasure.cpp + GUI/Gizmos/GLGizmoMeasure.hpp GUI/GLSelectionRectangle.cpp GUI/GLSelectionRectangle.hpp GUI/GLModel.hpp diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp new file mode 100644 index 0000000000..572ea75dbe --- /dev/null +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -0,0 +1,388 @@ +// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. +#include "GLGizmoMeasure.hpp" +#include "slic3r/GUI/GLCanvas3D.hpp" +#include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/Plater.hpp" + +#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" + +#include "libslic3r/Geometry/ConvexHull.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/SurfaceMesh.hpp" + +#include + +#include + +namespace Slic3r { +namespace GUI { + +static const Slic3r::ColorRGBA DEFAULT_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.5f }; +static const Slic3r::ColorRGBA DEFAULT_HOVER_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.75f }; + +GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) + : GLGizmoBase(parent, icon_filename, sprite_id) +{} + + + +bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) +{ + if (mouse_event.Moving()) { + // only for sure + m_mouse_left_down = false; + return false; + } + if (mouse_event.LeftDown()) { + if (m_hover_id != -1) { + m_mouse_left_down = true; + Selection &selection = m_parent.get_selection(); + if (selection.is_single_full_instance()) { + // Rotate the object so the normal points downward: + selection.flattening_rotate(m_planes[m_hover_id].normal); + m_parent.do_rotate(L("Gizmo-Place on Face")); + } + return true; + } + + // fix: prevent restart gizmo when reselect object + // take responsibility for left up + if (m_parent.get_first_hover_volume_idx() >= 0) m_mouse_left_down = true; + + } else if (mouse_event.LeftUp()) { + if (m_mouse_left_down) { + // responsible for mouse left up after selecting plane + m_mouse_left_down = false; + return true; + } + } else if (mouse_event.Leaving()) { + m_mouse_left_down = false; + } + return false; +} + + + +void GLGizmoMeasure::data_changed() +{ + const Selection & selection = m_parent.get_selection(); + const ModelObject *model_object = nullptr; + if (selection.is_single_full_instance() || + selection.is_from_single_object() ) { + model_object = selection.get_model()->objects[selection.get_object_idx()]; + } + set_flattening_data(model_object); +} + + + +bool GLGizmoMeasure::on_init() +{ + // FIXME m_shortcut_key = WXK_CONTROL_F; + return true; +} + + + +void GLGizmoMeasure::on_set_state() +{ +} + + + +CommonGizmosDataID GLGizmoMeasure::on_get_requirements() const +{ + return CommonGizmosDataID::SelectionInfo; +} + + + +std::string GLGizmoMeasure::on_get_name() const +{ + return _u8L("Measure"); +} + + + +bool GLGizmoMeasure::on_is_activable() const +{ + // This is assumed in GLCanvas3D::do_rotate, do not change this + // without updating that function too. + return m_parent.get_selection().is_single_full_instance(); +} + + + +void GLGizmoMeasure::on_render() +{ + const Selection& selection = m_parent.get_selection(); + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + + shader->start_using(); + + glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); + + glsafe(::glEnable(GL_DEPTH_TEST)); + glsafe(::glEnable(GL_BLEND)); + + if (selection.is_single_full_instance()) { + const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d view_model_matrix = camera.get_view_matrix() * + Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m; + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + if (this->is_plane_update_necessary()) + update_planes(); + for (int i = 0; i < (int)m_planes.size(); ++i) { + m_planes[i].vbo.set_color(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); + m_planes[i].vbo.render(); + } + } + + glsafe(::glEnable(GL_CULL_FACE)); + glsafe(::glDisable(GL_BLEND)); + + shader->stop_using(); +} + + + + + +#if ! ENABLE_LEGACY_OPENGL_REMOVAL + #error NOT IMPLEMENTED +#endif +#if ! ENABLE_GL_SHADERS_ATTRIBUTES + #error NOT IMPLEMENTED +#endif + + + + + +void GLGizmoMeasure::on_render_for_picking() +{ + const Selection& selection = m_parent.get_selection(); + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + + shader->start_using(); + + glsafe(::glDisable(GL_DEPTH_TEST)); + glsafe(::glDisable(GL_BLEND)); + + if (selection.is_single_full_instance() && !wxGetKeyState(WXK_CONTROL)) { + const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d view_model_matrix = camera.get_view_matrix() * + Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m; + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + if (this->is_plane_update_necessary()) + update_planes(); + for (int i = 0; i < (int)m_planes.size(); ++i) { + m_planes[i].vbo.set_color(picking_color_component(i)); + m_planes[i].vbo.render(); + } + } + + glsafe(::glEnable(GL_CULL_FACE)); + + shader->stop_using(); +} + + + +void GLGizmoMeasure::set_flattening_data(const ModelObject* model_object) +{ + if (model_object != m_old_model_object) { + m_planes.clear(); + m_planes_valid = false; + } +} + + + +void GLGizmoMeasure::update_planes() +{ + const ModelObject* mo = m_c->selection_info()->model_object(); + TriangleMesh ch; + for (const ModelVolume* vol : mo->volumes) { + if (vol->type() != ModelVolumeType::MODEL_PART) + continue; + TriangleMesh vol_ch = vol->mesh(); + vol_ch.transform(vol->get_matrix()); + ch.merge(vol_ch); + } + m_planes.clear(); + const Transform3d& inst_matrix = mo->instances.front()->get_matrix(); + + // Now we'll go through all the facets and append Points of facets sharing the same normal. + // This part is still performed in mesh coordinate system. + const int num_of_facets = ch.facets_count(); + std::vector face_to_plane(num_of_facets, 0); + const std::vector face_normals = its_face_normals(ch.its); + const std::vector face_neighbors = its_face_neighbors(ch.its); + std::vector facet_queue(num_of_facets, 0); + std::vector facet_visited(num_of_facets, false); + int facet_queue_cnt = 0; + const stl_normal* normal_ptr = nullptr; + int facet_idx = 0; + + auto is_same_normal = [](const stl_normal& a, const stl_normal& b) -> bool { + return (std::abs(a(0) - b(0)) < 0.001 && std::abs(a(1) - b(1)) < 0.001 && std::abs(a(2) - b(2)) < 0.001); + }; + + while (1) { + // Find next unvisited triangle: + for (; facet_idx < num_of_facets; ++ facet_idx) + if (!facet_visited[facet_idx]) { + facet_queue[facet_queue_cnt ++] = facet_idx; + facet_visited[facet_idx] = true; + normal_ptr = &face_normals[facet_idx]; + face_to_plane[facet_idx] = m_planes.size(); + m_planes.emplace_back(); + break; + } + if (facet_idx == num_of_facets) + break; // Everything was visited already + + while (facet_queue_cnt > 0) { + int facet_idx = facet_queue[-- facet_queue_cnt]; + const stl_normal& this_normal = face_normals[facet_idx]; + if (is_same_normal(this_normal, *normal_ptr)) { + const Vec3i& face = ch.its.indices[facet_idx]; + for (int j=0; j<3; ++j) + m_planes.back().vertices.emplace_back(ch.its.vertices[face[j]].cast()); + + facet_visited[facet_idx] = true; + face_to_plane[facet_idx] = m_planes.size() - 1; + for (int j = 0; j < 3; ++ j) + if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && ! facet_visited[neighbor_idx]) + facet_queue[facet_queue_cnt ++] = neighbor_idx; + } + } + m_planes.back().normal = normal_ptr->cast(); + + Pointf3s& verts = m_planes.back().vertices; + // Now we'll transform all the points into world coordinates, so that the areas, angles and distances + // make real sense. + verts = transform(verts, inst_matrix); + } + + // Let's prepare transformation of the normal vector from mesh to instance coordinates. + Geometry::Transformation t(inst_matrix); + Vec3d scaling = t.get_scaling_factor(); + t.set_scaling_factor(Vec3d(1./scaling(0), 1./scaling(1), 1./scaling(2))); + + // Now we'll go through all the polygons, transform the points into xy plane to process them: + for (unsigned int polygon_id=0; polygon_id < m_planes.size(); ++polygon_id) { + Pointf3s& polygon = m_planes[polygon_id].vertices; + const Vec3d& normal = m_planes[polygon_id].normal; + + // transform the normal according to the instance matrix: + Vec3d normal_transformed = t.get_matrix() * normal; + + // We are going to rotate about z and y to flatten the plane + Eigen::Quaterniond q; + Transform3d m = Transform3d::Identity(); + m.matrix().block(0, 0, 3, 3) = q.setFromTwoVectors(normal_transformed, Vec3d::UnitZ()).toRotationMatrix(); + polygon = transform(polygon, m); + + // Now to remove the inner points. We'll misuse Geometry::convex_hull for that, but since + // it works in fixed point representation, we will rescale the polygon to avoid overflows. + // And yes, it is a nasty thing to do. Whoever has time is free to refactor. + Vec3d bb_size = BoundingBoxf3(polygon).size(); + float sf = std::min(1./bb_size(0), 1./bb_size(1)); + Transform3d tr = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), Vec3d(sf, sf, 1.f)); + polygon = transform(polygon, tr); + polygon = Slic3r::Geometry::convex_hull(polygon); + polygon = transform(polygon, tr.inverse()); + + // We will shrink the polygon a little bit so it does not touch the object edges: + Vec3d centroid = std::accumulate(polygon.begin(), polygon.end(), Vec3d(0.0, 0.0, 0.0)); + centroid /= (double)polygon.size(); + for (auto& vertex : polygon) + vertex = 0.95f*vertex + 0.05f*centroid; + + // Raise a bit above the object surface to avoid flickering: + for (auto& b : polygon) + b(2) += 0.1f; + + // Transform back to 3D (and also back to mesh coordinates) + polygon = transform(polygon, inst_matrix.inverse() * m.inverse()); + } + + // We'll sort the planes by area and only keep the 254 largest ones (because of the picking pass limitations): + std::sort(m_planes.rbegin(), m_planes.rend(), [](const PlaneData& a, const PlaneData& b) { return a.area < b.area; }); + m_planes.resize(std::min((int)m_planes.size(), 254)); + + // Planes are finished - let's save what we calculated it from: + m_volumes_matrices.clear(); + m_volumes_types.clear(); + for (const ModelVolume* vol : mo->volumes) { + m_volumes_matrices.push_back(vol->get_matrix()); + m_volumes_types.push_back(vol->type()); + } + m_first_instance_scale = mo->instances.front()->get_scaling_factor(); + m_first_instance_mirror = mo->instances.front()->get_mirror(); + m_old_model_object = mo; + + // And finally create respective VBOs. The polygon is convex with + // the vertices in order, so triangulation is trivial. + for (auto& plane : m_planes) { + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::TriangleFan, GLModel::Geometry::EVertexLayout::P3N3 }; + init_data.reserve_vertices(plane.vertices.size()); + init_data.reserve_indices(plane.vertices.size()); + // vertices + indices + for (size_t i = 0; i < plane.vertices.size(); ++i) { + init_data.add_vertex((Vec3f)plane.vertices[i].cast(), (Vec3f)plane.normal.cast()); + init_data.add_index((unsigned int)i); + } + plane.vbo.init_from(std::move(init_data)); + + // FIXME: vertices should really be local, they need not + // persist now when we use VBOs + plane.vertices.clear(); + plane.vertices.shrink_to_fit(); + } + + m_planes_valid = true; +} + + + +bool GLGizmoMeasure::is_plane_update_necessary() const +{ + const ModelObject* mo = m_c->selection_info()->model_object(); + if (m_state != On || ! mo || mo->instances.empty()) + return false; + + if (! m_planes_valid || mo != m_old_model_object + || mo->volumes.size() != m_volumes_matrices.size()) + return true; + + // We want to recalculate when the scale changes - some planes could (dis)appear. + if (! mo->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale) + || ! mo->instances.front()->get_mirror().isApprox(m_first_instance_mirror)) + return true; + + for (unsigned int i=0; i < mo->volumes.size(); ++i) + if (! mo->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i]) + || mo->volumes[i]->type() != m_volumes_types[i]) + return true; + + return false; +} + +} // namespace GUI +} // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp new file mode 100644 index 0000000000..9bf87a29f6 --- /dev/null +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -0,0 +1,75 @@ +#ifndef slic3r_GLGizmoMeasure_hpp_ +#define slic3r_GLGizmoMeasure_hpp_ + +#include "GLGizmoBase.hpp" +#if ENABLE_LEGACY_OPENGL_REMOVAL +#include "slic3r/GUI/GLModel.hpp" +#else +#include "slic3r/GUI/3DScene.hpp" +#endif // ENABLE_LEGACY_OPENGL_REMOVAL + + +namespace Slic3r { + +enum class ModelVolumeType : int; + + +namespace GUI { + + +class GLGizmoMeasure : public GLGizmoBase +{ +// This gizmo does not use grabbers. The m_hover_id relates to polygon managed by the class itself. + +private: + + struct PlaneData { + std::vector vertices; // should be in fact local in update_planes() + std::vector borders_facets; + GLModel vbo; + Vec3d normal; + float area; + }; + + // This holds information to decide whether recalculation is necessary: + std::vector m_volumes_matrices; + std::vector m_volumes_types; + Vec3d m_first_instance_scale; + Vec3d m_first_instance_mirror; + + std::vector m_planes; + std::vector m_face_to_plane; + bool m_mouse_left_down = false; // for detection left_up of this gizmo + bool m_planes_valid = false; + const ModelObject* m_old_model_object = nullptr; + std::vector instances_matrices; + + void update_planes(); + bool is_plane_update_necessary() const; + void set_flattening_data(const ModelObject* model_object); + +public: + GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); + + /// + /// Apply rotation on select plane + /// + /// Keep information about mouse click + /// Return True when use the information otherwise False. + bool on_mouse(const wxMouseEvent &mouse_event) override; + + void data_changed() override; +protected: + bool on_init() override; + std::string on_get_name() const override; + bool on_is_activable() const override; + void on_render() override; + void on_render_for_picking() override; + void on_set_state() override; + CommonGizmosDataID on_get_requirements() const override; +}; + +} // namespace GUI +} // namespace Slic3r + +#endif // slic3r_GLGizmoMeasure_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 39a1cba8e3..2a1ccd176b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -21,6 +21,7 @@ #include "slic3r/GUI/Gizmos/GLGizmoSeam.hpp" #include "slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp" #include "slic3r/GUI/Gizmos/GLGizmoSimplify.hpp" +#include "slic3r/GUI/Gizmos/GLGizmoMeasure.hpp" #include "libslic3r/format.hpp" #include "libslic3r/Model.hpp" @@ -106,6 +107,7 @@ bool GLGizmosManager::init() m_gizmos.emplace_back(new GLGizmoSeam(m_parent, "seam.svg", 8)); m_gizmos.emplace_back(new GLGizmoMmuSegmentation(m_parent, "mmu_segmentation.svg", 9)); m_gizmos.emplace_back(new GLGizmoSimplify(m_parent, "cut.svg", 10)); + m_gizmos.emplace_back(new GLGizmoMeasure(m_parent, "measure.svg", 11)); m_common_gizmos_data.reset(new CommonGizmosDataPool(&m_parent)); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 2e9e6bb65c..1a203621d2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -80,6 +80,7 @@ public: Seam, MmuSegmentation, Simplify, + Measure, Undefined }; From 5d8aaed18f97906481ae6bbd53d8bc175ab28e9f Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 21 Jun 2022 12:47:47 +0200 Subject: [PATCH 005/250] Measuring: Initial plane detection --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 144 +++++++++++------------ src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 4 +- 2 files changed, 74 insertions(+), 74 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 572ea75dbe..129407764c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -127,6 +127,7 @@ void GLGizmoMeasure::on_render() glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_BLEND)); + glsafe(::glLineWidth(5.f)); if (selection.is_single_full_instance()) { const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); @@ -227,15 +228,14 @@ void GLGizmoMeasure::update_planes() // Now we'll go through all the facets and append Points of facets sharing the same normal. // This part is still performed in mesh coordinate system. - const int num_of_facets = ch.facets_count(); - std::vector face_to_plane(num_of_facets, 0); + const size_t num_of_facets = ch.facets_count(); + std::vector face_to_plane(num_of_facets, size_t(-1)); const std::vector face_normals = its_face_normals(ch.its); const std::vector face_neighbors = its_face_neighbors(ch.its); std::vector facet_queue(num_of_facets, 0); - std::vector facet_visited(num_of_facets, false); int facet_queue_cnt = 0; const stl_normal* normal_ptr = nullptr; - int facet_idx = 0; + size_t seed_facet_idx = 0; auto is_same_normal = [](const stl_normal& a, const stl_normal& b) -> bool { return (std::abs(a(0) - b(0)) < 0.001 && std::abs(a(1) - b(1)) < 0.001 && std::abs(a(2) - b(2)) < 0.001); @@ -243,16 +243,15 @@ void GLGizmoMeasure::update_planes() while (1) { // Find next unvisited triangle: - for (; facet_idx < num_of_facets; ++ facet_idx) - if (!facet_visited[facet_idx]) { - facet_queue[facet_queue_cnt ++] = facet_idx; - facet_visited[facet_idx] = true; - normal_ptr = &face_normals[facet_idx]; - face_to_plane[facet_idx] = m_planes.size(); + for (; seed_facet_idx < num_of_facets; ++ seed_facet_idx) + if (face_to_plane[seed_facet_idx] == size_t(-1)) { + facet_queue[facet_queue_cnt ++] = seed_facet_idx; + normal_ptr = &face_normals[seed_facet_idx]; + face_to_plane[seed_facet_idx] = m_planes.size(); m_planes.emplace_back(); break; } - if (facet_idx == num_of_facets) + if (seed_facet_idx == num_of_facets) break; // Everything was visited already while (facet_queue_cnt > 0) { @@ -260,70 +259,69 @@ void GLGizmoMeasure::update_planes() const stl_normal& this_normal = face_normals[facet_idx]; if (is_same_normal(this_normal, *normal_ptr)) { const Vec3i& face = ch.its.indices[facet_idx]; - for (int j=0; j<3; ++j) - m_planes.back().vertices.emplace_back(ch.its.vertices[face[j]].cast()); - facet_visited[facet_idx] = true; face_to_plane[facet_idx] = m_planes.size() - 1; + m_planes.back().facets.emplace_back(facet_idx); for (int j = 0; j < 3; ++ j) - if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && ! facet_visited[neighbor_idx]) + if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && face_to_plane[neighbor_idx] == size_t(-1)) facet_queue[facet_queue_cnt ++] = neighbor_idx; } } - m_planes.back().normal = normal_ptr->cast(); - Pointf3s& verts = m_planes.back().vertices; - // Now we'll transform all the points into world coordinates, so that the areas, angles and distances - // make real sense. - verts = transform(verts, inst_matrix); + m_planes.back().normal = normal_ptr->cast(); } + assert(std::none_of(face_to_plane.begin(), face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); + + SurfaceMesh sm(ch.its); + for (int plane_id=0; plane_id < m_planes.size(); ++plane_id) { + //int plane_id = 5; { + const auto& facets = m_planes[plane_id].facets; + std::vector pts; + for (int face_id=0; face_id{ sm.point(sm.source(he)).cast() }); + Vertex_index target = sm.target(he); + const Halfedge_index he_start = he; + + do { + const Halfedge_index he_orig = he; + he = sm.next_around_target(he); + while ( face_to_plane[sm.face(he)] == plane_id && he != he_orig) + he = sm.next_around_target(he); + he = sm.opposite(he); + m_planes[plane_id].borders.back().emplace_back(sm.point(sm.source(he)).cast()); + } while (he != he_start); + } + } + + + // DEBUGGING: + //m_planes.erase(std::remove_if(m_planes.begin(), m_planes.end(), [](const PlaneData& p) { return p.borders.empty(); }), m_planes.end()); + + + + + // Let's prepare transformation of the normal vector from mesh to instance coordinates. Geometry::Transformation t(inst_matrix); Vec3d scaling = t.get_scaling_factor(); t.set_scaling_factor(Vec3d(1./scaling(0), 1./scaling(1), 1./scaling(2))); - // Now we'll go through all the polygons, transform the points into xy plane to process them: - for (unsigned int polygon_id=0; polygon_id < m_planes.size(); ++polygon_id) { - Pointf3s& polygon = m_planes[polygon_id].vertices; - const Vec3d& normal = m_planes[polygon_id].normal; - - // transform the normal according to the instance matrix: - Vec3d normal_transformed = t.get_matrix() * normal; - - // We are going to rotate about z and y to flatten the plane - Eigen::Quaterniond q; - Transform3d m = Transform3d::Identity(); - m.matrix().block(0, 0, 3, 3) = q.setFromTwoVectors(normal_transformed, Vec3d::UnitZ()).toRotationMatrix(); - polygon = transform(polygon, m); - - // Now to remove the inner points. We'll misuse Geometry::convex_hull for that, but since - // it works in fixed point representation, we will rescale the polygon to avoid overflows. - // And yes, it is a nasty thing to do. Whoever has time is free to refactor. - Vec3d bb_size = BoundingBoxf3(polygon).size(); - float sf = std::min(1./bb_size(0), 1./bb_size(1)); - Transform3d tr = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), Vec3d(sf, sf, 1.f)); - polygon = transform(polygon, tr); - polygon = Slic3r::Geometry::convex_hull(polygon); - polygon = transform(polygon, tr.inverse()); - - // We will shrink the polygon a little bit so it does not touch the object edges: - Vec3d centroid = std::accumulate(polygon.begin(), polygon.end(), Vec3d(0.0, 0.0, 0.0)); - centroid /= (double)polygon.size(); - for (auto& vertex : polygon) - vertex = 0.95f*vertex + 0.05f*centroid; - - // Raise a bit above the object surface to avoid flickering: - for (auto& b : polygon) - b(2) += 0.1f; - - // Transform back to 3D (and also back to mesh coordinates) - polygon = transform(polygon, inst_matrix.inverse() * m.inverse()); - } - - // We'll sort the planes by area and only keep the 254 largest ones (because of the picking pass limitations): - std::sort(m_planes.rbegin(), m_planes.rend(), [](const PlaneData& a, const PlaneData& b) { return a.area < b.area; }); - m_planes.resize(std::min((int)m_planes.size(), 254)); + // Planes are finished - let's save what we calculated it from: m_volumes_matrices.clear(); @@ -339,21 +337,23 @@ void GLGizmoMeasure::update_planes() // And finally create respective VBOs. The polygon is convex with // the vertices in order, so triangulation is trivial. for (auto& plane : m_planes) { - GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::TriangleFan, GLModel::Geometry::EVertexLayout::P3N3 }; - init_data.reserve_vertices(plane.vertices.size()); - init_data.reserve_indices(plane.vertices.size()); - // vertices + indices - for (size_t i = 0; i < plane.vertices.size(); ++i) { - init_data.add_vertex((Vec3f)plane.vertices[i].cast(), (Vec3f)plane.normal.cast()); - init_data.add_index((unsigned int)i); + for (auto& vertices : plane.borders) { + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3N3 }; + init_data.reserve_vertices(vertices.size()); + init_data.reserve_indices(vertices.size()); + // vertices + indices + for (size_t i = 0; i < vertices.size(); ++i) { + init_data.add_vertex((Vec3f)vertices[i].cast(), (Vec3f)plane.normal.cast()); + init_data.add_index((unsigned int)i); + } + plane.vbo.init_from(std::move(init_data)); } - plane.vbo.init_from(std::move(init_data)); // FIXME: vertices should really be local, they need not // persist now when we use VBOs - plane.vertices.clear(); - plane.vertices.shrink_to_fit(); + plane.borders.clear(); + plane.borders.shrink_to_fit(); } m_planes_valid = true; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 9bf87a29f6..87ad73d8c6 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -24,8 +24,8 @@ class GLGizmoMeasure : public GLGizmoBase private: struct PlaneData { - std::vector vertices; // should be in fact local in update_planes() - std::vector borders_facets; + std::vector> borders; // should be in fact local in update_planes() + std::vector facets; GLModel vbo; Vec3d normal; float area; From 985b16e858621579d17c1b716ae42bd55ede7456 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 22 Jun 2022 10:34:58 +0200 Subject: [PATCH 006/250] Measuring: Simple visualization --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 62 ++++++++++++++++++------ src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 4 +- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 129407764c..de3fc398b9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -17,15 +17,13 @@ namespace Slic3r { namespace GUI { -static const Slic3r::ColorRGBA DEFAULT_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.5f }; -static const Slic3r::ColorRGBA DEFAULT_HOVER_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.75f }; +static const Slic3r::ColorRGBA DEFAULT_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.9f }; +static const Slic3r::ColorRGBA DEFAULT_HOVER_PLANE_COLOR = { 0.9f, 0.2f, 0.2f, 1.f }; GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) {} - - bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) { if (mouse_event.Moving()) { @@ -139,9 +137,29 @@ void GLGizmoMeasure::on_render() shader->set_uniform("projection_matrix", camera.get_projection_matrix()); if (this->is_plane_update_necessary()) update_planes(); - for (int i = 0; i < (int)m_planes.size(); ++i) { - m_planes[i].vbo.set_color(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); - m_planes[i].vbo.render(); + + m_imgui->begin(std::string("DEBUG")); + if (m_imgui->button("<-")) + --m_currently_shown_plane; + ImGui::SameLine(); + if (m_imgui->button("->")) + ++m_currently_shown_plane; + m_currently_shown_plane = std::clamp(m_currently_shown_plane, 0, int(m_planes.size())-1); + m_imgui->text(std::to_string(m_currently_shown_plane)); + m_imgui->end(); + + + //for (int i = 0; i < (int)m_planes.size(); ++i) { + int i = m_currently_shown_plane; + std::cout << m_hover_id << "\t" << m_currently_shown_plane << "\t" << std::endl; + if (i < m_planes.size()) { + for (int j=0; j<(int)m_planes[i].vbos.size(); ++j) { + m_planes[i].vbos[j].set_color(j == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); + if (j == m_hover_id) + m_planes[i].vbos[j].render(); + std::cout << " * " << j; + } + std::cout <get_instance_transformation().get_matrix(); @@ -189,9 +208,13 @@ void GLGizmoMeasure::on_render_for_picking() shader->set_uniform("projection_matrix", camera.get_projection_matrix()); if (this->is_plane_update_necessary()) update_planes(); - for (int i = 0; i < (int)m_planes.size(); ++i) { - m_planes[i].vbo.set_color(picking_color_component(i)); - m_planes[i].vbo.render(); + //for (int i = 0; i < (int)m_planes.size(); ++i) { + int i = m_currently_shown_plane; + if (i < m_planes.size()) { + for (int j=0; j<(int)m_planes[i].vbos.size(); ++j) { + m_planes[i].vbos[j].set_color(picking_color_component(j)); + m_planes[i].vbos[j].render(); + } } } @@ -277,7 +300,7 @@ void GLGizmoMeasure::update_planes() for (int plane_id=0; plane_id < m_planes.size(); ++plane_id) { //int plane_id = 5; { const auto& facets = m_planes[plane_id].facets; - std::vector pts; + std::vector pts; for (int face_id=0; face_id{ sm.point(sm.source(he)).cast() }); + pts.emplace_back(sm.point(sm.source(he)).cast()); Vertex_index target = sm.target(he); const Halfedge_index he_start = he; @@ -303,14 +326,20 @@ void GLGizmoMeasure::update_planes() while ( face_to_plane[sm.face(he)] == plane_id && he != he_orig) he = sm.next_around_target(he); he = sm.opposite(he); - m_planes[plane_id].borders.back().emplace_back(sm.point(sm.source(he)).cast()); + pts.emplace_back(sm.point(sm.source(he)).cast()); } while (he != he_start); + + if (pts.size() != 1) { + m_planes[plane_id].borders.emplace_back(pts); + pts.clear(); + } + } } // DEBUGGING: - //m_planes.erase(std::remove_if(m_planes.begin(), m_planes.end(), [](const PlaneData& p) { return p.borders.empty(); }), m_planes.end()); + m_planes.erase(std::remove_if(m_planes.begin(), m_planes.end(), [](const PlaneData& p) { return p.borders.empty(); }), m_planes.end()); @@ -337,7 +366,7 @@ void GLGizmoMeasure::update_planes() // And finally create respective VBOs. The polygon is convex with // the vertices in order, so triangulation is trivial. for (auto& plane : m_planes) { - for (auto& vertices : plane.borders) { + for (const auto& vertices : plane.borders) { GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3N3 }; init_data.reserve_vertices(vertices.size()); @@ -347,7 +376,8 @@ void GLGizmoMeasure::update_planes() init_data.add_vertex((Vec3f)vertices[i].cast(), (Vec3f)plane.normal.cast()); init_data.add_index((unsigned int)i); } - plane.vbo.init_from(std::move(init_data)); + plane.vbos.emplace_back(); + plane.vbos.back().init_from(std::move(init_data)); } // FIXME: vertices should really be local, they need not diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 87ad73d8c6..32b43e6f84 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -23,10 +23,12 @@ class GLGizmoMeasure : public GLGizmoBase private: + int m_currently_shown_plane = 0; + struct PlaneData { std::vector> borders; // should be in fact local in update_planes() std::vector facets; - GLModel vbo; + std::vector vbos; Vec3d normal; float area; }; From 9aa706c0a743d68847b3237c4027abafe0b7adee Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 1 Jul 2022 15:51:51 +0200 Subject: [PATCH 007/250] Measuring: First steps on extracting features --- src/libslic3r/SurfaceMesh.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 204 ++++++++++++++++++----- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 20 ++- 3 files changed, 183 insertions(+), 42 deletions(-) diff --git a/src/libslic3r/SurfaceMesh.hpp b/src/libslic3r/SurfaceMesh.hpp index e8ada4cd80..a4b261ceb9 100644 --- a/src/libslic3r/SurfaceMesh.hpp +++ b/src/libslic3r/SurfaceMesh.hpp @@ -17,6 +17,7 @@ class Halfedge_index { public: Halfedge_index() : m_face(Face_index(-1)), m_side(0) {} Face_index face() const { return m_face; } + unsigned char side() const { return m_side; } bool is_invalid() const { return int(m_face) < 0; } bool operator!=(const Halfedge_index& rhs) const { return ! ((*this) == rhs); } bool operator==(const Halfedge_index& rhs) const { return m_face == rhs.m_face && m_side == rhs.m_side; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index de3fc398b9..6c95e70b7f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -22,7 +22,10 @@ static const Slic3r::ColorRGBA DEFAULT_HOVER_PLANE_COLOR = { 0.9f, 0.2f, 0.2f, 1 GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) -{} +{ + m_vbo_sphere.init_from(its_make_sphere(1., M_PI/32.)); + m_vbo_cylinder.init_from(its_make_cylinder(1., 1.)); +} bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) { @@ -125,7 +128,7 @@ void GLGizmoMeasure::on_render() glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_BLEND)); - glsafe(::glLineWidth(5.f)); + glsafe(::glLineWidth(2.f)); if (selection.is_single_full_instance()) { const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); @@ -144,22 +147,47 @@ void GLGizmoMeasure::on_render() ImGui::SameLine(); if (m_imgui->button("->")) ++m_currently_shown_plane; - m_currently_shown_plane = std::clamp(m_currently_shown_plane, 0, int(m_planes.size())-1); - m_imgui->text(std::to_string(m_currently_shown_plane)); + m_currently_shown_plane = std::clamp(m_currently_shown_plane, 0, std::max(0, int(m_planes.size())-1)); + m_imgui->text(std::to_string(m_currently_shown_plane)); + m_imgui->checkbox(wxString("Show all"), m_show_all); m_imgui->end(); - //for (int i = 0; i < (int)m_planes.size(); ++i) { - int i = m_currently_shown_plane; - std::cout << m_hover_id << "\t" << m_currently_shown_plane << "\t" << std::endl; - if (i < m_planes.size()) { + int i = m_show_all ? 0 : m_currently_shown_plane; + for (int i = 0; i < (int)m_planes.size(); ++i) { + // Render all the borders. for (int j=0; j<(int)m_planes[i].vbos.size(); ++j) { m_planes[i].vbos[j].set_color(j == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); - if (j == m_hover_id) m_planes[i].vbos[j].render(); - std::cout << " * " << j; } - std::cout <::FromTwoVectors(Vec3d::UnitZ(), feature.endpoint - feature.pos); + view_feature_matrix *= q; + view_feature_matrix.scale(Vec3d(0.3, 0.3, (feature.endpoint - feature.pos).norm())); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_cylinder.set_color(ColorRGBA(0.7f, 0.7f, 0.f, 1.f)); + m_vbo_cylinder.render(); + } + + view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.pos)); + view_feature_matrix.scale(0.5); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_sphere.set_color(feature.type == SurfaceFeature::Line + ? ColorRGBA(1.f, 0.f, 0.f, 1.f) + : ColorRGBA(0.f, 1.f, 0.f, 1.f)); + m_vbo_sphere.render(); + + + shader->set_uniform("view_model_matrix", view_model_matrix); + } + + if (! m_show_all) + break; } } @@ -196,7 +224,7 @@ void GLGizmoMeasure::on_render_for_picking() glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_BLEND)); - glsafe(::glLineWidth(5.f)); + glsafe(::glLineWidth(2.f)); if (selection.is_single_full_instance() && !wxGetKeyState(WXK_CONTROL)) { const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); @@ -235,6 +263,73 @@ void GLGizmoMeasure::set_flattening_data(const ModelObject* model_object) +void GLGizmoMeasure::extract_features(GLGizmoMeasure::PlaneData& plane) +{ + plane.surface_features.clear(); + const Vec3d& normal = plane.normal; + + const double edge_threshold = 10. * (M_PI/180.); + + + + for (const std::vector& border : plane.borders) { + assert(border.size() > 1); + assert(! border.front().isApprox(border.back())); + double last_angle = 0.; + size_t first_idx = 0; + + for (size_t i=0; i edge_threshold || i == border.size() - 1) { + // Current feature ended. Save it and remember current point as beginning of the next. + bool is_line = (i == first_idx + 1); + plane.surface_features.emplace_back(SurfaceFeature{ + is_line ? SurfaceFeature::Line : SurfaceFeature::Circle, + is_line ? border[first_idx] : border[first_idx], // FIXME + border[i], + 0. // FIXME + }); + first_idx = i; + } else if (Slic3r::is_approx(angle, last_angle)) { + // possibly a segment of a circle + } else { + first_idx = i; + + } + } + last_angle = angle; + } + + // FIXME: Possibly merge the first and last feature. + + + + std::cout << "==================== " << std::endl; + } + + + for (const SurfaceFeature& f : plane.surface_features) { + std::cout << "- detected " << (f.type == SurfaceFeature::Line ? "Line" : "Circle") << std::endl; + std::cout<< f.pos << std::endl << std::endl << f.endpoint << std::endl; + std::cout << "----------------" << std::endl; + } + + + +} + + + void GLGizmoMeasure::update_planes() { const ModelObject* mo = m_c->selection_info()->model_object(); @@ -292,6 +387,7 @@ void GLGizmoMeasure::update_planes() } m_planes.back().normal = normal_ptr->cast(); + std::sort(m_planes.back().facets.begin(), m_planes.back().facets.end()); } assert(std::none_of(face_to_plane.begin(), face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); @@ -300,40 +396,57 @@ void GLGizmoMeasure::update_planes() for (int plane_id=0; plane_id < m_planes.size(); ++plane_id) { //int plane_id = 5; { const auto& facets = m_planes[plane_id].facets; - std::vector pts; + m_planes[plane_id].borders.clear(); + std::vector> visited(facets.size(), {false, false, false}); + for (int face_id=0; face_id()); - Vertex_index target = sm.target(he); - const Halfedge_index he_start = he; - - do { + // he is the first halfedge on the border. Now walk around and append the points. const Halfedge_index he_orig = he; - he = sm.next_around_target(he); - while ( face_to_plane[sm.face(he)] == plane_id && he != he_orig) - he = sm.next_around_target(he); - he = sm.opposite(he); - pts.emplace_back(sm.point(sm.source(he)).cast()); - } while (he != he_start); + m_planes[plane_id].borders.emplace_back(); + m_planes[plane_id].borders.back().emplace_back(sm.point(sm.source(he)).cast()); + Vertex_index target = sm.target(he); + const Halfedge_index he_start = he; + + Face_index fi = he.face(); + auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi)); + assert(face_it != facets.end()); + assert(*face_it == int(fi)); + visited[face_it - facets.begin()][he.side()] = true; - if (pts.size() != 1) { - m_planes[plane_id].borders.emplace_back(pts); - pts.clear(); + do { + const Halfedge_index he_orig = he; + he = sm.next_around_target(he); + while ( face_to_plane[sm.face(he)] == plane_id && he != he_orig) + he = sm.next_around_target(he); + he = sm.opposite(he); + + Face_index fi = he.face(); + auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi)); + assert(face_it != facets.end()); + assert(*face_it == int(fi)); + if (visited[face_it - facets.begin()][he.side()] && he != he_start) { + m_planes[plane_id].borders.back().resize(1); + break; + } + visited[face_it - facets.begin()][he.side()] = true; + + m_planes[plane_id].borders.back().emplace_back(sm.point(sm.source(he)).cast()); + } while (he != he_start); + + if (m_planes[plane_id].borders.back().size() == 1) + m_planes[plane_id].borders.pop_back(); } - } } @@ -365,8 +478,8 @@ void GLGizmoMeasure::update_planes() // And finally create respective VBOs. The polygon is convex with // the vertices in order, so triangulation is trivial. - for (auto& plane : m_planes) { - for (const auto& vertices : plane.borders) { + for (PlaneData& plane : m_planes) { + for (std::vector& vertices : plane.borders) { GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3N3 }; init_data.reserve_vertices(vertices.size()); @@ -378,8 +491,17 @@ void GLGizmoMeasure::update_planes() } plane.vbos.emplace_back(); plane.vbos.back().init_from(std::move(init_data)); + vertices.pop_back(); // first and last are the same } + static int n=0; + std::cout << "==================== " << std::endl; + std::cout << "==================== " << std::endl; + std::cout << "==================== " << std::endl; + std::cout << "Plane num. " << n++ << std::endl; + extract_features(plane); + + // FIXME: vertices should really be local, they need not // persist now when we use VBOs plane.borders.clear(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 32b43e6f84..3099366736 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -24,15 +24,33 @@ class GLGizmoMeasure : public GLGizmoBase private: int m_currently_shown_plane = 0; + bool m_show_all = false; + + GLModel m_vbo_sphere; + GLModel m_vbo_cylinder; + + struct SurfaceFeature { + enum Type { + Circle, + Line + }; + Type type; + Vec3d pos; + Vec3d endpoint; // for type == Line + double radius; // for type == Circle; + }; struct PlaneData { - std::vector> borders; // should be in fact local in update_planes() std::vector facets; + std::vector> borders; // should be in fact local in update_planes() + std::vector surface_features; std::vector vbos; Vec3d normal; float area; }; + static void extract_features(PlaneData& plane); + // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; std::vector m_volumes_types; From 9644fd4c595a382f3bd0dd1b1eb49092d123b704 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 7 Jul 2022 12:30:26 +0200 Subject: [PATCH 008/250] Measuring: Improved visualization --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 50 ++++++++++++++---------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 5 ++- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 6c95e70b7f..0cb1067c39 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -149,12 +149,15 @@ void GLGizmoMeasure::on_render() ++m_currently_shown_plane; m_currently_shown_plane = std::clamp(m_currently_shown_plane, 0, std::max(0, int(m_planes.size())-1)); m_imgui->text(std::to_string(m_currently_shown_plane)); - m_imgui->checkbox(wxString("Show all"), m_show_all); + m_imgui->checkbox(wxString("Show all"), m_show_all_planes); + m_imgui->checkbox(wxString("Show points"), m_show_points); + m_imgui->checkbox(wxString("Show edges"), m_show_edges); + m_imgui->checkbox(wxString("Show circles"), m_show_circles); m_imgui->end(); - int i = m_show_all ? 0 : m_currently_shown_plane; - for (int i = 0; i < (int)m_planes.size(); ++i) { + int i = m_show_all_planes ? 0 : m_currently_shown_plane; + for (; i < (int)m_planes.size(); ++i) { // Render all the borders. for (int j=0; j<(int)m_planes[i].vbos.size(); ++j) { m_planes[i].vbos[j].set_color(j == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); @@ -165,7 +168,7 @@ void GLGizmoMeasure::on_render() // Render features: for (const SurfaceFeature& feature : m_planes[i].surface_features) { Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.pos)); - if (feature.type == SurfaceFeature::Line) { + if (m_show_edges && feature.type == SurfaceFeature::Line) { auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), feature.endpoint - feature.pos); view_feature_matrix *= q; view_feature_matrix.scale(Vec3d(0.3, 0.3, (feature.endpoint - feature.pos).norm())); @@ -174,19 +177,21 @@ void GLGizmoMeasure::on_render() m_vbo_cylinder.render(); } - view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.pos)); - view_feature_matrix.scale(0.5); - shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_sphere.set_color(feature.type == SurfaceFeature::Line - ? ColorRGBA(1.f, 0.f, 0.f, 1.f) - : ColorRGBA(0.f, 1.f, 0.f, 1.f)); - m_vbo_sphere.render(); + if (m_show_points && feature.type == SurfaceFeature::Line || m_show_circles && feature.type == SurfaceFeature::Circle) { + view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.pos)); + view_feature_matrix.scale(0.5); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_sphere.set_color(feature.type == SurfaceFeature::Line + ? ColorRGBA(1.f, 0.f, 0.f, 1.f) + : ColorRGBA(0.f, 1.f, 0.f, 1.f)); + m_vbo_sphere.render(); + } shader->set_uniform("view_model_matrix", view_model_matrix); } - if (! m_show_all) + if (! m_show_all_planes) break; } } @@ -268,7 +273,7 @@ void GLGizmoMeasure::extract_features(GLGizmoMeasure::PlaneData& plane) plane.surface_features.clear(); const Vec3d& normal = plane.normal; - const double edge_threshold = 10. * (M_PI/180.); + const double edge_threshold = 25. * (M_PI/180.); @@ -276,9 +281,10 @@ void GLGizmoMeasure::extract_features(GLGizmoMeasure::PlaneData& plane) assert(border.size() > 1); assert(! border.front().isApprox(border.back())); double last_angle = 0.; - size_t first_idx = 0; + int first_idx = 0; + bool circle = false; - for (size_t i=0; i edge_threshold || i == border.size() - 1) { + bool same_as_last = Slic3r::is_approx(angle, last_angle); + + if (std::abs(angle) > edge_threshold || (! same_as_last && circle) || i == border.size() - 1) { // Current feature ended. Save it and remember current point as beginning of the next. bool is_line = (i == first_idx + 1); plane.surface_features.emplace_back(SurfaceFeature{ @@ -300,11 +308,13 @@ void GLGizmoMeasure::extract_features(GLGizmoMeasure::PlaneData& plane) 0. // FIXME }); first_idx = i; - } else if (Slic3r::is_approx(angle, last_angle)) { + circle = false; + } else if (same_as_last && ! circle) { // possibly a segment of a circle - } else { + first_idx = std::max(i-2, 0); + circle = true; + } else if (! circle) { first_idx = i; - } } last_angle = angle; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 3099366736..9534796a71 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -24,7 +24,10 @@ class GLGizmoMeasure : public GLGizmoBase private: int m_currently_shown_plane = 0; - bool m_show_all = false; + bool m_show_all_planes = false; + bool m_show_points = true; + bool m_show_edges = true; + bool m_show_circles = true; GLModel m_vbo_sphere; GLModel m_vbo_cylinder; From 00eb8661c0bfdc057dad9f3fd9472bb6069c1ebe Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 13 Jul 2022 16:37:16 +0200 Subject: [PATCH 009/250] Measuring: Improved feature detection, added circle center calculation --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 120 ++++++++++++++--------- 1 file changed, 75 insertions(+), 45 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 0cb1067c39..e00d587814 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -9,6 +9,7 @@ #include "libslic3r/Geometry/ConvexHull.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/SurfaceMesh.hpp" +#include "libslic3r/Geometry/Circle.hpp" #include @@ -177,7 +178,7 @@ void GLGizmoMeasure::on_render() m_vbo_cylinder.render(); } - if (m_show_points && feature.type == SurfaceFeature::Line || m_show_circles && feature.type == SurfaceFeature::Circle) { + if ((m_show_points && feature.type == SurfaceFeature::Line) || m_show_circles && feature.type == SurfaceFeature::Circle) { view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.pos)); view_feature_matrix.scale(0.5); shader->set_uniform("view_model_matrix", view_feature_matrix); @@ -185,6 +186,14 @@ void GLGizmoMeasure::on_render() ? ColorRGBA(1.f, 0.f, 0.f, 1.f) : ColorRGBA(0.f, 1.f, 0.f, 1.f)); m_vbo_sphere.render(); + + /*view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.endpoint)); + view_feature_matrix.scale(0.5); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_sphere.set_color(feature.type == SurfaceFeature::Line + ? ColorRGBA(1.f, 0.f, 0.f, 1.f) + : ColorRGBA(1.f, 1.f, 0.f, 1.f)); + m_vbo_sphere.render();*/ } @@ -243,7 +252,7 @@ void GLGizmoMeasure::on_render_for_picking() update_planes(); //for (int i = 0; i < (int)m_planes.size(); ++i) { int i = m_currently_shown_plane; - if (i < m_planes.size()) { + if (i < int(m_planes.size())) { for (int j=0; j<(int)m_planes[i].vbos.size(); ++j) { m_planes[i].vbos[j].set_color(picking_color_component(j)); m_planes[i].vbos[j].render(); @@ -268,60 +277,84 @@ void GLGizmoMeasure::set_flattening_data(const ModelObject* model_object) +static std::pair get_center_and_radius(const std::vector& border, int start_idx, int end_idx, const Transform3d& trafo) +{ + Vec2ds pts; + double z = 0.; + for (int i=start_idx; i<=end_idx; ++i) { + Vec3d pt_transformed = trafo * border[i]; + z = pt_transformed.z(); + pts.emplace_back(pt_transformed.x(), pt_transformed.y()); + } + + auto circle = Geometry::circle_ransac(pts, 20); // FIXME: iterations? + + return std::make_pair(trafo.inverse() * Vec3d(circle.center.x(), circle.center.y(), z), circle.radius); +} + + + void GLGizmoMeasure::extract_features(GLGizmoMeasure::PlaneData& plane) { plane.surface_features.clear(); const Vec3d& normal = plane.normal; const double edge_threshold = 25. * (M_PI/180.); + std::vector angles; + + Eigen::Quaterniond q; + q.setFromTwoVectors(plane.normal, Vec3d::UnitZ()); + Transform3d trafo = Transform3d::Identity(); + trafo.rotate(q); for (const std::vector& border : plane.borders) { assert(border.size() > 1); assert(! border.front().isApprox(border.back())); - double last_angle = 0.; - int first_idx = 0; - bool circle = false; + int start_idx = -1; + + // First calculate angles at all the vertices. + angles.clear(); for (int i=0; i edge_threshold || (! same_as_last && circle) || i == border.size() - 1) { - // Current feature ended. Save it and remember current point as beginning of the next. - bool is_line = (i == first_idx + 1); - plane.surface_features.emplace_back(SurfaceFeature{ - is_line ? SurfaceFeature::Line : SurfaceFeature::Circle, - is_line ? border[first_idx] : border[first_idx], // FIXME - border[i], - 0. // FIXME - }); - first_idx = i; - circle = false; - } else if (same_as_last && ! circle) { - // possibly a segment of a circle - first_idx = std::max(i-2, 0); + + bool circle = false; + std::vector> circles; + for (int i=1; i center_and_radius = get_center_and_radius(border, start_idx, end_idx, trafo); + plane.surface_features.emplace_back(SurfaceFeature{ + SurfaceFeature::Circle, + // border[start_idx], border[end_idx], + center_and_radius.first, center_and_radius.first, center_and_radius.second + }); + } std::cout << "==================== " << std::endl; @@ -352,7 +385,7 @@ void GLGizmoMeasure::update_planes() ch.merge(vol_ch); } m_planes.clear(); - const Transform3d& inst_matrix = mo->instances.front()->get_matrix(); + // Now we'll go through all the facets and append Points of facets sharing the same normal. // This part is still performed in mesh coordinate system. @@ -403,13 +436,13 @@ void GLGizmoMeasure::update_planes() assert(std::none_of(face_to_plane.begin(), face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); SurfaceMesh sm(ch.its); - for (int plane_id=0; plane_id < m_planes.size(); ++plane_id) { + for (int plane_id=0; plane_id < int(m_planes.size()); ++plane_id) { //int plane_id = 5; { const auto& facets = m_planes[plane_id].facets; m_planes[plane_id].borders.clear(); std::vector> visited(facets.size(), {false, false, false}); - for (int face_id=0; face_id()); - Vertex_index target = sm.target(he); + std::vector& last_border = m_planes[plane_id].borders.back(); + last_border.emplace_back(sm.point(sm.source(he)).cast()); + //Vertex_index target = sm.target(he); const Halfedge_index he_start = he; Face_index fi = he.face(); @@ -446,15 +480,15 @@ void GLGizmoMeasure::update_planes() assert(face_it != facets.end()); assert(*face_it == int(fi)); if (visited[face_it - facets.begin()][he.side()] && he != he_start) { - m_planes[plane_id].borders.back().resize(1); + last_border.resize(1); break; } visited[face_it - facets.begin()][he.side()] = true; - m_planes[plane_id].borders.back().emplace_back(sm.point(sm.source(he)).cast()); + last_border.emplace_back(sm.point(sm.source(he)).cast()); } while (he != he_start); - if (m_planes[plane_id].borders.back().size() == 1) + if (last_border.size() == 1) m_planes[plane_id].borders.pop_back(); } } @@ -468,11 +502,7 @@ void GLGizmoMeasure::update_planes() - // Let's prepare transformation of the normal vector from mesh to instance coordinates. - Geometry::Transformation t(inst_matrix); - Vec3d scaling = t.get_scaling_factor(); - t.set_scaling_factor(Vec3d(1./scaling(0), 1./scaling(1), 1./scaling(2))); - + // Planes are finished - let's save what we calculated it from: From fe9540130aaad4d0b5a76e6ce209fd1e49d7d4af Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 26 Jul 2022 10:12:59 +0200 Subject: [PATCH 010/250] Measuring: Separating frontend and backend --- src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/Measure.cpp | 323 ++++++++++++++++ src/libslic3r/Measure.hpp | 98 +++++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 448 ++++------------------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 43 +-- 5 files changed, 499 insertions(+), 415 deletions(-) create mode 100644 src/libslic3r/Measure.cpp create mode 100644 src/libslic3r/Measure.hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 396494a181..1c060243da 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -178,6 +178,8 @@ set(SLIC3R_SOURCES MultiMaterialSegmentation.hpp MeshNormals.hpp MeshNormals.cpp + Measure.hpp + Measure.cpp CustomGCode.cpp CustomGCode.hpp Arrange.hpp diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp new file mode 100644 index 0000000000..d5cb9c24b3 --- /dev/null +++ b/src/libslic3r/Measure.cpp @@ -0,0 +1,323 @@ +#include "Measure.hpp" + +#include "libslic3r/Geometry/Circle.hpp" +#include "libslic3r/SurfaceMesh.hpp" + + + +namespace Slic3r { +namespace Measure { + + + +static std::pair get_center_and_radius(const std::vector& border, int start_idx, int end_idx, const Transform3d& trafo) +{ + Vec2ds pts; + double z = 0.; + for (int i=start_idx; i<=end_idx; ++i) { + Vec3d pt_transformed = trafo * border[i]; + z = pt_transformed.z(); + pts.emplace_back(pt_transformed.x(), pt_transformed.y()); + } + + auto circle = Geometry::circle_ransac(pts, 20); // FIXME: iterations? + + return std::make_pair(trafo.inverse() * Vec3d(circle.center.x(), circle.center.y(), z), circle.radius); +} + + + + +class MeasuringImpl { +public: + explicit MeasuringImpl(const indexed_triangle_set& its); + struct PlaneData { + std::vector facets; + std::vector> borders; // FIXME: should be in fact local in update_planes() + std::vector> surface_features; + Vec3d normal; + float area; + }; + + const std::vector& get_features() const; + +private: + void update_planes(); + void extract_features(PlaneData& plane); + void save_features(); + + + std::vector m_planes; + std::vector m_features; + const indexed_triangle_set& m_its; +}; + + + + + + +MeasuringImpl::MeasuringImpl(const indexed_triangle_set& its) +: m_its{its} +{ + update_planes(); + + for (PlaneData& plane : m_planes) { + extract_features(plane); + + plane.borders.clear(); + plane.borders.shrink_to_fit(); + } + + save_features(); +} + + +void MeasuringImpl::update_planes() +{ + m_planes.clear(); + + // Now we'll go through all the facets and append Points of facets sharing the same normal. + // This part is still performed in mesh coordinate system. + const size_t num_of_facets = m_its.indices.size(); + std::vector face_to_plane(num_of_facets, size_t(-1)); + const std::vector face_normals = its_face_normals(m_its); + const std::vector face_neighbors = its_face_neighbors(m_its); + std::vector facet_queue(num_of_facets, 0); + int facet_queue_cnt = 0; + const stl_normal* normal_ptr = nullptr; + size_t seed_facet_idx = 0; + + auto is_same_normal = [](const stl_normal& a, const stl_normal& b) -> bool { + return (std::abs(a(0) - b(0)) < 0.001 && std::abs(a(1) - b(1)) < 0.001 && std::abs(a(2) - b(2)) < 0.001); + }; + + while (1) { + // Find next unvisited triangle: + for (; seed_facet_idx < num_of_facets; ++ seed_facet_idx) + if (face_to_plane[seed_facet_idx] == size_t(-1)) { + facet_queue[facet_queue_cnt ++] = seed_facet_idx; + normal_ptr = &face_normals[seed_facet_idx]; + face_to_plane[seed_facet_idx] = m_planes.size(); + m_planes.emplace_back(); + break; + } + if (seed_facet_idx == num_of_facets) + break; // Everything was visited already + + while (facet_queue_cnt > 0) { + int facet_idx = facet_queue[-- facet_queue_cnt]; + const stl_normal& this_normal = face_normals[facet_idx]; + if (is_same_normal(this_normal, *normal_ptr)) { + const Vec3i& face = m_its.indices[facet_idx]; + + face_to_plane[facet_idx] = m_planes.size() - 1; + m_planes.back().facets.emplace_back(facet_idx); + for (int j = 0; j < 3; ++ j) + if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && face_to_plane[neighbor_idx] == size_t(-1)) + facet_queue[facet_queue_cnt ++] = neighbor_idx; + } + } + + m_planes.back().normal = normal_ptr->cast(); + std::sort(m_planes.back().facets.begin(), m_planes.back().facets.end()); + } + + assert(std::none_of(face_to_plane.begin(), face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); + + SurfaceMesh sm(m_its); + for (int plane_id=0; plane_id < int(m_planes.size()); ++plane_id) { + //int plane_id = 5; { + const auto& facets = m_planes[plane_id].facets; + m_planes[plane_id].borders.clear(); + std::vector> visited(facets.size(), {false, false, false}); + + for (int face_id=0; face_id& last_border = m_planes[plane_id].borders.back(); + last_border.emplace_back(sm.point(sm.source(he)).cast()); + //Vertex_index target = sm.target(he); + const Halfedge_index he_start = he; + + Face_index fi = he.face(); + auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi)); + assert(face_it != facets.end()); + assert(*face_it == int(fi)); + visited[face_it - facets.begin()][he.side()] = true; + + do { + const Halfedge_index he_orig = he; + he = sm.next_around_target(he); + while ( face_to_plane[sm.face(he)] == plane_id && he != he_orig) + he = sm.next_around_target(he); + he = sm.opposite(he); + + Face_index fi = he.face(); + auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi)); + assert(face_it != facets.end()); + assert(*face_it == int(fi)); + if (visited[face_it - facets.begin()][he.side()] && he != he_start) { + last_border.resize(1); + break; + } + visited[face_it - facets.begin()][he.side()] = true; + + last_border.emplace_back(sm.point(sm.source(he)).cast()); + } while (he != he_start); + + if (last_border.size() == 1) + m_planes[plane_id].borders.pop_back(); + } + } + } + + m_planes.erase(std::remove_if(m_planes.begin(), m_planes.end(), + [](const PlaneData& p) { return p.borders.empty(); }), + m_planes.end()); +} + + + + + + +void MeasuringImpl::extract_features(PlaneData& plane) +{ + plane.surface_features.clear(); + const Vec3d& normal = plane.normal; + + const double edge_threshold = 25. * (M_PI/180.); + std::vector angles; + + Eigen::Quaterniond q; + q.setFromTwoVectors(plane.normal, Vec3d::UnitZ()); + Transform3d trafo = Transform3d::Identity(); + trafo.rotate(q); + + + + for (const std::vector& border : plane.borders) { + assert(border.size() > 1); + int start_idx = -1; + + + // First calculate angles at all the vertices. + angles.clear(); + for (int i=0; i> circles; + for (int i=1; i circles[cidx].first) + i = circles[cidx++].second; + else plane.surface_features.emplace_back(std::unique_ptr( + new Edge(border[i-1], border[i]))); + } + + // FIXME Throw away / do not create edges which are parts of circles. + + // FIXME Check and maybe merge first and last circle. + + for (const auto& [start_idx, end_idx] : circles) { + std::pair center_and_radius = get_center_and_radius(border, start_idx, end_idx, trafo); + plane.surface_features.emplace_back(std::unique_ptr( + new Circle(center_and_radius.first, center_and_radius.second) + )); + } + + } +} + + + +void MeasuringImpl::save_features() +{ + m_features.clear(); + for (PlaneData& plane : m_planes) + //PlaneData& plane = m_planes[0]; + { + for (std::unique_ptr& feature : plane.surface_features) { + m_features.emplace_back(feature.get()); + } + } +} + + + +const std::vector& MeasuringImpl::get_features() const +{ + return m_features; +} + + + + + + + + + + + + + +Measuring::Measuring(const indexed_triangle_set& its) +: priv{std::make_unique(its)} +{} + +Measuring::~Measuring() {} + + +const std::vector& Measuring::get_features() const +{ + return priv->get_features(); +} + + + + + + +} // namespace Measure +} // namespace Slic3r diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp new file mode 100644 index 0000000000..bbc7d9e1e9 --- /dev/null +++ b/src/libslic3r/Measure.hpp @@ -0,0 +1,98 @@ +#ifndef Slic3r_Measure_hpp_ +#define Slic3r_Measure_hpp_ + +#include + +#include "Point.hpp" + + +struct indexed_triangle_set; + + + +namespace Slic3r { +namespace Measure { + + +enum class SurfaceFeatureType { + Edge = 1 << 0, + Circle = 1 << 1, + Plane = 1 << 2 + }; + +class SurfaceFeature { +public: + virtual SurfaceFeatureType get_type() const = 0; +}; + +class Edge : public SurfaceFeature { +public: + Edge(const Vec3d& start, const Vec3d& end) : m_start{start}, m_end{end} {} + SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Edge; } + std::pair get_edge() const { return std::make_pair(m_start, m_end); } +private: + Vec3d m_start; + Vec3d m_end; +}; + +class Circle : public SurfaceFeature { +public: + Circle(const Vec3d& center, double radius) : m_center{center}, m_radius{radius} {} + SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Circle; } + Vec3d get_center() const { return m_center; } + double get_radius() const { return m_radius; } +private: + Vec3d m_center; + double m_radius; +}; + +class Plane : public SurfaceFeature { +public: + SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Plane; } + +}; + + +class MeasuringImpl; + + +class Measuring { +public: + // Construct the measurement object on a given its. The its must remain + // valid and unchanged during the whole lifetime of the object. + explicit Measuring(const indexed_triangle_set& its); + ~Measuring(); + + // Return a reference to a list of all features identified on the its. + const std::vector& get_features() const; + + // Given a face_idx where the mouse cursor points, return a feature that + // should be highlighted or nullptr. + const SurfaceFeature* get_feature(size_t face_idx, const Vec3d& point) const; + + // Returns distance between two SurfaceFeatures. + static double get_distance(const SurfaceFeature* a, const SurfaceFeature* b); + + // Returns true if an x/y/z distance between features makes sense. + // If so, result contains the distances. + static bool get_distances(const SurfaceFeature* a, const SurfaceFeature* b, std::array& result); + + // Returns true if an x/y/z distance between feature and a point makes sense. + // If so, result contains the distances. + static bool get_axis_aligned_distances(const SurfaceFeature* feature, const Vec3d* pt, std::array& result); + + // Returns true if measuring angles between features makes sense. + // If so, result contains the angle in radians. + static bool get_angle(const SurfaceFeature* a, const SurfaceFeature* b, double& result); + + +private: + + std::unique_ptr priv; +}; + + +} // namespace Measure +} // namespace Slic3r + +#endif // Slic3r_Measure_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index e00d587814..043adba976 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -6,10 +6,8 @@ #include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" -#include "libslic3r/Geometry/ConvexHull.hpp" #include "libslic3r/Model.hpp" -#include "libslic3r/SurfaceMesh.hpp" -#include "libslic3r/Geometry/Circle.hpp" +#include "libslic3r/Measure.hpp" #include @@ -30,6 +28,10 @@ GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filen bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) { + m_mouse_pos_x = mouse_event.GetX(); + m_mouse_pos_y = mouse_event.GetY(); + + if (mouse_event.Moving()) { // only for sure m_mouse_left_down = false; @@ -38,12 +40,7 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) if (mouse_event.LeftDown()) { if (m_hover_id != -1) { m_mouse_left_down = true; - Selection &selection = m_parent.get_selection(); - if (selection.is_single_full_instance()) { - // Rotate the object so the normal points downward: - selection.flattening_rotate(m_planes[m_hover_id].normal); - m_parent.do_rotate(L("Gizmo-Place on Face")); - } + return true; } @@ -94,7 +91,7 @@ void GLGizmoMeasure::on_set_state() CommonGizmosDataID GLGizmoMeasure::on_get_requirements() const { - return CommonGizmosDataID::SelectionInfo; + return CommonGizmosDataID(int(CommonGizmosDataID::SelectionInfo) | int(CommonGizmosDataID::Raycaster)); } @@ -139,70 +136,59 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - if (this->is_plane_update_necessary()) - update_planes(); + + + update_if_needed(); + m_imgui->begin(std::string("DEBUG")); - if (m_imgui->button("<-")) - --m_currently_shown_plane; - ImGui::SameLine(); - if (m_imgui->button("->")) - ++m_currently_shown_plane; - m_currently_shown_plane = std::clamp(m_currently_shown_plane, 0, std::max(0, int(m_planes.size())-1)); - m_imgui->text(std::to_string(m_currently_shown_plane)); - m_imgui->checkbox(wxString("Show all"), m_show_all_planes); - m_imgui->checkbox(wxString("Show points"), m_show_points); - m_imgui->checkbox(wxString("Show edges"), m_show_edges); - m_imgui->checkbox(wxString("Show circles"), m_show_circles); - m_imgui->end(); + + m_imgui->checkbox(wxString("Show all features"), m_show_all); + + Vec3f pos; + Vec3f normal; + size_t facet_idx; + m_c->raycaster()->raycasters().front()->unproject_on_mesh(Vec2d(m_mouse_pos_x, m_mouse_pos_y), m, camera, pos, normal, nullptr, &facet_idx); + ImGui::Separator(); + m_imgui->text(std::string("face_idx: ") + std::to_string(facet_idx)); + m_imgui->text(std::string("pos_x: ") + std::to_string(pos.x())); + m_imgui->text(std::string("pos_y: ") + std::to_string(pos.y())); + m_imgui->text(std::string("pos_z: ") + std::to_string(pos.z())); - int i = m_show_all_planes ? 0 : m_currently_shown_plane; - for (; i < (int)m_planes.size(); ++i) { - // Render all the borders. - for (int j=0; j<(int)m_planes[i].vbos.size(); ++j) { - m_planes[i].vbos[j].set_color(j == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); - m_planes[i].vbos[j].render(); - } + + if (m_show_all) { + const std::vector features = m_measuring->get_features(); + for (const Measure::SurfaceFeature* feature : features) { + + if (feature->get_type() == Measure::SurfaceFeatureType::Circle) { + const auto* circle = static_cast(feature); + Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(circle->get_center())); + view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(circle->get_center())); + view_feature_matrix.scale(0.5); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_sphere.set_color(ColorRGBA(0.f, 1.f, 0.f, 1.f)); + m_vbo_sphere.render(); + } - // Render features: - for (const SurfaceFeature& feature : m_planes[i].surface_features) { - Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.pos)); - if (m_show_edges && feature.type == SurfaceFeature::Line) { - auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), feature.endpoint - feature.pos); + else if (feature->get_type() == Measure::SurfaceFeatureType::Edge) { + const auto* edge = static_cast(feature); + auto& [start, end] = edge->get_edge(); + Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(start)); + auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); view_feature_matrix *= q; - view_feature_matrix.scale(Vec3d(0.3, 0.3, (feature.endpoint - feature.pos).norm())); + view_feature_matrix.scale(Vec3d(0.075, 0.075, (end - start).norm())); shader->set_uniform("view_model_matrix", view_feature_matrix); m_vbo_cylinder.set_color(ColorRGBA(0.7f, 0.7f, 0.f, 1.f)); m_vbo_cylinder.render(); } - if ((m_show_points && feature.type == SurfaceFeature::Line) || m_show_circles && feature.type == SurfaceFeature::Circle) { - view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.pos)); - view_feature_matrix.scale(0.5); - shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_sphere.set_color(feature.type == SurfaceFeature::Line - ? ColorRGBA(1.f, 0.f, 0.f, 1.f) - : ColorRGBA(0.f, 1.f, 0.f, 1.f)); - m_vbo_sphere.render(); - - /*view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.endpoint)); - view_feature_matrix.scale(0.5); - shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_sphere.set_color(feature.type == SurfaceFeature::Line - ? ColorRGBA(1.f, 0.f, 0.f, 1.f) - : ColorRGBA(1.f, 1.f, 0.f, 1.f)); - m_vbo_sphere.render();*/ - } - - shader->set_uniform("view_model_matrix", view_model_matrix); } - - if (! m_show_all_planes) - break; + shader->set_uniform("view_model_matrix", view_model_matrix); } + m_imgui->end(); } glsafe(::glEnable(GL_CULL_FACE)); @@ -222,290 +208,45 @@ void GLGizmoMeasure::on_render() #error NOT IMPLEMENTED #endif - - - - void GLGizmoMeasure::on_render_for_picking() { - const Selection& selection = m_parent.get_selection(); - - GLShaderProgram* shader = wxGetApp().get_shader("flat"); - if (shader == nullptr) - return; - - shader->start_using(); - - glsafe(::glDisable(GL_DEPTH_TEST)); - glsafe(::glDisable(GL_BLEND)); - glsafe(::glLineWidth(2.f)); - - if (selection.is_single_full_instance() && !wxGetKeyState(WXK_CONTROL)) { - const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); - const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d view_model_matrix = camera.get_view_matrix() * - Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m; - - shader->set_uniform("view_model_matrix", view_model_matrix); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - if (this->is_plane_update_necessary()) - update_planes(); - //for (int i = 0; i < (int)m_planes.size(); ++i) { - int i = m_currently_shown_plane; - if (i < int(m_planes.size())) { - for (int j=0; j<(int)m_planes[i].vbos.size(); ++j) { - m_planes[i].vbos[j].set_color(picking_color_component(j)); - m_planes[i].vbos[j].render(); - } - } - } - - glsafe(::glEnable(GL_CULL_FACE)); - - shader->stop_using(); } void GLGizmoMeasure::set_flattening_data(const ModelObject* model_object) { - if (model_object != m_old_model_object) { - m_planes.clear(); - m_planes_valid = false; - } + if (model_object != m_old_model_object) + update_if_needed(); } - -static std::pair get_center_and_radius(const std::vector& border, int start_idx, int end_idx, const Transform3d& trafo) -{ - Vec2ds pts; - double z = 0.; - for (int i=start_idx; i<=end_idx; ++i) { - Vec3d pt_transformed = trafo * border[i]; - z = pt_transformed.z(); - pts.emplace_back(pt_transformed.x(), pt_transformed.y()); - } - - auto circle = Geometry::circle_ransac(pts, 20); // FIXME: iterations? - - return std::make_pair(trafo.inverse() * Vec3d(circle.center.x(), circle.center.y(), z), circle.radius); -} - - - -void GLGizmoMeasure::extract_features(GLGizmoMeasure::PlaneData& plane) -{ - plane.surface_features.clear(); - const Vec3d& normal = plane.normal; - - const double edge_threshold = 25. * (M_PI/180.); - std::vector angles; - - Eigen::Quaterniond q; - q.setFromTwoVectors(plane.normal, Vec3d::UnitZ()); - Transform3d trafo = Transform3d::Identity(); - trafo.rotate(q); - - - - for (const std::vector& border : plane.borders) { - assert(border.size() > 1); - assert(! border.front().isApprox(border.back())); - int start_idx = -1; - - - // First calculate angles at all the vertices. - angles.clear(); - for (int i=0; i> circles; - for (int i=1; i center_and_radius = get_center_and_radius(border, start_idx, end_idx, trafo); - plane.surface_features.emplace_back(SurfaceFeature{ - SurfaceFeature::Circle, - // border[start_idx], border[end_idx], - center_and_radius.first, center_and_radius.first, center_and_radius.second - }); - } - - - std::cout << "==================== " << std::endl; - } - - - for (const SurfaceFeature& f : plane.surface_features) { - std::cout << "- detected " << (f.type == SurfaceFeature::Line ? "Line" : "Circle") << std::endl; - std::cout<< f.pos << std::endl << std::endl << f.endpoint << std::endl; - std::cout << "----------------" << std::endl; - } - - - -} - - - -void GLGizmoMeasure::update_planes() +void GLGizmoMeasure::update_if_needed() { const ModelObject* mo = m_c->selection_info()->model_object(); - TriangleMesh ch; - for (const ModelVolume* vol : mo->volumes) { - if (vol->type() != ModelVolumeType::MODEL_PART) - continue; - TriangleMesh vol_ch = vol->mesh(); - vol_ch.transform(vol->get_matrix()); - ch.merge(vol_ch); - } - m_planes.clear(); - + if (m_state != On || ! mo || mo->instances.empty()) + return; - // Now we'll go through all the facets and append Points of facets sharing the same normal. - // This part is still performed in mesh coordinate system. - const size_t num_of_facets = ch.facets_count(); - std::vector face_to_plane(num_of_facets, size_t(-1)); - const std::vector face_normals = its_face_normals(ch.its); - const std::vector face_neighbors = its_face_neighbors(ch.its); - std::vector facet_queue(num_of_facets, 0); - int facet_queue_cnt = 0; - const stl_normal* normal_ptr = nullptr; - size_t seed_facet_idx = 0; + if (! m_measuring || mo != m_old_model_object + || mo->volumes.size() != m_volumes_matrices.size()) + goto UPDATE; - auto is_same_normal = [](const stl_normal& a, const stl_normal& b) -> bool { - return (std::abs(a(0) - b(0)) < 0.001 && std::abs(a(1) - b(1)) < 0.001 && std::abs(a(2) - b(2)) < 0.001); - }; + // We want to recalculate when the scale changes - some planes could (dis)appear. + if (! mo->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale) + || ! mo->instances.front()->get_mirror().isApprox(m_first_instance_mirror)) + goto UPDATE; - while (1) { - // Find next unvisited triangle: - for (; seed_facet_idx < num_of_facets; ++ seed_facet_idx) - if (face_to_plane[seed_facet_idx] == size_t(-1)) { - facet_queue[facet_queue_cnt ++] = seed_facet_idx; - normal_ptr = &face_normals[seed_facet_idx]; - face_to_plane[seed_facet_idx] = m_planes.size(); - m_planes.emplace_back(); - break; - } - if (seed_facet_idx == num_of_facets) - break; // Everything was visited already + for (unsigned int i=0; i < mo->volumes.size(); ++i) + if (! mo->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i]) + || mo->volumes[i]->type() != m_volumes_types[i]) + goto UPDATE; - while (facet_queue_cnt > 0) { - int facet_idx = facet_queue[-- facet_queue_cnt]; - const stl_normal& this_normal = face_normals[facet_idx]; - if (is_same_normal(this_normal, *normal_ptr)) { - const Vec3i& face = ch.its.indices[facet_idx]; + return; - face_to_plane[facet_idx] = m_planes.size() - 1; - m_planes.back().facets.emplace_back(facet_idx); - for (int j = 0; j < 3; ++ j) - if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && face_to_plane[neighbor_idx] == size_t(-1)) - facet_queue[facet_queue_cnt ++] = neighbor_idx; - } - } +UPDATE: + m_measuring.reset(new Measure::Measuring(mo->volumes.front()->mesh().its)); - m_planes.back().normal = normal_ptr->cast(); - std::sort(m_planes.back().facets.begin(), m_planes.back().facets.end()); - } - - assert(std::none_of(face_to_plane.begin(), face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); - - SurfaceMesh sm(ch.its); - for (int plane_id=0; plane_id < int(m_planes.size()); ++plane_id) { - //int plane_id = 5; { - const auto& facets = m_planes[plane_id].facets; - m_planes[plane_id].borders.clear(); - std::vector> visited(facets.size(), {false, false, false}); - - for (int face_id=0; face_id& last_border = m_planes[plane_id].borders.back(); - last_border.emplace_back(sm.point(sm.source(he)).cast()); - //Vertex_index target = sm.target(he); - const Halfedge_index he_start = he; - - Face_index fi = he.face(); - auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi)); - assert(face_it != facets.end()); - assert(*face_it == int(fi)); - visited[face_it - facets.begin()][he.side()] = true; - - do { - const Halfedge_index he_orig = he; - he = sm.next_around_target(he); - while ( face_to_plane[sm.face(he)] == plane_id && he != he_orig) - he = sm.next_around_target(he); - he = sm.opposite(he); - - Face_index fi = he.face(); - auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi)); - assert(face_it != facets.end()); - assert(*face_it == int(fi)); - if (visited[face_it - facets.begin()][he.side()] && he != he_start) { - last_border.resize(1); - break; - } - visited[face_it - facets.begin()][he.side()] = true; - - last_border.emplace_back(sm.point(sm.source(he)).cast()); - } while (he != he_start); - - if (last_border.size() == 1) - m_planes[plane_id].borders.pop_back(); - } - } - } - - - // DEBUGGING: - m_planes.erase(std::remove_if(m_planes.begin(), m_planes.end(), [](const PlaneData& p) { return p.borders.empty(); }), m_planes.end()); - - - - - - - - - // Planes are finished - let's save what we calculated it from: + // Let's save what we calculated it from: m_volumes_matrices.clear(); m_volumes_types.clear(); for (const ModelVolume* vol : mo->volumes) { @@ -515,65 +256,6 @@ void GLGizmoMeasure::update_planes() m_first_instance_scale = mo->instances.front()->get_scaling_factor(); m_first_instance_mirror = mo->instances.front()->get_mirror(); m_old_model_object = mo; - - // And finally create respective VBOs. The polygon is convex with - // the vertices in order, so triangulation is trivial. - for (PlaneData& plane : m_planes) { - for (std::vector& vertices : plane.borders) { - GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3N3 }; - init_data.reserve_vertices(vertices.size()); - init_data.reserve_indices(vertices.size()); - // vertices + indices - for (size_t i = 0; i < vertices.size(); ++i) { - init_data.add_vertex((Vec3f)vertices[i].cast(), (Vec3f)plane.normal.cast()); - init_data.add_index((unsigned int)i); - } - plane.vbos.emplace_back(); - plane.vbos.back().init_from(std::move(init_data)); - vertices.pop_back(); // first and last are the same - } - - static int n=0; - std::cout << "==================== " << std::endl; - std::cout << "==================== " << std::endl; - std::cout << "==================== " << std::endl; - std::cout << "Plane num. " << n++ << std::endl; - extract_features(plane); - - - // FIXME: vertices should really be local, they need not - // persist now when we use VBOs - plane.borders.clear(); - plane.borders.shrink_to_fit(); - } - - m_planes_valid = true; -} - - - -bool GLGizmoMeasure::is_plane_update_necessary() const -{ - const ModelObject* mo = m_c->selection_info()->model_object(); - if (m_state != On || ! mo || mo->instances.empty()) - return false; - - if (! m_planes_valid || mo != m_old_model_object - || mo->volumes.size() != m_volumes_matrices.size()) - return true; - - // We want to recalculate when the scale changes - some planes could (dis)appear. - if (! mo->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale) - || ! mo->instances.front()->get_mirror().isApprox(m_first_instance_mirror)) - return true; - - for (unsigned int i=0; i < mo->volumes.size(); ++i) - if (! mo->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i]) - || mo->volumes[i]->type() != m_volumes_types[i]) - return true; - - return false; } } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 9534796a71..2781d2b353 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -9,10 +9,15 @@ #endif // ENABLE_LEGACY_OPENGL_REMOVAL +#include + + namespace Slic3r { enum class ModelVolumeType : int; +namespace Measure { class Measuring; } + namespace GUI { @@ -22,53 +27,27 @@ class GLGizmoMeasure : public GLGizmoBase // This gizmo does not use grabbers. The m_hover_id relates to polygon managed by the class itself. private: - - int m_currently_shown_plane = 0; - bool m_show_all_planes = false; - bool m_show_points = true; - bool m_show_edges = true; - bool m_show_circles = true; + std::unique_ptr m_measuring; GLModel m_vbo_sphere; GLModel m_vbo_cylinder; - struct SurfaceFeature { - enum Type { - Circle, - Line - }; - Type type; - Vec3d pos; - Vec3d endpoint; // for type == Line - double radius; // for type == Circle; - }; - - struct PlaneData { - std::vector facets; - std::vector> borders; // should be in fact local in update_planes() - std::vector surface_features; - std::vector vbos; - Vec3d normal; - float area; - }; - - static void extract_features(PlaneData& plane); - // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; std::vector m_volumes_types; Vec3d m_first_instance_scale; Vec3d m_first_instance_mirror; - std::vector m_planes; - std::vector m_face_to_plane; bool m_mouse_left_down = false; // for detection left_up of this gizmo bool m_planes_valid = false; const ModelObject* m_old_model_object = nullptr; std::vector instances_matrices; - void update_planes(); - bool is_plane_update_necessary() const; + int m_mouse_pos_x; + int m_mouse_pos_y; + bool m_show_all = true; + + void update_if_needed(); void set_flattening_data(const ModelObject* model_object); public: From c8e9622ab21e186f24e580a596d05ecc78e1905c Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 27 Jul 2022 09:58:21 +0200 Subject: [PATCH 011/250] Measuring: further separating frontend and backend --- src/libslic3r/Measure.cpp | 236 +++++++++++++++-------- src/libslic3r/Measure.hpp | 24 ++- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 91 ++++++--- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 4 +- 4 files changed, 233 insertions(+), 122 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index d5cb9c24b3..a8ee3d3265 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -39,16 +39,19 @@ public: float area; }; - const std::vector& get_features() const; + const std::vector& get_features() const; + const SurfaceFeature* get_feature(size_t face_idx, const Vec3d& point) const; + const std::vector> get_planes_triangle_indices() const; private: void update_planes(); - void extract_features(PlaneData& plane); + void extract_features(); void save_features(); std::vector m_planes; - std::vector m_features; + std::vector m_face_to_plane; + std::vector m_features; const indexed_triangle_set& m_its; }; @@ -61,14 +64,7 @@ MeasuringImpl::MeasuringImpl(const indexed_triangle_set& its) : m_its{its} { update_planes(); - - for (PlaneData& plane : m_planes) { - extract_features(plane); - - plane.borders.clear(); - plane.borders.shrink_to_fit(); - } - + extract_features(); save_features(); } @@ -80,7 +76,7 @@ void MeasuringImpl::update_planes() // Now we'll go through all the facets and append Points of facets sharing the same normal. // This part is still performed in mesh coordinate system. const size_t num_of_facets = m_its.indices.size(); - std::vector face_to_plane(num_of_facets, size_t(-1)); + m_face_to_plane.resize(num_of_facets, size_t(-1)); const std::vector face_normals = its_face_normals(m_its); const std::vector face_neighbors = its_face_neighbors(m_its); std::vector facet_queue(num_of_facets, 0); @@ -95,10 +91,10 @@ void MeasuringImpl::update_planes() while (1) { // Find next unvisited triangle: for (; seed_facet_idx < num_of_facets; ++ seed_facet_idx) - if (face_to_plane[seed_facet_idx] == size_t(-1)) { + if (m_face_to_plane[seed_facet_idx] == size_t(-1)) { facet_queue[facet_queue_cnt ++] = seed_facet_idx; normal_ptr = &face_normals[seed_facet_idx]; - face_to_plane[seed_facet_idx] = m_planes.size(); + m_face_to_plane[seed_facet_idx] = m_planes.size(); m_planes.emplace_back(); break; } @@ -111,10 +107,10 @@ void MeasuringImpl::update_planes() if (is_same_normal(this_normal, *normal_ptr)) { const Vec3i& face = m_its.indices[facet_idx]; - face_to_plane[facet_idx] = m_planes.size() - 1; + m_face_to_plane[facet_idx] = m_planes.size() - 1; m_planes.back().facets.emplace_back(facet_idx); for (int j = 0; j < 3; ++ j) - if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && face_to_plane[neighbor_idx] == size_t(-1)) + if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && m_face_to_plane[neighbor_idx] == size_t(-1)) facet_queue[facet_queue_cnt ++] = neighbor_idx; } } @@ -123,7 +119,7 @@ void MeasuringImpl::update_planes() std::sort(m_planes.back().facets.begin(), m_planes.back().facets.end()); } - assert(std::none_of(face_to_plane.begin(), face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); + assert(std::none_of(m_face_to_plane.begin(), m_face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); SurfaceMesh sm(m_its); for (int plane_id=0; plane_id < int(m_planes.size()); ++plane_id) { @@ -133,9 +129,9 @@ void MeasuringImpl::update_planes() std::vector> visited(facets.size(), {false, false, false}); for (int face_id=0; face_id angles; - Eigen::Quaterniond q; - q.setFromTwoVectors(plane.normal, Vec3d::UnitZ()); - Transform3d trafo = Transform3d::Identity(); - trafo.rotate(q); - - - for (const std::vector& border : plane.borders) { - assert(border.size() > 1); - int start_idx = -1; + for (int i=0; i& border : plane.borders) { + assert(border.size() > 1); + int start_idx = -1; + + // First calculate angles at all the vertices. + angles.clear(); + for (int i=0; i> circles; - for (int i=1; i> circles; + for (int i=1; i circles[cidx].first) + i = circles[cidx++].second; + else plane.surface_features.emplace_back(std::unique_ptr( + new Edge(border[i-1], border[i]))); + } + + // FIXME Throw away / do not create edges which are parts of circles or + // which lead to circle points (unless they belong to the same plane.) + + // FIXME Check and merge first and last circle if needed. + + // Now create the circle-typed surface features. + for (const auto& [start_idx, end_idx] : circles) { + std::pair center_and_radius = get_center_and_radius(border, start_idx, end_idx, trafo); + plane.surface_features.emplace_back(std::unique_ptr( + new Circle(center_and_radius.first, center_and_radius.second))); + } + } - // We have the circles. Now go around again and pick edges. - int cidx = 0; // index of next circle in the way - for (int i=1; i circles[cidx].first) - i = circles[cidx++].second; - else plane.surface_features.emplace_back(std::unique_ptr( - new Edge(border[i-1], border[i]))); - } - - // FIXME Throw away / do not create edges which are parts of circles. - - // FIXME Check and maybe merge first and last circle. - - for (const auto& [start_idx, end_idx] : circles) { - std::pair center_and_radius = get_center_and_radius(border, start_idx, end_idx, trafo); - plane.surface_features.emplace_back(std::unique_ptr( - new Circle(center_and_radius.first, center_and_radius.second) - )); - } + // The last surface feature is the plane itself. + plane.surface_features.emplace_back(std::unique_ptr( + new Plane(i))); + plane.borders.clear(); + plane.borders.shrink_to_fit(); } } @@ -277,7 +284,7 @@ void MeasuringImpl::save_features() for (PlaneData& plane : m_planes) //PlaneData& plane = m_planes[0]; { - for (std::unique_ptr& feature : plane.surface_features) { + for (const std::unique_ptr& feature : plane.surface_features) { m_features.emplace_back(feature.get()); } } @@ -285,13 +292,51 @@ void MeasuringImpl::save_features() -const std::vector& MeasuringImpl::get_features() const +const SurfaceFeature* MeasuringImpl::get_feature(size_t face_idx, const Vec3d& point) const +{ + if (face_idx >= m_face_to_plane.size()) + return nullptr; + + const PlaneData& plane = m_planes[m_face_to_plane[face_idx]]; + + const SurfaceFeature* closest_feature = nullptr; + double min_dist = std::numeric_limits::max(); + + for (const std::unique_ptr& feature : plane.surface_features) { + double dist = Measuring::get_distance(feature.get(), &point); + if (dist < 0.5 && dist < min_dist) { + min_dist = std::min(dist, min_dist); + closest_feature = feature.get(); + } + } + + if (closest_feature) + return closest_feature; + + // Nothing detected, return the plane as a whole. + assert(plane.surface_features.back().get()->get_type() == SurfaceFeatureType::Plane); + return plane.surface_features.back().get(); +} + + + +const std::vector& MeasuringImpl::get_features() const { return m_features; } +const std::vector> MeasuringImpl::get_planes_triangle_indices() const +{ + std::vector> out; + for (const PlaneData& plane : m_planes) + out.emplace_back(plane.facets); + return out; +} + + + @@ -309,12 +354,39 @@ Measuring::Measuring(const indexed_triangle_set& its) Measuring::~Measuring() {} -const std::vector& Measuring::get_features() const +const std::vector& Measuring::get_features() const { return priv->get_features(); } +const SurfaceFeature* Measuring::get_feature(size_t face_idx, const Vec3d& point) const +{ + return priv->get_feature(face_idx, point); +} + + + +const std::vector> Measuring::get_planes_triangle_indices() const +{ + return priv->get_planes_triangle_indices(); +} + + + +double Measuring::get_distance(const SurfaceFeature* feature, const Vec3d* pt) +{ + if (feature->get_type() == SurfaceFeatureType::Edge) { + const Edge* edge = static_cast(feature); + const auto& [s,e] = edge->get_edge(); + Eigen::ParametrizedLine line(s, (e-s).normalized()); + return line.distance(*pt); + } + + return std::numeric_limits::max(); +} + + diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index bbc7d9e1e9..1360b47ff7 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -48,8 +48,12 @@ private: class Plane : public SurfaceFeature { public: + Plane(int idx) : m_idx(idx) {} SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Plane; } + int get_plane_idx() const { return m_idx; } // index into vector provided by Measuring::get_plane_triangle_indices +private: + int m_idx; }; @@ -64,30 +68,30 @@ public: ~Measuring(); // Return a reference to a list of all features identified on the its. - const std::vector& get_features() const; + [[deprecated]]const std::vector& get_features() const; // Given a face_idx where the mouse cursor points, return a feature that // should be highlighted or nullptr. const SurfaceFeature* get_feature(size_t face_idx, const Vec3d& point) const; + // Returns a list of triangle indices for each identified plane. Each + // Plane object contains an index into this vector. + const std::vector> get_planes_triangle_indices() const; + + + // Returns distance between two SurfaceFeatures. static double get_distance(const SurfaceFeature* a, const SurfaceFeature* b); - // Returns true if an x/y/z distance between features makes sense. - // If so, result contains the distances. - static bool get_distances(const SurfaceFeature* a, const SurfaceFeature* b, std::array& result); - - // Returns true if an x/y/z distance between feature and a point makes sense. - // If so, result contains the distances. - static bool get_axis_aligned_distances(const SurfaceFeature* feature, const Vec3d* pt, std::array& result); + // Returns distance between a SurfaceFeature and a point. + static double get_distance(const SurfaceFeature* a, const Vec3d* pt); // Returns true if measuring angles between features makes sense. // If so, result contains the angle in radians. static bool get_angle(const SurfaceFeature* a, const SurfaceFeature* b, double& result); -private: - +private: std::unique_ptr priv; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 043adba976..a8b257a937 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -144,6 +144,7 @@ void GLGizmoMeasure::on_render() m_imgui->begin(std::string("DEBUG")); m_imgui->checkbox(wxString("Show all features"), m_show_all); + m_imgui->checkbox(wxString("Show all planes"), m_show_planes); Vec3f pos; Vec3f normal; @@ -157,37 +158,51 @@ void GLGizmoMeasure::on_render() - if (m_show_all) { - const std::vector features = m_measuring->get_features(); - for (const Measure::SurfaceFeature* feature : features) { + std::vector features = {m_measuring->get_feature(facet_idx, pos.cast())}; + if (m_show_all) { + features = m_measuring->get_features(); + features.erase(std::remove_if(features.begin(), features.end(), + [](const Measure::SurfaceFeature* f) { + return f->get_type() == Measure::SurfaceFeatureType::Plane; + }), features.end()); + } + + + for (const Measure::SurfaceFeature* feature : features) { + if (! feature) + continue; - if (feature->get_type() == Measure::SurfaceFeatureType::Circle) { - const auto* circle = static_cast(feature); - Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(circle->get_center())); - view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(circle->get_center())); - view_feature_matrix.scale(0.5); - shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_sphere.set_color(ColorRGBA(0.f, 1.f, 0.f, 1.f)); - m_vbo_sphere.render(); - } - - - else if (feature->get_type() == Measure::SurfaceFeatureType::Edge) { - const auto* edge = static_cast(feature); - auto& [start, end] = edge->get_edge(); - Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(start)); - auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); - view_feature_matrix *= q; - view_feature_matrix.scale(Vec3d(0.075, 0.075, (end - start).norm())); - shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_cylinder.set_color(ColorRGBA(0.7f, 0.7f, 0.f, 1.f)); - m_vbo_cylinder.render(); - } - - + if (feature->get_type() == Measure::SurfaceFeatureType::Circle) { + const auto* circle = static_cast(feature); + Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(circle->get_center())); + view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(circle->get_center())); + view_feature_matrix.scale(0.5); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_sphere.set_color(ColorRGBA(0.f, 1.f, 0.f, 1.f)); + m_vbo_sphere.render(); } - shader->set_uniform("view_model_matrix", view_model_matrix); + else if (feature->get_type() == Measure::SurfaceFeatureType::Edge) { + const auto* edge = static_cast(feature); + auto& [start, end] = edge->get_edge(); + Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(start)); + auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); + view_feature_matrix *= q; + view_feature_matrix.scale(Vec3d(0.075, 0.075, (end - start).norm())); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_cylinder.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); + m_vbo_cylinder.render(); + } + else if (feature->get_type() == Measure::SurfaceFeatureType::Plane) { + const auto* plane = static_cast(feature); + assert(plane->get_plane_idx() < m_plane_models.size()); + m_plane_models[plane->get_plane_idx()]->render(); + } } + shader->set_uniform("view_model_matrix", view_model_matrix); + if (m_show_planes) + for (const auto& glmodel : m_plane_models) + glmodel->render(); + m_imgui->end(); } @@ -244,7 +259,25 @@ void GLGizmoMeasure::update_if_needed() return; UPDATE: - m_measuring.reset(new Measure::Measuring(mo->volumes.front()->mesh().its)); + const indexed_triangle_set& its = mo->volumes.front()->mesh().its; + m_measuring.reset(new Measure::Measuring(its)); + m_plane_models.clear(); + const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); + for (const std::vector& triangle_indices : planes_triangles) { + m_plane_models.emplace_back(std::unique_ptr(new GLModel())); + GUI::GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GUI::GLModel::Geometry::EVertexLayout::P3 }; + init_data.color = ColorRGBA(0.9f, 0.9f, 0.9f, 0.5f); + int i = 0; + for (int idx : triangle_indices) { + init_data.add_vertex(its.vertices[its.indices[idx][0]]); + init_data.add_vertex(its.vertices[its.indices[idx][1]]); + init_data.add_vertex(its.vertices[its.indices[idx][2]]); + init_data.add_triangle(i, i+1, i+2); + i+=3; + } + m_plane_models.back()->init_from(std::move(init_data)); + } // Let's save what we calculated it from: m_volumes_matrices.clear(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 2781d2b353..f74b82fa46 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -45,7 +45,9 @@ private: int m_mouse_pos_x; int m_mouse_pos_y; - bool m_show_all = true; + bool m_show_all = false; + bool m_show_planes = false; + std::vector> m_plane_models; void update_if_needed(); void set_flattening_data(const ModelObject* model_object); From f68e7526b215428315d8fc269fe78cce80bb8303 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 27 Jul 2022 11:45:42 +0200 Subject: [PATCH 012/250] Measuring: added getters for circle visualization --- src/libslic3r/Measure.cpp | 11 ++++++++++- src/libslic3r/Measure.hpp | 8 +++++++- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 22 +++++++++++++++++++--- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index a8ee3d3265..724f4ab806 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -262,7 +262,7 @@ void MeasuringImpl::extract_features() for (const auto& [start_idx, end_idx] : circles) { std::pair center_and_radius = get_center_and_radius(border, start_idx, end_idx, trafo); plane.surface_features.emplace_back(std::unique_ptr( - new Circle(center_and_radius.first, center_and_radius.second))); + new Circle(center_and_radius.first, center_and_radius.second, plane.normal))); } } @@ -382,6 +382,15 @@ double Measuring::get_distance(const SurfaceFeature* feature, const Vec3d* pt) Eigen::ParametrizedLine line(s, (e-s).normalized()); return line.distance(*pt); } + else if (feature->get_type() == SurfaceFeatureType::Circle) { + const Circle* circle = static_cast(feature); + // Find a plane containing normal, center and the point. + const Vec3d& c = circle->get_center(); + const Vec3d& n = circle->get_normal(); + Eigen::Hyperplane circle_plane(n, c); + Vec3d proj = circle_plane.projection(*pt); + return std::sqrt( std::pow((proj - c).norm() - circle->get_radius(), 2.) + (*pt - proj).squaredNorm()); + } return std::numeric_limits::max(); } diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 1360b47ff7..0455291bfc 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -28,22 +28,28 @@ public: class Edge : public SurfaceFeature { public: Edge(const Vec3d& start, const Vec3d& end) : m_start{start}, m_end{end} {} + Edge(const Vec3d& start, const Vec3d& end, const Vec3d& pin) : m_start{start}, m_end{end}, + m_pin{std::unique_ptr(new Vec3d(pin))} {} SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Edge; } std::pair get_edge() const { return std::make_pair(m_start, m_end); } private: Vec3d m_start; Vec3d m_end; + std::unique_ptr m_pin; }; class Circle : public SurfaceFeature { public: - Circle(const Vec3d& center, double radius) : m_center{center}, m_radius{radius} {} + Circle(const Vec3d& center, double radius, const Vec3d& normal) + : m_center{center}, m_radius{radius}, m_normal{normal} {} SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Circle; } Vec3d get_center() const { return m_center; } double get_radius() const { return m_radius; } + Vec3d get_normal() const { return m_normal; } private: Vec3d m_center; double m_radius; + Vec3d m_normal; }; class Plane : public SurfaceFeature { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index a8b257a937..44dd44cc55 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -174,12 +174,28 @@ void GLGizmoMeasure::on_render() if (feature->get_type() == Measure::SurfaceFeatureType::Circle) { const auto* circle = static_cast(feature); - Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(circle->get_center())); - view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(circle->get_center())); + const Vec3d& c = circle->get_center(); + const Vec3d& n = circle->get_normal(); + Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(c)); view_feature_matrix.scale(0.5); shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_sphere.set_color(ColorRGBA(0.f, 1.f, 0.f, 1.f)); + m_vbo_sphere.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); m_vbo_sphere.render(); + + // Now draw the circle itself - let's take a funny shortcut: + Vec3d rad = n.cross(Vec3d::UnitX()); + if (rad.squaredNorm() < 0.1) + rad = n.cross(Vec3d::UnitY()); + rad *= circle->get_radius() * rad.norm(); + const int N = 20; + for (int i=0; iset_uniform("view_model_matrix", view_feature_matrix); + m_vbo_sphere.render(); + } } else if (feature->get_type() == Measure::SurfaceFeatureType::Edge) { const auto* edge = static_cast(feature); From 31baf5859bb85df8f977ce173d5e9f30b7544c75 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 27 Jul 2022 15:36:21 +0200 Subject: [PATCH 013/250] Measuring: Add detection of polygons and their centers --- src/libslic3r/Measure.cpp | 72 ++++++++++++++++++------ src/libslic3r/Measure.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 8 +++ 3 files changed, 63 insertions(+), 18 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 724f4ab806..056178bc4e 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -192,10 +192,11 @@ void MeasuringImpl::update_planes() void MeasuringImpl::extract_features() { - - - const double edge_threshold = 25. * (M_PI/180.); + auto N_to_angle = [](double N) -> double { return 2.*M_PI / N; }; + constexpr double polygon_upper_threshold = N_to_angle(4.5); + constexpr double polygon_lower_threshold = N_to_angle(8.5); std::vector angles; + std::vector lengths; for (int i=0; i M_PI) + angle = 2*M_PI - angle; + angles.push_back(angle); + lengths.push_back(v2.squaredNorm()); } assert(border.size() == angles.size()); + assert(border.size() == lengths.size()); bool circle = false; - std::vector> circles; + std::vector> circles; + std::vector> circles_idxs; for (int i=1; i( + new Circle(center, radius, plane.normal))); circle = false; } } } + // Some of the "circles" may actually be polygons. We want them detected as + // edges, but also to remember the center and save it into those edges. + // We will add all such edges manually and delete the detected circles, + // leaving it in circles_idxs so they are not picked again: + assert(circles.size() == circles_idxs.size()); + for (int i=circles.size()-1; i>=0; --i) { + assert(circles_idxs[i].first + 1 < angles.size() - 1); // Check that this is internal point of the circle, not the first, not the last. + double angle = angles[circles_idxs[i].first + 1]; + if (angle > polygon_lower_threshold) { + if (angle < polygon_upper_threshold) { + const Vec3d center = static_cast(circles[i].get())->get_center(); + for (int j=circles_idxs[i].first + 1; j<=circles_idxs[i].second; ++j) + plane.surface_features.emplace_back(std::unique_ptr( + new Edge(border[j-1], border[j], center))); + } else { + // This will be handled just like a regular edge. + circles_idxs.erase(circles_idxs.begin() + i); + } + circles.erase(circles.begin() + i); + } + } + + + + + + // We have the circles. Now go around again and pick edges. int cidx = 0; // index of next circle in the way for (int i=1; i circles[cidx].first) - i = circles[cidx++].second; + if (cidx < circles_idxs.size() && i > circles_idxs[cidx].first) + i = circles_idxs[cidx++].second; else plane.surface_features.emplace_back(std::unique_ptr( new Edge(border[i-1], border[i]))); } @@ -258,13 +297,10 @@ void MeasuringImpl::extract_features() // FIXME Check and merge first and last circle if needed. - // Now create the circle-typed surface features. - for (const auto& [start_idx, end_idx] : circles) { - std::pair center_and_radius = get_center_and_radius(border, start_idx, end_idx, trafo); - plane.surface_features.emplace_back(std::unique_ptr( - new Circle(center_and_radius.first, center_and_radius.second, plane.normal))); - } - + // Now move the circles into the feature list. + assert(std::all_of(circles.begin(), circles.end(), [](const std::unique_ptr& f) { return f->get_type() == SurfaceFeatureType::Circle; })); + plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(circles.begin()), + std::make_move_iterator(circles.end())); } // The last surface feature is the plane itself. diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 0455291bfc..1db35d9fcd 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -32,6 +32,7 @@ public: m_pin{std::unique_ptr(new Vec3d(pin))} {} SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Edge; } std::pair get_edge() const { return std::make_pair(m_start, m_end); } + const Vec3d* get_point_of_interest() const { return m_pin.get(); } private: Vec3d m_start; Vec3d m_end; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 44dd44cc55..1869983015 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -207,6 +207,14 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_feature_matrix); m_vbo_cylinder.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); m_vbo_cylinder.render(); + if (edge->get_point_of_interest()) { + Vec3d pin = *edge->get_point_of_interest(); + view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(pin)); + view_feature_matrix.scale(0.5); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_sphere.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); + m_vbo_sphere.render(); + } } else if (feature->get_type() == Measure::SurfaceFeatureType::Plane) { const auto* plane = static_cast(feature); From 72d7cdd5f8d73119ef04319c39a58249196bf7a7 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 18 Aug 2022 13:42:26 +0200 Subject: [PATCH 014/250] Measuring: refactoring --- src/libslic3r/Measure.cpp | 166 ++++++++++++++--------- src/libslic3r/Measure.hpp | 114 ++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 45 +++--- 3 files changed, 180 insertions(+), 145 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 056178bc4e..e59e3c04d4 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -34,24 +34,21 @@ public: struct PlaneData { std::vector facets; std::vector> borders; // FIXME: should be in fact local in update_planes() - std::vector> surface_features; + std::vector surface_features; Vec3d normal; float area; }; - const std::vector& get_features() const; - const SurfaceFeature* get_feature(size_t face_idx, const Vec3d& point) const; - const std::vector> get_planes_triangle_indices() const; + std::vector get_all_features() const; + std::optional get_feature(size_t face_idx, const Vec3d& point) const; + std::vector> get_planes_triangle_indices() const; private: void update_planes(); void extract_features(); - void save_features(); - - + std::vector m_planes; std::vector m_face_to_plane; - std::vector m_features; const indexed_triangle_set& m_its; }; @@ -65,7 +62,6 @@ MeasuringImpl::MeasuringImpl(const indexed_triangle_set& its) { update_planes(); extract_features(); - save_features(); } @@ -233,7 +229,7 @@ void MeasuringImpl::extract_features() bool circle = false; - std::vector> circles; + std::vector circles; std::vector> circles_idxs; for (int i=1; i( - new Circle(center, radius, plane.normal))); + circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::optional(), radius)); circle = false; } } @@ -266,10 +261,10 @@ void MeasuringImpl::extract_features() double angle = angles[circles_idxs[i].first + 1]; if (angle > polygon_lower_threshold) { if (angle < polygon_upper_threshold) { - const Vec3d center = static_cast(circles[i].get())->get_center(); + const Vec3d center = std::get<0>(circles[i].get_circle()); for (int j=circles_idxs[i].first + 1; j<=circles_idxs[i].second; ++j) - plane.surface_features.emplace_back(std::unique_ptr( - new Edge(border[j-1], border[j], center))); + plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, + border[j-1], border[j], std::make_optional(center), 0.)); } else { // This will be handled just like a regular edge. circles_idxs.erase(circles_idxs.begin() + i); @@ -288,8 +283,8 @@ void MeasuringImpl::extract_features() for (int i=1; i circles_idxs[cidx].first) i = circles_idxs[cidx++].second; - else plane.surface_features.emplace_back(std::unique_ptr( - new Edge(border[i-1], border[i]))); + else plane.surface_features.emplace_back(SurfaceFeature( + SurfaceFeatureType::Edge, border[i-1], border[i], std::optional(), 0.)); } // FIXME Throw away / do not create edges which are parts of circles or @@ -298,14 +293,16 @@ void MeasuringImpl::extract_features() // FIXME Check and merge first and last circle if needed. // Now move the circles into the feature list. - assert(std::all_of(circles.begin(), circles.end(), [](const std::unique_ptr& f) { return f->get_type() == SurfaceFeatureType::Circle; })); + assert(std::all_of(circles.begin(), circles.end(), [](const SurfaceFeature& f) { + return f.get_type() == SurfaceFeatureType::Circle; + })); plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(circles.begin()), std::make_move_iterator(circles.end())); } // The last surface feature is the plane itself. - plane.surface_features.emplace_back(std::unique_ptr( - new Plane(i))); + plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Plane, + Vec3d::Zero(), Vec3d::Zero(), std::optional(), i + 0.0001)); plane.borders.clear(); plane.borders.shrink_to_fit(); @@ -314,56 +311,58 @@ void MeasuringImpl::extract_features() -void MeasuringImpl::save_features() +std::vector MeasuringImpl::get_all_features() const { - m_features.clear(); - for (PlaneData& plane : m_planes) + std::vector features; //PlaneData& plane = m_planes[0]; - { - for (const std::unique_ptr& feature : plane.surface_features) { - m_features.emplace_back(feature.get()); - } - } + for (const PlaneData& plane : m_planes) + for (const SurfaceFeature& feature : plane.surface_features) + features.emplace_back(feature); + return features; } -const SurfaceFeature* MeasuringImpl::get_feature(size_t face_idx, const Vec3d& point) const + + + +std::optional MeasuringImpl::get_feature(size_t face_idx, const Vec3d& point) const { if (face_idx >= m_face_to_plane.size()) - return nullptr; + return std::optional(); const PlaneData& plane = m_planes[m_face_to_plane[face_idx]]; const SurfaceFeature* closest_feature = nullptr; double min_dist = std::numeric_limits::max(); - for (const std::unique_ptr& feature : plane.surface_features) { - double dist = Measuring::get_distance(feature.get(), &point); - if (dist < 0.5 && dist < min_dist) { - min_dist = std::min(dist, min_dist); - closest_feature = feature.get(); + MeasurementResult res; + SurfaceFeature point_sf(point); + + for (const SurfaceFeature& feature : plane.surface_features) { + res = get_measurement(feature, point_sf); + if (res.distance_strict) { // TODO: this should become an assert after all combinations are implemented. + double dist = *res.distance_strict; + if (dist < 0.5 && dist < min_dist) { + min_dist = std::min(dist, min_dist); + closest_feature = &feature; + } } } if (closest_feature) - return closest_feature; + return std::make_optional(*closest_feature); // Nothing detected, return the plane as a whole. - assert(plane.surface_features.back().get()->get_type() == SurfaceFeatureType::Plane); - return plane.surface_features.back().get(); + assert(plane.surface_features.back().get_type() == SurfaceFeatureType::Plane); + return std::make_optional(plane.surface_features.back()); } -const std::vector& MeasuringImpl::get_features() const -{ - return m_features; -} - -const std::vector> MeasuringImpl::get_planes_triangle_indices() const +std::vector> MeasuringImpl::get_planes_triangle_indices() const { std::vector> out; for (const PlaneData& plane : m_planes) @@ -390,45 +389,81 @@ Measuring::Measuring(const indexed_triangle_set& its) Measuring::~Measuring() {} -const std::vector& Measuring::get_features() const +std::vector Measuring::get_all_features() const { - return priv->get_features(); + return priv->get_all_features(); } -const SurfaceFeature* Measuring::get_feature(size_t face_idx, const Vec3d& point) const +std::optional Measuring::get_feature(size_t face_idx, const Vec3d& point) const { return priv->get_feature(face_idx, point); } -const std::vector> Measuring::get_planes_triangle_indices() const +std::vector> Measuring::get_planes_triangle_indices() const { return priv->get_planes_triangle_indices(); } -double Measuring::get_distance(const SurfaceFeature* feature, const Vec3d* pt) + + + + + + + + + + + +MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b) { - if (feature->get_type() == SurfaceFeatureType::Edge) { - const Edge* edge = static_cast(feature); - const auto& [s,e] = edge->get_edge(); - Eigen::ParametrizedLine line(s, (e-s).normalized()); - return line.distance(*pt); - } - else if (feature->get_type() == SurfaceFeatureType::Circle) { - const Circle* circle = static_cast(feature); - // Find a plane containing normal, center and the point. - const Vec3d& c = circle->get_center(); - const Vec3d& n = circle->get_normal(); - Eigen::Hyperplane circle_plane(n, c); - Vec3d proj = circle_plane.projection(*pt); - return std::sqrt( std::pow((proj - c).norm() - circle->get_radius(), 2.) + (*pt - proj).squaredNorm()); + assert(a.get_type() != SurfaceFeatureType::Undef && b.get_type() != SurfaceFeatureType::Undef); + + const bool swap = int(a.get_type()) > int(b.get_type()); + const SurfaceFeature& f1 = swap ? b : a; + const SurfaceFeature& f2 = swap ? a : b; + + MeasurementResult result; + if (f1.get_type() == SurfaceFeatureType::Point) { + if (f2.get_type() == SurfaceFeatureType::Point) { + Vec3d diff = (f2.get_point() - f1.get_point()); + result.distance_strict = diff.norm(); + result.distance_xyz = diff; + } else if (f2.get_type() == SurfaceFeatureType::Edge) { + const auto& [s,e] = f2.get_edge(); + Eigen::ParametrizedLine line(s, (e-s).normalized()); + result.distance_strict = std::make_optional(line.distance(f1.get_point())); // TODO: this is really infinite dist + } else if (f2.get_type() == SurfaceFeatureType::Circle) { + // Find a plane containing normal, center and the point. + const auto& [c, radius, n] = f2.get_circle(); + Eigen::Hyperplane circle_plane(n, c); + Vec3d proj = circle_plane.projection(f1.get_point()); + result.distance_strict = std::make_optional(std::sqrt( + std::pow((proj - c).norm() - radius, 2.) + (f1.get_point() - proj).squaredNorm())); + } else if (f2.get_type() == SurfaceFeatureType::Plane) { + } + } else if (f1.get_type() == SurfaceFeatureType::Edge) { + if (f2.get_type() == SurfaceFeatureType::Edge) { + } else if (f2.get_type() == SurfaceFeatureType::Circle) { + } else if (f2.get_type() == SurfaceFeatureType::Plane) { + } + } else if (f1.get_type() == SurfaceFeatureType::Circle) { + if (f2.get_type() == SurfaceFeatureType::Circle) { + } else if (f2.get_type() == SurfaceFeatureType::Plane) { + } + } else if (f1.get_type() == SurfaceFeatureType::Plane) { + assert(f2.get_type() == SurfaceFeatureType::Plane); + } - return std::numeric_limits::max(); + + + return result; } @@ -436,5 +471,8 @@ double Measuring::get_distance(const SurfaceFeature* feature, const Vec3d* pt) + + + } // namespace Measure } // namespace Slic3r diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 1db35d9fcd..87bed1cf17 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -1,6 +1,7 @@ #ifndef Slic3r_Measure_hpp_ #define Slic3r_Measure_hpp_ +#include #include #include "Point.hpp" @@ -15,55 +16,50 @@ namespace Measure { enum class SurfaceFeatureType { - Edge = 1 << 0, - Circle = 1 << 1, - Plane = 1 << 2 - }; + Undef, + Point, + Edge, + Circle, + Plane +}; class SurfaceFeature { -public: - virtual SurfaceFeatureType get_type() const = 0; -}; - -class Edge : public SurfaceFeature { public: - Edge(const Vec3d& start, const Vec3d& end) : m_start{start}, m_end{end} {} - Edge(const Vec3d& start, const Vec3d& end, const Vec3d& pin) : m_start{start}, m_end{end}, - m_pin{std::unique_ptr(new Vec3d(pin))} {} - SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Edge; } - std::pair get_edge() const { return std::make_pair(m_start, m_end); } - const Vec3d* get_point_of_interest() const { return m_pin.get(); } -private: - Vec3d m_start; - Vec3d m_end; - std::unique_ptr m_pin; -}; + SurfaceFeature(SurfaceFeatureType type, const Vec3d& pt1, const Vec3d& pt2, std::optional pt3, double value) + : m_type{type}, m_pt1{pt1}, m_pt2{pt2}, m_pt3{pt3}, m_value{value} {} -class Circle : public SurfaceFeature { -public: - Circle(const Vec3d& center, double radius, const Vec3d& normal) - : m_center{center}, m_radius{radius}, m_normal{normal} {} - SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Circle; } - Vec3d get_center() const { return m_center; } - double get_radius() const { return m_radius; } - Vec3d get_normal() const { return m_normal; } -private: - Vec3d m_center; - double m_radius; - Vec3d m_normal; -}; + explicit SurfaceFeature(const Vec3d& pt) + : m_type{SurfaceFeatureType::Point}, m_pt1{pt} {} -class Plane : public SurfaceFeature { -public: - Plane(int idx) : m_idx(idx) {} - SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Plane; } - int get_plane_idx() const { return m_idx; } // index into vector provided by Measuring::get_plane_triangle_indices + + // Get type of this feature. + SurfaceFeatureType get_type() const { return m_type; } + + // For points, return the point. + Vec3d get_point() const { assert(m_type == SurfaceFeatureType::Point); return m_pt1; } + + // For edges, return start and end. + std::pair get_edge() const { assert(m_type == SurfaceFeatureType::Edge); return std::make_pair(m_pt1, m_pt2); } + + // For circles, return center, radius and normal. + std::tuple get_circle() const { assert(m_type == SurfaceFeatureType::Circle); return std::make_tuple(m_pt1, m_value, m_pt2); } + + // For planes, return index into vector provided by Measuring::get_plane_triangle_indices. + int get_plane_idx() const { return int(m_value); } + + // For anything, return an extra point that should also be considered a part of this. + std::optional get_extra_point() const { assert(m_type != SurfaceFeatureType::Undef); return m_pt3; } private: - int m_idx; + SurfaceFeatureType m_type = SurfaceFeatureType::Undef; + Vec3d m_pt1; + Vec3d m_pt2; + std::optional m_pt3; + double m_value; }; + class MeasuringImpl; @@ -75,34 +71,36 @@ public: ~Measuring(); // Return a reference to a list of all features identified on the its. - [[deprecated]]const std::vector& get_features() const; + // Use only for debugging. Expensive, do not call often. + [[deprecated]] std::vector get_all_features() const; // Given a face_idx where the mouse cursor points, return a feature that - // should be highlighted or nullptr. - const SurfaceFeature* get_feature(size_t face_idx, const Vec3d& point) const; + // should be highlighted (if any). + std::optional get_feature(size_t face_idx, const Vec3d& point) const; // Returns a list of triangle indices for each identified plane. Each - // Plane object contains an index into this vector. - const std::vector> get_planes_triangle_indices() const; - - - - // Returns distance between two SurfaceFeatures. - static double get_distance(const SurfaceFeature* a, const SurfaceFeature* b); - - // Returns distance between a SurfaceFeature and a point. - static double get_distance(const SurfaceFeature* a, const Vec3d* pt); - - // Returns true if measuring angles between features makes sense. - // If so, result contains the angle in radians. - static bool get_angle(const SurfaceFeature* a, const SurfaceFeature* b, double& result); - - + // Plane object contains an index into this vector. Expensive, do not + // call too often. + std::vector> get_planes_triangle_indices() const; + private: std::unique_ptr priv; }; + + +struct MeasurementResult { + std::optional angle; + std::optional distance_infinite; + std::optional distance_strict; + std::optional distance_xyz; +}; + +// Returns distance/angle between two SurfaceFeatures. +static MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b); + + } // namespace Measure } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 3f12597987..6362e0053a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -158,24 +158,25 @@ void GLGizmoMeasure::on_render() - std::vector features = {m_measuring->get_feature(facet_idx, pos.cast())}; + std::vector features; if (m_show_all) { - features = m_measuring->get_features(); + features = m_measuring->get_all_features(); // EXPENSIVE - debugging only. features.erase(std::remove_if(features.begin(), features.end(), - [](const Measure::SurfaceFeature* f) { - return f->get_type() == Measure::SurfaceFeatureType::Plane; + [](const Measure::SurfaceFeature& f) { + return f.get_type() == Measure::SurfaceFeatureType::Plane; }), features.end()); + } else { + std::optional feat = m_measuring->get_feature(facet_idx, pos.cast()); + if (feat) + features.emplace_back(*feat); } - - - for (const Measure::SurfaceFeature* feature : features) { - if (! feature) - continue; - if (feature->get_type() == Measure::SurfaceFeatureType::Circle) { - const auto* circle = static_cast(feature); - const Vec3d& c = circle->get_center(); - const Vec3d& n = circle->get_normal(); + + + for (const Measure::SurfaceFeature& feature : features) { + + if (feature.get_type() == Measure::SurfaceFeatureType::Circle) { + const auto& [c, radius, n] = feature.get_circle(); Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(c)); view_feature_matrix.scale(0.5); shader->set_uniform("view_model_matrix", view_feature_matrix); @@ -186,7 +187,7 @@ void GLGizmoMeasure::on_render() Vec3d rad = n.cross(Vec3d::UnitX()); if (rad.squaredNorm() < 0.1) rad = n.cross(Vec3d::UnitY()); - rad *= circle->get_radius() * rad.norm(); + rad *= radius * rad.norm(); const int N = 20; for (int i=0; iget_type() == Measure::SurfaceFeatureType::Edge) { - const auto* edge = static_cast(feature); - auto& [start, end] = edge->get_edge(); + else if (feature.get_type() == Measure::SurfaceFeatureType::Edge) { + const auto& [start, end] = feature.get_edge(); Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(start)); auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); view_feature_matrix *= q; @@ -207,8 +207,8 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_feature_matrix); m_vbo_cylinder.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); m_vbo_cylinder.render(); - if (edge->get_point_of_interest()) { - Vec3d pin = *edge->get_point_of_interest(); + if (feature.get_extra_point()) { + Vec3d pin = *feature.get_extra_point(); view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(pin)); view_feature_matrix.scale(0.5); shader->set_uniform("view_model_matrix", view_feature_matrix); @@ -216,10 +216,9 @@ void GLGizmoMeasure::on_render() m_vbo_sphere.render(); } } - else if (feature->get_type() == Measure::SurfaceFeatureType::Plane) { - const auto* plane = static_cast(feature); - assert(plane->get_plane_idx() < m_plane_models.size()); - m_plane_models[plane->get_plane_idx()]->render(); + else if (feature.get_type() == Measure::SurfaceFeatureType::Plane) { + assert(feature.get_plane_idx() < m_plane_models.size()); + m_plane_models[feature.get_plane_idx()]->render(); } } shader->set_uniform("view_model_matrix", view_model_matrix); From aed6ddf8f392a49179f6bfbd91d813b26ca4c636 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 18 Aug 2022 18:50:49 +0200 Subject: [PATCH 015/250] Measuring: implemented edge endpoint detection --- src/libslic3r/Measure.cpp | 91 ++++++++++++++++++++---- src/libslic3r/Measure.hpp | 9 ++- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 14 +++- 3 files changed, 94 insertions(+), 20 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index e59e3c04d4..8c7254f85b 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -9,6 +9,10 @@ namespace Slic3r { namespace Measure { +constexpr double feature_hover_limit = 0.5; // how close to a feature the mouse must be to highlight it +constexpr double edge_endpoint_limit = 0.5; // how close to an edge endpoint the mouse ... + + static std::pair get_center_and_radius(const std::vector& border, int start_idx, int end_idx, const Transform3d& trafo) { @@ -302,7 +306,7 @@ void MeasuringImpl::extract_features() // The last surface feature is the plane itself. plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Plane, - Vec3d::Zero(), Vec3d::Zero(), std::optional(), i + 0.0001)); + plane.normal, plane.borders.front().front(), std::optional(), i + 0.0001)); plane.borders.clear(); plane.borders.shrink_to_fit(); @@ -333,25 +337,39 @@ std::optional MeasuringImpl::get_feature(size_t face_idx, const const PlaneData& plane = m_planes[m_face_to_plane[face_idx]]; - const SurfaceFeature* closest_feature = nullptr; + size_t closest_feature_idx = size_t(-1); double min_dist = std::numeric_limits::max(); MeasurementResult res; SurfaceFeature point_sf(point); - for (const SurfaceFeature& feature : plane.surface_features) { - res = get_measurement(feature, point_sf); + for (size_t i=0; i line(s, (e-s).normalized()); - result.distance_strict = std::make_optional(line.distance(f1.get_point())); // TODO: this is really infinite dist + double dist_inf = line.distance(f1.get_point()); + Vec3d proj = line.projection(f1.get_point()); + double len_sq = (e-s).squaredNorm(); + double dist_start_sq = (proj-s).squaredNorm(); + double dist_end_sq = (proj-e).squaredNorm(); + if (dist_start_sq < len_sq && dist_end_sq < len_sq) { + // projection falls on the line - the strict distance is the same as infinite + result.distance_strict = std::make_optional(dist_inf); + } else { // the result is the closer of the endpoints + result.distance_strict = std::make_optional(std::sqrt(std::min(dist_start_sq, dist_end_sq) + dist_inf)); + } + result.distance_infinite = std::make_optional(dist_inf); + /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Circle) { // Find a plane containing normal, center and the point. const auto& [c, radius, n] = f2.get_circle(); Eigen::Hyperplane circle_plane(n, c); Vec3d proj = circle_plane.projection(f1.get_point()); - result.distance_strict = std::make_optional(std::sqrt( - std::pow((proj - c).norm() - radius, 2.) + (f1.get_point() - proj).squaredNorm())); + double dist = std::sqrt(std::pow((proj - c).norm() - radius, 2.) + + (f1.get_point() - proj).squaredNorm()); + + result.distance_strict = std::make_optional(dist); + /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { + const auto& [idx, normal, pt] = f2.get_plane(); + Eigen::Hyperplane plane(normal, pt); + result.distance_infinite = plane.absDistance(f1.get_point()); + // TODO: result.distance_strict = } + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// } else if (f1.get_type() == SurfaceFeatureType::Edge) { if (f2.get_type() == SurfaceFeatureType::Edge) { + /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Circle) { + /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { } + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// } else if (f1.get_type() == SurfaceFeatureType::Circle) { if (f2.get_type() == SurfaceFeatureType::Circle) { + /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { } + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// } else if (f1.get_type() == SurfaceFeatureType::Plane) { assert(f2.get_type() == SurfaceFeatureType::Plane); - + + const auto& [idx1, normal1, pt1] = f1.get_plane(); + const auto& [idx2, normal2, pt2] = f2.get_plane(); + double angle = 0.; + + if (! normal1.isApprox(normal2)) { + // The planes are parallel, calculate distance. + Eigen::Hyperplane plane(normal1, pt1); + result.distance_infinite = plane.absDistance(pt2); + } else { + // Planes are not parallel, calculate angle. + angle = std::acos(std::abs(normal1.dot(normal2))); + } + result.angle = angle; } diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 87bed1cf17..fe0b1687a1 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -31,7 +31,6 @@ public: explicit SurfaceFeature(const Vec3d& pt) : m_type{SurfaceFeatureType::Point}, m_pt1{pt} {} - // Get type of this feature. SurfaceFeatureType get_type() const { return m_type; } @@ -44,8 +43,8 @@ public: // For circles, return center, radius and normal. std::tuple get_circle() const { assert(m_type == SurfaceFeatureType::Circle); return std::make_tuple(m_pt1, m_value, m_pt2); } - // For planes, return index into vector provided by Measuring::get_plane_triangle_indices. - int get_plane_idx() const { return int(m_value); } + // For planes, return index into vector provided by Measuring::get_plane_triangle_indices, normal and point. + std::tuple get_plane() const { return std::make_tuple(int(m_value), m_pt1, m_pt2); } // For anything, return an extra point that should also be considered a part of this. std::optional get_extra_point() const { assert(m_type != SurfaceFeatureType::Undef); return m_pt3; } @@ -84,7 +83,7 @@ public: std::vector> get_planes_triangle_indices() const; private: - std::unique_ptr priv; + std::unique_ptr priv; }; @@ -98,7 +97,7 @@ struct MeasurementResult { }; // Returns distance/angle between two SurfaceFeatures. -static MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b); +MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b); } // namespace Measure diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 6362e0053a..26ecfb5813 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -175,7 +175,14 @@ void GLGizmoMeasure::on_render() for (const Measure::SurfaceFeature& feature : features) { - if (feature.get_type() == Measure::SurfaceFeatureType::Circle) { + if (feature.get_type() == Measure::SurfaceFeatureType::Point) { + Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.get_point())); + view_feature_matrix.scale(0.5); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_sphere.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); + m_vbo_sphere.render(); + } + else if (feature.get_type() == Measure::SurfaceFeatureType::Circle) { const auto& [c, radius, n] = feature.get_circle(); Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(c)); view_feature_matrix.scale(0.5); @@ -217,8 +224,9 @@ void GLGizmoMeasure::on_render() } } else if (feature.get_type() == Measure::SurfaceFeatureType::Plane) { - assert(feature.get_plane_idx() < m_plane_models.size()); - m_plane_models[feature.get_plane_idx()]->render(); + const auto& [idx, normal, pt] = feature.get_plane(); + assert(idx < m_plane_models.size()); + m_plane_models[idx]->render(); } } shader->set_uniform("view_model_matrix", view_model_matrix); From decbf315930f627b9ccedfad390e694fa4eb1f16 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 19 Aug 2022 09:05:44 +0200 Subject: [PATCH 016/250] Partial revert of 1e494e30 --- src/libslic3r/TriangleMesh.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 8dc22f1490..da6fcf28f6 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -877,20 +877,13 @@ Polygon its_convex_hull_2d_above(const indexed_triangle_set &its, const Transfor indexed_triangle_set its_make_cube(double xd, double yd, double zd) { auto x = float(xd), y = float(yd), z = float(zd); - /*return { + return { { {0, 1, 2}, {0, 2, 3}, {4, 5, 6}, {4, 6, 7}, {0, 4, 7}, {0, 7, 1}, {1, 7, 6}, {1, 6, 2}, {2, 6, 5}, {2, 5, 3}, {4, 0, 3}, {4, 3, 5} }, { {x, y, 0}, {x, 0, 0}, {0, 0, 0}, {0, y, 0}, {x, y, z}, {0, y, z}, {0, 0, z}, {x, 0, z} } - };*/ - return { - { {0, 1, 2}, {0, 2, 3}, {4, 5, 6}, {4, 6, 7}, - {0, 4, 7}, {0, 7, 1}, {1, 7, 6}, {1, 6, 2}, - {2, 5, 6}, {2, 5, 3}, {4, 0, 3}, /*{4, 3, 5}*/ }, - { {x, y, 0}, {x, 0, 0}, {0, 0, 0}, {0, y, 0}, - {x, y, z}, {0, y, z}, {0, 0, z}, {x, 0, z} } - }; + }; } indexed_triangle_set its_make_prism(float width, float length, float height) From 4c8b78de726501f08a7c9762181cb360c8304c37 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 19 Aug 2022 09:19:10 +0200 Subject: [PATCH 017/250] Use unified color for hovering in GLGizmoMeasure --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 26ecfb5813..8fc2ff8ea0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -16,8 +16,7 @@ namespace Slic3r { namespace GUI { -static const Slic3r::ColorRGBA DEFAULT_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.9f }; -static const Slic3r::ColorRGBA DEFAULT_HOVER_PLANE_COLOR = { 0.9f, 0.2f, 0.2f, 1.f }; +static const Slic3r::ColorRGBA HOVER_COLOR = { 0.8f, 0.2f, 0.2f, 1.0f }; GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) @@ -126,7 +125,10 @@ void GLGizmoMeasure::on_render() glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_BLEND)); - glsafe(::glLineWidth(2.f)); +#if ENABLE_GL_CORE_PROFILE + if (!OpenGLManager::get_gl_info().is_core_profile()) +#endif // ENABLE_GL_CORE_PROFILE + glsafe(::glLineWidth(2.f)); if (selection.is_single_full_instance()) { const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); @@ -179,7 +181,7 @@ void GLGizmoMeasure::on_render() Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.get_point())); view_feature_matrix.scale(0.5); shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_sphere.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); + m_vbo_sphere.set_color(HOVER_COLOR); m_vbo_sphere.render(); } else if (feature.get_type() == Measure::SurfaceFeatureType::Circle) { @@ -187,7 +189,7 @@ void GLGizmoMeasure::on_render() Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(c)); view_feature_matrix.scale(0.5); shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_sphere.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); + m_vbo_sphere.set_color(HOVER_COLOR); m_vbo_sphere.render(); // Now draw the circle itself - let's take a funny shortcut: @@ -212,20 +214,21 @@ void GLGizmoMeasure::on_render() view_feature_matrix *= q; view_feature_matrix.scale(Vec3d(0.075, 0.075, (end - start).norm())); shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_cylinder.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); + m_vbo_cylinder.set_color(HOVER_COLOR); m_vbo_cylinder.render(); if (feature.get_extra_point()) { Vec3d pin = *feature.get_extra_point(); view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(pin)); view_feature_matrix.scale(0.5); shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_sphere.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); + m_vbo_sphere.set_color(HOVER_COLOR); m_vbo_sphere.render(); } } else if (feature.get_type() == Measure::SurfaceFeatureType::Plane) { const auto& [idx, normal, pt] = feature.get_plane(); assert(idx < m_plane_models.size()); + m_plane_models[idx]->set_color(HOVER_COLOR); m_plane_models[idx]->render(); } } From a14c27b42ed11be75a1cf8916b7aeaa31e7e1f1e Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 19 Aug 2022 10:36:28 +0200 Subject: [PATCH 018/250] New icon for Measure Gizmo --- resources/icons/measure.svg | 106 +++++++++++++++++++++++++++++++----- 1 file changed, 93 insertions(+), 13 deletions(-) diff --git a/resources/icons/measure.svg b/resources/icons/measure.svg index 275c522251..3ea137a1ed 100644 --- a/resources/icons/measure.svg +++ b/resources/icons/measure.svg @@ -1,13 +1,93 @@ - - - Layer 1 - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + From 4d9c564b9a7ca1a577ad645b1a9f095922e607ee Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 19 Aug 2022 10:48:32 +0200 Subject: [PATCH 019/250] Set Measure Gizmo to be activable for single volume selections only --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 11 ++--------- src/slic3r/GUI/Selection.hpp | 1 + 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 8fc2ff8ea0..712631be63 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -100,17 +100,12 @@ std::string GLGizmoMeasure::on_get_name() const return _u8L("Measure"); } - - bool GLGizmoMeasure::on_is_activable() const { - // This is assumed in GLCanvas3D::do_rotate, do not change this - // without updating that function too. - return m_parent.get_selection().is_single_full_instance(); + const Selection& selection = m_parent.get_selection(); + return selection.is_single_volume() || selection.is_single_volume_instance(); } - - void GLGizmoMeasure::on_render() { const Selection& selection = m_parent.get_selection(); @@ -139,9 +134,7 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - update_if_needed(); - m_imgui->begin(std::string("DEBUG")); diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index cebea29e05..e118f6bca5 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -328,6 +328,7 @@ public: #if ENABLE_WORLD_COORDINATE bool is_single_volume_or_modifier() const { return is_single_volume() || is_single_modifier(); } #endif // ENABLE_WORLD_COORDINATE + bool is_single_volume_instance() const { return is_single_full_instance() && m_list.size() == 1; } bool contains_volume(unsigned int volume_idx) const { return m_list.find(volume_idx) != m_list.end(); } // returns true if the selection contains all the given indices From 474624f89e9bc678950bc3ea400885a48526bdef Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 19 Aug 2022 11:02:13 +0200 Subject: [PATCH 020/250] Removed method set_flattening_data() from GLGizmoMeasure --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 9 ++------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 712631be63..9b3d30a0be 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -69,7 +69,8 @@ void GLGizmoMeasure::data_changed() selection.is_from_single_object() ) { model_object = selection.get_model()->objects[selection.get_object_idx()]; } - set_flattening_data(model_object); + if (model_object != m_old_model_object) + update_if_needed(); } @@ -247,12 +248,6 @@ void GLGizmoMeasure::on_render() #error NOT IMPLEMENTED #endif -void GLGizmoMeasure::set_flattening_data(const ModelObject* model_object) -{ - if (model_object != m_old_model_object) - update_if_needed(); -} - void GLGizmoMeasure::update_if_needed() { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 9094007b5d..e1460c2146 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -50,7 +50,6 @@ private: std::vector> m_plane_models; void update_if_needed(); - void set_flattening_data(const ModelObject* model_object); public: GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); @@ -63,6 +62,7 @@ public: bool on_mouse(const wxMouseEvent &mouse_event) override; void data_changed() override; + protected: bool on_init() override; std::string on_get_name() const override; From 9d81568bf956f6152d0c984c8d1f88d850d7c1b0 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 22 Aug 2022 08:52:02 +0200 Subject: [PATCH 021/250] Measuring: allow to select single parts of a multipart object while Gizmo Measure is active --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 136 +++++++++++++---------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 7 +- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 26 +++-- src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 6 +- 4 files changed, 105 insertions(+), 70 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 9b3d30a0be..92fb8691ef 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -64,12 +64,14 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) void GLGizmoMeasure::data_changed() { const Selection & selection = m_parent.get_selection(); - const ModelObject *model_object = nullptr; + const ModelObject* model_object = nullptr; + const ModelVolume* model_volume = nullptr; if (selection.is_single_full_instance() || selection.is_from_single_object() ) { model_object = selection.get_model()->objects[selection.get_object_idx()]; - } - if (model_object != m_old_model_object) + model_volume = model_object->volumes[selection.get_first_volume()->volume_idx()]; + } + if (model_object != m_old_model_object || model_volume != m_old_model_volume) update_if_needed(); } @@ -109,6 +111,10 @@ bool GLGizmoMeasure::on_is_activable() const void GLGizmoMeasure::on_render() { + // do not render if the user is panning/rotating the 3d scene + if (m_parent.is_mouse_dragging()) + return; + const Selection& selection = m_parent.get_selection(); GLShaderProgram* shader = wxGetApp().get_shader("flat"); @@ -126,33 +132,34 @@ void GLGizmoMeasure::on_render() #endif // ENABLE_GL_CORE_PROFILE glsafe(::glLineWidth(2.f)); - if (selection.is_single_full_instance()) { - const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); + if (selection.is_single_volume() || selection.is_single_volume_instance()) { + const Transform3d& model_matrix = selection.get_first_volume()->world_matrix(); const Camera& camera = wxGetApp().plater()->get_camera(); const Transform3d view_model_matrix = camera.get_view_matrix() * - Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m; + Geometry::assemble_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * model_matrix; shader->set_uniform("view_model_matrix", view_model_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); update_if_needed(); - m_imgui->begin(std::string("DEBUG")); - - m_imgui->checkbox(wxString("Show all features"), m_show_all); - m_imgui->checkbox(wxString("Show all planes"), m_show_planes); - Vec3f pos; Vec3f normal; size_t facet_idx; - m_c->raycaster()->raycasters().front()->unproject_on_mesh(Vec2d(m_mouse_pos_x, m_mouse_pos_y), m, camera, pos, normal, nullptr, &facet_idx); + m_c->raycaster()->raycasters().front()->unproject_on_mesh(Vec2d(m_mouse_pos_x, m_mouse_pos_y), model_matrix, camera, pos, normal, nullptr, &facet_idx); + +#define ENABLE_DEBUG_DIALOG 0 +#if ENABLE_DEBUG_DIALOG + m_imgui->begin(std::string("DEBUG")); + m_imgui->checkbox(wxString("Show all features"), m_show_all); + m_imgui->checkbox(wxString("Show all planes"), m_show_planes); ImGui::Separator(); m_imgui->text(std::string("face_idx: ") + std::to_string(facet_idx)); m_imgui->text(std::string("pos_x: ") + std::to_string(pos.x())); m_imgui->text(std::string("pos_y: ") + std::to_string(pos.y())); m_imgui->text(std::string("pos_z: ") + std::to_string(pos.z())); - - + m_imgui->end(); +#endif // ENABLE_DEBUG_DIALOG std::vector features; if (m_show_all) { @@ -230,8 +237,6 @@ void GLGizmoMeasure::on_render() if (m_show_planes) for (const auto& glmodel : m_plane_models) glmodel->render(); - - m_imgui->end(); } glsafe(::glEnable(GL_CULL_FACE)); @@ -251,57 +256,70 @@ void GLGizmoMeasure::on_render() void GLGizmoMeasure::update_if_needed() { + auto do_update = [this](const ModelObject* object, const ModelVolume* volume) { + const indexed_triangle_set& its = (volume != nullptr) ? volume->mesh().its : object->volumes.front()->mesh().its; + m_measuring.reset(new Measure::Measuring(its)); + m_plane_models.clear(); + const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); + for (const std::vector& triangle_indices : planes_triangles) { + m_plane_models.emplace_back(std::unique_ptr(new GLModel())); + GUI::GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GUI::GLModel::Geometry::EVertexLayout::P3 }; + init_data.color = ColorRGBA(0.9f, 0.9f, 0.9f, 0.5f); + int i = 0; + for (int idx : triangle_indices) { + init_data.add_vertex(its.vertices[its.indices[idx][0]]); + init_data.add_vertex(its.vertices[its.indices[idx][1]]); + init_data.add_vertex(its.vertices[its.indices[idx][2]]); + init_data.add_triangle(i, i + 1, i + 2); + i += 3; + } + m_plane_models.back()->init_from(std::move(init_data)); + } + + // Let's save what we calculated it from: + m_volumes_matrices.clear(); + m_volumes_types.clear(); + m_first_instance_scale = Vec3d::Ones(); + m_first_instance_mirror = Vec3d::Ones(); + if (object != nullptr) { + for (const ModelVolume* vol : object->volumes) { + m_volumes_matrices.push_back(vol->get_matrix()); + m_volumes_types.push_back(vol->type()); + } + m_first_instance_scale = object->instances.front()->get_scaling_factor(); + m_first_instance_mirror = object->instances.front()->get_mirror(); + } + m_old_model_object = object; + m_old_model_volume = volume; + }; + const ModelObject* mo = m_c->selection_info()->model_object(); - if (m_state != On || ! mo || mo->instances.empty()) + const ModelVolume* mv = m_c->selection_info()->model_volume(); + if (m_state != On || (mo == nullptr && mv == nullptr)) return; - if (! m_measuring || mo != m_old_model_object - || mo->volumes.size() != m_volumes_matrices.size()) - goto UPDATE; + if (mo == nullptr) + mo = mv->get_object(); + + if (mo->instances.empty()) + return; + + if (!m_measuring || mo != m_old_model_object || mv != m_old_model_volume || mo->volumes.size() != m_volumes_matrices.size()) + do_update(mo, mv); // We want to recalculate when the scale changes - some planes could (dis)appear. - if (! mo->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale) - || ! mo->instances.front()->get_mirror().isApprox(m_first_instance_mirror)) - goto UPDATE; + if (!mo->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale) || + !mo->instances.front()->get_mirror().isApprox(m_first_instance_mirror)) + do_update(mo, mv); - for (unsigned int i=0; i < mo->volumes.size(); ++i) - if (! mo->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i]) - || mo->volumes[i]->type() != m_volumes_types[i]) - goto UPDATE; - - return; - -UPDATE: - const indexed_triangle_set& its = mo->volumes.front()->mesh().its; - m_measuring.reset(new Measure::Measuring(its)); - m_plane_models.clear(); - const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); - for (const std::vector& triangle_indices : planes_triangles) { - m_plane_models.emplace_back(std::unique_ptr(new GLModel())); - GUI::GLModel::Geometry init_data; - init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GUI::GLModel::Geometry::EVertexLayout::P3 }; - init_data.color = ColorRGBA(0.9f, 0.9f, 0.9f, 0.5f); - int i = 0; - for (int idx : triangle_indices) { - init_data.add_vertex(its.vertices[its.indices[idx][0]]); - init_data.add_vertex(its.vertices[its.indices[idx][1]]); - init_data.add_vertex(its.vertices[its.indices[idx][2]]); - init_data.add_triangle(i, i+1, i+2); - i+=3; + for (unsigned int i = 0; i < mo->volumes.size(); ++i) { + if (!mo->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i]) || + mo->volumes[i]->type() != m_volumes_types[i]) { + do_update(mo, mv); + break; } - m_plane_models.back()->init_from(std::move(init_data)); } - - // Let's save what we calculated it from: - m_volumes_matrices.clear(); - m_volumes_types.clear(); - for (const ModelVolume* vol : mo->volumes) { - m_volumes_matrices.push_back(vol->get_matrix()); - m_volumes_types.push_back(vol->type()); - } - m_first_instance_scale = mo->instances.front()->get_scaling_factor(); - m_first_instance_mirror = mo->instances.front()->get_mirror(); - m_old_model_object = mo; } } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index e1460c2146..cfdc760608 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -14,6 +14,8 @@ namespace Slic3r { +class ModelVolume; + enum class ModelVolumeType : int; namespace Measure { class Measuring; } @@ -35,12 +37,13 @@ private: // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; std::vector m_volumes_types; - Vec3d m_first_instance_scale; - Vec3d m_first_instance_mirror; + Vec3d m_first_instance_scale{ Vec3d::Ones() }; + Vec3d m_first_instance_mirror{ Vec3d::Ones() }; bool m_mouse_left_down = false; // for detection left_up of this gizmo bool m_planes_valid = false; const ModelObject* m_old_model_object = nullptr; + const ModelVolume* m_old_model_volume = nullptr; std::vector instances_matrices; int m_mouse_pos_x; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index ce3ba1d4ab..1eef6aced5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -119,21 +119,25 @@ void SelectionInfo::on_update() const Selection& selection = get_pool()->get_canvas()->get_selection(); if (selection.is_single_full_instance()) { m_model_object = selection.get_model()->objects[selection.get_object_idx()]; + m_model_volume = nullptr; m_z_shift = selection.get_first_volume()->get_sla_shift_z(); } - else + else { m_model_object = nullptr; + if (selection.is_single_volume()) + m_model_volume = selection.get_model()->objects[selection.get_object_idx()]->volumes[selection.get_first_volume()->volume_idx()]; + } } void SelectionInfo::on_release() { m_model_object = nullptr; + m_model_volume = nullptr; } int SelectionInfo::get_active_instance() const { - const Selection& selection = get_pool()->get_canvas()->get_selection(); - return selection.get_instance_idx(); + return get_pool()->get_canvas()->get_selection().get_instance_idx(); } @@ -329,12 +333,18 @@ void Raycaster::on_update() { wxBusyCursor wait; const ModelObject* mo = get_pool()->selection_info()->model_object(); + const ModelVolume* mv = get_pool()->selection_info()->model_volume(); - if (! mo) + if (mo == nullptr && mv == nullptr) return; + std::vector mvs; + if (mv != nullptr) + mvs.push_back(const_cast(mv)); + else + mvs = mo->volumes; + std::vector meshes; - const std::vector& mvs = mo->volumes; if (mvs.size() == 1) { assert(mvs.front()->is_model_part()); const HollowedMesh* hollowed_mesh_tracker = get_pool()->hollowed_mesh(); @@ -342,9 +352,9 @@ void Raycaster::on_update() meshes.push_back(hollowed_mesh_tracker->get_hollowed_mesh()); } if (meshes.empty()) { - for (const ModelVolume* mv : mvs) { - if (mv->is_model_part()) - meshes.push_back(&mv->mesh()); + for (const ModelVolume* v : mvs) { + if (v->is_model_part()) + meshes.push_back(&v->mesh()); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index 7dd2c110ea..c8b29f761e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -10,7 +10,7 @@ namespace Slic3r { class ModelObject; - +class ModelVolume; namespace GUI { @@ -153,7 +153,10 @@ public: explicit SelectionInfo(CommonGizmosDataPool* cgdp) : CommonGizmosDataBase(cgdp) {} + // Returns a non-null pointer if the selection is a single full instance ModelObject* model_object() const { return m_model_object; } + // Returns a non-null pointer if the selection is a single volume + ModelVolume* model_volume() const { return m_model_volume; } int get_active_instance() const; float get_sla_shift() const { return m_z_shift; } @@ -163,6 +166,7 @@ protected: private: ModelObject* m_model_object = nullptr; + ModelVolume* m_model_volume = nullptr; // int m_active_inst = -1; float m_z_shift = 0.f; }; From a7d1c9b5e99132e51d84fcd5155ede7da1ecadd0 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 23 Aug 2022 13:17:09 +0200 Subject: [PATCH 022/250] Measuring: reworked rendering of hovered features --- src/slic3r/GUI/GLModel.cpp | 104 +++++++++++++++ src/slic3r/GUI/GLModel.hpp | 7 ++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 154 ++++++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 3 + 4 files changed, 211 insertions(+), 57 deletions(-) diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 5ae7f9fbf5..e05ae7619b 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -2274,6 +2274,110 @@ GLModel::Geometry smooth_sphere(unsigned int resolution, float radius) return data; } + +GLModel::Geometry smooth_cylinder(Axis axis, unsigned int resolution, float radius, float height) +{ + resolution = std::max(4, resolution); + + const unsigned int sectorCount = resolution; + const float sectorStep = 2.0f * float(M_PI) / float(sectorCount); + + GLModel::Geometry data; + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + data.reserve_vertices(sectorCount * 4 + 2); + data.reserve_indices(sectorCount * 4 * 3); + + auto generate_vertices_on_circle = [sectorCount, sectorStep](Axis axis, float radius) { + std::vector ret; + ret.reserve(sectorCount); + for (unsigned int i = 0; i < sectorCount; ++i) { + // from 0 to 2pi + const float sectorAngle = (i != sectorCount) ? sectorStep * i : 0.0f; + const float x1 = radius * std::cos(sectorAngle); + const float x2 = radius * std::sin(sectorAngle); + + Vec3f v; + switch (axis) + { + case X: { v = Vec3f(0.0f, x1, x2); break; } + case Y: { v = Vec3f(-x1, 0.0f, x2); break; } + case Z: { v = Vec3f(x1, x2, 0.0f); break; } + default: { assert(false); break; } + } + + ret.emplace_back(v); + } + return ret; + }; + + const std::vector base_vertices = generate_vertices_on_circle(axis, radius); + + Vec3f h; + switch (axis) + { + case X: { h = height * Vec3f::UnitX(); break; } + case Y: { h = height * Vec3f::UnitY(); break; } + case Z: { h = height * Vec3f::UnitZ(); break; } + default: { assert(false); break; } + } + + // stem vertices + for (unsigned int i = 0; i < sectorCount; ++i) { + const Vec3f& v = base_vertices[i]; + const Vec3f n = v.normalized(); + data.add_vertex(v, n); + data.add_vertex(v + h, n); + } + + // stem triangles + for (unsigned int i = 0; i < sectorCount; ++i) { + unsigned int v1 = i * 2; + unsigned int v2 = (i < sectorCount - 1) ? v1 + 2 : 0; + unsigned int v3 = v2 + 1; + unsigned int v4 = v1 + 1; + data.add_triangle(v1, v2, v3); + data.add_triangle(v1, v3, v4); + } + + // bottom cap vertices + Vec3f cap_center = Vec3f::Zero(); + unsigned int cap_center_id = data.vertices_count(); + Vec3f normal; + switch (axis) + { + case X: { normal = -Vec3f::UnitX(); break; } + case Y: { normal = -Vec3f::UnitY(); break; } + case Z: { normal = -Vec3f::UnitZ(); break; } + default: { assert(false); break; } + } + + data.add_vertex(cap_center, normal); + for (unsigned int i = 0; i < sectorCount; ++i) { + data.add_vertex(base_vertices[i], normal); + } + + // bottom cap triangles + for (unsigned int i = 0; i < sectorCount; ++i) { + data.add_triangle(cap_center_id, (i < sectorCount - 1) ? cap_center_id + i + 2 : cap_center_id + 1, cap_center_id + i + 1); + } + + // top cap vertices + cap_center += h; + cap_center_id = data.vertices_count(); + normal = -normal; + + data.add_vertex(cap_center, normal); + for (unsigned int i = 0; i < sectorCount; ++i) { + data.add_vertex(base_vertices[i] + h, normal); + } + + // top cap triangles + for (unsigned int i = 0; i < sectorCount; ++i) { + data.add_triangle(cap_center_id, cap_center_id + i + 1, (i < sectorCount - 1) ? cap_center_id + i + 2 : cap_center_id + 1); + } + + return data; +} #endif // ENABLE_LEGACY_OPENGL_REMOVAL } // namespace GUI diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index f3c62d786c..7d2f785573 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -365,7 +365,14 @@ namespace GUI { #if ENABLE_LEGACY_OPENGL_REMOVAL // create a sphere with the given resolution and smooth normals // the origin of the sphere is in its center + // the radius of the sphere is the given value GLModel::Geometry smooth_sphere(unsigned int resolution, float radius); + // create a cylinder with the given resolution and smooth normals + // the axis of the cylinder is the given value + // the radius of the cylinder is the given value + // the height of the cylinder is the given value + // the origin of the cylinder is in the center of the cap face having axis == 0 + GLModel::Geometry smooth_cylinder(Axis axis, unsigned int resolution, float radius, float height); #endif // ENABLE_LEGACY_OPENGL_REMOVAL } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 92fb8691ef..8b39582822 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -8,6 +8,7 @@ #include "libslic3r/Model.hpp" #include "libslic3r/Measure.hpp" +#include "libslic3r/PresetBundle.hpp" #include @@ -21,8 +22,8 @@ static const Slic3r::ColorRGBA HOVER_COLOR = { 0.8f, 0.2f, 0.2f, 1.0f }; GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) { - m_vbo_sphere.init_from(its_make_sphere(1., M_PI/32.)); - m_vbo_cylinder.init_from(its_make_cylinder(1., 1.)); + m_vbo_sphere.init_from(smooth_sphere(16, 7.5f)); + m_vbo_cylinder.init_from(smooth_cylinder(Z, 16, 5.0f, 1.0f)); } bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) @@ -106,7 +107,9 @@ std::string GLGizmoMeasure::on_get_name() const bool GLGizmoMeasure::on_is_activable() const { const Selection& selection = m_parent.get_selection(); - return selection.is_single_volume() || selection.is_single_volume_instance(); + return (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) ? + selection.is_single_full_instance() : + selection.is_single_volume() || selection.is_single_volume_instance(); } void GLGizmoMeasure::on_render() @@ -117,30 +120,27 @@ void GLGizmoMeasure::on_render() const Selection& selection = m_parent.get_selection(); - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) return; shader->start_using(); + shader->set_uniform("emission_factor", 0.25f); glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_BLEND)); -#if ENABLE_GL_CORE_PROFILE - if (!OpenGLManager::get_gl_info().is_core_profile()) -#endif // ENABLE_GL_CORE_PROFILE - glsafe(::glLineWidth(2.f)); - if (selection.is_single_volume() || selection.is_single_volume_instance()) { + if ((wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA && selection.is_single_full_instance()) || + (selection.is_single_volume() || selection.is_single_volume_instance())) { const Transform3d& model_matrix = selection.get_first_volume()->world_matrix(); const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d view_model_matrix = camera.get_view_matrix() * - Geometry::assemble_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * model_matrix; + const Transform3d& view_matrix = camera.get_view_matrix(); + const float inv_zoom = camera.get_inv_zoom(); - shader->set_uniform("view_model_matrix", view_model_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - + update_if_needed(); Vec3f pos; @@ -148,7 +148,6 @@ void GLGizmoMeasure::on_render() size_t facet_idx; m_c->raycaster()->raycasters().front()->unproject_on_mesh(Vec2d(m_mouse_pos_x, m_mouse_pos_y), model_matrix, camera, pos, normal, nullptr, &facet_idx); -#define ENABLE_DEBUG_DIALOG 0 #if ENABLE_DEBUG_DIALOG m_imgui->begin(std::string("DEBUG")); m_imgui->checkbox(wxString("Show all features"), m_show_all); @@ -162,34 +161,46 @@ void GLGizmoMeasure::on_render() #endif // ENABLE_DEBUG_DIALOG std::vector features; - if (m_show_all) { +#if ENABLE_DEBUG_DIALOG + if (m_show_all) { features = m_measuring->get_all_features(); // EXPENSIVE - debugging only. features.erase(std::remove_if(features.begin(), features.end(), [](const Measure::SurfaceFeature& f) { return f.get_type() == Measure::SurfaceFeatureType::Plane; }), features.end()); - } else { + } + else { +#endif // ENABLE_DEBUG_DIALOG std::optional feat = m_measuring->get_feature(facet_idx, pos.cast()); - if (feat) + if (feat.has_value()) features.emplace_back(*feat); - } - - +#if ENABLE_DEBUG_DIALOG + } +#endif // ENABLE_DEBUG_DIALOG for (const Measure::SurfaceFeature& feature : features) { - - if (feature.get_type() == Measure::SurfaceFeatureType::Point) { - Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.get_point())); - view_feature_matrix.scale(0.5); - shader->set_uniform("view_model_matrix", view_feature_matrix); + switch (feature.get_type()) { + case Measure::SurfaceFeatureType::Point: + { + const Vec3d& position = feature.get_point(); + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); + const Transform3d view_model_matrix = view_matrix * feature_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_vbo_sphere.set_color(HOVER_COLOR); m_vbo_sphere.render(); + break; } - else if (feature.get_type() == Measure::SurfaceFeatureType::Circle) { - const auto& [c, radius, n] = feature.get_circle(); - Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(c)); - view_feature_matrix.scale(0.5); - shader->set_uniform("view_model_matrix", view_feature_matrix); + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, n] = feature.get_circle(); + // render center + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); + const Transform3d view_model_matrix = view_matrix * feature_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_vbo_sphere.set_color(HOVER_COLOR); m_vbo_sphere.render(); @@ -198,45 +209,69 @@ void GLGizmoMeasure::on_render() if (rad.squaredNorm() < 0.1) rad = n.cross(Vec3d::UnitY()); rad *= radius * rad.norm(); - const int N = 20; - for (int i=0; iset_uniform("view_model_matrix", view_feature_matrix); + const int N = 32; + m_vbo_sphere.set_color(HOVER_COLOR); + for (int i = 0; i < N; ++i) { + rad = Eigen::AngleAxisd(2.0 * M_PI / N, n) * rad; + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(center + rad) * Geometry::scale_transform(N / 100.0 * inv_zoom); + const Transform3d view_model_matrix = view_matrix * feature_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_vbo_sphere.render(); } + break; } - else if (feature.get_type() == Measure::SurfaceFeatureType::Edge) { + case Measure::SurfaceFeatureType::Edge: + { const auto& [start, end] = feature.get_edge(); - Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(start)); - auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); - view_feature_matrix *= q; - view_feature_matrix.scale(Vec3d(0.075, 0.075, (end - start).norm())); - shader->set_uniform("view_model_matrix", view_feature_matrix); + auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * q * + Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); + const Transform3d view_model_matrix = view_matrix * feature_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_vbo_cylinder.set_color(HOVER_COLOR); m_vbo_cylinder.render(); - if (feature.get_extra_point()) { - Vec3d pin = *feature.get_extra_point(); - view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(pin)); - view_feature_matrix.scale(0.5); - shader->set_uniform("view_model_matrix", view_feature_matrix); + +/* + std::optional extra_point = feature.get_extra_point(); + if (extra_point.has_value()) { + const Vec3d pin = *extra_point; + const Transform3d feature_matrix = Geometry::translation_transform(pin + selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * + Geometry::scale_transform(inv_zoom) * model_matrix; + const Transform3d view_model_matrix = view_matrix * feature_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_vbo_sphere.set_color(HOVER_COLOR); m_vbo_sphere.render(); } +*/ + break; } - else if (feature.get_type() == Measure::SurfaceFeatureType::Plane) { + case Measure::SurfaceFeatureType::Plane: + { const auto& [idx, normal, pt] = feature.get_plane(); assert(idx < m_plane_models.size()); + const Transform3d view_model_matrix = view_matrix * model_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_plane_models[idx]->set_color(HOVER_COLOR); m_plane_models[idx]->render(); - } + break; + } + } } - shader->set_uniform("view_model_matrix", view_model_matrix); +#if ENABLE_DEBUG_DIALOG if (m_show_planes) - for (const auto& glmodel : m_plane_models) + for (const auto& glmodel : m_plane_models) { + glmodel->set_color(HOVER_COLOR); glmodel->render(); + } +#endif // ENABLE_DEBUG_DIALOG } glsafe(::glEnable(GL_CULL_FACE)); @@ -263,14 +298,19 @@ void GLGizmoMeasure::update_if_needed() const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); for (const std::vector& triangle_indices : planes_triangles) { m_plane_models.emplace_back(std::unique_ptr(new GLModel())); - GUI::GLModel::Geometry init_data; - init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GUI::GLModel::Geometry::EVertexLayout::P3 }; + GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; init_data.color = ColorRGBA(0.9f, 0.9f, 0.9f, 0.5f); int i = 0; for (int idx : triangle_indices) { - init_data.add_vertex(its.vertices[its.indices[idx][0]]); - init_data.add_vertex(its.vertices[its.indices[idx][1]]); - init_data.add_vertex(its.vertices[its.indices[idx][2]]); + const Vec3f& v0 = its.vertices[its.indices[idx][0]]; + const Vec3f& v1 = its.vertices[its.indices[idx][1]]; + const Vec3f& v2 = its.vertices[its.indices[idx][2]]; + + const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); + init_data.add_vertex(v0, n); + init_data.add_vertex(v1, n); + init_data.add_vertex(v2, n); init_data.add_triangle(i, i + 1, i + 2); i += 3; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index cfdc760608..72454f475d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -11,6 +11,7 @@ #include +#define ENABLE_DEBUG_DIALOG 0 namespace Slic3r { @@ -48,8 +49,10 @@ private: int m_mouse_pos_x; int m_mouse_pos_y; +#if ENABLE_DEBUG_DIALOG bool m_show_all = false; bool m_show_planes = false; +#endif // ENABLE_DEBUG_DIALOG std::vector> m_plane_models; void update_if_needed(); From 8f06086679eb695d3e79f36044255e0fa6ac4d21 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 23 Aug 2022 13:53:55 +0200 Subject: [PATCH 023/250] Follow-up of a7d1c9b5e99132e51d84fcd5155ede7da1ecadd0 - Simplified code to generate a smooth cylinder --- src/slic3r/GUI/GLModel.cpp | 39 ++++-------------------- src/slic3r/GUI/GLModel.hpp | 13 +++----- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- 3 files changed, 12 insertions(+), 42 deletions(-) diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index e05ae7619b..249a5cce7e 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -2275,7 +2275,7 @@ GLModel::Geometry smooth_sphere(unsigned int resolution, float radius) return data; } -GLModel::Geometry smooth_cylinder(Axis axis, unsigned int resolution, float radius, float height) +GLModel::Geometry smooth_cylinder(unsigned int resolution, float radius, float height) { resolution = std::max(4, resolution); @@ -2287,39 +2287,19 @@ GLModel::Geometry smooth_cylinder(Axis axis, unsigned int resolution, float radi data.reserve_vertices(sectorCount * 4 + 2); data.reserve_indices(sectorCount * 4 * 3); - auto generate_vertices_on_circle = [sectorCount, sectorStep](Axis axis, float radius) { + auto generate_vertices_on_circle = [sectorCount, sectorStep](float radius) { std::vector ret; ret.reserve(sectorCount); for (unsigned int i = 0; i < sectorCount; ++i) { // from 0 to 2pi const float sectorAngle = (i != sectorCount) ? sectorStep * i : 0.0f; - const float x1 = radius * std::cos(sectorAngle); - const float x2 = radius * std::sin(sectorAngle); - - Vec3f v; - switch (axis) - { - case X: { v = Vec3f(0.0f, x1, x2); break; } - case Y: { v = Vec3f(-x1, 0.0f, x2); break; } - case Z: { v = Vec3f(x1, x2, 0.0f); break; } - default: { assert(false); break; } - } - - ret.emplace_back(v); + ret.emplace_back(radius * std::cos(sectorAngle), radius * std::sin(sectorAngle), 0.0f); } return ret; }; - const std::vector base_vertices = generate_vertices_on_circle(axis, radius); - - Vec3f h; - switch (axis) - { - case X: { h = height * Vec3f::UnitX(); break; } - case Y: { h = height * Vec3f::UnitY(); break; } - case Z: { h = height * Vec3f::UnitZ(); break; } - default: { assert(false); break; } - } + const std::vector base_vertices = generate_vertices_on_circle(radius); + const Vec3f h = height * Vec3f::UnitZ(); // stem vertices for (unsigned int i = 0; i < sectorCount; ++i) { @@ -2342,14 +2322,7 @@ GLModel::Geometry smooth_cylinder(Axis axis, unsigned int resolution, float radi // bottom cap vertices Vec3f cap_center = Vec3f::Zero(); unsigned int cap_center_id = data.vertices_count(); - Vec3f normal; - switch (axis) - { - case X: { normal = -Vec3f::UnitX(); break; } - case Y: { normal = -Vec3f::UnitY(); break; } - case Z: { normal = -Vec3f::UnitZ(); break; } - default: { assert(false); break; } - } + Vec3f normal = -Vec3f::UnitZ(); data.add_vertex(cap_center, normal); for (unsigned int i = 0; i < sectorCount; ++i) { diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index 7d2f785573..c5b9f5e095 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -363,16 +363,13 @@ namespace GUI { GLModel::Geometry diamond(unsigned int resolution); #if ENABLE_LEGACY_OPENGL_REMOVAL - // create a sphere with the given resolution and smooth normals + // create a sphere with smooth normals // the origin of the sphere is in its center - // the radius of the sphere is the given value GLModel::Geometry smooth_sphere(unsigned int resolution, float radius); - // create a cylinder with the given resolution and smooth normals - // the axis of the cylinder is the given value - // the radius of the cylinder is the given value - // the height of the cylinder is the given value - // the origin of the cylinder is in the center of the cap face having axis == 0 - GLModel::Geometry smooth_cylinder(Axis axis, unsigned int resolution, float radius, float height); + // create a cylinder with smooth normals + // the axis of the cylinder is the Z axis + // the origin of the cylinder is the center of its bottom cap face + GLModel::Geometry smooth_cylinder(unsigned int resolution, float radius, float height); #endif // ENABLE_LEGACY_OPENGL_REMOVAL } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 8b39582822..32f110d9fd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -23,7 +23,7 @@ GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filen : GLGizmoBase(parent, icon_filename, sprite_id) { m_vbo_sphere.init_from(smooth_sphere(16, 7.5f)); - m_vbo_cylinder.init_from(smooth_cylinder(Z, 16, 5.0f, 1.0f)); + m_vbo_cylinder.init_from(smooth_cylinder(16, 5.0f, 1.0f)); } bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) From 26650a26588c2039a1743ef7e982de9fd6d58c0e Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 24 Aug 2022 11:25:15 +0200 Subject: [PATCH 024/250] Measuring: circle feature rendered using a torus --- src/slic3r/GUI/GLModel.cpp | 47 ++++++++++++++++- src/slic3r/GUI/GLModel.hpp | 4 ++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 67 ++++++++---------------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 5 +- 4 files changed, 76 insertions(+), 47 deletions(-) diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 249a5cce7e..b36db83ad1 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -2292,7 +2292,7 @@ GLModel::Geometry smooth_cylinder(unsigned int resolution, float radius, float h ret.reserve(sectorCount); for (unsigned int i = 0; i < sectorCount; ++i) { // from 0 to 2pi - const float sectorAngle = (i != sectorCount) ? sectorStep * i : 0.0f; + const float sectorAngle = sectorStep * i; ret.emplace_back(radius * std::cos(sectorAngle), radius * std::sin(sectorAngle), 0.0f); } return ret; @@ -2351,6 +2351,51 @@ GLModel::Geometry smooth_cylinder(unsigned int resolution, float radius, float h return data; } + +GLModel::Geometry smooth_torus(unsigned int primary_resolution, unsigned int secondary_resolution, float radius, float thickness) +{ + primary_resolution = std::max(4, primary_resolution); + secondary_resolution = std::max(4, secondary_resolution); + const unsigned int torusSectorCount = primary_resolution; + const float torusSectorStep = 2.0f * float(M_PI) / float(torusSectorCount); + const unsigned int sectionSectorCount = secondary_resolution; + const float sectionSectorStep = 2.0f * float(M_PI) / float(sectionSectorCount); + + GLModel::Geometry data; + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + data.reserve_vertices(torusSectorCount * sectionSectorCount); + data.reserve_indices(torusSectorCount * sectionSectorCount * 2 * 3); + + // vertices + for (unsigned int i = 0; i < torusSectorCount; ++i) { + const float sectionAngle = torusSectorStep * i; + const Vec3f sectionCenter(radius * std::cos(sectionAngle), radius * std::sin(sectionAngle), 0.0f); + for (unsigned int j = 0; j < sectionSectorCount; ++j) { + const float circleAngle = sectionSectorStep * j; + const float thickness_xy = thickness * std::cos(circleAngle); + const float thickness_z = thickness * std::sin(circleAngle); + const Vec3f v(thickness_xy * std::cos(sectionAngle), thickness_xy * std::sin(sectionAngle), thickness_z); + data.add_vertex(sectionCenter + v, (Vec3f)v.normalized()); + } + } + + // triangles + for (unsigned int i = 0; i < torusSectorCount; ++i) { + const unsigned int ii = i * sectionSectorCount; + const unsigned int ii_next = ((i + 1) % torusSectorCount) * sectionSectorCount; + for (unsigned int j = 0; j < sectionSectorCount; ++j) { + const unsigned int j_next = (j + 1) % sectionSectorCount; + const unsigned int i0 = ii + j; + const unsigned int i1 = ii_next + j; + const unsigned int i2 = ii_next + j_next; + const unsigned int i3 = ii + j_next; + data.add_triangle(i0, i1, i2); + data.add_triangle(i0, i2, i3); + } + } + + return data; +} #endif // ENABLE_LEGACY_OPENGL_REMOVAL } // namespace GUI diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index c5b9f5e095..8843d39eeb 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -370,6 +370,10 @@ namespace GUI { // the axis of the cylinder is the Z axis // the origin of the cylinder is the center of its bottom cap face GLModel::Geometry smooth_cylinder(unsigned int resolution, float radius, float height); + // create a torus with smooth normals + // the axis of the torus is the Z axis + // the origin of the torus is in its center + GLModel::Geometry smooth_torus(unsigned int primary_resolution, unsigned int secondary_resolution, float radius, float thickness); #endif // ENABLE_LEGACY_OPENGL_REMOVAL } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 32f110d9fd..6e1ba9991e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -22,8 +22,8 @@ static const Slic3r::ColorRGBA HOVER_COLOR = { 0.8f, 0.2f, 0.2f, 1.0f }; GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) { - m_vbo_sphere.init_from(smooth_sphere(16, 7.5f)); - m_vbo_cylinder.init_from(smooth_cylinder(16, 5.0f, 1.0f)); + m_sphere.init_from(smooth_sphere(16, 7.5f)); + m_cylinder.init_from(smooth_cylinder(16, 5.0f, 1.0f)); } bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) @@ -188,38 +188,32 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_vbo_sphere.set_color(HOVER_COLOR); - m_vbo_sphere.render(); + m_sphere.set_color(HOVER_COLOR); + m_sphere.render(); break; } case Measure::SurfaceFeatureType::Circle: { const auto& [center, radius, n] = feature.get_circle(); // render center - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); - const Transform3d view_model_matrix = view_matrix * feature_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_vbo_sphere.set_color(HOVER_COLOR); - m_vbo_sphere.render(); + const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); + const Transform3d center_view_model_matrix = view_matrix * center_matrix; + shader->set_uniform("view_model_matrix", center_view_model_matrix); + const Matrix3d center_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * center_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", center_view_normal_matrix); + m_sphere.set_color(HOVER_COLOR); + m_sphere.render(); - // Now draw the circle itself - let's take a funny shortcut: - Vec3d rad = n.cross(Vec3d::UnitX()); - if (rad.squaredNorm() < 0.1) - rad = n.cross(Vec3d::UnitY()); - rad *= radius * rad.norm(); - const int N = 32; - m_vbo_sphere.set_color(HOVER_COLOR); - for (int i = 0; i < N; ++i) { - rad = Eigen::AngleAxisd(2.0 * M_PI / N, n) * rad; - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(center + rad) * Geometry::scale_transform(N / 100.0 * inv_zoom); - const Transform3d view_model_matrix = view_matrix * feature_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_vbo_sphere.render(); - } + m_circle.reset(); + m_circle.init_from(smooth_torus(64, 16, float(radius), 5.0f * inv_zoom)); + + const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center); + const Transform3d circle_view_model_matrix = view_matrix * circle_matrix; + shader->set_uniform("view_model_matrix", circle_view_model_matrix); + const Matrix3d circle_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * circle_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", circle_view_normal_matrix); + m_circle.set_color(HOVER_COLOR); + m_circle.render(); break; } case Measure::SurfaceFeatureType::Edge: @@ -232,23 +226,8 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_vbo_cylinder.set_color(HOVER_COLOR); - m_vbo_cylinder.render(); - -/* - std::optional extra_point = feature.get_extra_point(); - if (extra_point.has_value()) { - const Vec3d pin = *extra_point; - const Transform3d feature_matrix = Geometry::translation_transform(pin + selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * - Geometry::scale_transform(inv_zoom) * model_matrix; - const Transform3d view_model_matrix = view_matrix * feature_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_vbo_sphere.set_color(HOVER_COLOR); - m_vbo_sphere.render(); - } -*/ + m_cylinder.set_color(HOVER_COLOR); + m_cylinder.render(); break; } case Measure::SurfaceFeatureType::Plane: diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 72454f475d..79bc934cbb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -32,8 +32,9 @@ class GLGizmoMeasure : public GLGizmoBase private: std::unique_ptr m_measuring; - GLModel m_vbo_sphere; - GLModel m_vbo_cylinder; + GLModel m_sphere; + GLModel m_cylinder; + GLModel m_circle; // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; From 2abb52ed4c88f9b5b3d52297d356955c1f4039e2 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 24 Aug 2022 12:00:04 +0200 Subject: [PATCH 025/250] Measuring: refactoring related to plane models cache --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 41 +++++++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 2 +- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 6e1ba9991e..d6bd5e67be 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -233,23 +233,28 @@ void GLGizmoMeasure::on_render() case Measure::SurfaceFeatureType::Plane: { const auto& [idx, normal, pt] = feature.get_plane(); - assert(idx < m_plane_models.size()); + assert(idx < m_plane_models_cache.size()); const Transform3d view_model_matrix = view_matrix * model_matrix; shader->set_uniform("view_model_matrix", view_model_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_plane_models[idx]->set_color(HOVER_COLOR); - m_plane_models[idx]->render(); + m_plane_models_cache[idx].set_color(HOVER_COLOR); + m_plane_models_cache[idx].render(); break; } } } #if ENABLE_DEBUG_DIALOG - if (m_show_planes) - for (const auto& glmodel : m_plane_models) { - glmodel->set_color(HOVER_COLOR); - glmodel->render(); + if (m_show_planes) { + const Transform3d view_model_matrix = view_matrix * model_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); + for (GLModel& glmodel : m_plane_models_cache) { + glmodel.set_color(HOVER_COLOR); + glmodel.render(); } + } #endif // ENABLE_DEBUG_DIALOG } @@ -270,17 +275,14 @@ void GLGizmoMeasure::on_render() void GLGizmoMeasure::update_if_needed() { - auto do_update = [this](const ModelObject* object, const ModelVolume* volume) { - const indexed_triangle_set& its = (volume != nullptr) ? volume->mesh().its : object->volumes.front()->mesh().its; - m_measuring.reset(new Measure::Measuring(its)); - m_plane_models.clear(); + auto update_plane_models_cache = [this](const indexed_triangle_set& its) { + m_plane_models_cache.clear(); const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); for (const std::vector& triangle_indices : planes_triangles) { - m_plane_models.emplace_back(std::unique_ptr(new GLModel())); + m_plane_models_cache.emplace_back(GLModel()); GLModel::Geometry init_data; init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; - init_data.color = ColorRGBA(0.9f, 0.9f, 0.9f, 0.5f); - int i = 0; + unsigned int i = 0; for (int idx : triangle_indices) { const Vec3f& v0 = its.vertices[its.indices[idx][0]]; const Vec3f& v1 = its.vertices[its.indices[idx][1]]; @@ -293,8 +295,15 @@ void GLGizmoMeasure::update_if_needed() init_data.add_triangle(i, i + 1, i + 2); i += 3; } - m_plane_models.back()->init_from(std::move(init_data)); + m_plane_models_cache.back().init_from(std::move(init_data)); } + }; + + auto do_update = [this, update_plane_models_cache](const ModelObject* object, const ModelVolume* volume) { + const indexed_triangle_set& its = (volume != nullptr) ? volume->mesh().its : object->volumes.front()->mesh().its; + m_measuring.reset(new Measure::Measuring(its)); + + update_plane_models_cache(its); // Let's save what we calculated it from: m_volumes_matrices.clear(); @@ -306,7 +315,7 @@ void GLGizmoMeasure::update_if_needed() m_volumes_matrices.push_back(vol->get_matrix()); m_volumes_types.push_back(vol->type()); } - m_first_instance_scale = object->instances.front()->get_scaling_factor(); + m_first_instance_scale = object->instances.front()->get_scaling_factor(); m_first_instance_mirror = object->instances.front()->get_mirror(); } m_old_model_object = object; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 79bc934cbb..8197ea6863 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -35,6 +35,7 @@ private: GLModel m_sphere; GLModel m_cylinder; GLModel m_circle; + std::vector m_plane_models_cache; // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; @@ -54,7 +55,6 @@ private: bool m_show_all = false; bool m_show_planes = false; #endif // ENABLE_DEBUG_DIALOG - std::vector> m_plane_models; void update_if_needed(); From d0bf05d1e9760e3d452f612c70bee282b6486c5e Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 24 Aug 2022 14:15:20 +0200 Subject: [PATCH 026/250] Refactoring into GLGizmoMeasure::on_render() --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 67 +++++++++++++----------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index d6bd5e67be..844ed8876f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -114,34 +114,20 @@ bool GLGizmoMeasure::on_is_activable() const void GLGizmoMeasure::on_render() { +#if !ENABLE_DEBUG_DIALOG // do not render if the user is panning/rotating the 3d scene if (m_parent.is_mouse_dragging()) return; +#endif // !ENABLE_DEBUG_DIALOG const Selection& selection = m_parent.get_selection(); - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); - if (shader == nullptr) - return; - - shader->start_using(); - shader->set_uniform("emission_factor", 0.25f); - - glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); - - glsafe(::glEnable(GL_DEPTH_TEST)); - glsafe(::glEnable(GL_BLEND)); - if ((wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA && selection.is_single_full_instance()) || (selection.is_single_volume() || selection.is_single_volume_instance())) { + update_if_needed(); + const Transform3d& model_matrix = selection.get_first_volume()->world_matrix(); const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d& view_matrix = camera.get_view_matrix(); - const float inv_zoom = camera.get_inv_zoom(); - - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - - update_if_needed(); Vec3f pos; Vec3f normal; @@ -165,19 +151,42 @@ void GLGizmoMeasure::on_render() if (m_show_all) { features = m_measuring->get_all_features(); // EXPENSIVE - debugging only. features.erase(std::remove_if(features.begin(), features.end(), - [](const Measure::SurfaceFeature& f) { - return f.get_type() == Measure::SurfaceFeatureType::Plane; - }), features.end()); + [](const Measure::SurfaceFeature& f) { + return f.get_type() == Measure::SurfaceFeatureType::Plane; + }), features.end()); } else { + if (!m_parent.is_mouse_dragging()) { #endif // ENABLE_DEBUG_DIALOG - std::optional feat = m_measuring->get_feature(facet_idx, pos.cast()); - if (feat.has_value()) - features.emplace_back(*feat); + std::optional feat = m_measuring->get_feature(facet_idx, pos.cast()); + if (feat.has_value()) + features.emplace_back(*feat); #if ENABLE_DEBUG_DIALOG + } } #endif // ENABLE_DEBUG_DIALOG - + +#if ENABLE_DEBUG_DIALOG + if (features.empty() && !m_show_planes) +#else + if (features.empty()) +#endif // ENABLE_DEBUG_DIALOG + return; + + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); + if (shader == nullptr) + return; + + shader->start_using(); + shader->set_uniform("emission_factor", 0.25f); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + + glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); + glsafe(::glEnable(GL_DEPTH_TEST)); + + const Transform3d& view_matrix = camera.get_view_matrix(); + const float inv_zoom = camera.get_inv_zoom(); + for (const Measure::SurfaceFeature& feature : features) { switch (feature.get_type()) { case Measure::SurfaceFeatureType::Point: @@ -256,18 +265,12 @@ void GLGizmoMeasure::on_render() } } #endif // ENABLE_DEBUG_DIALOG + shader->stop_using(); } - - glsafe(::glEnable(GL_CULL_FACE)); - glsafe(::glDisable(GL_BLEND)); - - shader->stop_using(); } - - #if ! ENABLE_LEGACY_OPENGL_REMOVAL #error NOT IMPLEMENTED #endif From 38c52941d68723b887b935622c6dd1f50fc46da6 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 24 Aug 2022 15:02:46 +0200 Subject: [PATCH 027/250] Added tech ENABLE_MEASURE_GIZMO_DEBUG to embed debug code related to GLGizmoMeasure --- src/libslic3r/Measure.cpp | 3 ++ src/libslic3r/Measure.hpp | 4 +- src/libslic3r/Technologies.hpp | 2 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 50 ++++++++++-------------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 6 +-- 5 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 8c7254f85b..9cb46edfc1 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -1,3 +1,4 @@ +#include "libslic3r/libslic3r.h" #include "Measure.hpp" #include "libslic3r/Geometry/Circle.hpp" @@ -407,10 +408,12 @@ Measuring::Measuring(const indexed_triangle_set& its) Measuring::~Measuring() {} +#if ENABLE_MEASURE_GIZMO_DEBUG std::vector Measuring::get_all_features() const { return priv->get_all_features(); } +#endif // ENABLE_MEASURE_GIZMO_DEBUG std::optional Measuring::get_feature(size_t face_idx, const Vec3d& point) const diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index fe0b1687a1..98517b991b 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -69,9 +69,11 @@ public: explicit Measuring(const indexed_triangle_set& its); ~Measuring(); +#if ENABLE_MEASURE_GIZMO_DEBUG // Return a reference to a list of all features identified on the its. // Use only for debugging. Expensive, do not call often. - [[deprecated]] std::vector get_all_features() const; + std::vector get_all_features() const; +#endif // ENABLE_MEASURE_GIZMO_DEBUG // Given a face_idx where the mouse cursor points, return a feature that // should be highlighted (if any). diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index ee2c0cd804..58720801f8 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -78,6 +78,8 @@ // Enable picking using raytracing #define ENABLE_RAYCAST_PICKING (1 && ENABLE_LEGACY_OPENGL_REMOVAL) #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) +// Enable debug code for Measure Gizmo +#define ENABLE_MEASURE_GIZMO_DEBUG (0 && ENABLE_2_5_0_ALPHA1) #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 844ed8876f..7ca051c7d1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -114,11 +114,11 @@ bool GLGizmoMeasure::on_is_activable() const void GLGizmoMeasure::on_render() { -#if !ENABLE_DEBUG_DIALOG +#if !ENABLE_MEASURE_GIZMO_DEBUG // do not render if the user is panning/rotating the 3d scene if (m_parent.is_mouse_dragging()) return; -#endif // !ENABLE_DEBUG_DIALOG +#endif // !ENABLE_MEASURE_GIZMO_DEBUG const Selection& selection = m_parent.get_selection(); @@ -134,7 +134,7 @@ void GLGizmoMeasure::on_render() size_t facet_idx; m_c->raycaster()->raycasters().front()->unproject_on_mesh(Vec2d(m_mouse_pos_x, m_mouse_pos_y), model_matrix, camera, pos, normal, nullptr, &facet_idx); -#if ENABLE_DEBUG_DIALOG +#if ENABLE_MEASURE_GIZMO_DEBUG m_imgui->begin(std::string("DEBUG")); m_imgui->checkbox(wxString("Show all features"), m_show_all); m_imgui->checkbox(wxString("Show all planes"), m_show_planes); @@ -144,33 +144,35 @@ void GLGizmoMeasure::on_render() m_imgui->text(std::string("pos_y: ") + std::to_string(pos.y())); m_imgui->text(std::string("pos_z: ") + std::to_string(pos.z())); m_imgui->end(); -#endif // ENABLE_DEBUG_DIALOG +#endif // ENABLE_MEASURE_GIZMO_DEBUG std::vector features; -#if ENABLE_DEBUG_DIALOG - if (m_show_all) { - features = m_measuring->get_all_features(); // EXPENSIVE - debugging only. - features.erase(std::remove_if(features.begin(), features.end(), - [](const Measure::SurfaceFeature& f) { - return f.get_type() == Measure::SurfaceFeatureType::Plane; - }), features.end()); +#if ENABLE_MEASURE_GIZMO_DEBUG + if (m_show_all || m_show_planes) { + features = m_measuring->get_all_features(); + if (!m_show_planes) + features.erase(std::remove_if(features.begin(), features.end(), + [](const Measure::SurfaceFeature& f) { + return f.get_type() == Measure::SurfaceFeatureType::Plane; + }), features.end()); + if (!m_show_all) + features.erase(std::remove_if(features.begin(), features.end(), + [](const Measure::SurfaceFeature& f) { + return f.get_type() != Measure::SurfaceFeatureType::Plane; + }), features.end()); } else { if (!m_parent.is_mouse_dragging()) { -#endif // ENABLE_DEBUG_DIALOG +#endif // ENABLE_MEASURE_GIZMO_DEBUG std::optional feat = m_measuring->get_feature(facet_idx, pos.cast()); if (feat.has_value()) features.emplace_back(*feat); -#if ENABLE_DEBUG_DIALOG +#if ENABLE_MEASURE_GIZMO_DEBUG } } -#endif // ENABLE_DEBUG_DIALOG +#endif // ENABLE_MEASURE_GIZMO_DEBUG -#if ENABLE_DEBUG_DIALOG - if (features.empty() && !m_show_planes) -#else if (features.empty()) -#endif // ENABLE_DEBUG_DIALOG return; GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); @@ -253,18 +255,6 @@ void GLGizmoMeasure::on_render() } } } -#if ENABLE_DEBUG_DIALOG - if (m_show_planes) { - const Transform3d view_model_matrix = view_matrix * model_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - for (GLModel& glmodel : m_plane_models_cache) { - glmodel.set_color(HOVER_COLOR); - glmodel.render(); - } - } -#endif // ENABLE_DEBUG_DIALOG shader->stop_using(); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 8197ea6863..49ab7fce8a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -11,8 +11,6 @@ #include -#define ENABLE_DEBUG_DIALOG 0 - namespace Slic3r { class ModelVolume; @@ -51,10 +49,10 @@ private: int m_mouse_pos_x; int m_mouse_pos_y; -#if ENABLE_DEBUG_DIALOG +#if ENABLE_MEASURE_GIZMO_DEBUG bool m_show_all = false; bool m_show_planes = false; -#endif // ENABLE_DEBUG_DIALOG +#endif // ENABLE_MEASURE_GIZMO_DEBUG void update_if_needed(); From 1787f780b60c02344f914087d280a6dd98877080 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 25 Aug 2022 13:01:26 +0200 Subject: [PATCH 028/250] Measuring: code for Measure gizmo embedded into new tech ENABLE_MEASURE_GIZMO --- src/libslic3r/Technologies.hpp | 4 +++- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 9 ++++----- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 11 ++++------- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 4 ++++ 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 58720801f8..5eadc8d098 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -78,8 +78,10 @@ // Enable picking using raytracing #define ENABLE_RAYCAST_PICKING (1 && ENABLE_LEGACY_OPENGL_REMOVAL) #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) +// Enable Measure Gizmo +#define ENABLE_MEASURE_GIZMO (1 && ENABLE_LEGACY_OPENGL_REMOVAL) // Enable debug code for Measure Gizmo -#define ENABLE_MEASURE_GIZMO_DEBUG (0 && ENABLE_2_5_0_ALPHA1) +#define ENABLE_MEASURE_GIZMO_DEBUG (0 && ENABLE_MEASURE_GIZMO) #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 7ca051c7d1..73ee87840a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -14,6 +14,8 @@ #include +#if ENABLE_MEASURE_GIZMO + namespace Slic3r { namespace GUI { @@ -261,11 +263,6 @@ void GLGizmoMeasure::on_render() -#if ! ENABLE_LEGACY_OPENGL_REMOVAL - #error NOT IMPLEMENTED -#endif - - void GLGizmoMeasure::update_if_needed() { auto update_plane_models_cache = [this](const indexed_triangle_set& its) { @@ -345,3 +342,5 @@ void GLGizmoMeasure::update_if_needed() } // namespace GUI } // namespace Slic3r + +#endif // ENABLE_MEASURE_GIZMO diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 49ab7fce8a..742c791131 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -1,15 +1,10 @@ #ifndef slic3r_GLGizmoMeasure_hpp_ #define slic3r_GLGizmoMeasure_hpp_ +#if ENABLE_MEASURE_GIZMO + #include "GLGizmoBase.hpp" -#if ENABLE_LEGACY_OPENGL_REMOVAL #include "slic3r/GUI/GLModel.hpp" -#else -#include "slic3r/GUI/3DScene.hpp" -#endif // ENABLE_LEGACY_OPENGL_REMOVAL - - -#include namespace Slic3r { @@ -80,4 +75,6 @@ protected: } // namespace GUI } // namespace Slic3r +#endif // ENABLE_MEASURE_GIZMO + #endif // slic3r_GLGizmoMeasure_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 6d25f84fbc..ff24dd84a3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -21,7 +21,9 @@ #include "slic3r/GUI/Gizmos/GLGizmoSeam.hpp" #include "slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp" #include "slic3r/GUI/Gizmos/GLGizmoSimplify.hpp" +#if ENABLE_MEASURE_GIZMO #include "slic3r/GUI/Gizmos/GLGizmoMeasure.hpp" +#endif // ENABLE_MEASURE_GIZMO #include "libslic3r/format.hpp" #include "libslic3r/Model.hpp" @@ -107,7 +109,9 @@ bool GLGizmosManager::init() m_gizmos.emplace_back(new GLGizmoSeam(m_parent, "seam.svg", 8)); m_gizmos.emplace_back(new GLGizmoMmuSegmentation(m_parent, "mmu_segmentation.svg", 9)); m_gizmos.emplace_back(new GLGizmoSimplify(m_parent, "cut.svg", 10)); +#if ENABLE_MEASURE_GIZMO m_gizmos.emplace_back(new GLGizmoMeasure(m_parent, "measure.svg", 11)); +#endif // ENABLE_MEASURE_GIZMO m_common_gizmos_data.reset(new CommonGizmosDataPool(&m_parent)); From 8833bc3138676461ed443f19f900e80e0402bac3 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 29 Aug 2022 12:55:34 +0200 Subject: [PATCH 029/250] Measuring: Measure gizmo features registered for raycasted picking --- src/libslic3r/Measure.hpp | 10 ++ src/libslic3r/Technologies.hpp | 2 +- src/slic3r/GUI/GLCanvas3D.cpp | 4 +- src/slic3r/GUI/GLCanvas3D.hpp | 2 +- src/slic3r/GUI/GLModel.cpp | 15 +++ src/slic3r/GUI/GLModel.hpp | 2 + src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 132 ++++++++++++++++--- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 16 ++- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 4 +- 10 files changed, 160 insertions(+), 29 deletions(-) diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 98517b991b..2f27a72598 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -49,6 +49,16 @@ public: // For anything, return an extra point that should also be considered a part of this. std::optional get_extra_point() const { assert(m_type != SurfaceFeatureType::Undef); return m_pt3; } + bool operator == (const SurfaceFeature& other) const { + if (this->m_type != other.m_type) return false; + if (!this->m_pt1.isApprox(other.m_pt1)) return false; + if (!this->m_pt2.isApprox(other.m_pt2)) return false; + if (this->m_pt3.has_value() && !other.m_pt3.has_value()) return false; + if (!this->m_pt3.has_value() && other.m_pt3.has_value()) return false; + if (this->m_pt3.has_value() && other.m_pt3.has_value() && !(*this->m_pt3).isApprox(*other.m_pt3)) return false; + return this->m_value == other.m_value; + } + private: SurfaceFeatureType m_type = SurfaceFeatureType::Undef; Vec3d m_pt1; diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 5eadc8d098..4e2011b3b4 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -79,7 +79,7 @@ #define ENABLE_RAYCAST_PICKING (1 && ENABLE_LEGACY_OPENGL_REMOVAL) #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) // Enable Measure Gizmo -#define ENABLE_MEASURE_GIZMO (1 && ENABLE_LEGACY_OPENGL_REMOVAL) +#define ENABLE_MEASURE_GIZMO (1 && ENABLE_RAYCAST_PICKING) // Enable debug code for Measure Gizmo #define ENABLE_MEASURE_GIZMO_DEBUG (0 && ENABLE_MEASURE_GIZMO) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index dcc0d2db4f..9c98a20e7a 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2234,7 +2234,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re #if ENABLE_LEGACY_OPENGL_REMOVAL volume.model.init_from(mesh); #if ENABLE_RAYCAST_PICKING - volume.mesh_raycaster = std::make_unique(std::make_shared(mesh)); + volume.mesh_raycaster = std::make_unique(std::make_shared(mesh)); #endif // ENABLE_RAYCAST_PICKING #else volume.indexed_vertex_array.load_mesh(mesh); @@ -2254,7 +2254,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re #if ENABLE_RAYCAST_PICKING const TriangleMesh& new_mesh = m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(); volume.model.init_from(new_mesh); - volume.mesh_raycaster = std::make_unique(std::make_shared(new_mesh)); + volume.mesh_raycaster = std::make_unique(std::make_shared(new_mesh)); #else volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh()); #endif // ENABLE_RAYCAST_PICKING diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 4b78b66d99..b058386f56 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -680,7 +680,7 @@ public: #if ENABLE_RAYCAST_PICKING std::shared_ptr add_raycaster_for_picking(SceneRaycaster::EType type, int id, const MeshRaycaster& raycaster, - const Transform3d& trafo, bool use_back_faces = false) { + const Transform3d& trafo = Transform3d::Identity(), bool use_back_faces = false) { return m_scene_raycaster.add_raycaster(type, id, raycaster, trafo, use_back_faces); } void remove_raycasters_for_picking(SceneRaycaster::EType type, int id) { diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index b36db83ad1..445711f885 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -278,6 +278,21 @@ void GLModel::Geometry::remove_vertex(size_t id) } } +indexed_triangle_set GLModel::Geometry::get_as_indexed_triangle_set() const +{ + indexed_triangle_set its; + its.vertices.reserve(vertices_count()); + for (size_t i = 0; i < vertices_count(); ++i) { + its.vertices.emplace_back(extract_position_3(i)); + } + its.indices.reserve(indices_count() / 3); + for (size_t i = 0; i < indices_count() / 3; ++i) { + const size_t tri_id = i * 3; + its.indices.emplace_back(extract_index(tri_id), extract_index(tri_id + 1), extract_index(tri_id + 2)); + } + return its; +} + size_t GLModel::Geometry::vertex_stride_floats(const Format& format) { switch (format.vertex_layout) diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index 8843d39eeb..d4d7307855 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -129,6 +129,8 @@ namespace GUI { size_t vertices_size_bytes() const { return vertices_size_floats() * sizeof(float); } size_t indices_size_bytes() const { return indices.size() * index_stride_bytes(*this); } + indexed_triangle_set get_as_indexed_triangle_set() const; + static size_t vertex_stride_floats(const Format& format); static size_t vertex_stride_bytes(const Format& format) { return vertex_stride_floats(format) * sizeof(float); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index bbae3f2429..99769e0061 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -114,7 +114,7 @@ void GLGizmoHollow::on_register_raycasters_for_picking() if (info != nullptr && !info->model_object()->sla_drain_holes.empty()) { const sla::DrainHoles& drain_holes = info->model_object()->sla_drain_holes; for (int i = 0; i < (int)drain_holes.size(); ++i) { - m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_cylinder.mesh_raycaster, Transform3d::Identity())); + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_cylinder.mesh_raycaster)); } update_raycasters_for_picking_transform(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 73ee87840a..e132cf2ce1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -7,7 +7,6 @@ #include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include "libslic3r/Model.hpp" -#include "libslic3r/Measure.hpp" #include "libslic3r/PresetBundle.hpp" #include @@ -20,12 +19,22 @@ namespace Slic3r { namespace GUI { static const Slic3r::ColorRGBA HOVER_COLOR = { 0.8f, 0.2f, 0.2f, 1.0f }; +static const int POINT_ID = 100; +static const int EDGE_ID = 200; +static const int CIRCLE_ID = 300; +static const int CIRCLE_CENTER_ID = 301; +static const int PLANE_ID = 400; GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) { - m_sphere.init_from(smooth_sphere(16, 7.5f)); - m_cylinder.init_from(smooth_cylinder(16, 5.0f, 1.0f)); + GLModel::Geometry sphere_geometry = smooth_sphere(16, 7.5f); + m_sphere.mesh_raycaster = std::make_unique(std::make_shared(std::move(sphere_geometry.get_as_indexed_triangle_set()))); + m_sphere.model.init_from(std::move(sphere_geometry)); + + GLModel::Geometry cylinder_geometry = smooth_cylinder(16, 5.0f, 1.0f); + m_cylinder.mesh_raycaster = std::make_unique(std::make_shared(std::move(cylinder_geometry.get_as_indexed_triangle_set()))); + m_cylinder.model.init_from(std::move(cylinder_geometry)); } bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) @@ -130,6 +139,7 @@ void GLGizmoMeasure::on_render() const Transform3d& model_matrix = selection.get_first_volume()->world_matrix(); const Camera& camera = wxGetApp().plater()->get_camera(); + const float inv_zoom = (float)camera.get_inv_zoom(); Vec3f pos; Vec3f normal; @@ -174,8 +184,70 @@ void GLGizmoMeasure::on_render() } #endif // ENABLE_MEASURE_GIZMO_DEBUG - if (features.empty()) - return; + if (m_features != features) { + GLGizmoMeasure::on_unregister_raycasters_for_picking(); + m_features = features; + if (m_features.empty()) + return; + +#if !ENABLE_MEASURE_GIZMO_DEBUG + for (const Measure::SurfaceFeature& feature : m_features) { + switch (feature.get_type()) { + case Measure::SurfaceFeatureType::Point: + { + m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, n] = feature.get_circle(); + m_circle.reset(); + GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); + m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); + m_circle.model.init_from(std::move(circle_geometry)); + + m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); + m_raycasters.insert({ CIRCLE_CENTER_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_CENTER_ID, *m_sphere.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto& [idx, normal, pt] = feature.get_plane(); + const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); + const std::vector& triangle_indices = planes_triangles[idx]; + + const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; + GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + unsigned int i = 0; + for (int idx : triangle_indices) { + const Vec3f& v0 = its.vertices[its.indices[idx][0]]; + const Vec3f& v1 = its.vertices[its.indices[idx][1]]; + const Vec3f& v2 = its.vertices[its.indices[idx][2]]; + + const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); + init_data.add_vertex(v0, n); + init_data.add_vertex(v1, n); + init_data.add_vertex(v2, n); + init_data.add_triangle(i, i + 1, i + 2); + i += 3; + } + + m_plane.reset(); + m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(init_data.get_as_indexed_triangle_set()))); + m_plane.model.init_from(std::move(init_data)); + m_raycasters.insert({ PLANE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID, *m_plane.mesh_raycaster) }); + break; + } + } + } +#endif // !ENABLE_MEASURE_GIZMO_DEBUG + } GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) @@ -189,9 +261,8 @@ void GLGizmoMeasure::on_render() glsafe(::glEnable(GL_DEPTH_TEST)); const Transform3d& view_matrix = camera.get_view_matrix(); - const float inv_zoom = camera.get_inv_zoom(); - for (const Measure::SurfaceFeature& feature : features) { + for (const Measure::SurfaceFeature& feature : m_features) { switch (feature.get_type()) { case Measure::SurfaceFeatureType::Point: { @@ -201,8 +272,11 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_sphere.set_color(HOVER_COLOR); - m_sphere.render(); + m_sphere.model.set_color(HOVER_COLOR); + m_sphere.model.render(); + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); break; } case Measure::SurfaceFeatureType::Circle: @@ -214,19 +288,22 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", center_view_model_matrix); const Matrix3d center_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * center_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", center_view_normal_matrix); - m_sphere.set_color(HOVER_COLOR); - m_sphere.render(); - - m_circle.reset(); - m_circle.init_from(smooth_torus(64, 16, float(radius), 5.0f * inv_zoom)); + m_sphere.model.set_color(HOVER_COLOR); + m_sphere.model.render(); + auto it = m_raycasters.find(CIRCLE_CENTER_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(center_matrix); const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center); const Transform3d circle_view_model_matrix = view_matrix * circle_matrix; shader->set_uniform("view_model_matrix", circle_view_model_matrix); const Matrix3d circle_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * circle_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", circle_view_normal_matrix); - m_circle.set_color(HOVER_COLOR); - m_circle.render(); + m_circle.model.set_color(HOVER_COLOR); + m_circle.model.render(); + it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(circle_matrix); break; } case Measure::SurfaceFeatureType::Edge: @@ -239,8 +316,11 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_cylinder.set_color(HOVER_COLOR); - m_cylinder.render(); + m_cylinder.model.set_color(HOVER_COLOR); + m_cylinder.model.render(); + auto it = m_raycasters.find(EDGE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); break; } case Measure::SurfaceFeatureType::Plane: @@ -253,6 +333,9 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_normal_matrix", view_normal_matrix); m_plane_models_cache[idx].set_color(HOVER_COLOR); m_plane_models_cache[idx].render(); + auto it = m_raycasters.find(PLANE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(model_matrix); break; } } @@ -340,6 +423,19 @@ void GLGizmoMeasure::update_if_needed() } } +void GLGizmoMeasure::on_register_raycasters_for_picking() +{ + // the features are rendered on top of the scene, so the raytraced picker should take it into account + m_parent.set_raycaster_gizmos_on_top(true); +} + +void GLGizmoMeasure::on_unregister_raycasters_for_picking() +{ + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo); + m_parent.set_raycaster_gizmos_on_top(false); + m_raycasters.clear(); +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 742c791131..9decf82fdc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -5,6 +5,7 @@ #include "GLGizmoBase.hpp" #include "slic3r/GUI/GLModel.hpp" +#include "libslic3r/Measure.hpp" namespace Slic3r { @@ -25,10 +26,14 @@ class GLGizmoMeasure : public GLGizmoBase private: std::unique_ptr m_measuring; - GLModel m_sphere; - GLModel m_cylinder; - GLModel m_circle; + PickingModel m_sphere; + PickingModel m_cylinder; + PickingModel m_circle; + PickingModel m_plane; + std::vector m_plane_models_cache; + std::map> m_raycasters; + std::vector m_features; // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; @@ -53,7 +58,7 @@ private: public: GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); - + /// /// Apply rotation on select plane /// @@ -70,6 +75,9 @@ protected: void on_render() override; void on_set_state() override; CommonGizmosDataID on_get_requirements() const override; + + virtual void on_register_raycasters_for_picking() override; + virtual void on_unregister_raycasters_for_picking() override; }; } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 026fae17b6..237b101617 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -148,8 +148,8 @@ void GLGizmoSlaSupports::on_register_raycasters_for_picking() if (m_editing_mode && !m_editing_cache.empty()) { for (size_t i = 0; i < m_editing_cache.size(); ++i) { - m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_sphere.mesh_raycaster, Transform3d::Identity()), - m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_cone.mesh_raycaster, Transform3d::Identity())); + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_sphere.mesh_raycaster), + m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_cone.mesh_raycaster)); } update_raycasters_for_picking_transform(); } From 4675ae2173ff2a9477f77b5bc321c8ee85e504ac Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 30 Aug 2022 14:30:38 +0200 Subject: [PATCH 030/250] Measuring: Added Measure gizmo imgui dialog + removed tech ENABLE_MEASURE_GIZMO_DEBUG + locking of features by pressing CTRL key --- src/libslic3r/Measure.cpp | 2 - src/libslic3r/Measure.hpp | 6 +- src/libslic3r/Technologies.hpp | 2 - src/slic3r/GUI/GLCanvas3D.hpp | 5 + src/slic3r/GUI/GUI_Utils.hpp | 12 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 365 ++++++++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 19 +- src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 4 + src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 58 ++-- 9 files changed, 311 insertions(+), 162 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 9cb46edfc1..cdde276dda 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -408,12 +408,10 @@ Measuring::Measuring(const indexed_triangle_set& its) Measuring::~Measuring() {} -#if ENABLE_MEASURE_GIZMO_DEBUG std::vector Measuring::get_all_features() const { return priv->get_all_features(); } -#endif // ENABLE_MEASURE_GIZMO_DEBUG std::optional Measuring::get_feature(size_t face_idx, const Vec3d& point) const diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 2f27a72598..95d8f34cba 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -59,6 +59,10 @@ public: return this->m_value == other.m_value; } + bool operator != (const SurfaceFeature& other) const { + return !operator == (other); + } + private: SurfaceFeatureType m_type = SurfaceFeatureType::Undef; Vec3d m_pt1; @@ -79,11 +83,9 @@ public: explicit Measuring(const indexed_triangle_set& its); ~Measuring(); -#if ENABLE_MEASURE_GIZMO_DEBUG // Return a reference to a list of all features identified on the its. // Use only for debugging. Expensive, do not call often. std::vector get_all_features() const; -#endif // ENABLE_MEASURE_GIZMO_DEBUG // Given a face_idx where the mouse cursor points, return a feature that // should be highlighted (if any). diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 4e2011b3b4..a5125fba95 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -80,8 +80,6 @@ #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) // Enable Measure Gizmo #define ENABLE_MEASURE_GIZMO (1 && ENABLE_RAYCAST_PICKING) -// Enable debug code for Measure Gizmo -#define ENABLE_MEASURE_GIZMO_DEBUG (0 && ENABLE_MEASURE_GIZMO) #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index b058386f56..effd15d5cb 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -19,6 +19,9 @@ #if ENABLE_RAYCAST_PICKING #include "SceneRaycaster.hpp" #endif // ENABLE_RAYCAST_PICKING +#if ENABLE_MEASURE_GIZMO +#include "GUI_Utils.hpp" +#endif // ENABLE_MEASURE_GIZMO #include "libslic3r/Slicing.hpp" @@ -135,6 +138,7 @@ private: wxTimer* m_timer; }; +#if !ENABLE_MEASURE_GIZMO class KeyAutoRepeatFilter { size_t m_count{ 0 }; @@ -144,6 +148,7 @@ public: void reset_count() { m_count = 0; } bool is_first() const { return m_count == 0; } }; +#endif // !ENABLE_MEASURE_GIZMO wxDECLARE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index d7d3529fee..e2152edd6d 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -416,6 +416,18 @@ public: ~TaskTimer(); }; +#if ENABLE_MEASURE_GIZMO +class KeyAutoRepeatFilter +{ + size_t m_count{ 0 }; + +public: + void increase_count() { ++m_count; } + void reset_count() { m_count = 0; } + bool is_first() const { return m_count == 0; } +}; +#endif // ENABLE_MEASURE_GIZMO + }} #endif diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index e132cf2ce1..2a856fb830 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -15,10 +15,26 @@ #if ENABLE_MEASURE_GIZMO +std::string surface_feature_type_as_string(Slic3r::Measure::SurfaceFeatureType type) +{ + switch (type) + { + default: + case Slic3r::Measure::SurfaceFeatureType::Undef: { return L("Undefined"); } + case Slic3r::Measure::SurfaceFeatureType::Point: { return L("Point"); } + case Slic3r::Measure::SurfaceFeatureType::Edge: { return L("Edge"); } + case Slic3r::Measure::SurfaceFeatureType::Circle: { return L("Circle"); } + case Slic3r::Measure::SurfaceFeatureType::Plane: { return L("Plane"); } + } +} + namespace Slic3r { namespace GUI { -static const Slic3r::ColorRGBA HOVER_COLOR = { 0.8f, 0.2f, 0.2f, 1.0f }; +static const Slic3r::ColorRGBA BASIC_HOVER_COLOR = { 0.8f, 0.2f, 0.2f, 1.0f }; +static const Slic3r::ColorRGBA EXTENDED_HOVER_COLOR = { 0.2f, 0.8f, 0.2f, 1.0f }; +static const Slic3r::ColorRGBA LOCK_COLOR = { 0.5f, 0.5f, 0.5f, 1.0f }; + static const int POINT_ID = 100; static const int EDGE_ID = 200; static const int CIRCLE_ID = 300; @@ -42,40 +58,39 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) m_mouse_pos_x = mouse_event.GetX(); m_mouse_pos_y = mouse_event.GetY(); - if (mouse_event.Moving()) { // only for sure m_mouse_left_down = false; return false; } - if (mouse_event.LeftDown()) { + else if (mouse_event.LeftDown()) { if (m_hover_id != -1) { - m_mouse_left_down = true; - + m_mouse_left_down = true; return true; } // fix: prevent restart gizmo when reselect object // take responsibility for left up - if (m_parent.get_first_hover_volume_idx() >= 0) m_mouse_left_down = true; + if (m_parent.get_first_hover_volume_idx() >= 0) + m_mouse_left_down = true; - } else if (mouse_event.LeftUp()) { + } + else if (mouse_event.LeftUp()) { if (m_mouse_left_down) { // responsible for mouse left up after selecting plane m_mouse_left_down = false; return true; } - } else if (mouse_event.Leaving()) { - m_mouse_left_down = false; } + else if (mouse_event.Leaving()) + m_mouse_left_down = false; + return false; } - - void GLGizmoMeasure::data_changed() { - const Selection & selection = m_parent.get_selection(); + const Selection& selection = m_parent.get_selection(); const ModelObject* model_object = nullptr; const ModelVolume* model_volume = nullptr; if (selection.is_single_full_instance() || @@ -87,29 +102,43 @@ void GLGizmoMeasure::data_changed() update_if_needed(); } - - -bool GLGizmoMeasure::on_init() +bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) { - // FIXME m_shortcut_key = WXK_CONTROL_F; + if (action == SLAGizmoEventType::CtrlDown) { + if (m_ctrl_kar_filter.is_first()) { + if (!m_features.empty()) + m_mode = EMode::ExtendedSelection; + } + + m_ctrl_kar_filter.increase_count(); + } + else if (action == SLAGizmoEventType::CtrlUp) { + m_ctrl_kar_filter.reset_count(); + m_mode = EMode::BasicSelection; + } + return true; } - +bool GLGizmoMeasure::on_init() +{ + m_shortcut_key = WXK_CONTROL_U; + return true; +} void GLGizmoMeasure::on_set_state() { + if (m_state == Off) + m_ctrl_kar_filter.reset_count(); + else + m_mode = EMode::BasicSelection; } - - CommonGizmosDataID GLGizmoMeasure::on_get_requirements() const { return CommonGizmosDataID(int(CommonGizmosDataID::SelectionInfo) | int(CommonGizmosDataID::Raycaster)); } - - std::string GLGizmoMeasure::on_get_name() const { return _u8L("Measure"); @@ -125,11 +154,9 @@ bool GLGizmoMeasure::on_is_activable() const void GLGizmoMeasure::on_render() { -#if !ENABLE_MEASURE_GIZMO_DEBUG // do not render if the user is panning/rotating the 3d scene if (m_parent.is_mouse_dragging()) return; -#endif // !ENABLE_MEASURE_GIZMO_DEBUG const Selection& selection = m_parent.get_selection(); @@ -146,107 +173,76 @@ void GLGizmoMeasure::on_render() size_t facet_idx; m_c->raycaster()->raycasters().front()->unproject_on_mesh(Vec2d(m_mouse_pos_x, m_mouse_pos_y), model_matrix, camera, pos, normal, nullptr, &facet_idx); -#if ENABLE_MEASURE_GIZMO_DEBUG - m_imgui->begin(std::string("DEBUG")); - m_imgui->checkbox(wxString("Show all features"), m_show_all); - m_imgui->checkbox(wxString("Show all planes"), m_show_planes); - ImGui::Separator(); - m_imgui->text(std::string("face_idx: ") + std::to_string(facet_idx)); - m_imgui->text(std::string("pos_x: ") + std::to_string(pos.x())); - m_imgui->text(std::string("pos_y: ") + std::to_string(pos.y())); - m_imgui->text(std::string("pos_z: ") + std::to_string(pos.z())); - m_imgui->end(); -#endif // ENABLE_MEASURE_GIZMO_DEBUG - std::vector features; -#if ENABLE_MEASURE_GIZMO_DEBUG - if (m_show_all || m_show_planes) { - features = m_measuring->get_all_features(); - if (!m_show_planes) - features.erase(std::remove_if(features.begin(), features.end(), - [](const Measure::SurfaceFeature& f) { - return f.get_type() == Measure::SurfaceFeatureType::Plane; - }), features.end()); - if (!m_show_all) - features.erase(std::remove_if(features.begin(), features.end(), - [](const Measure::SurfaceFeature& f) { - return f.get_type() != Measure::SurfaceFeatureType::Plane; - }), features.end()); + if (m_mode == EMode::BasicSelection) { + std::optional feat = m_measuring->get_feature(facet_idx, pos.cast()); + if (feat.has_value()) + features.emplace_back(*feat); } - else { - if (!m_parent.is_mouse_dragging()) { -#endif // ENABLE_MEASURE_GIZMO_DEBUG - std::optional feat = m_measuring->get_feature(facet_idx, pos.cast()); - if (feat.has_value()) - features.emplace_back(*feat); -#if ENABLE_MEASURE_GIZMO_DEBUG - } - } -#endif // ENABLE_MEASURE_GIZMO_DEBUG - if (m_features != features) { - GLGizmoMeasure::on_unregister_raycasters_for_picking(); - m_features = features; - if (m_features.empty()) - return; + if (m_mode == EMode::BasicSelection) { + if (m_features != features) { + GLGizmoMeasure::on_unregister_raycasters_for_picking(); + m_features = features; + if (m_features.empty()) + return; -#if !ENABLE_MEASURE_GIZMO_DEBUG - for (const Measure::SurfaceFeature& feature : m_features) { - switch (feature.get_type()) { - case Measure::SurfaceFeatureType::Point: - { - m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); - break; - } - case Measure::SurfaceFeatureType::Edge: - { - m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); - break; - } - case Measure::SurfaceFeatureType::Circle: - { - const auto& [center, radius, n] = feature.get_circle(); - m_circle.reset(); - GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); - m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); - m_circle.model.init_from(std::move(circle_geometry)); - - m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); - m_raycasters.insert({ CIRCLE_CENTER_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_CENTER_ID, *m_sphere.mesh_raycaster) }); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - const auto& [idx, normal, pt] = feature.get_plane(); - const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); - const std::vector& triangle_indices = planes_triangles[idx]; - - const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; - GLModel::Geometry init_data; - init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; - unsigned int i = 0; - for (int idx : triangle_indices) { - const Vec3f& v0 = its.vertices[its.indices[idx][0]]; - const Vec3f& v1 = its.vertices[its.indices[idx][1]]; - const Vec3f& v2 = its.vertices[its.indices[idx][2]]; - - const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); - init_data.add_vertex(v0, n); - init_data.add_vertex(v1, n); - init_data.add_vertex(v2, n); - init_data.add_triangle(i, i + 1, i + 2); - i += 3; + for (const Measure::SurfaceFeature& feature : m_features) { + switch (feature.get_type()) { + case Measure::SurfaceFeatureType::Point: + { + m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); + break; } + case Measure::SurfaceFeatureType::Edge: + { + m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, n] = feature.get_circle(); + m_circle.reset(); + GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); + m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); + m_circle.model.init_from(std::move(circle_geometry)); - m_plane.reset(); - m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(init_data.get_as_indexed_triangle_set()))); - m_plane.model.init_from(std::move(init_data)); - m_raycasters.insert({ PLANE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID, *m_plane.mesh_raycaster) }); - break; - } + m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); + m_raycasters.insert({ CIRCLE_CENTER_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_CENTER_ID, *m_sphere.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto& [idx, normal, pt] = feature.get_plane(); + const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); + const std::vector& triangle_indices = planes_triangles[idx]; + + const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; + GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + unsigned int i = 0; + for (int idx : triangle_indices) { + const Vec3f& v0 = its.vertices[its.indices[idx][0]]; + const Vec3f& v1 = its.vertices[its.indices[idx][1]]; + const Vec3f& v2 = its.vertices[its.indices[idx][2]]; + + const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); + init_data.add_vertex(v0, n); + init_data.add_vertex(v1, n); + init_data.add_vertex(v2, n); + init_data.add_triangle(i, i + 1, i + 2); + i += 3; + } + + m_plane.reset(); + m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(init_data.get_as_indexed_triangle_set()))); + m_plane.model.init_from(std::move(init_data)); + m_raycasters.insert({ PLANE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID, *m_plane.mesh_raycaster) }); + break; + } + } } } -#endif // !ENABLE_MEASURE_GIZMO_DEBUG } GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); @@ -262,6 +258,13 @@ void GLGizmoMeasure::on_render() const Transform3d& view_matrix = camera.get_view_matrix(); + ColorRGBA color; + switch (m_mode) + { + case EMode::BasicSelection: { color = BASIC_HOVER_COLOR; break; } + case EMode::ExtendedSelection: { color = LOCK_COLOR; break; } + } + for (const Measure::SurfaceFeature& feature : m_features) { switch (feature.get_type()) { case Measure::SurfaceFeatureType::Point: @@ -272,7 +275,7 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_sphere.model.set_color(HOVER_COLOR); + m_sphere.model.set_color(color); m_sphere.model.render(); auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) @@ -288,7 +291,7 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", center_view_model_matrix); const Matrix3d center_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * center_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", center_view_normal_matrix); - m_sphere.model.set_color(HOVER_COLOR); + m_sphere.model.set_color(color); m_sphere.model.render(); auto it = m_raycasters.find(CIRCLE_CENTER_ID); if (it != m_raycasters.end() && it->second != nullptr) @@ -299,7 +302,7 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", circle_view_model_matrix); const Matrix3d circle_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * circle_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", circle_view_normal_matrix); - m_circle.model.set_color(HOVER_COLOR); + m_circle.model.set_color(color); m_circle.model.render(); it = m_raycasters.find(CIRCLE_ID); if (it != m_raycasters.end() && it->second != nullptr) @@ -316,7 +319,7 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_cylinder.model.set_color(HOVER_COLOR); + m_cylinder.model.set_color(color); m_cylinder.model.render(); auto it = m_raycasters.find(EDGE_ID); if (it != m_raycasters.end() && it->second != nullptr) @@ -331,7 +334,7 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_plane_models_cache[idx].set_color(HOVER_COLOR); + m_plane_models_cache[idx].set_color(color); m_plane_models_cache[idx].render(); auto it = m_raycasters.find(PLANE_ID); if (it != m_raycasters.end() && it->second != nullptr) @@ -344,8 +347,6 @@ void GLGizmoMeasure::on_render() } } - - void GLGizmoMeasure::update_if_needed() { auto update_plane_models_cache = [this](const indexed_triangle_set& its) { @@ -423,6 +424,124 @@ void GLGizmoMeasure::update_if_needed() } } +void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit) +{ + static Measure::SurfaceFeature last_feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Undef, Vec3d::Zero(), Vec3d::Zero(), std::nullopt, 0.0); + + static float last_y = 0.0f; + static float last_h = 0.0f; + + m_imgui->begin(_L("Measure tool"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + + // adjust window position to avoid overlap the view toolbar + const float win_h = ImGui::GetWindowHeight(); + y = std::min(y, bottom_limit - win_h); + ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always); + if (last_h != win_h || last_y != y) { + // ask canvas for another frame to render the window in the correct position + m_imgui->set_requires_extra_frame(); + if (last_h != win_h) + last_h = win_h; + if (last_y != y) + last_y = y; + } + + if (m_features.empty()) + m_imgui->text(_u8L("Select features to measure")); + + auto add_row_to_table = [this](const wxString& label, const std::string& value) { + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, label); + ImGui::TableSetColumnIndex(1); + m_imgui->text(value); + }; + + const Transform3d volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); + Measure::SurfaceFeature curr_feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Undef, Vec3d::Zero(), Vec3d::Zero(), std::nullopt, 0.0); + for (size_t i = 0; i < m_features.size(); ++i) { + curr_feature = m_features[i]; + const Measure::SurfaceFeatureType type = curr_feature.get_type(); + if (type != Measure::SurfaceFeatureType::Undef) { + const std::string header = surface_feature_type_as_string(type) + std::string("##") + std::to_string(i); + if (ImGui::CollapsingHeader(header.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { + if (ImGui::BeginTable("Data", 2)) { + switch (type) + { + case Measure::SurfaceFeatureType::Point: + { + const Vec3d position = volume_matrix * curr_feature.get_point(); + char buf[1024]; + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", position.x(), position.y(), position.z()); + add_row_to_table(_u8L("Position") + ":", std::string(buf)); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + auto [from, to] = curr_feature.get_edge(); + from = volume_matrix * from; + to = volume_matrix * to; + char buf[1024]; + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", from.x(), from.y(), from.z()); + add_row_to_table(_u8L("From") + ":", std::string(buf)); + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", to.x(), to.y(), to.z()); + add_row_to_table(_u8L("To") + ":", std::string(buf)); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + auto [center, radius, normal] = curr_feature.get_circle(); + center = volume_matrix * center; + normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + char buf[1024]; + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", center.x(), center.y(), center.z()); + add_row_to_table(_u8L("Center") + ":", std::string(buf)); + sprintf(buf, "%.3f", radius); + add_row_to_table(_u8L("Radius") + ":", std::string(buf)); + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", normal.x(), normal.y(), normal.z()); + add_row_to_table(_u8L("Normal") + ":", std::string(buf)); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + auto [idx, normal, origin] = curr_feature.get_plane(); + origin = volume_matrix * origin; + normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + char buf[1024]; + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", origin.x(), origin.y(), origin.z()); + add_row_to_table(_u8L("Origin") + ":", std::string(buf)); + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", normal.x(), normal.y(), normal.z()); + add_row_to_table(_u8L("Normal") + ":", std::string(buf)); + break; + } + } + ImGui::EndTable(); + } + } + } + } + + if (last_feature != curr_feature) { + // the dialog may have changed its size, ask for an extra frame to render it properly + last_feature = curr_feature; + m_imgui->set_requires_extra_frame(); + } + + if (!m_features.empty()) { + static const std::string ctrl = +#ifdef __APPLE__ + "⌘" +#else + "Ctrl" +#endif //__APPLE__ + ; + + ImGui::Separator(); + m_imgui->text(_u8L("Press") + " " + ctrl + " " + _u8L("to enable extended selection")); + } + m_imgui->end(); +} + void GLGizmoMeasure::on_register_raycasters_for_picking() { // the features are rendered on top of the scene, so the raytraced picker should take it into account diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 9decf82fdc..13c46a48d9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -5,6 +5,7 @@ #include "GLGizmoBase.hpp" #include "slic3r/GUI/GLModel.hpp" +#include "slic3r/GUI/GUI_Utils.hpp" #include "libslic3r/Measure.hpp" namespace Slic3r { @@ -18,12 +19,19 @@ namespace Measure { class Measuring; } namespace GUI { +enum class SLAGizmoEventType : unsigned char; class GLGizmoMeasure : public GLGizmoBase { // This gizmo does not use grabbers. The m_hover_id relates to polygon managed by the class itself. -private: + enum class EMode : unsigned char + { + BasicSelection, + ExtendedSelection + }; + + EMode m_mode{ EMode::BasicSelection }; std::unique_ptr m_measuring; PickingModel m_sphere; @@ -49,10 +57,8 @@ private: int m_mouse_pos_x; int m_mouse_pos_y; -#if ENABLE_MEASURE_GIZMO_DEBUG - bool m_show_all = false; - bool m_show_planes = false; -#endif // ENABLE_MEASURE_GIZMO_DEBUG + + KeyAutoRepeatFilter m_ctrl_kar_filter; void update_if_needed(); @@ -68,6 +74,8 @@ public: void data_changed() override; + bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); + protected: bool on_init() override; std::string on_get_name() const override; @@ -76,6 +84,7 @@ protected: void on_set_state() override; CommonGizmosDataID on_get_requirements() const override; + virtual void on_render_input_window(float x, float y, float bottom_limit) override; virtual void on_register_raycasters_for_picking() override; virtual void on_unregister_raycasters_for_picking() override; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index c8b29f761e..c3aa1691f1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -24,6 +24,10 @@ enum class SLAGizmoEventType : unsigned char { Dragging, Delete, SelectAll, +#if ENABLE_MEASURE_GIZMO + CtrlDown, + CtrlUp, +#endif // ENABLE_MEASURE_GIZMO ShiftUp, AltUp, ApplyChanges, diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index ff24dd84a3..fbf0afe13a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -294,6 +294,10 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p return dynamic_cast(m_gizmos[Seam].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); else if (m_current == MmuSegmentation) return dynamic_cast(m_gizmos[MmuSegmentation].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); +#if ENABLE_MEASURE_GIZMO + else if (m_current == Measure) + return dynamic_cast(m_gizmos[Measure].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); +#endif // ENABLE_MEASURE_GIZMO else return false; } @@ -499,8 +503,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) bool processed = false; - if ((evt.GetModifiers() & ctrlMask) != 0) - { + if ((evt.GetModifiers() & ctrlMask) != 0) { switch (keyCode) { #ifdef __APPLE__ @@ -518,15 +521,13 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) } } } - else if (!evt.HasModifiers()) - { + else if (!evt.HasModifiers()) { switch (keyCode) { // key ESC case WXK_ESCAPE: { - if (m_current != Undefined) - { + if (m_current != Undefined) { if ((m_current != SlaSupports) || !gizmo_event(SLAGizmoEventType::DiscardChanges)) reset_all_states(); @@ -563,8 +564,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) case 'A': case 'a': { - if (m_current == SlaSupports) - { + if (m_current == SlaSupports) { gizmo_event(SLAGizmoEventType::AutomaticGeneration); // set as processed no matter what's returned by gizmo_event() to avoid the calling canvas to process 'A' as arrange processed = true; @@ -582,8 +582,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) case 'F': case 'f': { - if (m_current == Scale) - { + if (m_current == Scale) { if (!is_dragging()) wxGetApp().plater()->scale_selection_to_fit_print_volume(); @@ -595,8 +594,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) } } - if (!processed && !evt.HasModifiers()) - { + if (!processed && !evt.HasModifiers()) { if (handle_shortcut(keyCode)) processed = true; } @@ -612,10 +610,8 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) const int keyCode = evt.GetKeyCode(); bool processed = false; - if (evt.GetEventType() == wxEVT_KEY_UP) - { - if (m_current == SlaSupports || m_current == Hollow) - { + if (evt.GetEventType() == wxEVT_KEY_UP) { + if (m_current == SlaSupports || m_current == Hollow) { bool is_editing = true; bool is_rectangle_dragging = false; @@ -629,33 +625,33 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) is_rectangle_dragging = gizmo->is_selection_rectangle_dragging(); } - if (keyCode == WXK_SHIFT) - { + if (keyCode == WXK_SHIFT) { // shift has been just released - SLA gizmo might want to close rectangular selection. if (gizmo_event(SLAGizmoEventType::ShiftUp) || (is_editing && is_rectangle_dragging)) processed = true; } - else if (keyCode == WXK_ALT) - { + else if (keyCode == WXK_ALT) { // alt has been just released - SLA gizmo might want to close rectangular selection. if (gizmo_event(SLAGizmoEventType::AltUp) || (is_editing && is_rectangle_dragging)) processed = true; } } +#if ENABLE_MEASURE_GIZMO + else if (m_current == Measure && keyCode == WXK_CONTROL) { + gizmo_event(SLAGizmoEventType::CtrlUp, Vec2d::Zero(), false); + } +#endif // ENABLE_MEASURE_GIZMO // if (processed) // m_parent.set_cursor(GLCanvas3D::Standard); } - else if (evt.GetEventType() == wxEVT_KEY_DOWN) - { - if ((m_current == SlaSupports) && ((keyCode == WXK_SHIFT) || (keyCode == WXK_ALT)) - && dynamic_cast(get_current())->is_in_editing_mode()) - { + else if (evt.GetEventType() == wxEVT_KEY_DOWN) { + if (m_current == SlaSupports && (keyCode == WXK_SHIFT || keyCode == WXK_ALT) + && dynamic_cast(get_current())->is_in_editing_mode()) { // m_parent.set_cursor(GLCanvas3D::Cross); processed = true; } - else if (m_current == Cut) - { + else if (m_current == Cut) { auto do_move = [this, &processed](double delta_z) { GLGizmoCut* cut = dynamic_cast(get_current()); cut->set_cut_z(delta_z + cut->get_cut_z()); @@ -668,11 +664,17 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) case WXK_NUMPAD_DOWN: case WXK_DOWN: { do_move(-1.0); break; } default: { break; } } - } else if (m_current == Simplify && keyCode == WXK_ESCAPE) { + } + else if (m_current == Simplify && keyCode == WXK_ESCAPE) { GLGizmoSimplify *simplify = dynamic_cast(get_current()); if (simplify != nullptr) processed = simplify->on_esc_key_down(); } +#if ENABLE_MEASURE_GIZMO + else if (m_current == Measure && keyCode == WXK_CONTROL) { + gizmo_event(SLAGizmoEventType::CtrlDown, Vec2d::Zero(), true); + } +#endif // ENABLE_MEASURE_GIZMO } if (processed) From db1b2fbfc111f98ae2f9f380e53cead6b7b5b433 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 30 Aug 2022 15:38:29 +0200 Subject: [PATCH 031/250] Refactoring of GLGizmoMeasure to simplify code --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 329 ++++++++++++----------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 7 +- 2 files changed, 167 insertions(+), 169 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 2a856fb830..2c040c9c3b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -55,8 +55,7 @@ GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filen bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) { - m_mouse_pos_x = mouse_event.GetX(); - m_mouse_pos_y = mouse_event.GetY(); + m_mouse_pos = { double(mouse_event.GetX()), double(mouse_event.GetY()) }; if (mouse_event.Moving()) { // only for sure @@ -106,7 +105,7 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po { if (action == SLAGizmoEventType::CtrlDown) { if (m_ctrl_kar_filter.is_first()) { - if (!m_features.empty()) + if (m_curr_feature.has_value()) m_mode = EMode::ExtendedSelection; } @@ -171,80 +170,84 @@ void GLGizmoMeasure::on_render() Vec3f pos; Vec3f normal; size_t facet_idx; - m_c->raycaster()->raycasters().front()->unproject_on_mesh(Vec2d(m_mouse_pos_x, m_mouse_pos_y), model_matrix, camera, pos, normal, nullptr, &facet_idx); + m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, model_matrix, camera, pos, normal, nullptr, &facet_idx); - std::vector features; - if (m_mode == EMode::BasicSelection) { - std::optional feat = m_measuring->get_feature(facet_idx, pos.cast()); - if (feat.has_value()) - features.emplace_back(*feat); - } + std::optional curr_feature; + if (m_mode == EMode::BasicSelection) + curr_feature = m_measuring->get_feature(facet_idx, pos.cast()); if (m_mode == EMode::BasicSelection) { - if (m_features != features) { + if (m_curr_feature != curr_feature) { GLGizmoMeasure::on_unregister_raycasters_for_picking(); - m_features = features; - if (m_features.empty()) + m_curr_feature = curr_feature; + if (!m_curr_feature.has_value()) return; - for (const Measure::SurfaceFeature& feature : m_features) { - switch (feature.get_type()) { - case Measure::SurfaceFeatureType::Point: - { - m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); - break; - } - case Measure::SurfaceFeatureType::Edge: - { - m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); - break; - } - case Measure::SurfaceFeatureType::Circle: - { - const auto& [center, radius, n] = feature.get_circle(); - m_circle.reset(); - GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); - m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); - m_circle.model.init_from(std::move(circle_geometry)); + switch (m_curr_feature->get_type()) { + case Measure::SurfaceFeatureType::Point: + { + m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, n] = m_curr_feature->get_circle(); - m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); - m_raycasters.insert({ CIRCLE_CENTER_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_CENTER_ID, *m_sphere.mesh_raycaster) }); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - const auto& [idx, normal, pt] = feature.get_plane(); - const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); - const std::vector& triangle_indices = planes_triangles[idx]; + // TODO: check for changed inv_zoom - const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; - GLModel::Geometry init_data; - init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; - unsigned int i = 0; - for (int idx : triangle_indices) { - const Vec3f& v0 = its.vertices[its.indices[idx][0]]; - const Vec3f& v1 = its.vertices[its.indices[idx][1]]; - const Vec3f& v2 = its.vertices[its.indices[idx][2]]; + m_circle.reset(); + GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); + m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); + m_circle.model.init_from(std::move(circle_geometry)); - const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); - init_data.add_vertex(v0, n); - init_data.add_vertex(v1, n); - init_data.add_vertex(v2, n); - init_data.add_triangle(i, i + 1, i + 2); - i += 3; - } + m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); + m_raycasters.insert({ CIRCLE_CENTER_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_CENTER_ID, *m_sphere.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto& [idx, normal, pt] = m_curr_feature->get_plane(); - m_plane.reset(); - m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(init_data.get_as_indexed_triangle_set()))); - m_plane.model.init_from(std::move(init_data)); - m_raycasters.insert({ PLANE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID, *m_plane.mesh_raycaster) }); - break; - } + // TODO: check for changed idx + + const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); + const std::vector& triangle_indices = planes_triangles[idx]; + + const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; + GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + unsigned int i = 0; + for (int idx : triangle_indices) { + const Vec3f& v0 = its.vertices[its.indices[idx][0]]; + const Vec3f& v1 = its.vertices[its.indices[idx][1]]; + const Vec3f& v2 = its.vertices[its.indices[idx][2]]; + + const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); + init_data.add_vertex(v0, n); + init_data.add_vertex(v1, n); + init_data.add_vertex(v2, n); + init_data.add_triangle(i, i + 1, i + 2); + i += 3; } + + m_plane.reset(); + m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(init_data.get_as_indexed_triangle_set()))); + m_plane.model.init_from(std::move(init_data)); + m_raycasters.insert({ PLANE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID, *m_plane.mesh_raycaster) }); + break; + } } } } + if (!m_curr_feature.has_value()) + return; + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) return; @@ -265,84 +268,84 @@ void GLGizmoMeasure::on_render() case EMode::ExtendedSelection: { color = LOCK_COLOR; break; } } - for (const Measure::SurfaceFeature& feature : m_features) { - switch (feature.get_type()) { - case Measure::SurfaceFeatureType::Point: - { - const Vec3d& position = feature.get_point(); - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); - const Transform3d view_model_matrix = view_matrix * feature_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_sphere.model.set_color(color); - m_sphere.model.render(); - auto it = m_raycasters.find(POINT_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(feature_matrix); - break; - } - case Measure::SurfaceFeatureType::Circle: - { - const auto& [center, radius, n] = feature.get_circle(); - // render center - const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); - const Transform3d center_view_model_matrix = view_matrix * center_matrix; - shader->set_uniform("view_model_matrix", center_view_model_matrix); - const Matrix3d center_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * center_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", center_view_normal_matrix); - m_sphere.model.set_color(color); - m_sphere.model.render(); - auto it = m_raycasters.find(CIRCLE_CENTER_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(center_matrix); - - const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center); - const Transform3d circle_view_model_matrix = view_matrix * circle_matrix; - shader->set_uniform("view_model_matrix", circle_view_model_matrix); - const Matrix3d circle_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * circle_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", circle_view_normal_matrix); - m_circle.model.set_color(color); - m_circle.model.render(); - it = m_raycasters.find(CIRCLE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(circle_matrix); - break; - } - case Measure::SurfaceFeatureType::Edge: - { - const auto& [start, end] = feature.get_edge(); - auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * q * - Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); - const Transform3d view_model_matrix = view_matrix * feature_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_cylinder.model.set_color(color); - m_cylinder.model.render(); - auto it = m_raycasters.find(EDGE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(feature_matrix); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - const auto& [idx, normal, pt] = feature.get_plane(); - assert(idx < m_plane_models_cache.size()); - const Transform3d view_model_matrix = view_matrix * model_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_plane_models_cache[idx].set_color(color); - m_plane_models_cache[idx].render(); - auto it = m_raycasters.find(PLANE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(model_matrix); - break; - } - } + switch (m_curr_feature->get_type()) { + case Measure::SurfaceFeatureType::Point: + { + const Vec3d& position = m_curr_feature->get_point(); + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); + const Transform3d view_model_matrix = view_matrix * feature_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); + m_sphere.model.set_color(color); + m_sphere.model.render(); + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); + break; } + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, n] = m_curr_feature->get_circle(); + // render center + const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); + const Transform3d center_view_model_matrix = view_matrix * center_matrix; + shader->set_uniform("view_model_matrix", center_view_model_matrix); + const Matrix3d center_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * center_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", center_view_normal_matrix); + m_sphere.model.set_color(color); + m_sphere.model.render(); + auto it = m_raycasters.find(CIRCLE_CENTER_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(center_matrix); + + // render circle + const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center); + const Transform3d circle_view_model_matrix = view_matrix * circle_matrix; + shader->set_uniform("view_model_matrix", circle_view_model_matrix); + const Matrix3d circle_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * circle_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", circle_view_normal_matrix); + m_circle.model.set_color(color); + m_circle.model.render(); + it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(circle_matrix); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + const auto& [start, end] = m_curr_feature->get_edge(); + auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * q * + Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); + const Transform3d view_model_matrix = view_matrix * feature_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); + m_cylinder.model.set_color(color); + m_cylinder.model.render(); + auto it = m_raycasters.find(EDGE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto& [idx, normal, pt] = m_curr_feature->get_plane(); + assert(idx < m_plane_models_cache.size()); + const Transform3d view_model_matrix = view_matrix * model_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); + m_plane_models_cache[idx].set_color(color); + m_plane_models_cache[idx].render(); + auto it = m_raycasters.find(PLANE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(model_matrix); + break; + } + } + shader->stop_using(); } } @@ -426,7 +429,8 @@ void GLGizmoMeasure::update_if_needed() void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit) { - static Measure::SurfaceFeature last_feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Undef, Vec3d::Zero(), Vec3d::Zero(), std::nullopt, 0.0); + static std::optional last_feature; + static EMode last_mode = EMode::BasicSelection; static float last_y = 0.0f; static float last_h = 0.0f; @@ -446,31 +450,27 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit last_y = y; } - if (m_features.empty()) + if (!m_curr_feature.has_value()) m_imgui->text(_u8L("Select features to measure")); + else { + auto add_row_to_table = [this](const wxString& label, const std::string& value) { + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, label); + ImGui::TableSetColumnIndex(1); + m_imgui->text(value); + }; - auto add_row_to_table = [this](const wxString& label, const std::string& value) { - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, label); - ImGui::TableSetColumnIndex(1); - m_imgui->text(value); - }; - - const Transform3d volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); - Measure::SurfaceFeature curr_feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Undef, Vec3d::Zero(), Vec3d::Zero(), std::nullopt, 0.0); - for (size_t i = 0; i < m_features.size(); ++i) { - curr_feature = m_features[i]; - const Measure::SurfaceFeatureType type = curr_feature.get_type(); + const Transform3d volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); + const Measure::SurfaceFeatureType type = m_curr_feature->get_type(); if (type != Measure::SurfaceFeatureType::Undef) { - const std::string header = surface_feature_type_as_string(type) + std::string("##") + std::to_string(i); - if (ImGui::CollapsingHeader(header.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { + if (ImGui::CollapsingHeader(surface_feature_type_as_string(type).c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { if (ImGui::BeginTable("Data", 2)) { switch (type) { case Measure::SurfaceFeatureType::Point: { - const Vec3d position = volume_matrix * curr_feature.get_point(); + const Vec3d position = volume_matrix * m_curr_feature->get_point(); char buf[1024]; sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", position.x(), position.y(), position.z()); add_row_to_table(_u8L("Position") + ":", std::string(buf)); @@ -478,7 +478,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } case Measure::SurfaceFeatureType::Edge: { - auto [from, to] = curr_feature.get_edge(); + auto [from, to] = m_curr_feature->get_edge(); from = volume_matrix * from; to = volume_matrix * to; char buf[1024]; @@ -490,7 +490,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } case Measure::SurfaceFeatureType::Circle: { - auto [center, radius, normal] = curr_feature.get_circle(); + auto [center, radius, normal] = m_curr_feature->get_circle(); center = volume_matrix * center; normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; char buf[1024]; @@ -504,7 +504,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } case Measure::SurfaceFeatureType::Plane: { - auto [idx, normal, origin] = curr_feature.get_plane(); + auto [idx, normal, origin] = m_curr_feature->get_plane(); origin = volume_matrix * origin; normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; char buf[1024]; @@ -521,14 +521,15 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } } - if (last_feature != curr_feature) { + if (last_feature != m_curr_feature || last_mode != m_mode) { // the dialog may have changed its size, ask for an extra frame to render it properly - last_feature = curr_feature; + last_feature = m_curr_feature; + last_mode = m_mode; m_imgui->set_requires_extra_frame(); } - if (!m_features.empty()) { - static const std::string ctrl = + if (m_curr_feature.has_value() && m_mode == EMode::BasicSelection) { + static const std::string ctrl = #ifdef __APPLE__ "⌘" #else diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 13c46a48d9..093584c7f4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -41,7 +41,7 @@ class GLGizmoMeasure : public GLGizmoBase std::vector m_plane_models_cache; std::map> m_raycasters; - std::vector m_features; + std::optional m_curr_feature; // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; @@ -50,13 +50,10 @@ class GLGizmoMeasure : public GLGizmoBase Vec3d m_first_instance_mirror{ Vec3d::Ones() }; bool m_mouse_left_down = false; // for detection left_up of this gizmo - bool m_planes_valid = false; const ModelObject* m_old_model_object = nullptr; const ModelVolume* m_old_model_volume = nullptr; - std::vector instances_matrices; - int m_mouse_pos_x; - int m_mouse_pos_y; + Vec2d m_mouse_pos{ Vec2d::Zero() }; KeyAutoRepeatFilter m_ctrl_kar_filter; From 6694817cd6a893c5ce34f6628a36cdeb5c71119b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 30 Aug 2022 15:50:11 +0200 Subject: [PATCH 032/250] Refactoring of GLGizmoMeasure::on_render_input_window to simplify code --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 38 +++++++++++------------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 6 ++-- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 2c040c9c3b..3e803fa603 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -460,6 +460,16 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::TableSetColumnIndex(1); m_imgui->text(value); }; + auto format_double = [](double value) { + char buf[1024]; + sprintf(buf, "%.3f", value); + return std::string(buf); + }; + auto format_vec3 = [](const Vec3d& v) { + char buf[1024]; + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", v.x(), v.y(), v.z()); + return std::string(buf); + }; const Transform3d volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); const Measure::SurfaceFeatureType type = m_curr_feature->get_type(); @@ -471,9 +481,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit case Measure::SurfaceFeatureType::Point: { const Vec3d position = volume_matrix * m_curr_feature->get_point(); - char buf[1024]; - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", position.x(), position.y(), position.z()); - add_row_to_table(_u8L("Position") + ":", std::string(buf)); + add_row_to_table(_u8L("Position") + ":", format_vec3(position)); break; } case Measure::SurfaceFeatureType::Edge: @@ -481,11 +489,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit auto [from, to] = m_curr_feature->get_edge(); from = volume_matrix * from; to = volume_matrix * to; - char buf[1024]; - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", from.x(), from.y(), from.z()); - add_row_to_table(_u8L("From") + ":", std::string(buf)); - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", to.x(), to.y(), to.z()); - add_row_to_table(_u8L("To") + ":", std::string(buf)); + add_row_to_table(_u8L("From") + ":", format_vec3(from)); + add_row_to_table(_u8L("To") + ":", format_vec3(to)); break; } case Measure::SurfaceFeatureType::Circle: @@ -493,13 +498,9 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit auto [center, radius, normal] = m_curr_feature->get_circle(); center = volume_matrix * center; normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; - char buf[1024]; - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", center.x(), center.y(), center.z()); - add_row_to_table(_u8L("Center") + ":", std::string(buf)); - sprintf(buf, "%.3f", radius); - add_row_to_table(_u8L("Radius") + ":", std::string(buf)); - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", normal.x(), normal.y(), normal.z()); - add_row_to_table(_u8L("Normal") + ":", std::string(buf)); + add_row_to_table(_u8L("Center") + ":", format_vec3(center)); + add_row_to_table(_u8L("Radius") + ":", format_double(radius)); + add_row_to_table(_u8L("Normal") + ":", format_vec3(normal)); break; } case Measure::SurfaceFeatureType::Plane: @@ -507,11 +508,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit auto [idx, normal, origin] = m_curr_feature->get_plane(); origin = volume_matrix * origin; normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; - char buf[1024]; - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", origin.x(), origin.y(), origin.z()); - add_row_to_table(_u8L("Origin") + ":", std::string(buf)); - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", normal.x(), normal.y(), normal.z()); - add_row_to_table(_u8L("Normal") + ":", std::string(buf)); + add_row_to_table(_u8L("Origin") + ":", format_vec3(origin)); + add_row_to_table(_u8L("Normal") + ":", format_vec3(normal)); break; } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 093584c7f4..8a8cdac755 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -49,9 +49,9 @@ class GLGizmoMeasure : public GLGizmoBase Vec3d m_first_instance_scale{ Vec3d::Ones() }; Vec3d m_first_instance_mirror{ Vec3d::Ones() }; - bool m_mouse_left_down = false; // for detection left_up of this gizmo - const ModelObject* m_old_model_object = nullptr; - const ModelVolume* m_old_model_volume = nullptr; + bool m_mouse_left_down{ false }; // for detection left_up of this gizmo + const ModelObject* m_old_model_object{ nullptr }; + const ModelVolume* m_old_model_volume{ nullptr }; Vec2d m_mouse_pos{ Vec2d::Zero() }; From 83990562c5089248427056685b976c92e4c20fab Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 31 Aug 2022 12:42:55 +0200 Subject: [PATCH 033/250] Measuring: Measure gizmo - added visualization of point for extended selection and updates to imgui dialog --- src/slic3r/GUI/GLCanvas3D.cpp | 9 +- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 255 +++++++++++++---------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 + 3 files changed, 151 insertions(+), 114 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 9c98a20e7a..9adef7b472 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5465,8 +5465,13 @@ void GLCanvas3D::_picking_pass() // do not add the volume id if any gizmo is active and CTRL is pressed if (m_gizmos.get_current_type() == GLGizmosManager::EType::Undefined || !wxGetKeyState(WXK_CONTROL)) { m_hover_volume_idxs.emplace_back(hit.raycaster_id); +#if !ENABLE_MEASURE_GIZMO m_gizmos.set_hover_id(-1); +#endif // !ENABLE_MEASURE_GIZMO } +#if ENABLE_MEASURE_GIZMO + m_gizmos.set_hover_id(-1); +#endif // ENABLE_MEASURE_GIZMO } } else @@ -5477,8 +5482,8 @@ void GLCanvas3D::_picking_pass() case SceneRaycaster::EType::Gizmo: { const Size& cnv_size = get_canvas_size(); - bool inside = 0 <= m_mouse.position.x() && m_mouse.position.x() < cnv_size.get_width() && - 0 <= m_mouse.position.y() && m_mouse.position.y() < cnv_size.get_height(); + const bool inside = 0 <= m_mouse.position.x() && m_mouse.position.x() < cnv_size.get_width() && + 0 <= m_mouse.position.y() && m_mouse.position.y() < cnv_size.get_height(); m_gizmos.set_hover_id(inside ? hit.raycaster_id : -1); break; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 3e803fa603..932f9113f1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -21,7 +21,7 @@ std::string surface_feature_type_as_string(Slic3r::Measure::SurfaceFeatureType t { default: case Slic3r::Measure::SurfaceFeatureType::Undef: { return L("Undefined"); } - case Slic3r::Measure::SurfaceFeatureType::Point: { return L("Point"); } + case Slic3r::Measure::SurfaceFeatureType::Point: { return L("Vertex"); } case Slic3r::Measure::SurfaceFeatureType::Edge: { return L("Edge"); } case Slic3r::Measure::SurfaceFeatureType::Circle: { return L("Circle"); } case Slic3r::Measure::SurfaceFeatureType::Plane: { return L("Plane"); } @@ -32,15 +32,22 @@ namespace Slic3r { namespace GUI { static const Slic3r::ColorRGBA BASIC_HOVER_COLOR = { 0.8f, 0.2f, 0.2f, 1.0f }; -static const Slic3r::ColorRGBA EXTENDED_HOVER_COLOR = { 0.2f, 0.8f, 0.2f, 1.0f }; +static const Slic3r::ColorRGBA EXTENDED_HOVER_COLOR = { 0.8f, 0.8f, 0.2f, 1.0f }; static const Slic3r::ColorRGBA LOCK_COLOR = { 0.5f, 0.5f, 0.5f, 1.0f }; static const int POINT_ID = 100; static const int EDGE_ID = 200; static const int CIRCLE_ID = 300; -static const int CIRCLE_CENTER_ID = 301; static const int PLANE_ID = 400; +static const std::string CTRL_STR = +#ifdef __APPLE__ +"⌘" +#else +"Ctrl" +#endif //__APPLE__ +; + GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) { @@ -127,8 +134,11 @@ bool GLGizmoMeasure::on_init() void GLGizmoMeasure::on_set_state() { - if (m_state == Off) + if (m_state == Off) { m_ctrl_kar_filter.reset_count(); + m_curr_feature.reset(); + m_curr_ex_feature_position.reset(); + } else m_mode = EMode::BasicSelection; } @@ -167,16 +177,19 @@ void GLGizmoMeasure::on_render() const Camera& camera = wxGetApp().plater()->get_camera(); const float inv_zoom = (float)camera.get_inv_zoom(); - Vec3f pos; - Vec3f normal; + Vec3f position_on_model; + Vec3f normal_on_model; size_t facet_idx; - m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, model_matrix, camera, pos, normal, nullptr, &facet_idx); + m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, model_matrix, camera, position_on_model, normal_on_model, nullptr, &facet_idx); + + const bool is_hovering_on_extended_selection = m_mode == EMode::ExtendedSelection && m_hover_id != -1; std::optional curr_feature; if (m_mode == EMode::BasicSelection) - curr_feature = m_measuring->get_feature(facet_idx, pos.cast()); + curr_feature = m_measuring->get_feature(facet_idx, position_on_model.cast()); if (m_mode == EMode::BasicSelection) { + m_curr_ex_feature_position.reset(); if (m_curr_feature != curr_feature) { GLGizmoMeasure::on_unregister_raycasters_for_picking(); m_curr_feature = curr_feature; @@ -196,7 +209,7 @@ void GLGizmoMeasure::on_render() } case Measure::SurfaceFeatureType::Circle: { - const auto& [center, radius, n] = m_curr_feature->get_circle(); + const auto& [center, radius, normal] = m_curr_feature->get_circle(); // TODO: check for changed inv_zoom @@ -206,12 +219,12 @@ void GLGizmoMeasure::on_render() m_circle.model.init_from(std::move(circle_geometry)); m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); - m_raycasters.insert({ CIRCLE_CENTER_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_CENTER_ID, *m_sphere.mesh_raycaster) }); + m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); break; } case Measure::SurfaceFeatureType::Plane: { - const auto& [idx, normal, pt] = m_curr_feature->get_plane(); + const auto& [idx, normal, point] = m_curr_feature->get_plane(); // TODO: check for changed idx @@ -244,6 +257,8 @@ void GLGizmoMeasure::on_render() } } } + else if (m_mode == EMode::ExtendedSelection) + m_curr_ex_feature_position = position_on_model.cast(); if (!m_curr_feature.has_value()) return; @@ -261,23 +276,27 @@ void GLGizmoMeasure::on_render() const Transform3d& view_matrix = camera.get_view_matrix(); - ColorRGBA color; + ColorRGBA feature_color; switch (m_mode) { - case EMode::BasicSelection: { color = BASIC_HOVER_COLOR; break; } - case EMode::ExtendedSelection: { color = LOCK_COLOR; break; } + case EMode::BasicSelection: { feature_color = BASIC_HOVER_COLOR; break; } + case EMode::ExtendedSelection: { feature_color = LOCK_COLOR; break; } } + auto set_matrix_uniforms = [shader, &view_matrix](const Transform3d& model_matrix) { + const Transform3d view_model_matrix = view_matrix * model_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); + }; + switch (m_curr_feature->get_type()) { case Measure::SurfaceFeatureType::Point: { const Vec3d& position = m_curr_feature->get_point(); const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); - const Transform3d view_model_matrix = view_matrix * feature_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_sphere.model.set_color(color); + set_matrix_uniforms(feature_matrix); + m_sphere.model.set_color(is_hovering_on_extended_selection ? EXTENDED_HOVER_COLOR : feature_color); m_sphere.model.render(); auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) @@ -289,23 +308,17 @@ void GLGizmoMeasure::on_render() const auto& [center, radius, n] = m_curr_feature->get_circle(); // render center const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); - const Transform3d center_view_model_matrix = view_matrix * center_matrix; - shader->set_uniform("view_model_matrix", center_view_model_matrix); - const Matrix3d center_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * center_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", center_view_normal_matrix); - m_sphere.model.set_color(color); + set_matrix_uniforms(center_matrix); + m_sphere.model.set_color((is_hovering_on_extended_selection && m_hover_id == POINT_ID) ? EXTENDED_HOVER_COLOR : feature_color); m_sphere.model.render(); - auto it = m_raycasters.find(CIRCLE_CENTER_ID); + auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) it->second->set_transform(center_matrix); // render circle const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center); - const Transform3d circle_view_model_matrix = view_matrix * circle_matrix; - shader->set_uniform("view_model_matrix", circle_view_model_matrix); - const Matrix3d circle_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * circle_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", circle_view_normal_matrix); - m_circle.model.set_color(color); + set_matrix_uniforms(circle_matrix); + m_circle.model.set_color(feature_color); m_circle.model.render(); it = m_raycasters.find(CIRCLE_ID); if (it != m_raycasters.end() && it->second != nullptr) @@ -318,11 +331,8 @@ void GLGizmoMeasure::on_render() auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * q * Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); - const Transform3d view_model_matrix = view_matrix * feature_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_cylinder.model.set_color(color); + set_matrix_uniforms(feature_matrix); + m_cylinder.model.set_color(feature_color); m_cylinder.model.render(); auto it = m_raycasters.find(EDGE_ID); if (it != m_raycasters.end() && it->second != nullptr) @@ -333,11 +343,8 @@ void GLGizmoMeasure::on_render() { const auto& [idx, normal, pt] = m_curr_feature->get_plane(); assert(idx < m_plane_models_cache.size()); - const Transform3d view_model_matrix = view_matrix * model_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_plane_models_cache[idx].set_color(color); + set_matrix_uniforms(model_matrix); + m_plane_models_cache[idx].set_color(feature_color); m_plane_models_cache[idx].render(); auto it = m_raycasters.find(PLANE_ID); if (it != m_raycasters.end() && it->second != nullptr) @@ -346,6 +353,15 @@ void GLGizmoMeasure::on_render() } } + if (is_hovering_on_extended_selection && m_curr_ex_feature_position.has_value()) { + if (m_hover_id != POINT_ID) { + Transform3d matrix = model_matrix * Geometry::translation_transform(*m_curr_ex_feature_position) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(matrix); + m_sphere.model.set_color(EXTENDED_HOVER_COLOR); + m_sphere.model.render(); + } + } + shader->stop_using(); } } @@ -450,70 +466,97 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit last_y = y; } - if (!m_curr_feature.has_value()) - m_imgui->text(_u8L("Select features to measure")); - else { - auto add_row_to_table = [this](const wxString& label, const std::string& value) { - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, label); - ImGui::TableSetColumnIndex(1); - m_imgui->text(value); - }; - auto format_double = [](double value) { - char buf[1024]; - sprintf(buf, "%.3f", value); - return std::string(buf); - }; - auto format_vec3 = [](const Vec3d& v) { - char buf[1024]; - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", v.x(), v.y(), v.z()); - return std::string(buf); - }; + auto add_row_to_table = [this](const wxString& label, const std::string& value) { + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, label); + ImGui::TableSetColumnIndex(1); + m_imgui->text(value); + }; + auto format_double = [](double value) { + char buf[1024]; + sprintf(buf, "%.3f", value); + return std::string(buf); + }; + auto format_vec3 = [](const Vec3d& v) { + char buf[1024]; + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", v.x(), v.y(), v.z()); + return std::string(buf); + }; + if (ImGui::BeginTable("Commands", 2)) { + add_row_to_table(_u8L("Left mouse button"), (m_mode == EMode::BasicSelection) ? _u8L("Select feature") : _u8L("Select point")); + if (m_mode == EMode::BasicSelection && m_hover_id != -1) + add_row_to_table(CTRL_STR, _u8L("Enable point selection")); + ImGui::EndTable(); + } + + if (m_curr_feature.has_value()) { const Transform3d volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); - const Measure::SurfaceFeatureType type = m_curr_feature->get_type(); - if (type != Measure::SurfaceFeatureType::Undef) { - if (ImGui::CollapsingHeader(surface_feature_type_as_string(type).c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { - if (ImGui::BeginTable("Data", 2)) { - switch (type) - { - case Measure::SurfaceFeatureType::Point: - { - const Vec3d position = volume_matrix * m_curr_feature->get_point(); + const Measure::SurfaceFeatureType feature_type = m_curr_feature->get_type(); + if (m_mode == EMode::BasicSelection) { + if (feature_type != Measure::SurfaceFeatureType::Undef) { + if (ImGui::CollapsingHeader(surface_feature_type_as_string(feature_type).c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { + if (ImGui::BeginTable("Data", 2)) { + switch (feature_type) + { + case Measure::SurfaceFeatureType::Point: + { + const Vec3d position = volume_matrix * m_curr_feature->get_point(); + add_row_to_table(_u8L("Position") + ":", format_vec3(position)); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + auto [from, to] = m_curr_feature->get_edge(); + from = volume_matrix * from; + to = volume_matrix * to; + add_row_to_table(_u8L("From") + ":", format_vec3(from)); + add_row_to_table(_u8L("To") + ":", format_vec3(to)); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + auto [center, radius, normal] = m_curr_feature->get_circle(); + center = volume_matrix * center; + normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + add_row_to_table(_u8L("Center") + ":", format_vec3(center)); + add_row_to_table(_u8L("Radius") + ":", format_double(radius)); + add_row_to_table(_u8L("Normal") + ":", format_vec3(normal)); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + auto [idx, normal, origin] = m_curr_feature->get_plane(); + origin = volume_matrix * origin; + normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + add_row_to_table(_u8L("Origin") + ":", format_vec3(origin)); + add_row_to_table(_u8L("Normal") + ":", format_vec3(normal)); + break; + } + } + ImGui::EndTable(); + } + } + } + } + else if (m_mode == EMode::ExtendedSelection) { + if (m_hover_id != -1) { + std::string header; + switch (feature_type) { + case Measure::SurfaceFeatureType::Point: { header = _u8L("Vertex"); break; } + case Measure::SurfaceFeatureType::Edge: { header = _u8L("Point on edge"); break; } + case Measure::SurfaceFeatureType::Circle: { header = (m_hover_id == POINT_ID) ? _u8L("Center of circle") : _u8L("Point on circle"); break; } + case Measure::SurfaceFeatureType::Plane: { header = _u8L("Point on plane"); break; } + default: { assert(false); break; } + } + + if (ImGui::CollapsingHeader(header.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { + const Vec3d position = volume_matrix * *m_curr_ex_feature_position; + if (ImGui::BeginTable("Data", 2)) { add_row_to_table(_u8L("Position") + ":", format_vec3(position)); - break; + ImGui::EndTable(); } - case Measure::SurfaceFeatureType::Edge: - { - auto [from, to] = m_curr_feature->get_edge(); - from = volume_matrix * from; - to = volume_matrix * to; - add_row_to_table(_u8L("From") + ":", format_vec3(from)); - add_row_to_table(_u8L("To") + ":", format_vec3(to)); - break; - } - case Measure::SurfaceFeatureType::Circle: - { - auto [center, radius, normal] = m_curr_feature->get_circle(); - center = volume_matrix * center; - normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; - add_row_to_table(_u8L("Center") + ":", format_vec3(center)); - add_row_to_table(_u8L("Radius") + ":", format_double(radius)); - add_row_to_table(_u8L("Normal") + ":", format_vec3(normal)); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - auto [idx, normal, origin] = m_curr_feature->get_plane(); - origin = volume_matrix * origin; - normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; - add_row_to_table(_u8L("Origin") + ":", format_vec3(origin)); - add_row_to_table(_u8L("Normal") + ":", format_vec3(normal)); - break; - } - } - ImGui::EndTable(); } } } @@ -526,18 +569,6 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit m_imgui->set_requires_extra_frame(); } - if (m_curr_feature.has_value() && m_mode == EMode::BasicSelection) { - static const std::string ctrl = -#ifdef __APPLE__ - "⌘" -#else - "Ctrl" -#endif //__APPLE__ - ; - - ImGui::Separator(); - m_imgui->text(_u8L("Press") + " " + ctrl + " " + _u8L("to enable extended selection")); - } m_imgui->end(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 8a8cdac755..09d40b47ba 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -42,6 +42,7 @@ class GLGizmoMeasure : public GLGizmoBase std::vector m_plane_models_cache; std::map> m_raycasters; std::optional m_curr_feature; + std::optional m_curr_ex_feature_position; // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; From 7cf85a1565c790e885d886921d6cd165fb7bb45a Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 31 Aug 2022 14:56:00 +0200 Subject: [PATCH 034/250] Measuring: Measure gizmo - Improved visualization of points for extended selection --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 53 +++++++++++++++++++++--- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 932f9113f1..89ba8cd410 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -257,8 +257,50 @@ void GLGizmoMeasure::on_render() } } } - else if (m_mode == EMode::ExtendedSelection) - m_curr_ex_feature_position = position_on_model.cast(); + else if (is_hovering_on_extended_selection) { + switch (m_curr_feature->get_type()) + { + case Measure::SurfaceFeatureType::Point: + { + m_curr_ex_feature_position = model_matrix * m_curr_feature->get_point(); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + auto it = m_raycasters.find(EDGE_ID); + if (it != m_raycasters.end() && it->second != nullptr) { + Vec3f p; + Vec3f n; + const Transform3d& trafo = it->second->get_transform(); + it->second->get_raycaster()->unproject_on_mesh(m_mouse_pos, trafo, camera, p, n); + m_curr_ex_feature_position = trafo * p.cast(); + } + break; + } + case Measure::SurfaceFeatureType::Plane: + { + m_curr_ex_feature_position = model_matrix * position_on_model.cast(); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, normal] = m_curr_feature->get_circle(); + if (m_hover_id == POINT_ID) + m_curr_ex_feature_position = model_matrix * center; + else { + auto it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end() && it->second != nullptr) { + Vec3f p; + Vec3f n; + const Transform3d& trafo = it->second->get_transform(); + it->second->get_raycaster()->unproject_on_mesh(m_mouse_pos, trafo, camera, p, n); + m_curr_ex_feature_position = trafo * p.cast(); + } + } + break; + } + } + } if (!m_curr_feature.has_value()) return; @@ -355,7 +397,7 @@ void GLGizmoMeasure::on_render() if (is_hovering_on_extended_selection && m_curr_ex_feature_position.has_value()) { if (m_hover_id != POINT_ID) { - Transform3d matrix = model_matrix * Geometry::translation_transform(*m_curr_ex_feature_position) * Geometry::scale_transform(inv_zoom); + const Transform3d matrix = Geometry::translation_transform(*m_curr_ex_feature_position) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(matrix); m_sphere.model.set_color(EXTENDED_HOVER_COLOR); m_sphere.model.render(); @@ -541,7 +583,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } } else if (m_mode == EMode::ExtendedSelection) { - if (m_hover_id != -1) { + if (m_hover_id != -1 && m_curr_ex_feature_position.has_value()) { std::string header; switch (feature_type) { case Measure::SurfaceFeatureType::Point: { header = _u8L("Vertex"); break; } @@ -552,9 +594,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } if (ImGui::CollapsingHeader(header.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { - const Vec3d position = volume_matrix * *m_curr_ex_feature_position; if (ImGui::BeginTable("Data", 2)) { - add_row_to_table(_u8L("Position") + ":", format_vec3(position)); + add_row_to_table(_u8L("Position") + ":", format_vec3(*m_curr_ex_feature_position)); ImGui::EndTable(); } } From 58da6e994cd4c9eea2750760681f33c86c9279ea Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 31 Aug 2022 15:31:39 +0200 Subject: [PATCH 035/250] Measuring: Measure gizmo - Further improvements in visualization of points for extended selection --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 89ba8cd410..a9c2e18257 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -273,6 +273,7 @@ void GLGizmoMeasure::on_render() Vec3f n; const Transform3d& trafo = it->second->get_transform(); it->second->get_raycaster()->unproject_on_mesh(m_mouse_pos, trafo, camera, p, n); + p = { 0.0f, 0.0f, p.z() }; m_curr_ex_feature_position = trafo * p.cast(); } break; @@ -294,6 +295,10 @@ void GLGizmoMeasure::on_render() Vec3f n; const Transform3d& trafo = it->second->get_transform(); it->second->get_raycaster()->unproject_on_mesh(m_mouse_pos, trafo, camera, p, n); + float angle = std::atan2(p.y(), p.x()); + if (angle < 0.0f) + angle += 2.0f * float(M_PI); + p = float(radius) * Vec3f(std::cos(angle), std::sin(angle), 0.0f); m_curr_ex_feature_position = trafo * p.cast(); } } From ec9001c57e9eb4f0847ca0c58f7cd19b07b41707 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 1 Sep 2022 09:44:40 +0200 Subject: [PATCH 036/250] Measuring: Optimization into GLGizmoMeasure::on_render() --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 59 +++++++++++++----------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 4 +- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index a9c2e18257..13415e70ac 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -106,6 +106,9 @@ void GLGizmoMeasure::data_changed() } if (model_object != m_old_model_object || model_volume != m_old_model_volume) update_if_needed(); + + m_last_inv_zoom = 0.0f; + m_last_plane_idx = -1; } bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) @@ -211,12 +214,13 @@ void GLGizmoMeasure::on_render() { const auto& [center, radius, normal] = m_curr_feature->get_circle(); - // TODO: check for changed inv_zoom - - m_circle.reset(); - GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); - m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); - m_circle.model.init_from(std::move(circle_geometry)); + if (m_last_inv_zoom != inv_zoom) { + m_last_inv_zoom = inv_zoom; + m_circle.reset(); + GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); + m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); + m_circle.model.init_from(std::move(circle_geometry)); + } m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); @@ -225,32 +229,33 @@ void GLGizmoMeasure::on_render() case Measure::SurfaceFeatureType::Plane: { const auto& [idx, normal, point] = m_curr_feature->get_plane(); + if (m_last_plane_idx != idx) { + m_last_plane_idx = idx; + const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); + const std::vector& triangle_indices = planes_triangles[idx]; - // TODO: check for changed idx + const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; + GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + unsigned int i = 0; + for (int idx : triangle_indices) { + const Vec3f& v0 = its.vertices[its.indices[idx][0]]; + const Vec3f& v1 = its.vertices[its.indices[idx][1]]; + const Vec3f& v2 = its.vertices[its.indices[idx][2]]; - const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); - const std::vector& triangle_indices = planes_triangles[idx]; + const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); + init_data.add_vertex(v0, n); + init_data.add_vertex(v1, n); + init_data.add_vertex(v2, n); + init_data.add_triangle(i, i + 1, i + 2); + i += 3; + } - const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; - GLModel::Geometry init_data; - init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; - unsigned int i = 0; - for (int idx : triangle_indices) { - const Vec3f& v0 = its.vertices[its.indices[idx][0]]; - const Vec3f& v1 = its.vertices[its.indices[idx][1]]; - const Vec3f& v2 = its.vertices[its.indices[idx][2]]; - - const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); - init_data.add_vertex(v0, n); - init_data.add_vertex(v1, n); - init_data.add_vertex(v2, n); - init_data.add_triangle(i, i + 1, i + 2); - i += 3; + m_plane.reset(); + m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(init_data.get_as_indexed_triangle_set()))); + m_plane.model.init_from(std::move(init_data)); } - m_plane.reset(); - m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(init_data.get_as_indexed_triangle_set()))); - m_plane.model.init_from(std::move(init_data)); m_raycasters.insert({ PLANE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID, *m_plane.mesh_raycaster) }); break; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 09d40b47ba..46b37737ae 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -44,11 +44,13 @@ class GLGizmoMeasure : public GLGizmoBase std::optional m_curr_feature; std::optional m_curr_ex_feature_position; - // This holds information to decide whether recalculation is necessary: + // These hold information to decide whether recalculation is necessary: std::vector m_volumes_matrices; std::vector m_volumes_types; Vec3d m_first_instance_scale{ Vec3d::Ones() }; Vec3d m_first_instance_mirror{ Vec3d::Ones() }; + float m_last_inv_zoom{ 0.0f }; + int m_last_plane_idx{ -1 }; bool m_mouse_left_down{ false }; // for detection left_up of this gizmo const ModelObject* m_old_model_object{ nullptr }; From fe7982cb08428aec915d3ab7262e7618e2cde2c8 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 1 Sep 2022 09:54:16 +0200 Subject: [PATCH 037/250] Fixed warnings --- src/libslic3r/Measure.cpp | 18 +++++++++--------- src/libslic3r/Measure.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 7 ++++++- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index cdde276dda..1a79369a3e 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -106,7 +106,7 @@ void MeasuringImpl::update_planes() int facet_idx = facet_queue[-- facet_queue_cnt]; const stl_normal& this_normal = face_normals[facet_idx]; if (is_same_normal(this_normal, *normal_ptr)) { - const Vec3i& face = m_its.indices[facet_idx]; +// const Vec3i& face = m_its.indices[facet_idx]; m_face_to_plane[facet_idx] = m_planes.size() - 1; m_planes.back().facets.emplace_back(facet_idx); @@ -132,7 +132,7 @@ void MeasuringImpl::update_planes() for (int face_id=0; face_id lengths; - for (int i=0; i M_PI) @@ -236,10 +236,10 @@ void MeasuringImpl::extract_features() bool circle = false; std::vector circles; std::vector> circles_idxs; - for (int i=1; i polygon_lower_threshold) { if (angle < polygon_upper_threshold) { const Vec3d center = std::get<0>(circles[i].get_circle()); - for (int j=circles_idxs[i].first + 1; j<=circles_idxs[i].second; ++j) + for (int j=(int)circles_idxs[i].first + 1; j<=(int)circles_idxs[i].second; ++j) plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[j-1], border[j], std::make_optional(center), 0.)); } else { @@ -286,7 +286,7 @@ void MeasuringImpl::extract_features() // We have the circles. Now go around again and pick edges. int cidx = 0; // index of next circle in the way for (int i=1; i circles_idxs[cidx].first) + if (cidx < (int)circles_idxs.size() && i > (int)circles_idxs[cidx].first) i = circles_idxs[cidx++].second; else plane.surface_features.emplace_back(SurfaceFeature( SurfaceFeatureType::Edge, border[i-1], border[i], std::optional(), 0.)); diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 95d8f34cba..9e3629589b 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -68,7 +68,7 @@ private: Vec3d m_pt1; Vec3d m_pt2; std::optional m_pt3; - double m_value; + double m_value{ 0.0 }; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 13415e70ac..54c944590b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -200,6 +200,7 @@ void GLGizmoMeasure::on_render() return; switch (m_curr_feature->get_type()) { + default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); @@ -265,6 +266,7 @@ void GLGizmoMeasure::on_render() else if (is_hovering_on_extended_selection) { switch (m_curr_feature->get_type()) { + default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { m_curr_ex_feature_position = model_matrix * m_curr_feature->get_point(); @@ -342,7 +344,9 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_normal_matrix", view_normal_matrix); }; - switch (m_curr_feature->get_type()) { + switch (m_curr_feature->get_type()) + { + default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { const Vec3d& position = m_curr_feature->get_point(); @@ -552,6 +556,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (ImGui::BeginTable("Data", 2)) { switch (feature_type) { + default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { const Vec3d position = volume_matrix * m_curr_feature->get_point(); From c6e6c86627f2889253425787fedaea08c1d2f850 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 1 Sep 2022 10:19:12 +0200 Subject: [PATCH 038/250] Refactoring into GLGizmoMeasure.cpp to remove duplicated code --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 63 +++++++++++------------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 54c944590b..3b257076a2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -48,6 +48,30 @@ static const std::string CTRL_STR = #endif //__APPLE__ ; +static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const std::vector>& planes_triangles, int idx) +{ + assert(0 <= idx && idx < (int)planes_triangles.size()); + const std::vector& triangle_indices = planes_triangles[idx]; + + GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + unsigned int i = 0; + for (int idx : triangle_indices) { + const Vec3f& v0 = its.vertices[its.indices[idx][0]]; + const Vec3f& v1 = its.vertices[its.indices[idx][1]]; + const Vec3f& v2 = its.vertices[its.indices[idx][2]]; + + const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); + init_data.add_vertex(v0, n); + init_data.add_vertex(v1, n); + init_data.add_vertex(v2, n); + init_data.add_triangle(i, i + 1, i + 2); + i += 3; + } + + return init_data; +} + GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) { @@ -232,26 +256,9 @@ void GLGizmoMeasure::on_render() const auto& [idx, normal, point] = m_curr_feature->get_plane(); if (m_last_plane_idx != idx) { m_last_plane_idx = idx; - const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); - const std::vector& triangle_indices = planes_triangles[idx]; - const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; - GLModel::Geometry init_data; - init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; - unsigned int i = 0; - for (int idx : triangle_indices) { - const Vec3f& v0 = its.vertices[its.indices[idx][0]]; - const Vec3f& v1 = its.vertices[its.indices[idx][1]]; - const Vec3f& v2 = its.vertices[its.indices[idx][2]]; - - const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); - init_data.add_vertex(v0, n); - init_data.add_vertex(v1, n); - init_data.add_vertex(v2, n); - init_data.add_triangle(i, i + 1, i + 2); - i += 3; - } - + const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); + GLModel::Geometry init_data = init_plane_data(its, planes_triangles, idx); m_plane.reset(); m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(init_data.get_as_indexed_triangle_set()))); m_plane.model.init_from(std::move(init_data)); @@ -427,23 +434,9 @@ void GLGizmoMeasure::update_if_needed() auto update_plane_models_cache = [this](const indexed_triangle_set& its) { m_plane_models_cache.clear(); const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); - for (const std::vector& triangle_indices : planes_triangles) { + for (int idx = 0; idx < (int)planes_triangles.size(); ++idx) { m_plane_models_cache.emplace_back(GLModel()); - GLModel::Geometry init_data; - init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; - unsigned int i = 0; - for (int idx : triangle_indices) { - const Vec3f& v0 = its.vertices[its.indices[idx][0]]; - const Vec3f& v1 = its.vertices[its.indices[idx][1]]; - const Vec3f& v2 = its.vertices[its.indices[idx][2]]; - - const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); - init_data.add_vertex(v0, n); - init_data.add_vertex(v1, n); - init_data.add_vertex(v2, n); - init_data.add_triangle(i, i + 1, i + 2); - i += 3; - } + GLModel::Geometry init_data = init_plane_data(its, planes_triangles, idx); m_plane_models_cache.back().init_from(std::move(init_data)); } }; From c5532b175ed894428eec232b90d00bd3a21c59f8 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 2 Sep 2022 11:24:06 +0200 Subject: [PATCH 039/250] Measuring: Added features selection in GLGizmoMeasure --- src/libslic3r/Measure.hpp | 6 +- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 382 +++++++++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 39 ++- 3 files changed, 297 insertions(+), 130 deletions(-) diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 9e3629589b..3aefc0b54b 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -107,7 +107,11 @@ struct MeasurementResult { std::optional angle; std::optional distance_infinite; std::optional distance_strict; - std::optional distance_xyz; + std::optional distance_xyz; + + bool has_any_data() const { + return angle.has_value() || distance_infinite.has_value() || distance_strict.has_value() || distance_xyz.has_value(); + } }; // Returns distance/angle between two SurfaceFeatures. diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 3b257076a2..8c27678ce0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -31,9 +31,8 @@ std::string surface_feature_type_as_string(Slic3r::Measure::SurfaceFeatureType t namespace Slic3r { namespace GUI { -static const Slic3r::ColorRGBA BASIC_HOVER_COLOR = { 0.8f, 0.2f, 0.2f, 1.0f }; -static const Slic3r::ColorRGBA EXTENDED_HOVER_COLOR = { 0.8f, 0.8f, 0.2f, 1.0f }; -static const Slic3r::ColorRGBA LOCK_COLOR = { 0.5f, 0.5f, 0.5f, 1.0f }; +static const Slic3r::ColorRGBA SELECTED_1ST_COLOR = { 0.25f, 0.75f, 0.75f, 1.0f }; +static const Slic3r::ColorRGBA SELECTED_2ND_COLOR = { 0.75f, 0.25f, 0.75f, 1.0f }; static const int POINT_ID = 100; static const int EDGE_ID = 200; @@ -95,7 +94,23 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) } else if (mouse_event.LeftDown()) { if (m_hover_id != -1) { - m_mouse_left_down = true; + m_mouse_left_down = true; + + auto set_item_from_feature = [this]() { + const SelectedFeatures::Item item = { m_mode, (m_mode == EMode::ExtendedSelection) ? + Measure::SurfaceFeature(Measure::SurfaceFeatureType::Point, *m_curr_ex_feature_position, Vec3d::Zero(), std::nullopt, 0.0) : + m_curr_feature }; + return item; + }; + + if (m_selected_features.first.feature.has_value()) { + const SelectedFeatures::Item item = set_item_from_feature(); + if (m_selected_features.first != item) + m_selected_features.second = item; + } + else + m_selected_features.first = set_item_from_feature(); + return true; } @@ -103,7 +118,6 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) // take responsibility for left up if (m_parent.get_first_hover_volume_idx() >= 0) m_mouse_left_down = true; - } else if (mouse_event.LeftUp()) { if (m_mouse_left_down) { @@ -133,6 +147,7 @@ void GLGizmoMeasure::data_changed() m_last_inv_zoom = 0.0f; m_last_plane_idx = -1; + m_selected_features.reset(); } bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) @@ -321,13 +336,13 @@ void GLGizmoMeasure::on_render() } } - if (!m_curr_feature.has_value()) + if (!m_curr_feature.has_value() && !m_selected_features.first.feature.has_value()) return; GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) return; - + shader->start_using(); shader->set_uniform("emission_factor", 0.25f); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); @@ -337,13 +352,6 @@ void GLGizmoMeasure::on_render() const Transform3d& view_matrix = camera.get_view_matrix(); - ColorRGBA feature_color; - switch (m_mode) - { - case EMode::BasicSelection: { feature_color = BASIC_HOVER_COLOR; break; } - case EMode::ExtendedSelection: { feature_color = LOCK_COLOR; break; } - } - auto set_matrix_uniforms = [shader, &view_matrix](const Transform3d& model_matrix) { const Transform3d view_model_matrix = view_matrix * model_matrix; shader->set_uniform("view_model_matrix", view_model_matrix); @@ -351,76 +359,143 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_normal_matrix", view_normal_matrix); }; - switch (m_curr_feature->get_type()) - { - default: { assert(false); break; } - case Measure::SurfaceFeatureType::Point: - { - const Vec3d& position = m_curr_feature->get_point(); - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); - set_matrix_uniforms(feature_matrix); - m_sphere.model.set_color(is_hovering_on_extended_selection ? EXTENDED_HOVER_COLOR : feature_color); - m_sphere.model.render(); - auto it = m_raycasters.find(POINT_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(feature_matrix); - break; - } - case Measure::SurfaceFeatureType::Circle: - { - const auto& [center, radius, n] = m_curr_feature->get_circle(); - // render center - const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); - set_matrix_uniforms(center_matrix); - m_sphere.model.set_color((is_hovering_on_extended_selection && m_hover_id == POINT_ID) ? EXTENDED_HOVER_COLOR : feature_color); - m_sphere.model.render(); - auto it = m_raycasters.find(POINT_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(center_matrix); + auto render_feature = [this, set_matrix_uniforms](const Measure::SurfaceFeature& feature, const std::vector& colors, + const Transform3d& model_matrix, float inv_zoom, bool update_raycasters) { + switch (feature.get_type()) + { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + const Vec3d& position = feature.get_point(); + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(feature_matrix); + m_sphere.model.set_color(colors.front()); + m_sphere.model.render(); + if (update_raycasters) { + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); + } + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, n] = feature.get_circle(); + // render center + const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(center_matrix); + m_sphere.model.set_color(colors.front()); + m_sphere.model.render(); + if (update_raycasters) { + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(center_matrix); + } + // render circle + const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center); + set_matrix_uniforms(circle_matrix); + m_circle.model.set_color(colors.back()); + m_circle.model.render(); + if (update_raycasters) { + auto it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(circle_matrix); + } + break; + } + case Measure::SurfaceFeatureType::Edge: + { + const auto& [start, end] = feature.get_edge(); + auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * q * + Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); + set_matrix_uniforms(feature_matrix); + m_cylinder.model.set_color(colors.front()); + m_cylinder.model.render(); + if (update_raycasters) { + auto it = m_raycasters.find(EDGE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); + } + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto& [idx, normal, pt] = feature.get_plane(); + assert(idx < m_plane_models_cache.size()); + set_matrix_uniforms(model_matrix); + m_plane_models_cache[idx].set_color(colors.front()); + m_plane_models_cache[idx].render(); + if (update_raycasters) { + auto it = m_raycasters.find(PLANE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(model_matrix); + } + break; + } + } + }; - // render circle - const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center); - set_matrix_uniforms(circle_matrix); - m_circle.model.set_color(feature_color); - m_circle.model.render(); - it = m_raycasters.find(CIRCLE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(circle_matrix); - break; + auto hover_selection_color = [this]() { + return saturate(!m_selected_features.first.feature.has_value() ? SELECTED_1ST_COLOR : SELECTED_2ND_COLOR, 1.5f); + }; + + auto hovering_color = [this, hover_selection_color, &selection]() { + return (m_mode == EMode::ExtendedSelection) ? selection.get_first_volume()->render_color : hover_selection_color(); + }; + + if (m_curr_feature.has_value()) { + std::vector colors; + if (m_selected_features.first.feature.has_value() && *m_curr_feature == *m_selected_features.first.feature) + colors.emplace_back(SELECTED_1ST_COLOR); + else if (m_selected_features.second.feature.has_value() && *m_curr_feature == *m_selected_features.second.feature) + colors.emplace_back(SELECTED_2ND_COLOR); + else { + switch (m_curr_feature->get_type()) + { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + colors.emplace_back(hover_selection_color()); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + colors.emplace_back((m_hover_id == POINT_ID) ? hover_selection_color() : hovering_color()); + colors.emplace_back(hovering_color()); + break; + } + case Measure::SurfaceFeatureType::Edge: + case Measure::SurfaceFeatureType::Plane: + { + colors.emplace_back(hovering_color()); + break; + } + } + } + + render_feature(*m_curr_feature, colors, model_matrix, inv_zoom, true); } - case Measure::SurfaceFeatureType::Edge: - { - const auto& [start, end] = m_curr_feature->get_edge(); - auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * q * - Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); - set_matrix_uniforms(feature_matrix); - m_cylinder.model.set_color(feature_color); - m_cylinder.model.render(); - auto it = m_raycasters.find(EDGE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(feature_matrix); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - const auto& [idx, normal, pt] = m_curr_feature->get_plane(); - assert(idx < m_plane_models_cache.size()); - set_matrix_uniforms(model_matrix); - m_plane_models_cache[idx].set_color(feature_color); - m_plane_models_cache[idx].render(); - auto it = m_raycasters.find(PLANE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(model_matrix); - break; + + if (m_selected_features.first.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.first.feature)) { + std::vector colors; + colors.emplace_back(SELECTED_1ST_COLOR); + render_feature(*m_selected_features.first.feature, colors, + (m_selected_features.first.mode == EMode::BasicSelection) ? model_matrix : Transform3d::Identity(), inv_zoom, false); } + if (m_selected_features.second.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.second.feature)) { + std::vector colors; + colors.emplace_back(SELECTED_2ND_COLOR); + render_feature(*m_selected_features.second.feature, colors, + (m_selected_features.second.mode == EMode::BasicSelection) ? model_matrix : Transform3d::Identity(), inv_zoom, false); } if (is_hovering_on_extended_selection && m_curr_ex_feature_position.has_value()) { if (m_hover_id != POINT_ID) { const Transform3d matrix = Geometry::translation_transform(*m_curr_ex_feature_position) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(matrix); - m_sphere.model.set_color(EXTENDED_HOVER_COLOR); + m_sphere.model.set_color(hover_selection_color()); +// m_sphere.model.set_color(EXTENDED_HOVER_COLOR); m_sphere.model.render(); } } @@ -496,6 +571,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit { static std::optional last_feature; static EMode last_mode = EMode::BasicSelection; + static SelectedFeatures last_selected_features; static float last_y = 0.0f; static float last_h = 0.0f; @@ -515,18 +591,20 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit last_y = y; } - auto add_row_to_table = [this](const wxString& label, const std::string& value) { + auto add_row_to_table = [this](const std::string& label, const ImVec4& label_color, const std::string& value, const ImVec4& value_color) { ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, label); + m_imgui->text_colored(label_color, label); ImGui::TableSetColumnIndex(1); - m_imgui->text(value); + m_imgui->text_colored(value_color, value); }; + auto format_double = [](double value) { char buf[1024]; sprintf(buf, "%.3f", value); return std::string(buf); }; + auto format_vec3 = [](const Vec3d& v) { char buf[1024]; sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", v.x(), v.y(), v.z()); @@ -534,9 +612,10 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit }; if (ImGui::BeginTable("Commands", 2)) { - add_row_to_table(_u8L("Left mouse button"), (m_mode == EMode::BasicSelection) ? _u8L("Select feature") : _u8L("Select point")); + add_row_to_table(_u8L("Left mouse button"), ImGuiWrapper::COL_ORANGE_LIGHT, + (m_mode == EMode::BasicSelection) ? _u8L("Select feature") : _u8L("Select point"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); if (m_mode == EMode::BasicSelection && m_hover_id != -1) - add_row_to_table(CTRL_STR, _u8L("Enable point selection")); + add_row_to_table(CTRL_STR, ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable point selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); } @@ -545,48 +624,49 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit const Measure::SurfaceFeatureType feature_type = m_curr_feature->get_type(); if (m_mode == EMode::BasicSelection) { if (feature_type != Measure::SurfaceFeatureType::Undef) { - if (ImGui::CollapsingHeader(surface_feature_type_as_string(feature_type).c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { - if (ImGui::BeginTable("Data", 2)) { - switch (feature_type) - { - default: { assert(false); break; } - case Measure::SurfaceFeatureType::Point: - { - const Vec3d position = volume_matrix * m_curr_feature->get_point(); - add_row_to_table(_u8L("Position") + ":", format_vec3(position)); - break; - } - case Measure::SurfaceFeatureType::Edge: - { - auto [from, to] = m_curr_feature->get_edge(); - from = volume_matrix * from; - to = volume_matrix * to; - add_row_to_table(_u8L("From") + ":", format_vec3(from)); - add_row_to_table(_u8L("To") + ":", format_vec3(to)); - break; - } - case Measure::SurfaceFeatureType::Circle: - { - auto [center, radius, normal] = m_curr_feature->get_circle(); - center = volume_matrix * center; - normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; - add_row_to_table(_u8L("Center") + ":", format_vec3(center)); - add_row_to_table(_u8L("Radius") + ":", format_double(radius)); - add_row_to_table(_u8L("Normal") + ":", format_vec3(normal)); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - auto [idx, normal, origin] = m_curr_feature->get_plane(); - origin = volume_matrix * origin; - normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; - add_row_to_table(_u8L("Origin") + ":", format_vec3(origin)); - add_row_to_table(_u8L("Normal") + ":", format_vec3(normal)); - break; - } - } - ImGui::EndTable(); + ImGui::Separator(); + m_imgui->text(surface_feature_type_as_string(feature_type) + ":"); + if (ImGui::BeginTable("Data", 2)) { + switch (feature_type) + { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + const Vec3d position = volume_matrix * m_curr_feature->get_point(); + add_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; } + case Measure::SurfaceFeatureType::Edge: + { + auto [from, to] = m_curr_feature->get_edge(); + from = volume_matrix * from; + to = volume_matrix * to; + add_row_to_table(_u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_row_to_table(_u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_row_to_table(_u8L("Length") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + auto [center, radius, normal] = m_curr_feature->get_circle(); + center = volume_matrix * center; + normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + add_row_to_table(_u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_row_to_table(_u8L("Radius") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + auto [idx, normal, origin] = m_curr_feature->get_plane(); + origin = volume_matrix * origin; + normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + add_row_to_table(_u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; + } + } + ImGui::EndTable(); } } } @@ -601,20 +681,68 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit default: { assert(false); break; } } - if (ImGui::CollapsingHeader(header.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { - if (ImGui::BeginTable("Data", 2)) { - add_row_to_table(_u8L("Position") + ":", format_vec3(*m_curr_ex_feature_position)); - ImGui::EndTable(); - } + ImGui::Separator(); + m_imgui->text(header + ":"); + if (ImGui::BeginTable("Data", 2)) { + add_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(*m_curr_ex_feature_position), + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ImGui::EndTable(); } } } } - if (last_feature != m_curr_feature || last_mode != m_mode) { + ImGui::Separator(); + m_imgui->text(_u8L("Selection")); + if (ImGui::BeginTable("Selection", 2)) { + add_row_to_table("1", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), m_selected_features.first.feature.has_value() ? + surface_feature_type_as_string(m_selected_features.first.feature->get_type()) : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR)); + add_row_to_table("2", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), m_selected_features.second.feature.has_value() ? + surface_feature_type_as_string(m_selected_features.second.feature->get_type()) : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR)); + ImGui::EndTable(); + } + + if (m_selected_features.first.feature.has_value()) { + if (m_imgui->button(_u8L("Restart"))) { + m_selected_features.reset(); + m_imgui->set_requires_extra_frame(); + } + } + + if (m_selected_features.second.feature.has_value()) { + const Measure::MeasurementResult measure = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature); + ImGui::Separator(); + if (measure.has_any_data()) { + m_imgui->text(_u8L("Measure")); + if (ImGui::BeginTable("Measure", 2)) { + if (measure.angle.has_value()) { + add_row_to_table(_u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(*measure.angle)), + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + if (measure.distance_infinite.has_value()) { + add_row_to_table(_u8L("Distance Infinite") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(*measure.distance_infinite), + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + if (measure.distance_strict.has_value()) { + add_row_to_table(_u8L("Distance Strict") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(*measure.distance_strict), + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + if (measure.distance_xyz.has_value()) { + add_row_to_table(_u8L("Distance XYZ") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(*measure.distance_xyz), + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + ImGui::EndTable(); + } + } + else + m_imgui->text(_u8L("No measure available")); + } + + if (last_feature != m_curr_feature || last_mode != m_mode || last_selected_features != m_selected_features) { // the dialog may have changed its size, ask for an extra frame to render it properly last_feature = m_curr_feature; last_mode = m_mode; + last_selected_features = m_selected_features; m_imgui->set_requires_extra_frame(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 46b37737ae..9e0cbd946c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -23,14 +23,47 @@ enum class SLAGizmoEventType : unsigned char; class GLGizmoMeasure : public GLGizmoBase { -// This gizmo does not use grabbers. The m_hover_id relates to polygon managed by the class itself. - enum class EMode : unsigned char { BasicSelection, ExtendedSelection }; + struct SelectedFeatures + { + struct Item + { + EMode mode{ EMode::BasicSelection }; + std::optional feature; + + bool operator == (const Item& other) const { + if (this->mode != other.mode) return false; + return this->feature == other.feature; + } + + bool operator != (const Item& other) const { + return !operator == (other); + } + }; + + Item first; + Item second; + + void reset() { + first.feature.reset(); + second.feature.reset(); + } + + bool operator == (const SelectedFeatures& other) const { + if (this->first != other.first) return false; + return this->second == other.second; + } + + bool operator != (const SelectedFeatures& other) const { + return !operator == (other); + } + }; + EMode m_mode{ EMode::BasicSelection }; std::unique_ptr m_measuring; @@ -60,6 +93,8 @@ class GLGizmoMeasure : public GLGizmoBase KeyAutoRepeatFilter m_ctrl_kar_filter; + SelectedFeatures m_selected_features; + void update_if_needed(); public: From 5e271a18df789de7af53749b767a9587c726685b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 2 Sep 2022 12:26:56 +0200 Subject: [PATCH 040/250] Measuring: Changes in GLGizmoMeasure imgui dialog layout --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 97 ++++++++++++------------ src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 14 +++- 2 files changed, 61 insertions(+), 50 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 8c27678ce0..6fe6c36ef3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -15,19 +15,6 @@ #if ENABLE_MEASURE_GIZMO -std::string surface_feature_type_as_string(Slic3r::Measure::SurfaceFeatureType type) -{ - switch (type) - { - default: - case Slic3r::Measure::SurfaceFeatureType::Undef: { return L("Undefined"); } - case Slic3r::Measure::SurfaceFeatureType::Point: { return L("Vertex"); } - case Slic3r::Measure::SurfaceFeatureType::Edge: { return L("Edge"); } - case Slic3r::Measure::SurfaceFeatureType::Circle: { return L("Circle"); } - case Slic3r::Measure::SurfaceFeatureType::Plane: { return L("Plane"); } - } -} - namespace Slic3r { namespace GUI { @@ -47,6 +34,32 @@ static const std::string CTRL_STR = #endif //__APPLE__ ; +static std::string surface_feature_type_as_string(Measure::SurfaceFeatureType type) +{ + switch (type) + { + default: + case Measure::SurfaceFeatureType::Undef: { return L("Undefined"); } + case Measure::SurfaceFeatureType::Point: { return L("Vertex"); } + case Measure::SurfaceFeatureType::Edge: { return L("Edge"); } + case Measure::SurfaceFeatureType::Circle: { return L("Circle"); } + case Measure::SurfaceFeatureType::Plane: { return L("Plane"); } + } +} + +static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType type, int hover_id) +{ + std::string ret; + switch (type) { + case Measure::SurfaceFeatureType::Point: { ret = _u8L("Vertex"); break; } + case Measure::SurfaceFeatureType::Edge: { ret = _u8L("Point on edge"); break; } + case Measure::SurfaceFeatureType::Circle: { ret = (hover_id == POINT_ID) ? _u8L("Center of circle") : _u8L("Point on circle"); break; } + case Measure::SurfaceFeatureType::Plane: { ret = _u8L("Point on plane"); break; } + default: { assert(false); break; } + } + return ret; +} + static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const std::vector>& planes_triangles, int idx) { assert(0 <= idx && idx < (int)planes_triangles.size()); @@ -97,9 +110,9 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) m_mouse_left_down = true; auto set_item_from_feature = [this]() { - const SelectedFeatures::Item item = { m_mode, (m_mode == EMode::ExtendedSelection) ? - Measure::SurfaceFeature(Measure::SurfaceFeatureType::Point, *m_curr_ex_feature_position, Vec3d::Zero(), std::nullopt, 0.0) : - m_curr_feature }; + const SelectedFeatures::Item item = { m_mode, + (m_mode == EMode::ExtendedSelection) ? point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id) : surface_feature_type_as_string(m_curr_feature->get_type()), + (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(Measure::SurfaceFeatureType::Point, *m_curr_point_on_feature_position, Vec3d::Zero(), std::nullopt, 0.0) : m_curr_feature }; return item; }; @@ -179,7 +192,7 @@ void GLGizmoMeasure::on_set_state() if (m_state == Off) { m_ctrl_kar_filter.reset_count(); m_curr_feature.reset(); - m_curr_ex_feature_position.reset(); + m_curr_point_on_feature_position.reset(); } else m_mode = EMode::BasicSelection; @@ -231,7 +244,7 @@ void GLGizmoMeasure::on_render() curr_feature = m_measuring->get_feature(facet_idx, position_on_model.cast()); if (m_mode == EMode::BasicSelection) { - m_curr_ex_feature_position.reset(); + m_curr_point_on_feature_position.reset(); if (m_curr_feature != curr_feature) { GLGizmoMeasure::on_unregister_raycasters_for_picking(); m_curr_feature = curr_feature; @@ -291,7 +304,7 @@ void GLGizmoMeasure::on_render() default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { - m_curr_ex_feature_position = model_matrix * m_curr_feature->get_point(); + m_curr_point_on_feature_position = model_matrix * m_curr_feature->get_point(); break; } case Measure::SurfaceFeatureType::Edge: @@ -303,20 +316,20 @@ void GLGizmoMeasure::on_render() const Transform3d& trafo = it->second->get_transform(); it->second->get_raycaster()->unproject_on_mesh(m_mouse_pos, trafo, camera, p, n); p = { 0.0f, 0.0f, p.z() }; - m_curr_ex_feature_position = trafo * p.cast(); + m_curr_point_on_feature_position = trafo * p.cast(); } break; } case Measure::SurfaceFeatureType::Plane: { - m_curr_ex_feature_position = model_matrix * position_on_model.cast(); + m_curr_point_on_feature_position = model_matrix * position_on_model.cast(); break; } case Measure::SurfaceFeatureType::Circle: { const auto& [center, radius, normal] = m_curr_feature->get_circle(); if (m_hover_id == POINT_ID) - m_curr_ex_feature_position = model_matrix * center; + m_curr_point_on_feature_position = model_matrix * center; else { auto it = m_raycasters.find(CIRCLE_ID); if (it != m_raycasters.end() && it->second != nullptr) { @@ -328,7 +341,7 @@ void GLGizmoMeasure::on_render() if (angle < 0.0f) angle += 2.0f * float(M_PI); p = float(radius) * Vec3f(std::cos(angle), std::sin(angle), 0.0f); - m_curr_ex_feature_position = trafo * p.cast(); + m_curr_point_on_feature_position = trafo * p.cast(); } } break; @@ -490,12 +503,11 @@ void GLGizmoMeasure::on_render() (m_selected_features.second.mode == EMode::BasicSelection) ? model_matrix : Transform3d::Identity(), inv_zoom, false); } - if (is_hovering_on_extended_selection && m_curr_ex_feature_position.has_value()) { + if (is_hovering_on_extended_selection && m_curr_point_on_feature_position.has_value()) { if (m_hover_id != POINT_ID) { - const Transform3d matrix = Geometry::translation_transform(*m_curr_ex_feature_position) * Geometry::scale_transform(inv_zoom); + const Transform3d matrix = Geometry::translation_transform(*m_curr_point_on_feature_position) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(matrix); m_sphere.model.set_color(hover_selection_color()); -// m_sphere.model.set_color(EXTENDED_HOVER_COLOR); m_sphere.model.render(); } } @@ -591,12 +603,12 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit last_y = y; } - auto add_row_to_table = [this](const std::string& label, const ImVec4& label_color, const std::string& value, const ImVec4& value_color) { + auto add_row_to_table = [this](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) { ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); - m_imgui->text_colored(label_color, label); + m_imgui->text_colored(col_1_color, col_1); ImGui::TableSetColumnIndex(1); - m_imgui->text_colored(value_color, value); + m_imgui->text_colored(col_2_color, col_2); }; auto format_double = [](double value) { @@ -671,20 +683,11 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } } else if (m_mode == EMode::ExtendedSelection) { - if (m_hover_id != -1 && m_curr_ex_feature_position.has_value()) { - std::string header; - switch (feature_type) { - case Measure::SurfaceFeatureType::Point: { header = _u8L("Vertex"); break; } - case Measure::SurfaceFeatureType::Edge: { header = _u8L("Point on edge"); break; } - case Measure::SurfaceFeatureType::Circle: { header = (m_hover_id == POINT_ID) ? _u8L("Center of circle") : _u8L("Point on circle"); break; } - case Measure::SurfaceFeatureType::Plane: { header = _u8L("Point on plane"); break; } - default: { assert(false); break; } - } - + if (m_hover_id != -1 && m_curr_point_on_feature_position.has_value()) { ImGui::Separator(); - m_imgui->text(header + ":"); + m_imgui->text(point_on_feature_type_as_string(feature_type, m_hover_id) + ":"); if (ImGui::BeginTable("Data", 2)) { - add_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(*m_curr_ex_feature_position), + add_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(*m_curr_point_on_feature_position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); } @@ -693,12 +696,12 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } ImGui::Separator(); - m_imgui->text(_u8L("Selection")); - if (ImGui::BeginTable("Selection", 2)) { - add_row_to_table("1", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), m_selected_features.first.feature.has_value() ? - surface_feature_type_as_string(m_selected_features.first.feature->get_type()) : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR)); - add_row_to_table("2", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), m_selected_features.second.feature.has_value() ? - surface_feature_type_as_string(m_selected_features.second.feature->get_type()) : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR)); + const ImGuiTableFlags flags = /*ImGuiTableFlags_SizingStretchSame | */ImGuiTableFlags_BordersOuter | /*ImGuiTableFlags_BordersV | */ImGuiTableFlags_BordersH; + if (ImGui::BeginTable("Selection", 2, flags)) { + add_row_to_table(_u8L("Selection") + " 1:", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), m_selected_features.first.feature.has_value() ? + m_selected_features.first.source : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR)); + add_row_to_table(_u8L("Selection") + " 2:", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), m_selected_features.second.feature.has_value() ? + m_selected_features.second.source : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR)); ImGui::EndTable(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 9e0cbd946c..5755d9a912 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -34,24 +34,32 @@ class GLGizmoMeasure : public GLGizmoBase struct Item { EMode mode{ EMode::BasicSelection }; + std::string source; std::optional feature; bool operator == (const Item& other) const { if (this->mode != other.mode) return false; + if (this->source != other.source) return false; return this->feature == other.feature; } bool operator != (const Item& other) const { return !operator == (other); } + + void reset() { + mode = EMode::BasicSelection; + source.clear(); + feature.reset(); + } }; Item first; Item second; void reset() { - first.feature.reset(); - second.feature.reset(); + first.reset(); + second.reset(); } bool operator == (const SelectedFeatures& other) const { @@ -75,7 +83,7 @@ class GLGizmoMeasure : public GLGizmoBase std::vector m_plane_models_cache; std::map> m_raycasters; std::optional m_curr_feature; - std::optional m_curr_ex_feature_position; + std::optional m_curr_point_on_feature_position; // These hold information to decide whether recalculation is necessary: std::vector m_volumes_matrices; From 91266e48158ed1c7e47a18eab0c7aaa4551838bd Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 5 Sep 2022 08:26:19 +0200 Subject: [PATCH 041/250] Measuring: Disable scene raycasters while GLGizmoMeasure is active --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 101 +++++++++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 5 ++ 2 files changed, 71 insertions(+), 35 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 6fe6c36ef3..8fddf11adf 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -167,8 +167,10 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po { if (action == SLAGizmoEventType::CtrlDown) { if (m_ctrl_kar_filter.is_first()) { - if (m_curr_feature.has_value()) + if (m_curr_feature.has_value()) { m_mode = EMode::ExtendedSelection; + disable_scene_raycasters(); + } } m_ctrl_kar_filter.increase_count(); @@ -176,6 +178,7 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po else if (action == SLAGizmoEventType::CtrlUp) { m_ctrl_kar_filter.reset_count(); m_mode = EMode::BasicSelection; + restore_scene_raycasters_state(); } return true; @@ -193,9 +196,19 @@ void GLGizmoMeasure::on_set_state() m_ctrl_kar_filter.reset_count(); m_curr_feature.reset(); m_curr_point_on_feature_position.reset(); + restore_scene_raycasters_state(); } - else + else { m_mode = EMode::BasicSelection; + // store current state of scene raycaster for later use + m_scene_raycaster_state.clear(); + m_scene_raycasters = m_parent.get_raycasters_for_picking(SceneRaycaster::EType::Volume); + if (m_scene_raycasters != nullptr) { + for (const auto r : *m_scene_raycasters) { + m_scene_raycaster_state.emplace_back(r->is_active()); + } + } + } } CommonGizmosDataID GLGizmoMeasure::on_get_requirements() const @@ -234,16 +247,13 @@ void GLGizmoMeasure::on_render() Vec3f position_on_model; Vec3f normal_on_model; - size_t facet_idx; - m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, model_matrix, camera, position_on_model, normal_on_model, nullptr, &facet_idx); + size_t model_facet_idx; + m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, model_matrix, camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); - const bool is_hovering_on_extended_selection = m_mode == EMode::ExtendedSelection && m_hover_id != -1; - - std::optional curr_feature; - if (m_mode == EMode::BasicSelection) - curr_feature = m_measuring->get_feature(facet_idx, position_on_model.cast()); + const bool is_hovering_on_locked_feature = m_mode == EMode::ExtendedSelection && m_hover_id != -1; if (m_mode == EMode::BasicSelection) { + std::optional curr_feature = m_measuring->get_feature(model_facet_idx, position_on_model.cast()); m_curr_point_on_feature_position.reset(); if (m_curr_feature != curr_feature) { GLGizmoMeasure::on_unregister_raycasters_for_picking(); @@ -265,8 +275,7 @@ void GLGizmoMeasure::on_render() } case Measure::SurfaceFeatureType::Circle: { - const auto& [center, radius, normal] = m_curr_feature->get_circle(); - + const auto [center, radius, normal] = m_curr_feature->get_circle(); if (m_last_inv_zoom != inv_zoom) { m_last_inv_zoom = inv_zoom; m_circle.reset(); @@ -281,7 +290,7 @@ void GLGizmoMeasure::on_render() } case Measure::SurfaceFeatureType::Plane: { - const auto& [idx, normal, point] = m_curr_feature->get_plane(); + const auto [idx, normal, point] = m_curr_feature->get_plane(); if (m_last_plane_idx != idx) { m_last_plane_idx = idx; const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; @@ -298,7 +307,23 @@ void GLGizmoMeasure::on_render() } } } - else if (is_hovering_on_extended_selection) { + else if (is_hovering_on_locked_feature) { + auto default_callback = [](const Vec3f& v) { return v; }; + auto position_on_feature = [this](int feature_type_id, const Camera& camera, std::function callback = nullptr) -> Vec3d { + auto it = m_raycasters.find(feature_type_id); + if (it != m_raycasters.end() && it->second != nullptr) { + Vec3f p; + Vec3f n; + const Transform3d& trafo = it->second->get_transform(); + bool res = it->second->get_raycaster()->closest_hit(m_mouse_pos, trafo, camera, p, n); + assert(res); + if (callback) + p = callback(p); + return trafo * p.cast(); + } + return Vec3d::Zero(); + }; + switch (m_curr_feature->get_type()) { default: { assert(false); break; } @@ -309,40 +334,27 @@ void GLGizmoMeasure::on_render() } case Measure::SurfaceFeatureType::Edge: { - auto it = m_raycasters.find(EDGE_ID); - if (it != m_raycasters.end() && it->second != nullptr) { - Vec3f p; - Vec3f n; - const Transform3d& trafo = it->second->get_transform(); - it->second->get_raycaster()->unproject_on_mesh(m_mouse_pos, trafo, camera, p, n); - p = { 0.0f, 0.0f, p.z() }; - m_curr_point_on_feature_position = trafo * p.cast(); - } + m_curr_point_on_feature_position = position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); break; } case Measure::SurfaceFeatureType::Plane: { - m_curr_point_on_feature_position = model_matrix * position_on_model.cast(); + m_curr_point_on_feature_position = position_on_feature(PLANE_ID, camera); break; } case Measure::SurfaceFeatureType::Circle: { - const auto& [center, radius, normal] = m_curr_feature->get_circle(); + const auto [center, radius, normal] = m_curr_feature->get_circle(); if (m_hover_id == POINT_ID) m_curr_point_on_feature_position = model_matrix * center; else { - auto it = m_raycasters.find(CIRCLE_ID); - if (it != m_raycasters.end() && it->second != nullptr) { - Vec3f p; - Vec3f n; - const Transform3d& trafo = it->second->get_transform(); - it->second->get_raycaster()->unproject_on_mesh(m_mouse_pos, trafo, camera, p, n); - float angle = std::atan2(p.y(), p.x()); + const float r = radius; // needed for the following lambda + m_curr_point_on_feature_position = position_on_feature(CIRCLE_ID, camera, [r](const Vec3f& v) { + float angle = std::atan2(v.y(), v.x()); if (angle < 0.0f) angle += 2.0f * float(M_PI); - p = float(radius) * Vec3f(std::cos(angle), std::sin(angle), 0.0f); - m_curr_point_on_feature_position = trafo * p.cast(); - } + return float(r) * Vec3f(std::cos(angle), std::sin(angle), 0.0f); + }); } break; } @@ -503,7 +515,7 @@ void GLGizmoMeasure::on_render() (m_selected_features.second.mode == EMode::BasicSelection) ? model_matrix : Transform3d::Identity(), inv_zoom, false); } - if (is_hovering_on_extended_selection && m_curr_point_on_feature_position.has_value()) { + if (is_hovering_on_locked_feature && m_curr_point_on_feature_position.has_value()) { if (m_hover_id != POINT_ID) { const Transform3d matrix = Geometry::translation_transform(*m_curr_point_on_feature_position) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(matrix); @@ -579,6 +591,25 @@ void GLGizmoMeasure::update_if_needed() } } +void GLGizmoMeasure::disable_scene_raycasters() +{ + if (m_scene_raycasters != nullptr) { + for (auto r : *m_scene_raycasters) { + r->set_active(false); + } + } +} + +void GLGizmoMeasure::restore_scene_raycasters_state() +{ + if (m_scene_raycasters != nullptr) { + assert(m_scene_raycasters->size() == m_scene_raycaster_state.size()); + for (size_t i = 0; i < m_scene_raycasters->size(); ++i) { + (*m_scene_raycasters)[i]->set_active(m_scene_raycaster_state[i]); + } + } +} + void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit) { static std::optional last_feature; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 5755d9a912..3bbeb92b44 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -84,6 +84,8 @@ class GLGizmoMeasure : public GLGizmoBase std::map> m_raycasters; std::optional m_curr_feature; std::optional m_curr_point_on_feature_position; + std::vector>* m_scene_raycasters{ nullptr }; + std::vector m_scene_raycaster_state; // These hold information to decide whether recalculation is necessary: std::vector m_volumes_matrices; @@ -105,6 +107,9 @@ class GLGizmoMeasure : public GLGizmoBase void update_if_needed(); + void disable_scene_raycasters(); + void restore_scene_raycasters_state(); + public: GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); From ae3beeb50a60631f4c6c67162d709d3ee34506a7 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 5 Sep 2022 08:57:49 +0200 Subject: [PATCH 042/250] Fixed warnings --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 8fddf11adf..74a5c93f7c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -308,7 +308,6 @@ void GLGizmoMeasure::on_render() } } else if (is_hovering_on_locked_feature) { - auto default_callback = [](const Vec3f& v) { return v; }; auto position_on_feature = [this](int feature_type_id, const Camera& camera, std::function callback = nullptr) -> Vec3d { auto it = m_raycasters.find(feature_type_id); if (it != m_raycasters.end() && it->second != nullptr) { @@ -317,9 +316,11 @@ void GLGizmoMeasure::on_render() const Transform3d& trafo = it->second->get_transform(); bool res = it->second->get_raycaster()->closest_hit(m_mouse_pos, trafo, camera, p, n); assert(res); - if (callback) - p = callback(p); - return trafo * p.cast(); + if (res) { + if (callback) + p = callback(p); + return trafo * p.cast(); + } } return Vec3d::Zero(); }; From 8050d457d38cd1250cb529a5ad17d845ef7fdc68 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 5 Sep 2022 09:18:07 +0200 Subject: [PATCH 043/250] Measuring: GLGizmoMeasure - Fixed update of circle geometry --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 3 ++- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 74a5c93f7c..bf7fd04a7d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -276,8 +276,9 @@ void GLGizmoMeasure::on_render() case Measure::SurfaceFeatureType::Circle: { const auto [center, radius, normal] = m_curr_feature->get_circle(); - if (m_last_inv_zoom != inv_zoom) { + if (m_last_inv_zoom != inv_zoom || m_last_circle != m_curr_feature) { m_last_inv_zoom = inv_zoom; + m_last_circle = m_curr_feature; m_circle.reset(); GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 3bbeb92b44..d74fb9ed8e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -93,6 +93,7 @@ class GLGizmoMeasure : public GLGizmoBase Vec3d m_first_instance_scale{ Vec3d::Ones() }; Vec3d m_first_instance_mirror{ Vec3d::Ones() }; float m_last_inv_zoom{ 0.0f }; + std::optional m_last_circle; int m_last_plane_idx{ -1 }; bool m_mouse_left_down{ false }; // for detection left_up of this gizmo From bac3eebf51e5fdb5cd189aff06d2ad7678562b08 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 5 Sep 2022 12:05:25 +0200 Subject: [PATCH 044/250] Measuring: GLGizmoMeasure - show data in inches into imgui dialog, when needed --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 42 ++++++++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index bf7fd04a7d..f8f84d7bc8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -3,6 +3,7 @@ #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/Plater.hpp" +#include "slic3r/GUI/GUI_ObjectManipulation.hpp" #include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" @@ -664,6 +665,9 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::EndTable(); } + const bool use_inches = wxGetApp().app_config->get("use_inches") == "1"; + const std::string units = use_inches ? _u8L(" (in)") : _u8L(" (mm)"); + if (m_curr_feature.has_value()) { const Transform3d volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); const Measure::SurfaceFeatureType feature_type = m_curr_feature->get_type(); @@ -677,7 +681,9 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { - const Vec3d position = volume_matrix * m_curr_feature->get_point(); + Vec3d position = volume_matrix * m_curr_feature->get_point(); + if (use_inches) + position = ObjectManipulation::mm_to_in * position; add_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } @@ -686,9 +692,13 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit auto [from, to] = m_curr_feature->get_edge(); from = volume_matrix * from; to = volume_matrix * to; + if (use_inches) { + from = ObjectManipulation::mm_to_in * from; + to = ObjectManipulation::mm_to_in * to; + } add_row_to_table(_u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_row_to_table(_u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_row_to_table(_u8L("Length") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_row_to_table(_u8L("Length") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } case Measure::SurfaceFeatureType::Circle: @@ -696,8 +706,12 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit auto [center, radius, normal] = m_curr_feature->get_circle(); center = volume_matrix * center; normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + if (use_inches) { + center = ObjectManipulation::mm_to_in * center; + radius = ObjectManipulation::mm_to_in * radius; + } add_row_to_table(_u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_row_to_table(_u8L("Radius") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_row_to_table(_u8L("Radius") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } @@ -706,6 +720,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit auto [idx, normal, origin] = m_curr_feature->get_plane(); origin = volume_matrix * origin; normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + if (use_inches) + origin = ObjectManipulation::mm_to_in * origin; add_row_to_table(_u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; @@ -720,7 +736,10 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::Separator(); m_imgui->text(point_on_feature_type_as_string(feature_type, m_hover_id) + ":"); if (ImGui::BeginTable("Data", 2)) { - add_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(*m_curr_point_on_feature_position), + Vec3d position = ObjectManipulation::mm_to_in * *m_curr_point_on_feature_position; + if (use_inches) + position = ObjectManipulation::mm_to_in * position; + add_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); } @@ -756,15 +775,24 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::GetStyleColorVec4(ImGuiCol_Text)); } if (measure.distance_infinite.has_value()) { - add_row_to_table(_u8L("Distance Infinite") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(*measure.distance_infinite), + double distance = ObjectManipulation::mm_to_in * *measure.distance_infinite; + if (use_inches) + distance = ObjectManipulation::mm_to_in * distance; + add_row_to_table(_u8L("Distance Infinite") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } if (measure.distance_strict.has_value()) { - add_row_to_table(_u8L("Distance Strict") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(*measure.distance_strict), + double distance = ObjectManipulation::mm_to_in * *measure.distance_strict; + if (use_inches) + distance = ObjectManipulation::mm_to_in * distance; + add_row_to_table(_u8L("Distance Strict") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } if (measure.distance_xyz.has_value()) { - add_row_to_table(_u8L("Distance XYZ") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(*measure.distance_xyz), + Vec3d distance = ObjectManipulation::mm_to_in * *measure.distance_xyz; + if (use_inches) + distance = ObjectManipulation::mm_to_in * distance; + add_row_to_table(_u8L("Distance XYZ") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } ImGui::EndTable(); From 8a88b98f7f32fa9c276e45ce6edb7f599d3d3171 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 5 Sep 2022 12:49:19 +0200 Subject: [PATCH 045/250] Measuring: GLGizmoMeasure - Fixed detection of current hovered feature --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index f8f84d7bc8..40ca6d3df3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -249,12 +249,11 @@ void GLGizmoMeasure::on_render() Vec3f position_on_model; Vec3f normal_on_model; size_t model_facet_idx; - m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, model_matrix, camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); - + const bool mouse_on_object = m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, model_matrix, camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); const bool is_hovering_on_locked_feature = m_mode == EMode::ExtendedSelection && m_hover_id != -1; if (m_mode == EMode::BasicSelection) { - std::optional curr_feature = m_measuring->get_feature(model_facet_idx, position_on_model.cast()); + std::optional curr_feature = mouse_on_object ? m_measuring->get_feature(model_facet_idx, position_on_model.cast()) : std::nullopt; m_curr_point_on_feature_position.reset(); if (m_curr_feature != curr_feature) { GLGizmoMeasure::on_unregister_raycasters_for_picking(); @@ -552,7 +551,7 @@ void GLGizmoMeasure::update_if_needed() // Let's save what we calculated it from: m_volumes_matrices.clear(); m_volumes_types.clear(); - m_first_instance_scale = Vec3d::Ones(); + m_first_instance_scale = Vec3d::Ones(); m_first_instance_mirror = Vec3d::Ones(); if (object != nullptr) { for (const ModelVolume* vol : object->volumes) { From b788628a18929bd20b00279de869b01520af7fe2 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 5 Sep 2022 13:26:01 +0200 Subject: [PATCH 046/250] Fixed warnings on ARM64 --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 40ca6d3df3..c1e81ff21d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -89,11 +89,11 @@ GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filen : GLGizmoBase(parent, icon_filename, sprite_id) { GLModel::Geometry sphere_geometry = smooth_sphere(16, 7.5f); - m_sphere.mesh_raycaster = std::make_unique(std::make_shared(std::move(sphere_geometry.get_as_indexed_triangle_set()))); + m_sphere.mesh_raycaster = std::make_unique(std::make_shared(sphere_geometry.get_as_indexed_triangle_set())); m_sphere.model.init_from(std::move(sphere_geometry)); GLModel::Geometry cylinder_geometry = smooth_cylinder(16, 5.0f, 1.0f); - m_cylinder.mesh_raycaster = std::make_unique(std::make_shared(std::move(cylinder_geometry.get_as_indexed_triangle_set()))); + m_cylinder.mesh_raycaster = std::make_unique(std::make_shared(cylinder_geometry.get_as_indexed_triangle_set())); m_cylinder.model.init_from(std::move(cylinder_geometry)); } @@ -205,7 +205,7 @@ void GLGizmoMeasure::on_set_state() m_scene_raycaster_state.clear(); m_scene_raycasters = m_parent.get_raycasters_for_picking(SceneRaycaster::EType::Volume); if (m_scene_raycasters != nullptr) { - for (const auto r : *m_scene_raycasters) { + for (const auto& r : *m_scene_raycasters) { m_scene_raycaster_state.emplace_back(r->is_active()); } } @@ -281,7 +281,7 @@ void GLGizmoMeasure::on_render() m_last_circle = m_curr_feature; m_circle.reset(); GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); - m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); + m_circle.mesh_raycaster = std::make_unique(std::make_shared(circle_geometry.get_as_indexed_triangle_set())); m_circle.model.init_from(std::move(circle_geometry)); } @@ -298,7 +298,7 @@ void GLGizmoMeasure::on_render() const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); GLModel::Geometry init_data = init_plane_data(its, planes_triangles, idx); m_plane.reset(); - m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(init_data.get_as_indexed_triangle_set()))); + m_plane.mesh_raycaster = std::make_unique(std::make_shared(init_data.get_as_indexed_triangle_set())); m_plane.model.init_from(std::move(init_data)); } From cb57b3c5cb4bd8e849f41dee04e52a82ed007288 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 5 Sep 2022 15:16:31 +0200 Subject: [PATCH 047/250] Measuring: GLGizmoMeasure - Added colored icon into imgui dialog --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 68 +++++++++++++++--------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index c1e81ff21d..21e86532a1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -636,12 +636,20 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit last_y = y; } - auto add_row_to_table = [this](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) { + auto add_row_to_table = [this](std::function col_1 = nullptr, std::function col_2 = nullptr) { + assert(col_1 != nullptr && col_2 != nullptr); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); - m_imgui->text_colored(col_1_color, col_1); + col_1(); ImGui::TableSetColumnIndex(1); - m_imgui->text_colored(col_2_color, col_2); + col_2(); + }; + + auto add_strings_row_to_table = [this, add_row_to_table](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) { + add_row_to_table( + [this, &col_1, &col_1_color]() { m_imgui->text_colored(col_1_color, col_1); }, + [this, &col_2, &col_2_color]() { m_imgui->text_colored(col_2_color, col_2); } + ); }; auto format_double = [](double value) { @@ -657,10 +665,22 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit }; if (ImGui::BeginTable("Commands", 2)) { - add_row_to_table(_u8L("Left mouse button"), ImGuiWrapper::COL_ORANGE_LIGHT, - (m_mode == EMode::BasicSelection) ? _u8L("Select feature") : _u8L("Select point"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_row_to_table( + [this]() { + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Left mouse button")); + }, + [this]() { + m_imgui->text_colored(ImGui::GetStyleColorVec4(ImGuiCol_Text), (m_mode == EMode::BasicSelection) ? _u8L("Select feature") : _u8L("Select point")); + ImGui::SameLine(); + const ImVec2 pos = ImGui::GetCursorScreenPos(); + const float rect_size = ImGui::GetTextLineHeight(); + ImGui::GetWindowDrawList()->AddRectFilled({ pos.x + 1.0f, pos.y + 1.0f }, { pos.x + rect_size, pos.y + rect_size }, + ImGuiWrapper::to_ImU32(m_selected_features.first.feature.has_value() ? SELECTED_2ND_COLOR : SELECTED_1ST_COLOR)); + ImGui::Dummy(ImVec2(rect_size, rect_size)); + } + ); if (m_mode == EMode::BasicSelection && m_hover_id != -1) - add_row_to_table(CTRL_STR, ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable point selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(CTRL_STR, ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable point selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); } @@ -683,7 +703,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit Vec3d position = volume_matrix * m_curr_feature->get_point(); if (use_inches) position = ObjectManipulation::mm_to_in * position; - add_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } case Measure::SurfaceFeatureType::Edge: @@ -695,9 +715,9 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit from = ObjectManipulation::mm_to_in * from; to = ObjectManipulation::mm_to_in * to; } - add_row_to_table(_u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_row_to_table(_u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_row_to_table(_u8L("Length") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(_u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(_u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(_u8L("Length") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } case Measure::SurfaceFeatureType::Circle: @@ -709,9 +729,9 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit center = ObjectManipulation::mm_to_in * center; radius = ObjectManipulation::mm_to_in * radius; } - add_row_to_table(_u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_row_to_table(_u8L("Radius") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(_u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(_u8L("Radius") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } case Measure::SurfaceFeatureType::Plane: @@ -721,8 +741,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; if (use_inches) origin = ObjectManipulation::mm_to_in * origin; - add_row_to_table(_u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(_u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } } @@ -738,7 +758,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit Vec3d position = ObjectManipulation::mm_to_in * *m_curr_point_on_feature_position; if (use_inches) position = ObjectManipulation::mm_to_in * position; - add_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), + add_strings_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); } @@ -747,11 +767,11 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } ImGui::Separator(); - const ImGuiTableFlags flags = /*ImGuiTableFlags_SizingStretchSame | */ImGuiTableFlags_BordersOuter | /*ImGuiTableFlags_BordersV | */ImGuiTableFlags_BordersH; + const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; if (ImGui::BeginTable("Selection", 2, flags)) { - add_row_to_table(_u8L("Selection") + " 1:", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), m_selected_features.first.feature.has_value() ? + add_strings_row_to_table(_u8L("Selection") + " 1:", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), m_selected_features.first.feature.has_value() ? m_selected_features.first.source : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR)); - add_row_to_table(_u8L("Selection") + " 2:", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), m_selected_features.second.feature.has_value() ? + add_strings_row_to_table(_u8L("Selection") + " 2:", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), m_selected_features.second.feature.has_value() ? m_selected_features.second.source : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR)); ImGui::EndTable(); } @@ -767,31 +787,31 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit const Measure::MeasurementResult measure = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature); ImGui::Separator(); if (measure.has_any_data()) { - m_imgui->text(_u8L("Measure")); + m_imgui->text(_u8L("Measure") + ":"); if (ImGui::BeginTable("Measure", 2)) { if (measure.angle.has_value()) { - add_row_to_table(_u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(*measure.angle)), + add_strings_row_to_table(_u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(*measure.angle)), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } if (measure.distance_infinite.has_value()) { double distance = ObjectManipulation::mm_to_in * *measure.distance_infinite; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - add_row_to_table(_u8L("Distance Infinite") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), + add_strings_row_to_table(_u8L("Distance Infinite") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } if (measure.distance_strict.has_value()) { double distance = ObjectManipulation::mm_to_in * *measure.distance_strict; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - add_row_to_table(_u8L("Distance Strict") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), + add_strings_row_to_table(_u8L("Distance Strict") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } if (measure.distance_xyz.has_value()) { Vec3d distance = ObjectManipulation::mm_to_in * *measure.distance_xyz; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - add_row_to_table(_u8L("Distance XYZ") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), + add_strings_row_to_table(_u8L("Distance XYZ") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } ImGui::EndTable(); From 49885b9c6f8948c723ff8c6f93dc2b8388f6a3ae Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 6 Sep 2022 10:17:53 +0200 Subject: [PATCH 048/250] Measuring: Added missing default values to SurfaceFeature member variables --- src/libslic3r/Measure.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 3aefc0b54b..3b811db0c5 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -64,9 +64,9 @@ public: } private: - SurfaceFeatureType m_type = SurfaceFeatureType::Undef; - Vec3d m_pt1; - Vec3d m_pt2; + SurfaceFeatureType m_type{ SurfaceFeatureType::Undef }; + Vec3d m_pt1{ Vec3d::Zero() }; + Vec3d m_pt2{ Vec3d::Zero() }; std::optional m_pt3; double m_value{ 0.0 }; }; From 80e1d8298b0feb335aa2d5752ca74df4076484e5 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 6 Sep 2022 10:54:56 +0200 Subject: [PATCH 049/250] Measuring: Rewritten method SurfaceFeature::operator ==() --- src/libslic3r/Measure.hpp | 23 ++++++++++++++++------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 4 ++-- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 3b811db0c5..5d71983f0b 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -44,19 +44,28 @@ public: std::tuple get_circle() const { assert(m_type == SurfaceFeatureType::Circle); return std::make_tuple(m_pt1, m_value, m_pt2); } // For planes, return index into vector provided by Measuring::get_plane_triangle_indices, normal and point. - std::tuple get_plane() const { return std::make_tuple(int(m_value), m_pt1, m_pt2); } + std::tuple get_plane() const { assert(m_type == SurfaceFeatureType::Plane); return std::make_tuple(int(m_value), m_pt1, m_pt2); } // For anything, return an extra point that should also be considered a part of this. std::optional get_extra_point() const { assert(m_type != SurfaceFeatureType::Undef); return m_pt3; } bool operator == (const SurfaceFeature& other) const { if (this->m_type != other.m_type) return false; - if (!this->m_pt1.isApprox(other.m_pt1)) return false; - if (!this->m_pt2.isApprox(other.m_pt2)) return false; - if (this->m_pt3.has_value() && !other.m_pt3.has_value()) return false; - if (!this->m_pt3.has_value() && other.m_pt3.has_value()) return false; - if (this->m_pt3.has_value() && other.m_pt3.has_value() && !(*this->m_pt3).isApprox(*other.m_pt3)) return false; - return this->m_value == other.m_value; + switch (this->m_type) + { + case SurfaceFeatureType::Undef: { break; } + case SurfaceFeatureType::Point: { return (this->m_pt1.isApprox(other.m_pt1)); } + case SurfaceFeatureType::Edge: { + return (this->m_pt1.isApprox(other.m_pt1) && this->m_pt2.isApprox(other.m_pt2)) || + (this->m_pt1.isApprox(other.m_pt2) && this->m_pt2.isApprox(other.m_pt1)); + } + case SurfaceFeatureType::Plane: + case SurfaceFeatureType::Circle: { + return (this->m_pt1.isApprox(other.m_pt1) && this->m_pt2.isApprox(other.m_pt2) && std::abs(this->m_value - other.m_value) < EPSILON); + } + } + + return false; } bool operator != (const SurfaceFeature& other) const { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 21e86532a1..942a8c93eb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -113,7 +113,7 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) auto set_item_from_feature = [this]() { const SelectedFeatures::Item item = { m_mode, (m_mode == EMode::ExtendedSelection) ? point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id) : surface_feature_type_as_string(m_curr_feature->get_type()), - (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(Measure::SurfaceFeatureType::Point, *m_curr_point_on_feature_position, Vec3d::Zero(), std::nullopt, 0.0) : m_curr_feature }; + (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(*m_curr_point_on_feature_position) : m_curr_feature }; return item; }; @@ -331,7 +331,7 @@ void GLGizmoMeasure::on_render() default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { - m_curr_point_on_feature_position = model_matrix * m_curr_feature->get_point(); + m_curr_point_on_feature_position = position_on_feature(POINT_ID, camera); break; } case Measure::SurfaceFeatureType::Edge: From 2b7520dc9eee8063c7d376811603c2d09c4a75e4 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 6 Sep 2022 12:02:44 +0200 Subject: [PATCH 050/250] Measuring: GLGizmoMeasure - Use mouse right click to restart selection --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 49 ++++++++++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 + 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 942a8c93eb..ebf3139868 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -110,20 +110,13 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) if (m_hover_id != -1) { m_mouse_left_down = true; - auto set_item_from_feature = [this]() { - const SelectedFeatures::Item item = { m_mode, - (m_mode == EMode::ExtendedSelection) ? point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id) : surface_feature_type_as_string(m_curr_feature->get_type()), - (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(*m_curr_point_on_feature_position) : m_curr_feature }; - return item; - }; - if (m_selected_features.first.feature.has_value()) { - const SelectedFeatures::Item item = set_item_from_feature(); + const SelectedFeatures::Item item = item_from_feature(); if (m_selected_features.first != item) m_selected_features.second = item; } else - m_selected_features.first = set_item_from_feature(); + m_selected_features.first = item_from_feature(); return true; } @@ -140,6 +133,16 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) return true; } } + else if (mouse_event.RightDown()) { + if (m_hover_id != -1) { + if (m_selected_features.first.feature.has_value()) { + if (m_selected_features.first == item_from_feature()) { + m_selected_features.reset(); + m_imgui->set_requires_extra_frame(); + } + } + } + } else if (mouse_event.Leaving()) m_mouse_left_down = false; @@ -612,6 +615,14 @@ void GLGizmoMeasure::restore_scene_raycasters_state() } } +GLGizmoMeasure::SelectedFeatures::Item GLGizmoMeasure::item_from_feature() const +{ + const SelectedFeatures::Item item = { m_mode, + (m_mode == EMode::ExtendedSelection) ? point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id) : surface_feature_type_as_string(m_curr_feature->get_type()), + (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(*m_curr_point_on_feature_position) : m_curr_feature }; + return item; +} + void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit) { static std::optional last_feature; @@ -679,6 +690,14 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::Dummy(ImVec2(rect_size, rect_size)); } ); + + if (m_hover_id != -1) { + if (m_selected_features.first.feature.has_value()) { + if (m_selected_features.first == item_from_feature()) + add_strings_row_to_table(_u8L("Right mouse button"), ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + } + if (m_mode == EMode::BasicSelection && m_hover_id != -1) add_strings_row_to_table(CTRL_STR, ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable point selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); @@ -776,12 +795,12 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::EndTable(); } - if (m_selected_features.first.feature.has_value()) { - if (m_imgui->button(_u8L("Restart"))) { - m_selected_features.reset(); - m_imgui->set_requires_extra_frame(); - } - } + //if (m_selected_features.first.feature.has_value()) { + // if (m_imgui->button(_u8L("Restart"))) { + // m_selected_features.reset(); + // m_imgui->set_requires_extra_frame(); + // } + //} if (m_selected_features.second.feature.has_value()) { const Measure::MeasurementResult measure = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index d74fb9ed8e..ccd542b86a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -110,6 +110,7 @@ class GLGizmoMeasure : public GLGizmoBase void disable_scene_raycasters(); void restore_scene_raycasters_state(); + SelectedFeatures::Item item_from_feature() const; public: GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); From 67c004498c0a38bb89466007bf273d01178a2c7e Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 6 Sep 2022 15:06:56 +0200 Subject: [PATCH 051/250] Follow-up of 2b7520dc9eee8063c7d376811603c2d09c4a75e4 - Use CTRL + mouse right click to restart selection --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 35 ++++++++---------------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 - 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index ebf3139868..f1a011e572 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -109,6 +109,13 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) else if (mouse_event.LeftDown()) { if (m_hover_id != -1) { m_mouse_left_down = true; + + auto item_from_feature = [this]() { + const SelectedFeatures::Item item = { m_mode, + (m_mode == EMode::ExtendedSelection) ? point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id) : surface_feature_type_as_string(m_curr_feature->get_type()), + (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(*m_curr_point_on_feature_position) : m_curr_feature }; + return item; + }; if (m_selected_features.first.feature.has_value()) { const SelectedFeatures::Item item = item_from_feature(); @@ -133,15 +140,9 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) return true; } } - else if (mouse_event.RightDown()) { - if (m_hover_id != -1) { - if (m_selected_features.first.feature.has_value()) { - if (m_selected_features.first == item_from_feature()) { - m_selected_features.reset(); - m_imgui->set_requires_extra_frame(); - } - } - } + else if (mouse_event.RightDown() && mouse_event.CmdDown()) { + m_selected_features.reset(); + m_imgui->set_requires_extra_frame(); } else if (mouse_event.Leaving()) m_mouse_left_down = false; @@ -615,14 +616,6 @@ void GLGizmoMeasure::restore_scene_raycasters_state() } } -GLGizmoMeasure::SelectedFeatures::Item GLGizmoMeasure::item_from_feature() const -{ - const SelectedFeatures::Item item = { m_mode, - (m_mode == EMode::ExtendedSelection) ? point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id) : surface_feature_type_as_string(m_curr_feature->get_type()), - (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(*m_curr_point_on_feature_position) : m_curr_feature }; - return item; -} - void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit) { static std::optional last_feature; @@ -691,12 +684,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } ); - if (m_hover_id != -1) { - if (m_selected_features.first.feature.has_value()) { - if (m_selected_features.first == item_from_feature()) - add_strings_row_to_table(_u8L("Right mouse button"), ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - } - } + if (m_selected_features.first.feature.has_value()) + add_strings_row_to_table(CTRL_STR + "+" + _u8L("Right mouse button"), ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); if (m_mode == EMode::BasicSelection && m_hover_id != -1) add_strings_row_to_table(CTRL_STR, ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable point selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index ccd542b86a..d74fb9ed8e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -110,7 +110,6 @@ class GLGizmoMeasure : public GLGizmoBase void disable_scene_raycasters(); void restore_scene_raycasters_state(); - SelectedFeatures::Item item_from_feature() const; public: GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); From 2dd67745a5086b72e2f7ea8b0d31e129247e6378 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 7 Sep 2022 13:07:15 +0200 Subject: [PATCH 052/250] Measuring: bunch of fixes into GLGizmoMeasure + new tech ENABLE_MEASURE_GIZMO_DEBUG to show a debug imgui dialog containing data related to Measure Gizmo --- src/libslic3r/Technologies.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 222 +++++++++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 12 +- 3 files changed, 152 insertions(+), 83 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index ebb469e509..903612f29b 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -78,6 +78,7 @@ #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) // Enable Measure Gizmo #define ENABLE_MEASURE_GIZMO (1 && ENABLE_RAYCAST_PICKING) +#define ENABLE_MEASURE_GIZMO_DEBUG (0 && ENABLE_MEASURE_GIZMO) #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index f1a011e572..b434cea9a7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -111,7 +111,7 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) m_mouse_left_down = true; auto item_from_feature = [this]() { - const SelectedFeatures::Item item = { m_mode, + const SelectedFeatures::Item item = { (m_mode == EMode::ExtendedSelection) ? point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id) : surface_feature_type_as_string(m_curr_feature->get_type()), (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(*m_curr_point_on_feature_position) : m_curr_feature }; return item; @@ -236,6 +236,10 @@ bool GLGizmoMeasure::on_is_activable() const void GLGizmoMeasure::on_render() { +#if ENABLE_MEASURE_GIZMO_DEBUG + render_debug_dialog(); +#endif // ENABLE_MEASURE_GIZMO_DEBUG + // do not render if the user is panning/rotating the 3d scene if (m_parent.is_mouse_dragging()) return; @@ -246,14 +250,14 @@ void GLGizmoMeasure::on_render() (selection.is_single_volume() || selection.is_single_volume_instance())) { update_if_needed(); - const Transform3d& model_matrix = selection.get_first_volume()->world_matrix(); + m_volume_matrix = selection.get_first_volume()->world_matrix(); const Camera& camera = wxGetApp().plater()->get_camera(); const float inv_zoom = (float)camera.get_inv_zoom(); Vec3f position_on_model; Vec3f normal_on_model; size_t model_facet_idx; - const bool mouse_on_object = m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, model_matrix, camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); + const bool mouse_on_object = m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, m_volume_matrix, camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); const bool is_hovering_on_locked_feature = m_mode == EMode::ExtendedSelection && m_hover_id != -1; if (m_mode == EMode::BasicSelection) { @@ -335,31 +339,31 @@ void GLGizmoMeasure::on_render() default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { - m_curr_point_on_feature_position = position_on_feature(POINT_ID, camera); + m_curr_point_on_feature_position = m_curr_feature->get_point(); break; } case Measure::SurfaceFeatureType::Edge: { - m_curr_point_on_feature_position = position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); + m_curr_point_on_feature_position = m_volume_matrix.inverse() * position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); break; } case Measure::SurfaceFeatureType::Plane: { - m_curr_point_on_feature_position = position_on_feature(PLANE_ID, camera); + m_curr_point_on_feature_position = m_volume_matrix.inverse() * position_on_feature(PLANE_ID, camera); break; } case Measure::SurfaceFeatureType::Circle: { const auto [center, radius, normal] = m_curr_feature->get_circle(); if (m_hover_id == POINT_ID) - m_curr_point_on_feature_position = model_matrix * center; + m_curr_point_on_feature_position = center; else { const float r = radius; // needed for the following lambda - m_curr_point_on_feature_position = position_on_feature(CIRCLE_ID, camera, [r](const Vec3f& v) { + m_curr_point_on_feature_position = m_volume_matrix.inverse() * position_on_feature(CIRCLE_ID, camera, [r](const Vec3f& v) { float angle = std::atan2(v.y(), v.x()); if (angle < 0.0f) angle += 2.0f * float(M_PI); - return float(r) * Vec3f(std::cos(angle), std::sin(angle), 0.0f); + return Vec3f(float(r) * std::cos(angle), float(r) * std::sin(angle), 0.0f); }); } break; @@ -411,7 +415,7 @@ void GLGizmoMeasure::on_render() } case Measure::SurfaceFeatureType::Circle: { - const auto& [center, radius, n] = feature.get_circle(); + const auto& [center, radius, normal] = feature.get_circle(); // render center const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(center_matrix); @@ -423,7 +427,7 @@ void GLGizmoMeasure::on_render() it->second->set_transform(center_matrix); } // render circle - const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center); + const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); set_matrix_uniforms(circle_matrix); m_circle.model.set_color(colors.back()); m_circle.model.render(); @@ -437,8 +441,8 @@ void GLGizmoMeasure::on_render() case Measure::SurfaceFeatureType::Edge: { const auto& [start, end] = feature.get_edge(); - auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * q * + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start) * Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); set_matrix_uniforms(feature_matrix); m_cylinder.model.set_color(colors.front()); @@ -505,25 +509,23 @@ void GLGizmoMeasure::on_render() } } - render_feature(*m_curr_feature, colors, model_matrix, inv_zoom, true); + render_feature(*m_curr_feature, colors, m_volume_matrix, inv_zoom, true); } if (m_selected_features.first.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.first.feature)) { std::vector colors; colors.emplace_back(SELECTED_1ST_COLOR); - render_feature(*m_selected_features.first.feature, colors, - (m_selected_features.first.mode == EMode::BasicSelection) ? model_matrix : Transform3d::Identity(), inv_zoom, false); + render_feature(*m_selected_features.first.feature, colors, m_volume_matrix, inv_zoom, false); } if (m_selected_features.second.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.second.feature)) { std::vector colors; colors.emplace_back(SELECTED_2ND_COLOR); - render_feature(*m_selected_features.second.feature, colors, - (m_selected_features.second.mode == EMode::BasicSelection) ? model_matrix : Transform3d::Identity(), inv_zoom, false); + render_feature(*m_selected_features.second.feature, colors, m_volume_matrix, inv_zoom, false); } if (is_hovering_on_locked_feature && m_curr_point_on_feature_position.has_value()) { if (m_hover_id != POINT_ID) { - const Transform3d matrix = Geometry::translation_transform(*m_curr_point_on_feature_position) * Geometry::scale_transform(inv_zoom); + const Transform3d matrix = m_volume_matrix * Geometry::translation_transform(*m_curr_point_on_feature_position) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(matrix); m_sphere.model.set_color(hover_selection_color()); m_sphere.model.render(); @@ -616,6 +618,100 @@ void GLGizmoMeasure::restore_scene_raycasters_state() } } +static void add_row_to_table(std::function col_1 = nullptr, std::function col_2 = nullptr) +{ + assert(col_1 != nullptr && col_2 != nullptr); + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + col_1(); + ImGui::TableSetColumnIndex(1); + col_2(); +}; + +static void add_strings_row_to_table(ImGuiWrapper& imgui, const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) +{ + add_row_to_table([&]() { imgui.text_colored(col_1_color, col_1); }, [&]() { imgui.text_colored(col_2_color, col_2); }); +}; + +static std::string format_double(double value) +{ + char buf[1024]; + sprintf(buf, "%.3f", value); + return std::string(buf); +}; + +static std::string format_vec3(const Vec3d& v) +{ + char buf[1024]; + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", v.x(), v.y(), v.z()); + return std::string(buf); +}; + +#if ENABLE_MEASURE_GIZMO_DEBUG +void GLGizmoMeasure::render_debug_dialog() +{ + auto add_feature_data = [this](const SelectedFeatures::Item& item) { + add_strings_row_to_table(*m_imgui, "Type", ImGuiWrapper::COL_ORANGE_LIGHT, item.source, ImGui::GetStyleColorVec4(ImGuiCol_Text)); + switch (item.feature->get_type()) + { + case Measure::SurfaceFeatureType::Point: + { + add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(item.feature->get_point()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + auto [from, to] = item.feature->get_edge(); + add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + auto [idx, normal, origin] = item.feature->get_plane(); + add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_value", ImGuiWrapper::COL_ORANGE_LIGHT, format_double(idx), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + auto [center, radius, normal] = item.feature->get_circle(); + add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_value", ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; + } + } + std::optional extra_point = item.feature->get_extra_point(); + if (extra_point.has_value()) + add_strings_row_to_table(*m_imgui, "m_pt3", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(*extra_point), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + }; + + m_imgui->begin(_L("Measure tool debug"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + if (!m_selected_features.first.feature.has_value() && !m_selected_features.second.feature.has_value()) + m_imgui->text("Empty selection"); + else { + const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; + if (m_selected_features.first.feature.has_value()) { + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Selection 1"); + if (ImGui::BeginTable("Selection 1", 2, flags)) { + add_feature_data(m_selected_features.first); + ImGui::EndTable(); + } + } + if (m_selected_features.second.feature.has_value()) { + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Selection 2"); + if (ImGui::BeginTable("Selection 2", 2, flags)) { + add_feature_data(m_selected_features.second); + ImGui::EndTable(); + } + } + } + m_imgui->end(); +} +#endif // ENABLE_MEASURE_GIZMO_DEBUG + void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit) { static std::optional last_feature; @@ -640,34 +736,6 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit last_y = y; } - auto add_row_to_table = [this](std::function col_1 = nullptr, std::function col_2 = nullptr) { - assert(col_1 != nullptr && col_2 != nullptr); - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - col_1(); - ImGui::TableSetColumnIndex(1); - col_2(); - }; - - auto add_strings_row_to_table = [this, add_row_to_table](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) { - add_row_to_table( - [this, &col_1, &col_1_color]() { m_imgui->text_colored(col_1_color, col_1); }, - [this, &col_2, &col_2_color]() { m_imgui->text_colored(col_2_color, col_2); } - ); - }; - - auto format_double = [](double value) { - char buf[1024]; - sprintf(buf, "%.3f", value); - return std::string(buf); - }; - - auto format_vec3 = [](const Vec3d& v) { - char buf[1024]; - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", v.x(), v.y(), v.z()); - return std::string(buf); - }; - if (ImGui::BeginTable("Commands", 2)) { add_row_to_table( [this]() { @@ -685,10 +753,10 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ); if (m_selected_features.first.feature.has_value()) - add_strings_row_to_table(CTRL_STR + "+" + _u8L("Right mouse button"), ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, CTRL_STR + "+" + _u8L("Right mouse button"), ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); if (m_mode == EMode::BasicSelection && m_hover_id != -1) - add_strings_row_to_table(CTRL_STR, ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable point selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, CTRL_STR, ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable point selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); } @@ -696,7 +764,6 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit const std::string units = use_inches ? _u8L(" (in)") : _u8L(" (mm)"); if (m_curr_feature.has_value()) { - const Transform3d volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); const Measure::SurfaceFeatureType feature_type = m_curr_feature->get_type(); if (m_mode == EMode::BasicSelection) { if (feature_type != Measure::SurfaceFeatureType::Undef) { @@ -708,49 +775,49 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { - Vec3d position = volume_matrix * m_curr_feature->get_point(); + Vec3d position = m_volume_matrix * m_curr_feature->get_point(); if (use_inches) position = ObjectManipulation::mm_to_in * position; - add_strings_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } case Measure::SurfaceFeatureType::Edge: { auto [from, to] = m_curr_feature->get_edge(); - from = volume_matrix * from; - to = volume_matrix * to; + from = m_volume_matrix * from; + to = m_volume_matrix * to; if (use_inches) { from = ObjectManipulation::mm_to_in * from; to = ObjectManipulation::mm_to_in * to; } - add_strings_row_to_table(_u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(_u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(_u8L("Length") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Length") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } case Measure::SurfaceFeatureType::Circle: { auto [center, radius, normal] = m_curr_feature->get_circle(); - center = volume_matrix * center; - normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + center = m_volume_matrix * center; + normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; if (use_inches) { center = ObjectManipulation::mm_to_in * center; radius = ObjectManipulation::mm_to_in * radius; } - add_strings_row_to_table(_u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(_u8L("Radius") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Radius") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } case Measure::SurfaceFeatureType::Plane: { auto [idx, normal, origin] = m_curr_feature->get_plane(); - origin = volume_matrix * origin; - normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + origin = m_volume_matrix * origin; + normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; if (use_inches) origin = ObjectManipulation::mm_to_in * origin; - add_strings_row_to_table(_u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } } @@ -763,11 +830,10 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::Separator(); m_imgui->text(point_on_feature_type_as_string(feature_type, m_hover_id) + ":"); if (ImGui::BeginTable("Data", 2)) { - Vec3d position = ObjectManipulation::mm_to_in * *m_curr_point_on_feature_position; + Vec3d position = m_volume_matrix * *m_curr_point_on_feature_position; if (use_inches) position = ObjectManipulation::mm_to_in * position; - add_strings_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), - ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); } } @@ -777,9 +843,9 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::Separator(); const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; if (ImGui::BeginTable("Selection", 2, flags)) { - add_strings_row_to_table(_u8L("Selection") + " 1:", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), m_selected_features.first.feature.has_value() ? + add_strings_row_to_table(*m_imgui, _u8L("Selection") + " 1:", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), m_selected_features.first.feature.has_value() ? m_selected_features.first.source : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR)); - add_strings_row_to_table(_u8L("Selection") + " 2:", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), m_selected_features.second.feature.has_value() ? + add_strings_row_to_table(*m_imgui, _u8L("Selection") + " 2:", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), m_selected_features.second.feature.has_value() ? m_selected_features.second.source : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR)); ImGui::EndTable(); } @@ -798,28 +864,28 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit m_imgui->text(_u8L("Measure") + ":"); if (ImGui::BeginTable("Measure", 2)) { if (measure.angle.has_value()) { - add_strings_row_to_table(_u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(*measure.angle)), + add_strings_row_to_table(*m_imgui, _u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(*measure.angle)), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } if (measure.distance_infinite.has_value()) { - double distance = ObjectManipulation::mm_to_in * *measure.distance_infinite; + double distance = *measure.distance_infinite; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - add_strings_row_to_table(_u8L("Distance Infinite") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), + add_strings_row_to_table(*m_imgui, _u8L("Distance Infinite") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } if (measure.distance_strict.has_value()) { - double distance = ObjectManipulation::mm_to_in * *measure.distance_strict; + double distance = *measure.distance_strict; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - add_strings_row_to_table(_u8L("Distance Strict") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), + add_strings_row_to_table(*m_imgui, _u8L("Distance Strict") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } if (measure.distance_xyz.has_value()) { - Vec3d distance = ObjectManipulation::mm_to_in * *measure.distance_xyz; + Vec3d distance = *measure.distance_xyz; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - add_strings_row_to_table(_u8L("Distance XYZ") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), + add_strings_row_to_table(*m_imgui, _u8L("Distance XYZ") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } ImGui::EndTable(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index d74fb9ed8e..6576787cb5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -33,12 +33,10 @@ class GLGizmoMeasure : public GLGizmoBase { struct Item { - EMode mode{ EMode::BasicSelection }; std::string source; std::optional feature; bool operator == (const Item& other) const { - if (this->mode != other.mode) return false; if (this->source != other.source) return false; return this->feature == other.feature; } @@ -48,7 +46,6 @@ class GLGizmoMeasure : public GLGizmoBase } void reset() { - mode = EMode::BasicSelection; source.clear(); feature.reset(); } @@ -62,12 +59,12 @@ class GLGizmoMeasure : public GLGizmoBase second.reset(); } - bool operator == (const SelectedFeatures& other) const { + bool operator == (const SelectedFeatures & other) const { if (this->first != other.first) return false; return this->second == other.second; } - bool operator != (const SelectedFeatures& other) const { + bool operator != (const SelectedFeatures & other) const { return !operator == (other); } }; @@ -80,6 +77,7 @@ class GLGizmoMeasure : public GLGizmoBase PickingModel m_circle; PickingModel m_plane; + Transform3d m_volume_matrix{ Transform3d::Identity() }; std::vector m_plane_models_cache; std::map> m_raycasters; std::optional m_curr_feature; @@ -111,6 +109,10 @@ class GLGizmoMeasure : public GLGizmoBase void disable_scene_raycasters(); void restore_scene_raycasters_state(); +#if ENABLE_MEASURE_GIZMO_DEBUG + void render_debug_dialog(); +#endif // ENABLE_MEASURE_GIZMO_DEBUG + public: GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); From 3d72f224e1ffda8d4aaa90514c508d9e03d20950 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 7 Sep 2022 14:04:18 +0200 Subject: [PATCH 053/250] Measuring: Gizmo measure disabled for sinking volumes --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index b434cea9a7..db9fc0dd34 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -229,9 +229,12 @@ std::string GLGizmoMeasure::on_get_name() const bool GLGizmoMeasure::on_is_activable() const { const Selection& selection = m_parent.get_selection(); - return (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) ? + bool res = (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) ? selection.is_single_full_instance() : selection.is_single_volume() || selection.is_single_volume_instance(); + if (res) + res &= !selection.get_first_volume()->is_sinking(); + return res; } void GLGizmoMeasure::on_render() From f1a59de7f4c959b0fc6b09f44824ac0c980c5845 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 15 Sep 2022 12:28:16 +0200 Subject: [PATCH 054/250] Measuring: Gizmo measure shows dimensioning for distance point-point --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 146 +++++++++++++++++++++++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 8 ++ 2 files changed, 154 insertions(+) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index db9fc0dd34..92046c299f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -27,6 +27,9 @@ static const int EDGE_ID = 200; static const int CIRCLE_ID = 300; static const int PLANE_ID = 400; +static const float TRIANGLE_BASE = 16.0f; +static const float TRIANGLE_HEIGHT = TRIANGLE_BASE * 1.618033f; + static const std::string CTRL_STR = #ifdef __APPLE__ "⌘" @@ -537,6 +540,8 @@ void GLGizmoMeasure::on_render() shader->stop_using(); } + + render_dimensioning(); } void GLGizmoMeasure::update_if_needed() @@ -621,6 +626,147 @@ void GLGizmoMeasure::restore_scene_raycasters_state() } } +void GLGizmoMeasure::render_dimensioning() +{ + if (!m_selected_features.first.feature.has_value() || !m_selected_features.second.feature.has_value()) + return; + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + + auto point_point_2D = [this, shader](const Vec3d& v1, const Vec3d& v2) { + if (v1.isApprox(v2)) + return; + + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d& view_matrix = camera.get_view_matrix(); + const Transform3d& projection_matrix = camera.get_projection_matrix(); + const Matrix4d projection_view_matrix = projection_matrix.matrix() * view_matrix.matrix(); + const std::array& viewport = camera.get_viewport(); + const double inv_zoom = camera.get_inv_zoom(); + + auto model_to_world = [this](const Vec3d& model) { + return (Vec3d)(m_volume_matrix * model); + }; + + auto world_to_clip = [&projection_view_matrix](const Vec3d& world) { + return (Vec4d)(projection_view_matrix * Vec4d(world.x(), world.y(), world.z(), 1.0)); + }; + + auto clip_to_ndc = [](const Vec4d& clip) { + return Vec2d(clip.x(), clip.y()) / clip.w(); + }; + + const double half_w = 0.5 * double(viewport[2]); + const double half_h = 0.5 * double(viewport[3]); + + auto ndc_to_ss = [&viewport, half_w, half_h](const Vec2d& ndc) { + return Vec2d(half_w * ndc.x() + double(viewport[0]) + half_w, half_h * ndc.y() + double(viewport[1]) + half_h); + }; + + Matrix4d ndc_to_ss_matrix; + ndc_to_ss_matrix << half_w, 0.0, 0.0, double(viewport[0]) + half_w, + 0.0, half_h, 0.0, double(viewport[1]) + half_h, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0; + + const Transform3d ss_to_ndc_matrix = Transform3d(ndc_to_ss_matrix.inverse()); + + // ndc coordinates + const Vec2d v1ndc = clip_to_ndc(world_to_clip(model_to_world(v1))); + const Vec2d v2ndc = clip_to_ndc(world_to_clip(model_to_world(v2))); + const Vec2d v12ndc = v2ndc - v1ndc; + const double v12ndc_len = v12ndc.norm(); + + // screen coordinates + const Vec2d v1ss = ndc_to_ss(v1ndc); + const Vec2d v2ss = ndc_to_ss(v2ndc); + + if (v1ss.isApprox(v2ss)) + return; + + const Vec2d v12ss = v2ss - v1ss; + const double v12ss_len = v12ss.norm(); + + const bool overlap = v12ss_len - 2.0 * TRIANGLE_HEIGHT < 0.0; + + const auto q12ss = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Vec3d(v12ss.x(), v12ss.y(), 0.0)); + const auto q21ss = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Vec3d(-v12ss.x(), -v12ss.y(), 0.0)); + + shader->set_uniform("projection_matrix", Transform3d::Identity()); + + const Vec3d v1ss_3 = { v1ss.x(), v1ss.y(), 0.0 }; + const Vec3d v2ss_3 = { v2ss.x(), v2ss.y(), 0.0 }; + + // stem + shader->set_uniform("view_model_matrix", overlap ? + ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q12ss * Geometry::translation_transform(-2.0 * TRIANGLE_HEIGHT * Vec3d::UnitX()) * Geometry::scale_transform({ v12ss_len + 4.0 * TRIANGLE_HEIGHT, 1.0f, 1.0f }) : + ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q12ss * Geometry::scale_transform({ v12ss_len, 1.0f, 1.0f })); + m_dimensioning.line.render(); + + // arrow 1 + shader->set_uniform("view_model_matrix", overlap ? + ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q12ss : + ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q21ss); + m_dimensioning.triangle.render(); + + // arrow 2 + shader->set_uniform("view_model_matrix", overlap ? + ss_to_ndc_matrix * Geometry::translation_transform(v2ss_3) * q21ss : + ss_to_ndc_matrix * Geometry::translation_transform(v2ss_3) * q12ss); + m_dimensioning.triangle.render(); + }; + + shader->start_using(); + + if (!m_dimensioning.line.is_initialized()) { + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; + init_data.color = ColorRGBA::WHITE(); + init_data.reserve_vertices(2); + init_data.reserve_indices(2); + + // vertices + init_data.add_vertex(Vec3f(0.0f, 0.0f, 0.0f)); + init_data.add_vertex(Vec3f(1.0f, 0.0f, 0.0f)); + + // indices + init_data.add_line(0, 1); + + m_dimensioning.line.init_from(std::move(init_data)); + } + + if (!m_dimensioning.triangle.is_initialized()) { + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 }; + init_data.color = ColorRGBA::WHITE(); + init_data.reserve_vertices(3); + init_data.reserve_indices(3); + + // vertices + init_data.add_vertex(Vec3f(0.0f, 0.0f, 0.0f)); + init_data.add_vertex(Vec3f(-TRIANGLE_HEIGHT, 0.5f * TRIANGLE_BASE, 0.0f)); + init_data.add_vertex(Vec3f(-TRIANGLE_HEIGHT, -0.5f * TRIANGLE_BASE, 0.0f)); + + // indices + init_data.add_triangle(0, 1, 2); + + m_dimensioning.triangle.init_from(std::move(init_data)); + } + + glsafe(::glDisable(GL_DEPTH_TEST)); + + if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { + point_point_2D(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_point()); + } + + glsafe(::glEnable(GL_DEPTH_TEST)); + + shader->stop_using(); +} + static void add_row_to_table(std::function col_1 = nullptr, std::function col_2 = nullptr) { assert(col_1 != nullptr && col_2 != nullptr); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 6576787cb5..b6bd1ee5af 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -76,6 +76,12 @@ class GLGizmoMeasure : public GLGizmoBase PickingModel m_cylinder; PickingModel m_circle; PickingModel m_plane; + struct Dimensioning + { + GLModel line; + GLModel triangle; + }; + Dimensioning m_dimensioning; Transform3d m_volume_matrix{ Transform3d::Identity() }; std::vector m_plane_models_cache; @@ -109,6 +115,8 @@ class GLGizmoMeasure : public GLGizmoBase void disable_scene_raycasters(); void restore_scene_raycasters_state(); + void render_dimensioning(); + #if ENABLE_MEASURE_GIZMO_DEBUG void render_debug_dialog(); #endif // ENABLE_MEASURE_GIZMO_DEBUG From 00bcddb19d074c023a7478511a245ffb716f222e Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 15 Sep 2022 14:42:04 +0200 Subject: [PATCH 055/250] Measuring: Gizmo measure shows dimensioning for distance point-edge --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 166 +++++++++++++++++------ 1 file changed, 125 insertions(+), 41 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 92046c299f..4caae10f43 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -626,6 +626,79 @@ void GLGizmoMeasure::restore_scene_raycasters_state() } } +class DimensioningHelper +{ + struct Cache + { + std::array viewport; + Matrix4d ndc_to_ss_matrix; + Transform3d ndc_to_ss_matrix_inverse; + }; + + static Cache s_cache; + +public: + static Vec3d model_to_world(const Vec3d& model, const Transform3d& world_matrix) { + return world_matrix * model; + } + + static Vec4d world_to_clip(const Vec3d& world, const Matrix4d& projection_view_matrix) { + return projection_view_matrix * Vec4d(world.x(), world.y(), world.z(), 1.0); + } + + static Vec3d clip_to_ndc(const Vec4d& clip) { + return Vec3d(clip.x(), clip.y(), clip.z()) / clip.w(); + } + + static Vec2d ndc_to_ss(const Vec3d& ndc, const std::array& viewport) { + const double half_w = 0.5 * double(viewport[2]); + const double half_h = 0.5 * double(viewport[3]); + return { half_w * ndc.x() + double(viewport[0]) + half_w, half_h * ndc.y() + double(viewport[1]) + half_h }; + }; + + static Vec4d model_to_clip(const Vec3d& model, const Transform3d& world_matrix, const Matrix4d& projection_view_matrix) { + return world_to_clip(model_to_world(model, world_matrix), projection_view_matrix); + } + + static Vec3d model_to_ndc(const Vec3d& model, const Transform3d& world_matrix, const Matrix4d& projection_view_matrix) { + return clip_to_ndc(world_to_clip(model_to_world(model, world_matrix), projection_view_matrix)); + } + + static Vec2d model_to_ss(const Vec3d& model, const Transform3d& world_matrix, const Matrix4d& projection_view_matrix, const std::array& viewport) { + return ndc_to_ss(clip_to_ndc(world_to_clip(model_to_world(model, world_matrix), projection_view_matrix)), viewport); + } + + static const Matrix4d& ndc_to_ss_matrix(const std::array& viewport) { + update(viewport); + return s_cache.ndc_to_ss_matrix; + } + + static const Transform3d ndc_to_ss_matrix_inverse(const std::array& viewport) { + update(viewport); + return s_cache.ndc_to_ss_matrix_inverse; + } + +private: + static void update(const std::array& viewport) { + if (s_cache.viewport == viewport) + return; + + std::cout << "DimensioningHelper::update()\n"; + + const double half_w = 0.5 * double(viewport[2]); + const double half_h = 0.5 * double(viewport[3]); + s_cache.ndc_to_ss_matrix << half_w, 0.0, 0.0, double(viewport[0]) + half_w, + 0.0, half_h, 0.0, double(viewport[1]) + half_h, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0; + + s_cache.ndc_to_ss_matrix_inverse = s_cache.ndc_to_ss_matrix.inverse(); + s_cache.viewport = viewport; + } +}; + +DimensioningHelper::Cache DimensioningHelper::s_cache = { { 0, 0, 0, 0 }, Matrix4d::Identity(), Transform3d::Identity() }; + void GLGizmoMeasure::render_dimensioning() { if (!m_selected_features.first.feature.has_value() || !m_selected_features.second.feature.has_value()) @@ -635,53 +708,17 @@ void GLGizmoMeasure::render_dimensioning() if (shader == nullptr) return; - auto point_point_2D = [this, shader](const Vec3d& v1, const Vec3d& v2) { + auto point_point = [this, shader](const Vec3d& v1, const Vec3d& v2) { if (v1.isApprox(v2)) return; const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d& view_matrix = camera.get_view_matrix(); - const Transform3d& projection_matrix = camera.get_projection_matrix(); - const Matrix4d projection_view_matrix = projection_matrix.matrix() * view_matrix.matrix(); + const Matrix4d projection_view_matrix = camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix(); const std::array& viewport = camera.get_viewport(); - const double inv_zoom = camera.get_inv_zoom(); - - auto model_to_world = [this](const Vec3d& model) { - return (Vec3d)(m_volume_matrix * model); - }; - - auto world_to_clip = [&projection_view_matrix](const Vec3d& world) { - return (Vec4d)(projection_view_matrix * Vec4d(world.x(), world.y(), world.z(), 1.0)); - }; - - auto clip_to_ndc = [](const Vec4d& clip) { - return Vec2d(clip.x(), clip.y()) / clip.w(); - }; - - const double half_w = 0.5 * double(viewport[2]); - const double half_h = 0.5 * double(viewport[3]); - - auto ndc_to_ss = [&viewport, half_w, half_h](const Vec2d& ndc) { - return Vec2d(half_w * ndc.x() + double(viewport[0]) + half_w, half_h * ndc.y() + double(viewport[1]) + half_h); - }; - - Matrix4d ndc_to_ss_matrix; - ndc_to_ss_matrix << half_w, 0.0, 0.0, double(viewport[0]) + half_w, - 0.0, half_h, 0.0, double(viewport[1]) + half_h, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0; - - const Transform3d ss_to_ndc_matrix = Transform3d(ndc_to_ss_matrix.inverse()); - - // ndc coordinates - const Vec2d v1ndc = clip_to_ndc(world_to_clip(model_to_world(v1))); - const Vec2d v2ndc = clip_to_ndc(world_to_clip(model_to_world(v2))); - const Vec2d v12ndc = v2ndc - v1ndc; - const double v12ndc_len = v12ndc.norm(); // screen coordinates - const Vec2d v1ss = ndc_to_ss(v1ndc); - const Vec2d v2ss = ndc_to_ss(v2ndc); + const Vec2d v1ss = DimensioningHelper::model_to_ss(v1, m_volume_matrix, projection_view_matrix, viewport); + const Vec2d v2ss = DimensioningHelper::model_to_ss(v2, m_volume_matrix, projection_view_matrix, viewport); if (v1ss.isApprox(v2ss)) return; @@ -699,6 +736,8 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d v1ss_3 = { v1ss.x(), v1ss.y(), 0.0 }; const Vec3d v2ss_3 = { v2ss.x(), v2ss.y(), 0.0 }; + const Transform3d ss_to_ndc_matrix = DimensioningHelper::ndc_to_ss_matrix_inverse(viewport); + // stem shader->set_uniform("view_model_matrix", overlap ? ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q12ss * Geometry::translation_transform(-2.0 * TRIANGLE_HEIGHT * Vec3d::UnitX()) * Geometry::scale_transform({ v12ss_len + 4.0 * TRIANGLE_HEIGHT, 1.0f, 1.0f }) : @@ -718,6 +757,43 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.triangle.render(); }; + auto point_edge = [this, shader, point_point](const Vec3d& v, const std::pair& e) { + const Vec3d e1v = v - e.first; + const Vec3d e1e2 = e.second - e.first; + const Vec3d e1e2_unit = e1e2.normalized(); + const Vec3d v_proj_on_e1e2 = e.first + e1v.dot(e1e2_unit) * e1e2_unit; + point_point(v, v_proj_on_e1e2); + + const Vec3d v_proj_on_e1e2e1 = v_proj_on_e1e2 - e.first; + bool on_e1_side = v_proj_on_e1e2e1.dot(e1e2) < 0.0; + bool on_e2_side = v_proj_on_e1e2e1.norm() > e1e2.norm(); + if (on_e1_side || on_e2_side) { + 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 Transform3d ss_to_ndc_matrix = DimensioningHelper::ndc_to_ss_matrix_inverse(viewport); + + shader->set_uniform("projection_matrix", Transform3d::Identity()); + + const Vec2d v_proj_on_e1e2ss = DimensioningHelper::model_to_ss(v_proj_on_e1e2, m_volume_matrix, projection_view_matrix, viewport); + auto render_extension = [this, &v_proj_on_e1e2ss, &projection_view_matrix, &viewport, &ss_to_ndc_matrix, shader](const Vec3d& p) { + const Vec2d pss = DimensioningHelper::model_to_ss(p, m_volume_matrix, projection_view_matrix, viewport); + if (!pss.isApprox(v_proj_on_e1e2ss)) { + const Vec2d pv_proj_on_e1e2ss = v_proj_on_e1e2ss - pss; + const double pv_proj_on_e1e2ss_len = pv_proj_on_e1e2ss.norm(); + + const auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Vec3d(pv_proj_on_e1e2ss.x(), pv_proj_on_e1e2ss.y(), 0.0)); + + shader->set_uniform("view_model_matrix", ss_to_ndc_matrix * Geometry::translation_transform({ pss.x(), pss.y(), 0.0 }) * q * + Geometry::scale_transform({ pv_proj_on_e1e2ss_len, 1.0f, 1.0f })); + m_dimensioning.line.render(); + } + }; + + render_extension(on_e1_side ? e.first : e.second); + } + }; + shader->start_using(); if (!m_dimensioning.line.is_initialized()) { @@ -759,7 +835,15 @@ void GLGizmoMeasure::render_dimensioning() if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - point_point_2D(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_point()); + point_point(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_point()); + } + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { + point_edge(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_edge()); + } + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { + point_edge(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_edge()); } glsafe(::glEnable(GL_DEPTH_TEST)); From bf0f7c609dd3f6c9d35fde8a4f15ef551ad8d93f Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 15 Sep 2022 15:27:49 +0200 Subject: [PATCH 056/250] Measuring: Gizmo measure shows dimensioning for distance point-plane --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 45 ++++++++++++++++-------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 4caae10f43..c1e6a0c9ff 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -758,34 +758,32 @@ void GLGizmoMeasure::render_dimensioning() }; auto point_edge = [this, shader, point_point](const Vec3d& v, const std::pair& e) { - const Vec3d e1v = v - e.first; const Vec3d e1e2 = e.second - e.first; const Vec3d e1e2_unit = e1e2.normalized(); - const Vec3d v_proj_on_e1e2 = e.first + e1v.dot(e1e2_unit) * e1e2_unit; - point_point(v, v_proj_on_e1e2); + const Vec3d v_proj = e.first + e1e2_unit.dot(v - e.first) * e1e2_unit; + point_point(v, v_proj); - const Vec3d v_proj_on_e1e2e1 = v_proj_on_e1e2 - e.first; - bool on_e1_side = v_proj_on_e1e2e1.dot(e1e2) < 0.0; - bool on_e2_side = v_proj_on_e1e2e1.norm() > e1e2.norm(); + const Vec3d v_proje1 = v_proj - e.first; + bool on_e1_side = v_proje1.dot(e1e2) < 0.0; + bool on_e2_side = v_proje1.norm() > e1e2.norm(); if (on_e1_side || on_e2_side) { 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 Transform3d ss_to_ndc_matrix = DimensioningHelper::ndc_to_ss_matrix_inverse(viewport); - shader->set_uniform("projection_matrix", Transform3d::Identity()); - - const Vec2d v_proj_on_e1e2ss = DimensioningHelper::model_to_ss(v_proj_on_e1e2, m_volume_matrix, projection_view_matrix, viewport); - auto render_extension = [this, &v_proj_on_e1e2ss, &projection_view_matrix, &viewport, &ss_to_ndc_matrix, shader](const Vec3d& p) { + const Vec2d v_projss = DimensioningHelper::model_to_ss(v_proj, m_volume_matrix, projection_view_matrix, viewport); + auto render_extension = [this, &v_projss, &projection_view_matrix, &viewport, &ss_to_ndc_matrix, shader](const Vec3d& p) { const Vec2d pss = DimensioningHelper::model_to_ss(p, m_volume_matrix, projection_view_matrix, viewport); - if (!pss.isApprox(v_proj_on_e1e2ss)) { - const Vec2d pv_proj_on_e1e2ss = v_proj_on_e1e2ss - pss; - const double pv_proj_on_e1e2ss_len = pv_proj_on_e1e2ss.norm(); + if (!pss.isApprox(v_projss)) { + const Vec2d pv_projss = v_projss - pss; + const double pv_projss_len = pv_projss.norm(); - const auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Vec3d(pv_proj_on_e1e2ss.x(), pv_proj_on_e1e2ss.y(), 0.0)); + const auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Vec3d(pv_projss.x(), pv_projss.y(), 0.0)); + shader->set_uniform("projection_matrix", Transform3d::Identity()); shader->set_uniform("view_model_matrix", ss_to_ndc_matrix * Geometry::translation_transform({ pss.x(), pss.y(), 0.0 }) * q * - Geometry::scale_transform({ pv_proj_on_e1e2ss_len, 1.0f, 1.0f })); + Geometry::scale_transform({ pv_projss_len, 1.0f, 1.0f })); m_dimensioning.line.render(); } }; @@ -794,6 +792,15 @@ void GLGizmoMeasure::render_dimensioning() } }; + auto point_plane = [this, shader, point_point](const Vec3d& v, const std::tuple& p) { + const auto& [idx, normal, origin] = p; + const double distance = normal.dot(v - origin); + if (std::abs(distance) < EPSILON) + return; + + point_point(v, v - distance * normal); + }; + shader->start_using(); if (!m_dimensioning.line.is_initialized()) { @@ -845,6 +852,14 @@ void GLGizmoMeasure::render_dimensioning() m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { point_edge(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_edge()); } + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { + point_plane(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_plane()); + } + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { + point_plane(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_plane()); + } glsafe(::glEnable(GL_DEPTH_TEST)); From 8d98f0869dc6c6c6e3c67da4bb0670f17c7acf36 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 16 Sep 2022 08:30:19 +0200 Subject: [PATCH 057/250] Measuring: Gizmo measure shows dimensioning for distance edge-edge --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 39 +++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index c1e6a0c9ff..d166982144 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -792,7 +792,7 @@ void GLGizmoMeasure::render_dimensioning() } }; - auto point_plane = [this, shader, point_point](const Vec3d& v, const std::tuple& p) { + auto point_plane = [shader, point_point](const Vec3d& v, const std::tuple& p) { const auto& [idx, normal, origin] = p; const double distance = normal.dot(v - origin); if (std::abs(distance) < EPSILON) @@ -801,6 +801,39 @@ void GLGizmoMeasure::render_dimensioning() point_point(v, v - distance * normal); }; + auto edge_edge = [this, shader, point_point](const std::pair& e1, const std::pair& e2) { + auto min_distance_edge_edge = [](const std::pair& e1, const std::pair& e2) { + auto distance_point_edge = [](const Vec3d& v, const std::pair& e) { + const Vec3d e1v = v - e.first; + const Vec3d e1e2_unit = (e.second - e.first).normalized(); + const Vec3d v_proj = e.first + e1e2_unit.dot(v - e.first) * e1e2_unit; + return std::make_pair((e1v - v_proj).norm(), v_proj); + }; + + std::vector> distances; + distances.emplace_back(std::make_tuple((e2.first - e1.first).norm(), e1.first, e2.first)); + distances.emplace_back(std::make_tuple((e2.second - e1.first).norm(), e1.first, e2.second)); + distances.emplace_back(std::make_tuple((e2.first - e1.second).norm(), e1.second, e2.first)); + distances.emplace_back(std::make_tuple((e2.second - e1.second).norm(), e1.second, e2.second)); + const auto dist_e11e2 = distance_point_edge(e1.first, e2); + distances.emplace_back(std::make_tuple(dist_e11e2.first, e1.first, dist_e11e2.second)); + const auto dist_e12e2 = distance_point_edge(e1.second, e2); + distances.emplace_back(std::make_tuple(dist_e12e2.first, e1.second, dist_e12e2.second)); + const auto dist_e21e1 = distance_point_edge(e2.first, e1); + distances.emplace_back(std::make_tuple(dist_e21e1.first, e2.first, dist_e21e1.second)); + const auto dist_e22e1 = distance_point_edge(e2.second, e1); + distances.emplace_back(std::make_tuple(dist_e22e1.first, e2.second, dist_e22e1.second)); + std::sort(distances.begin(), distances.end(), + [](const std::tuple& item1, const std::tuple& item2) { + return std::get<0>(item1) < std::get<0>(item2); + }); + return distances.front(); + }; + + const auto [dist, v1, v2] = min_distance_edge_edge(e1, e2); + point_point(v1, v2); + }; + shader->start_using(); if (!m_dimensioning.line.is_initialized()) { @@ -860,6 +893,10 @@ void GLGizmoMeasure::render_dimensioning() m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { point_plane(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_plane()); } + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { + edge_edge(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_edge()); + } glsafe(::glEnable(GL_DEPTH_TEST)); From 3eae55bd0669c82cf3d1bff10d4f23455f3a5d7a Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 16 Sep 2022 09:57:07 +0200 Subject: [PATCH 058/250] Measuring: Gizmo measure shows dimensioning for distance point-circle --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 122 ++++++++++++++--------- 1 file changed, 77 insertions(+), 45 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index d166982144..bc89051520 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -19,6 +19,10 @@ namespace Slic3r { namespace GUI { +using Edge = std::pair; +using Plane = std::tuple; +using Circle = std::tuple; + static const Slic3r::ColorRGBA SELECTED_1ST_COLOR = { 0.25f, 0.75f, 0.75f, 1.0f }; static const Slic3r::ColorRGBA SELECTED_2ND_COLOR = { 0.75f, 0.25f, 0.75f, 1.0f }; @@ -64,6 +68,46 @@ static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType t return ret; } +static std::tuple distance_point_plane(const Vec3d& v, const Plane& p) +{ + const double distance = std::get<1>(p).dot(v - std::get<2>(p)); + return std::make_tuple(std::abs(distance), v, v - distance * std::get<1>(p)); +} + +static std::tuple distance_point_edge(const Vec3d& v, const Edge& e) +{ + const Vec3d e1v = v - e.first; + const Vec3d e1e2_unit = (e.second - e.first).normalized(); + const Vec3d v_proj = e.first + e1e2_unit.dot(e1v) * e1e2_unit; + return std::make_tuple((e1v - v_proj).norm(), v, v_proj); +} + +static std::tuple distance_point_circle(const Vec3d& v, const Circle& c) +{ + const auto& [center, radius, normal] = c; + const auto [distance, v1, v2] = distance_point_plane(v, std::make_tuple(0, normal, center)); + const Vec3d p_on_circle = center + radius * (v2 - center).normalized(); + return std::make_tuple((v - p_on_circle).norm(), v, p_on_circle); +} + +static std::tuple min_distance_edge_edge(const Edge& e1, const Edge& e2) +{ + std::vector> distances; + distances.emplace_back(std::make_tuple((e2.first - e1.first).norm(), e1.first, e2.first)); + distances.emplace_back(std::make_tuple((e2.second - e1.first).norm(), e1.first, e2.second)); + distances.emplace_back(std::make_tuple((e2.first - e1.second).norm(), e1.second, e2.first)); + distances.emplace_back(std::make_tuple((e2.second - e1.second).norm(), e1.second, e2.second)); + distances.emplace_back(distance_point_edge(e1.first, e2)); + distances.emplace_back(distance_point_edge(e1.second, e2)); + distances.emplace_back(distance_point_edge(e2.first, e1)); + distances.emplace_back(distance_point_edge(e2.second, e1)); + std::sort(distances.begin(), distances.end(), + [](const std::tuple& item1, const std::tuple& item2) { + return std::get<0>(item1) < std::get<0>(item2); + }); + return distances.front(); +} + static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const std::vector>& planes_triangles, int idx) { assert(0 <= idx && idx < (int)planes_triangles.size()); @@ -757,12 +801,11 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.triangle.render(); }; - auto point_edge = [this, shader, point_point](const Vec3d& v, const std::pair& e) { - const Vec3d e1e2 = e.second - e.first; - const Vec3d e1e2_unit = e1e2.normalized(); - const Vec3d v_proj = e.first + e1e2_unit.dot(v - e.first) * e1e2_unit; - point_point(v, v_proj); + auto point_edge = [this, shader, point_point](const Vec3d& v, const Edge& e) { + const auto [distance, v1, v_proj] = distance_point_edge(v, e); + point_point(v1, v_proj); + const Vec3d e1e2 = e.second - e.first; const Vec3d v_proje1 = v_proj - e.first; bool on_e1_side = v_proje1.dot(e1e2) < 0.0; bool on_e2_side = v_proje1.norm() > e1e2.norm(); @@ -792,45 +835,18 @@ void GLGizmoMeasure::render_dimensioning() } }; - auto point_plane = [shader, point_point](const Vec3d& v, const std::tuple& p) { - const auto& [idx, normal, origin] = p; - const double distance = normal.dot(v - origin); - if (std::abs(distance) < EPSILON) - return; - - point_point(v, v - distance * normal); + auto point_plane = [point_point](const Vec3d& v, const Plane& p) { + const auto [distance, v1, v2] = distance_point_plane(v, p); + point_point(v1, v2); }; - auto edge_edge = [this, shader, point_point](const std::pair& e1, const std::pair& e2) { - auto min_distance_edge_edge = [](const std::pair& e1, const std::pair& e2) { - auto distance_point_edge = [](const Vec3d& v, const std::pair& e) { - const Vec3d e1v = v - e.first; - const Vec3d e1e2_unit = (e.second - e.first).normalized(); - const Vec3d v_proj = e.first + e1e2_unit.dot(v - e.first) * e1e2_unit; - return std::make_pair((e1v - v_proj).norm(), v_proj); - }; + auto point_circle = [point_point](const Vec3d& v, const Circle& c) { + const auto [distance, v1, v2] = distance_point_circle(v, c); + point_point(v1, v2); + }; - std::vector> distances; - distances.emplace_back(std::make_tuple((e2.first - e1.first).norm(), e1.first, e2.first)); - distances.emplace_back(std::make_tuple((e2.second - e1.first).norm(), e1.first, e2.second)); - distances.emplace_back(std::make_tuple((e2.first - e1.second).norm(), e1.second, e2.first)); - distances.emplace_back(std::make_tuple((e2.second - e1.second).norm(), e1.second, e2.second)); - const auto dist_e11e2 = distance_point_edge(e1.first, e2); - distances.emplace_back(std::make_tuple(dist_e11e2.first, e1.first, dist_e11e2.second)); - const auto dist_e12e2 = distance_point_edge(e1.second, e2); - distances.emplace_back(std::make_tuple(dist_e12e2.first, e1.second, dist_e12e2.second)); - const auto dist_e21e1 = distance_point_edge(e2.first, e1); - distances.emplace_back(std::make_tuple(dist_e21e1.first, e2.first, dist_e21e1.second)); - const auto dist_e22e1 = distance_point_edge(e2.second, e1); - distances.emplace_back(std::make_tuple(dist_e22e1.first, e2.second, dist_e22e1.second)); - std::sort(distances.begin(), distances.end(), - [](const std::tuple& item1, const std::tuple& item2) { - return std::get<0>(item1) < std::get<0>(item2); - }); - return distances.front(); - }; - - const auto [dist, v1, v2] = min_distance_edge_edge(e1, e2); + auto edge_edge = [point_point](const Edge& e1, const Edge& e2) { + const auto [distance, v1, v2] = min_distance_edge_edge(e1, e2); point_point(v1, v2); }; @@ -873,26 +889,42 @@ void GLGizmoMeasure::render_dimensioning() glsafe(::glDisable(GL_DEPTH_TEST)); + // point-point if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { point_point(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_point()); } + // point-edge else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { point_edge(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_edge()); } - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - point_edge(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_edge()); - } + // point-plane else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { point_plane(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_plane()); } + // point-circle + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Circle) { + point_circle(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_circle()); + } + // edge-point + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { + point_edge(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_edge()); + } + // plane-point else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { point_plane(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_plane()); } + // circle-point + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { + point_circle(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_circle()); + } + // edge-edge else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { edge_edge(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_edge()); From e5c22b5694eab16d50a5220effef0ca704b6f3ff Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 16 Sep 2022 11:24:44 +0200 Subject: [PATCH 059/250] Measuring: Use eigen library in distance calculations for Gizmo measure --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index bc89051520..bfcef7365b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -70,23 +70,22 @@ static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType t static std::tuple distance_point_plane(const Vec3d& v, const Plane& p) { - const double distance = std::get<1>(p).dot(v - std::get<2>(p)); - return std::make_tuple(std::abs(distance), v, v - distance * std::get<1>(p)); + const auto& [idx, normal, origin] = p; + const Eigen::Hyperplane plane(normal, origin); + return std::make_tuple(plane.absDistance(v), v, plane.projection(v)); } static std::tuple distance_point_edge(const Vec3d& v, const Edge& e) { - const Vec3d e1v = v - e.first; - const Vec3d e1e2_unit = (e.second - e.first).normalized(); - const Vec3d v_proj = e.first + e1e2_unit.dot(e1v) * e1e2_unit; - return std::make_tuple((e1v - v_proj).norm(), v, v_proj); + const Eigen::ParametrizedLine line(e.first, (e.second - e.first).normalized()); + return std::make_tuple(line.distance(v), v, line.projection(v)); } static std::tuple distance_point_circle(const Vec3d& v, const Circle& c) { const auto& [center, radius, normal] = c; - const auto [distance, v1, v2] = distance_point_plane(v, std::make_tuple(0, normal, center)); - const Vec3d p_on_circle = center + radius * (v2 - center).normalized(); + const Eigen::Hyperplane plane(normal, center); + const Vec3d p_on_circle = center + radius * (plane.projection(v) - center).normalized(); return std::make_tuple((v - p_on_circle).norm(), v, p_on_circle); } From 3a2a6d4a2f47f5ecfd7bbe13d97309b6d65842dc Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 16 Sep 2022 13:28:15 +0200 Subject: [PATCH 060/250] Measuring: Gizmo measure shows dimensioning for distance plane-plane --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index bfcef7365b..9e0d2f60f8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -89,6 +89,14 @@ static std::tuple distance_point_circle(const Vec3d& v, co return std::make_tuple((v - p_on_circle).norm(), v, p_on_circle); } +static std::tuple distance_plane_plane(const Plane& p1, const Plane& p2) +{ + const auto& [idx1, normal1, origin1] = p1; + const auto& [idx2, normal2, origin2] = p2; + return (std::abs(std::abs(normal1.dot(normal2)) - 1.0) < EPSILON) ? distance_point_plane(origin2, p1) : + std::make_tuple(0.0, Vec3d::Zero(), Vec3d::Zero()); +} + static std::tuple min_distance_edge_edge(const Edge& e1, const Edge& e2) { std::vector> distances; @@ -726,8 +734,6 @@ private: if (s_cache.viewport == viewport) return; - std::cout << "DimensioningHelper::update()\n"; - const double half_w = 0.5 * double(viewport[2]); const double half_h = 0.5 * double(viewport[3]); s_cache.ndc_to_ss_matrix << half_w, 0.0, 0.0, double(viewport[0]) + half_w, @@ -849,6 +855,11 @@ void GLGizmoMeasure::render_dimensioning() point_point(v1, v2); }; + auto plane_plane = [point_point](const Plane& p1, const Plane& p2) { + const auto [distance, v1, v2] = distance_plane_plane(p1, p2); + point_point(v1, v2); + }; + shader->start_using(); if (!m_dimensioning.line.is_initialized()) { @@ -928,6 +939,11 @@ void GLGizmoMeasure::render_dimensioning() m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { edge_edge(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_edge()); } + // plane-plane + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { + plane_plane(m_selected_features.first.feature->get_plane(), m_selected_features.second.feature->get_plane()); + } glsafe(::glEnable(GL_DEPTH_TEST)); From 81d28c545cc1bbb31ee618934ae3afc72f3fc668 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 19 Sep 2022 10:01:02 +0200 Subject: [PATCH 061/250] Measuring: Gizmo measure shows dimensioning for distance edge-circle --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 62 +++++++++++++++++++----- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 9e0d2f60f8..bdb0420a8c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -89,15 +89,7 @@ static std::tuple distance_point_circle(const Vec3d& v, co return std::make_tuple((v - p_on_circle).norm(), v, p_on_circle); } -static std::tuple distance_plane_plane(const Plane& p1, const Plane& p2) -{ - const auto& [idx1, normal1, origin1] = p1; - const auto& [idx2, normal2, origin2] = p2; - return (std::abs(std::abs(normal1.dot(normal2)) - 1.0) < EPSILON) ? distance_point_plane(origin2, p1) : - std::make_tuple(0.0, Vec3d::Zero(), Vec3d::Zero()); -} - -static std::tuple min_distance_edge_edge(const Edge& e1, const Edge& e2) +static std::tuple distance_edge_edge(const Edge& e1, const Edge& e2) { std::vector> distances; distances.emplace_back(std::make_tuple((e2.first - e1.first).norm(), e1.first, e2.first)); @@ -115,6 +107,37 @@ static std::tuple min_distance_edge_edge(const Edge& e1, c return distances.front(); } +static std::tuple distance_edge_circle(const Edge& e, const Circle& c) +{ + const auto& [center, radius, normal] = c; + const Vec3d e1e2_unit = (e.second - e.first).normalized(); + double dot = std::abs(e1e2_unit.dot(normal)); + + if (dot < EPSILON) { + // edge parallel to circle's plane + const Eigen::Hyperplane plane(e1e2_unit, center); + const Eigen::ParametrizedLine line(e.first, e1e2_unit); + const Vec3d inter = line.intersectionPoint(plane); + return distance_point_circle(inter, c); + } + else if (std::abs(dot - 1.0) < EPSILON) + // edge parallel to circle's normal + return distance_point_circle(e.first, c); + else { + const auto [distance1, v11, v12] = distance_point_circle(e.first, c); + const auto [distance2, v21, v22] = distance_point_circle(e.second, c); + return (distance1 <= distance2) ? std::make_tuple(distance1, v11, v12) : std::make_tuple(distance2, v21, v22); + } +} + +static std::tuple distance_plane_plane(const Plane& p1, const Plane& p2) +{ + const auto& [idx1, normal1, origin1] = p1; + const auto& [idx2, normal2, origin2] = p2; + return (std::abs(std::abs(normal1.dot(normal2)) - 1.0) < EPSILON) ? distance_point_plane(origin2, p1) : + std::make_tuple(0.0, Vec3d::Zero(), Vec3d::Zero()); +} + static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const std::vector>& planes_triangles, int idx) { assert(0 <= idx && idx < (int)planes_triangles.size()); @@ -812,8 +835,8 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d e1e2 = e.second - e.first; const Vec3d v_proje1 = v_proj - e.first; - bool on_e1_side = v_proje1.dot(e1e2) < 0.0; - bool on_e2_side = v_proje1.norm() > e1e2.norm(); + const bool on_e1_side = v_proje1.dot(e1e2) < 0.0; + const bool on_e2_side = v_proje1.norm() > e1e2.norm(); if (on_e1_side || on_e2_side) { const Camera& camera = wxGetApp().plater()->get_camera(); const Matrix4d projection_view_matrix = camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix(); @@ -851,7 +874,12 @@ void GLGizmoMeasure::render_dimensioning() }; auto edge_edge = [point_point](const Edge& e1, const Edge& e2) { - const auto [distance, v1, v2] = min_distance_edge_edge(e1, e2); + const auto [distance, v1, v2] = distance_edge_edge(e1, e2); + point_point(v1, v2); + }; + + auto edge_circle = [point_point](const Edge& e, const Circle& c) { + const auto [distance, v1, v2] = distance_edge_circle(e, c); point_point(v1, v2); }; @@ -939,11 +967,21 @@ void GLGizmoMeasure::render_dimensioning() m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { edge_edge(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_edge()); } + // edge-circle + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Circle) { + edge_circle(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_circle()); + } // plane-plane else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { plane_plane(m_selected_features.first.feature->get_plane(), m_selected_features.second.feature->get_plane()); } + // circle-edge + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { + edge_circle(m_selected_features.second.feature->get_edge(), m_selected_features.first.feature->get_circle()); + } glsafe(::glEnable(GL_DEPTH_TEST)); From c87c9886a51cdf2a670aff4dd953e1d9e37aa72e Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 19 Sep 2022 11:44:03 +0200 Subject: [PATCH 062/250] Follow-up of 81d28c545cc1bbb31ee618934ae3afc72f3fc668 - Distance edge-circle calculated as in Fusion 360 --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 35 ++++++++++++------------ 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index bdb0420a8c..89396071c7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -110,24 +110,25 @@ static std::tuple distance_edge_edge(const Edge& e1, const static std::tuple distance_edge_circle(const Edge& e, const Circle& c) { const auto& [center, radius, normal] = c; - const Vec3d e1e2_unit = (e.second - e.first).normalized(); - double dot = std::abs(e1e2_unit.dot(normal)); + const Vec3d e1e2 = (e.second - e.first); + const Vec3d e1e2_unit = e1e2.normalized(); - if (dot < EPSILON) { - // edge parallel to circle's plane - const Eigen::Hyperplane plane(e1e2_unit, center); - const Eigen::ParametrizedLine line(e.first, e1e2_unit); - const Vec3d inter = line.intersectionPoint(plane); - return distance_point_circle(inter, c); - } - else if (std::abs(dot - 1.0) < EPSILON) - // edge parallel to circle's normal - return distance_point_circle(e.first, c); - else { - const auto [distance1, v11, v12] = distance_point_circle(e.first, c); - const auto [distance2, v21, v22] = distance_point_circle(e.second, c); - return (distance1 <= distance2) ? std::make_tuple(distance1, v11, v12) : std::make_tuple(distance2, v21, v22); - } + std::vector> distances; + distances.emplace_back(distance_point_circle(e.first, c)); + distances.emplace_back(distance_point_circle(e.second, c)); + + const Eigen::Hyperplane plane(e1e2_unit, center); + const Eigen::ParametrizedLine line(e.first, e1e2_unit); + const Vec3d inter = line.intersectionPoint(plane); + const Vec3d e1inter = inter - e.first; + if (e1inter.dot(e1e2) >= 0.0 && e1inter.norm() < e1e2.norm()) + distances.emplace_back(distance_point_circle(inter, c)); + + std::sort(distances.begin(), distances.end(), + [](const std::tuple& item1, const std::tuple& item2) { + return std::get<0>(item1) < std::get<0>(item2); + }); + return distances.front(); } static std::tuple distance_plane_plane(const Plane& p1, const Plane& p2) From 116644677436b51b935d4250081a42544c1b2cb4 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 19 Sep 2022 13:22:09 +0200 Subject: [PATCH 063/250] Follow-up of 8d98f0869dc6c6c6e3c67da4bb0670f17c7acf36 - Distance edge-edge calculated as in Fusion 360 --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 89396071c7..5a477034ea 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -92,14 +92,22 @@ static std::tuple distance_point_circle(const Vec3d& v, co static std::tuple distance_edge_edge(const Edge& e1, const Edge& e2) { std::vector> distances; + auto add_point_edge_distance = [&distances](const Vec3d& v, const Edge& e) { + const auto [distance, v1, v2] = distance_point_edge(v, e); + const Vec3d e1e2 = e.second - e.first; + const Vec3d e1v2 = v2 - e.first; + if (e1v2.dot(e1e2) >= 0.0 && e1v2.norm() < e1e2.norm()) + distances.emplace_back(std::make_tuple(distance, v, v2)); + }; + distances.emplace_back(std::make_tuple((e2.first - e1.first).norm(), e1.first, e2.first)); distances.emplace_back(std::make_tuple((e2.second - e1.first).norm(), e1.first, e2.second)); distances.emplace_back(std::make_tuple((e2.first - e1.second).norm(), e1.second, e2.first)); distances.emplace_back(std::make_tuple((e2.second - e1.second).norm(), e1.second, e2.second)); - distances.emplace_back(distance_point_edge(e1.first, e2)); - distances.emplace_back(distance_point_edge(e1.second, e2)); - distances.emplace_back(distance_point_edge(e2.first, e1)); - distances.emplace_back(distance_point_edge(e2.second, e1)); + add_point_edge_distance(e1.first, e2); + add_point_edge_distance(e1.second, e2); + add_point_edge_distance(e2.first, e1); + add_point_edge_distance(e2.second, e1); std::sort(distances.begin(), distances.end(), [](const std::tuple& item1, const std::tuple& item2) { return std::get<0>(item1) < std::get<0>(item2); From a79e78cee106afe64bfca206f7719c10e9893e26 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 21 Sep 2022 09:16:49 +0200 Subject: [PATCH 064/250] Measuring: Gizmo measure shows dimensioning for angle edge-edge --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 135 ++++++++++++++++++++++- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 3 +- 2 files changed, 133 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 5a477034ea..f6a6a46ca5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -31,7 +31,7 @@ static const int EDGE_ID = 200; static const int CIRCLE_ID = 300; static const int PLANE_ID = 400; -static const float TRIANGLE_BASE = 16.0f; +static const float TRIANGLE_BASE = 10.0f; static const float TRIANGLE_HEIGHT = TRIANGLE_BASE * 1.618033f; static const std::string CTRL_STR = @@ -782,6 +782,8 @@ DimensioningHelper::Cache DimensioningHelper::s_cache = { { 0, 0, 0, 0 }, Matrix void GLGizmoMeasure::render_dimensioning() { + static SelectedFeatures last_selected_features; + if (!m_selected_features.first.feature.has_value() || !m_selected_features.second.feature.has_value()) return; @@ -844,8 +846,8 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d e1e2 = e.second - e.first; const Vec3d v_proje1 = v_proj - e.first; - const bool on_e1_side = v_proje1.dot(e1e2) < 0.0; - const bool on_e2_side = v_proje1.norm() > e1e2.norm(); + const bool on_e1_side = v_proje1.dot(e1e2) < -EPSILON; + const bool on_e2_side = !on_e1_side && v_proje1.norm() > e1e2.norm(); if (on_e1_side || on_e2_side) { const Camera& camera = wxGetApp().plater()->get_camera(); const Matrix4d projection_view_matrix = camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix(); @@ -882,9 +884,131 @@ void GLGizmoMeasure::render_dimensioning() point_point(v1, v2); }; - auto edge_edge = [point_point](const Edge& e1, const Edge& e2) { + auto arc_edge_edge = [this, shader](Edge e1, Edge e2) { + Vec3d e1_unit = (e1.second - e1.first).normalized(); + Vec3d e2_unit = (e2.second - e2.first).normalized(); + const double dot = e1_unit.dot(e2_unit); + if (std::abs(std::abs(dot) - 1.0) < EPSILON) + // edges are parallel, return + return; + + // project edges on the plane defined by them + Vec3d normal = e1_unit.cross(e2_unit).normalized(); + const Eigen::Hyperplane plane(normal, e1.first); + Vec3d e11_proj = plane.projection(e1.first); + Vec3d e12_proj = plane.projection(e1.second); + Vec3d e21_proj = plane.projection(e2.first); + Vec3d e22_proj = plane.projection(e2.second); + + const bool coplanar = (e2.first - e21_proj).norm() < EPSILON && (e2.second - e22_proj).norm() < EPSILON; + + // rotate the plane to become the XY plane + auto qp = Eigen::Quaternion::FromTwoVectors(normal, Vec3d::UnitZ()); + auto qp_inverse = qp.inverse(); + const Vec3d e11_rot = qp * e11_proj; + const Vec3d e12_rot = qp * e12_proj; + const Vec3d e21_rot = qp * e21_proj; + const Vec3d e22_rot = qp * e22_proj; + + // discard Z + const Vec2d e11_rot_2d = Vec2d(e11_rot.x(), e11_rot.y()); + const Vec2d e12_rot_2d = Vec2d(e12_rot.x(), e12_rot.y()); + const Vec2d e21_rot_2d = Vec2d(e21_rot.x(), e21_rot.y()); + const Vec2d e22_rot_2d = Vec2d(e22_rot.x(), e22_rot.y()); + + // find intersection of edges in XY plane + const Eigen::Hyperplane e1_rot_2d_line = Eigen::Hyperplane::Through(e11_rot_2d, e12_rot_2d); + const Eigen::Hyperplane e2_rot_2d_line = Eigen::Hyperplane::Through(e21_rot_2d, e22_rot_2d); + const Vec2d center_rot_2d = e1_rot_2d_line.intersection(e2_rot_2d_line); + + // center in world coordinate + const Vec3d center = qp.inverse() * Vec3d(center_rot_2d.x(), center_rot_2d.y(), e11_rot.z()); + + // revert edges, if needed (we want them to move away from the center) + unsigned int revert_count = 0; + if ((center_rot_2d - e11_rot_2d).squaredNorm() > (center_rot_2d - e12_rot_2d).squaredNorm()) { + std::swap(e1.first, e1.second); + std::swap(e11_proj, e12_proj); + e1_unit = -e1_unit; + ++revert_count; + } + if ((center_rot_2d - e21_rot_2d).squaredNorm() > (center_rot_2d - e22_rot_2d).squaredNorm()) { + std::swap(e2.first, e2.second); + std::swap(e21_proj, e22_proj); + e2_unit = -e2_unit; + ++revert_count; + } + + if (revert_count == 1) { + normal = -normal; + qp = Eigen::Quaternion::FromTwoVectors(normal, Vec3d::UnitZ()); + qp_inverse = qp.inverse(); + } + + // arc angle + const double angle = std::acos(std::clamp(e1_unit.dot(e2_unit), -1.0, 1.0)); + // arc radius + const Vec3d e1_proj_mid = 0.5 * (e11_proj + e12_proj); + const Vec3d e2_proj_mid = 0.5 * (e21_proj + e22_proj); + const double radius = std::min((center - e1_proj_mid).norm(), (center - e2_proj_mid).norm()); + + if (!m_dimensioning.arc.is_initialized()) { + const unsigned int resolution = std::max(2, 64 * angle / double(PI)); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3 }; + init_data.color = ColorRGBA::WHITE(); + init_data.reserve_vertices(resolution + 1); + init_data.reserve_indices(resolution + 1); + + // vertices + indices + const double step = angle / double(resolution); + for (unsigned int i = 0; i <= resolution; ++i) { + const double a = step * double(i); + const Vec3d v = radius * (Eigen::Quaternion(Eigen::AngleAxisd(a, normal)) * e1_unit); + init_data.add_vertex((Vec3f)v.cast()); + init_data.add_index(i); + } + + m_dimensioning.arc.init_from(std::move(init_data)); + } + + auto render_edge_entension = [this, shader, ¢er, radius](const Edge& e, bool coplanar) { + const Vec3d e1center = center - e.first; + const Vec3d e1e2 = e.second - e.first; + const bool on_e1_side = e1center.dot(e1e2) < -EPSILON; + const bool on_e2_side = !on_e1_side && e1center.norm() > e1e2.norm(); + if (!coplanar || on_e1_side || on_e2_side) { + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + auto render_extension = [this, shader, &camera, ¢er, radius, coplanar](const Vec3d& p) { + const Vec3d centerp = p - center; + const auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), centerp.normalized()); + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * q * + Geometry::scale_transform({ coplanar ? centerp.norm() : radius, 1.0f, 1.0f })); + m_dimensioning.line.render(); + }; + render_extension(on_e1_side ? e.first : e.second); + } + }; + + auto render_arc = [this, shader, ¢er]() { + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center)); + m_dimensioning.arc.render(); + }; + + render_edge_entension({ e11_proj , e12_proj }, true); + render_edge_entension({ e21_proj , e22_proj }, coplanar); + render_arc(); + }; + + auto edge_edge = [point_point, arc_edge_edge](const Edge& e1, const Edge& e2) { + // distance const auto [distance, v1, v2] = distance_edge_edge(e1, e2); point_point(v1, v2); + // arc + arc_edge_edge(e1, e2); }; auto edge_circle = [point_point](const Edge& e, const Circle& c) { @@ -934,6 +1058,9 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.triangle.init_from(std::move(init_data)); } + if (last_selected_features != m_selected_features) + m_dimensioning.arc.reset(); + glsafe(::glDisable(GL_DEPTH_TEST)); // point-point diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index b6bd1ee5af..11e861cc7c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -80,7 +80,8 @@ class GLGizmoMeasure : public GLGizmoBase { GLModel line; GLModel triangle; - }; + GLModel arc; + }; Dimensioning m_dimensioning; Transform3d m_volume_matrix{ Transform3d::Identity() }; From ba21f54afb245333dc1adeea1d03fa128af9fb54 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 23 Sep 2022 12:44:06 +0200 Subject: [PATCH 065/250] Measuring: Gizmo measure shows dimensioning for angle edge-plane --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 284 +++++++++++++++-------- 1 file changed, 181 insertions(+), 103 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index f6a6a46ca5..fc49e9883f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -75,20 +75,33 @@ static std::tuple distance_point_plane(const Vec3d& v, con return std::make_tuple(plane.absDistance(v), v, plane.projection(v)); } +static Vec3d vector_direction(const Vec3d& from, const Vec3d& to) +{ + return (to - from).normalized(); +} + +static Vec3d edge_direction(const Edge& e) +{ + return vector_direction(e.first, e.second); +} + +// returns: distance, 1st vertex, 2nd vertex static std::tuple distance_point_edge(const Vec3d& v, const Edge& e) { - const Eigen::ParametrizedLine line(e.first, (e.second - e.first).normalized()); + const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); return std::make_tuple(line.distance(v), v, line.projection(v)); } +// returns: distance, 1st vertex, 2nd vertex static std::tuple distance_point_circle(const Vec3d& v, const Circle& c) { const auto& [center, radius, normal] = c; const Eigen::Hyperplane plane(normal, center); - const Vec3d p_on_circle = center + radius * (plane.projection(v) - center).normalized(); + const Vec3d p_on_circle = center + radius * vector_direction(center, plane.projection(v)); return std::make_tuple((v - p_on_circle).norm(), v, p_on_circle); } +// returns: distance, 1st vertex, 2nd vertex static std::tuple distance_edge_edge(const Edge& e1, const Edge& e2) { std::vector> distances; @@ -115,18 +128,19 @@ static std::tuple distance_edge_edge(const Edge& e1, const return distances.front(); } +// returns: distance, 1st vertex, 2nd vertex static std::tuple distance_edge_circle(const Edge& e, const Circle& c) { const auto& [center, radius, normal] = c; const Vec3d e1e2 = (e.second - e.first); - const Vec3d e1e2_unit = e1e2.normalized(); + const Vec3d e1e2_unit = vector_direction(e.first, e.second); std::vector> distances; distances.emplace_back(distance_point_circle(e.first, c)); distances.emplace_back(distance_point_circle(e.second, c)); const Eigen::Hyperplane plane(e1e2_unit, center); - const Eigen::ParametrizedLine line(e.first, e1e2_unit); + const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); const Vec3d inter = line.intersectionPoint(plane); const Vec3d e1inter = inter - e.first; if (e1inter.dot(e1e2) >= 0.0 && e1inter.norm() < e1e2.norm()) @@ -139,6 +153,7 @@ static std::tuple distance_edge_circle(const Edge& e, cons return distances.front(); } +// returns: distance, 1st vertex, 2nd vertex static std::tuple distance_plane_plane(const Plane& p1, const Plane& p2) { const auto& [idx1, normal1, origin1] = p1; @@ -147,6 +162,71 @@ static std::tuple distance_plane_plane(const Plane& p1, co std::make_tuple(0.0, Vec3d::Zero(), Vec3d::Zero()); } +// returns: angle in rad, center of arc, radius of arc, whether or not the edges are coplanar +// After return, the edges are oriented so that they point away from their intersection point +static std::tuple angle_edge_edge(Edge& e1, Edge& e2) +{ + Vec3d e1_unit = edge_direction(e1); + Vec3d e2_unit = edge_direction(e2); + const double dot = e1_unit.dot(e2_unit); + // are edges parallel ? + if (std::abs(std::abs(dot) - 1.0) < EPSILON) + return std::make_tuple(0.0, e1.first, 0.0, true); + + // project edges on the plane defined by them + Vec3d normal = e1_unit.cross(e2_unit).normalized(); + const Eigen::Hyperplane plane(normal, e1.first); + Vec3d e11_proj = plane.projection(e1.first); + Vec3d e12_proj = plane.projection(e1.second); + Vec3d e21_proj = plane.projection(e2.first); + Vec3d e22_proj = plane.projection(e2.second); + + const bool coplanar = (e2.first - e21_proj).norm() < EPSILON && (e2.second - e22_proj).norm() < EPSILON; + + // rotate the plane to become the XY plane + auto qp = Eigen::Quaternion::FromTwoVectors(normal, Vec3d::UnitZ()); + auto qp_inverse = qp.inverse(); + const Vec3d e11_rot = qp * e11_proj; + const Vec3d e12_rot = qp * e12_proj; + const Vec3d e21_rot = qp * e21_proj; + const Vec3d e22_rot = qp * e22_proj; + + // discard Z + const Vec2d e11_rot_2d = Vec2d(e11_rot.x(), e11_rot.y()); + const Vec2d e12_rot_2d = Vec2d(e12_rot.x(), e12_rot.y()); + const Vec2d e21_rot_2d = Vec2d(e21_rot.x(), e21_rot.y()); + const Vec2d e22_rot_2d = Vec2d(e22_rot.x(), e22_rot.y()); + + // find intersection (arc center) of edges in XY plane + const Eigen::Hyperplane e1_rot_2d_line = Eigen::Hyperplane::Through(e11_rot_2d, e12_rot_2d); + const Eigen::Hyperplane e2_rot_2d_line = Eigen::Hyperplane::Through(e21_rot_2d, e22_rot_2d); + const Vec2d center_rot_2d = e1_rot_2d_line.intersection(e2_rot_2d_line); + + // arc center in original coordinate + const Vec3d center = qp_inverse * Vec3d(center_rot_2d.x(), center_rot_2d.y(), e11_rot.z()); + + // ensure the edges are pointing away from the center + if ((center_rot_2d - e11_rot_2d).squaredNorm() > (center_rot_2d - e12_rot_2d).squaredNorm()) { + std::swap(e1.first, e1.second); + std::swap(e11_proj, e12_proj); + e1_unit = -e1_unit; + } + if ((center_rot_2d - e21_rot_2d).squaredNorm() > (center_rot_2d - e22_rot_2d).squaredNorm()) { + std::swap(e2.first, e2.second); + std::swap(e21_proj, e22_proj); + e2_unit = -e2_unit; + } + + // arc angle + const double angle = std::acos(std::clamp(e1_unit.dot(e2_unit), -1.0, 1.0)); + // arc radius + const Vec3d e1_proj_mid = 0.5 * (e11_proj + e12_proj); + const Vec3d e2_proj_mid = 0.5 * (e21_proj + e22_proj); + const double radius = std::min((center - e1_proj_mid).norm(), (center - e2_proj_mid).norm()); + + return std::make_tuple(angle, center, radius, coplanar); +} + static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const std::vector>& planes_triangles, int idx) { assert(0 <= idx && idx < (int)planes_triangles.size()); @@ -884,73 +964,21 @@ void GLGizmoMeasure::render_dimensioning() point_point(v1, v2); }; - auto arc_edge_edge = [this, shader](Edge e1, Edge e2) { - Vec3d e1_unit = (e1.second - e1.first).normalized(); - Vec3d e2_unit = (e2.second - e2.first).normalized(); - const double dot = e1_unit.dot(e2_unit); - if (std::abs(std::abs(dot) - 1.0) < EPSILON) - // edges are parallel, return + auto arc_edge_edge = [this, shader](const Edge& e1, const Edge& e2, const double* const force_radius = nullptr) { + Edge e1copy = e1; + Edge e2copy = e2; + const auto [angle, center, radius, coplanar] = angle_edge_edge(e1copy, e2copy); + + if (radius == 0.0) return; - // project edges on the plane defined by them - Vec3d normal = e1_unit.cross(e2_unit).normalized(); - const Eigen::Hyperplane plane(normal, e1.first); - Vec3d e11_proj = plane.projection(e1.first); - Vec3d e12_proj = plane.projection(e1.second); - Vec3d e21_proj = plane.projection(e2.first); - Vec3d e22_proj = plane.projection(e2.second); + assert(force_radius == nullptr || *force_radius > 0.0); - const bool coplanar = (e2.first - e21_proj).norm() < EPSILON && (e2.second - e22_proj).norm() < EPSILON; + const double draw_radius = (force_radius != nullptr) ? *force_radius : radius; - // rotate the plane to become the XY plane - auto qp = Eigen::Quaternion::FromTwoVectors(normal, Vec3d::UnitZ()); - auto qp_inverse = qp.inverse(); - const Vec3d e11_rot = qp * e11_proj; - const Vec3d e12_rot = qp * e12_proj; - const Vec3d e21_rot = qp * e21_proj; - const Vec3d e22_rot = qp * e22_proj; - - // discard Z - const Vec2d e11_rot_2d = Vec2d(e11_rot.x(), e11_rot.y()); - const Vec2d e12_rot_2d = Vec2d(e12_rot.x(), e12_rot.y()); - const Vec2d e21_rot_2d = Vec2d(e21_rot.x(), e21_rot.y()); - const Vec2d e22_rot_2d = Vec2d(e22_rot.x(), e22_rot.y()); - - // find intersection of edges in XY plane - const Eigen::Hyperplane e1_rot_2d_line = Eigen::Hyperplane::Through(e11_rot_2d, e12_rot_2d); - const Eigen::Hyperplane e2_rot_2d_line = Eigen::Hyperplane::Through(e21_rot_2d, e22_rot_2d); - const Vec2d center_rot_2d = e1_rot_2d_line.intersection(e2_rot_2d_line); - - // center in world coordinate - const Vec3d center = qp.inverse() * Vec3d(center_rot_2d.x(), center_rot_2d.y(), e11_rot.z()); - - // revert edges, if needed (we want them to move away from the center) - unsigned int revert_count = 0; - if ((center_rot_2d - e11_rot_2d).squaredNorm() > (center_rot_2d - e12_rot_2d).squaredNorm()) { - std::swap(e1.first, e1.second); - std::swap(e11_proj, e12_proj); - e1_unit = -e1_unit; - ++revert_count; - } - if ((center_rot_2d - e21_rot_2d).squaredNorm() > (center_rot_2d - e22_rot_2d).squaredNorm()) { - std::swap(e2.first, e2.second); - std::swap(e21_proj, e22_proj); - e2_unit = -e2_unit; - ++revert_count; - } - - if (revert_count == 1) { - normal = -normal; - qp = Eigen::Quaternion::FromTwoVectors(normal, Vec3d::UnitZ()); - qp_inverse = qp.inverse(); - } - - // arc angle - const double angle = std::acos(std::clamp(e1_unit.dot(e2_unit), -1.0, 1.0)); - // arc radius - const Vec3d e1_proj_mid = 0.5 * (e11_proj + e12_proj); - const Vec3d e2_proj_mid = 0.5 * (e21_proj + e22_proj); - const double radius = std::min((center - e1_proj_mid).norm(), (center - e2_proj_mid).norm()); + const Vec3d e1_unit = edge_direction(e1copy); + const Vec3d e2_unit = edge_direction(e2copy); + const Vec3d normal = e1_unit.cross(e2_unit).normalized(); if (!m_dimensioning.arc.is_initialized()) { const unsigned int resolution = std::max(2, 64 * angle / double(PI)); @@ -964,7 +992,7 @@ void GLGizmoMeasure::render_dimensioning() const double step = angle / double(resolution); for (unsigned int i = 0; i <= resolution; ++i) { const double a = step * double(i); - const Vec3d v = radius * (Eigen::Quaternion(Eigen::AngleAxisd(a, normal)) * e1_unit); + const Vec3d v = draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(a, normal)) * e1_unit); init_data.add_vertex((Vec3f)v.cast()); init_data.add_index(i); } @@ -972,35 +1000,70 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.arc.init_from(std::move(init_data)); } - auto render_edge_entension = [this, shader, ¢er, radius](const Edge& e, bool coplanar) { - const Vec3d e1center = center - e.first; - const Vec3d e1e2 = e.second - e.first; - const bool on_e1_side = e1center.dot(e1e2) < -EPSILON; - const bool on_e2_side = !on_e1_side && e1center.norm() > e1e2.norm(); - if (!coplanar || on_e1_side || on_e2_side) { - const Camera& camera = wxGetApp().plater()->get_camera(); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - auto render_extension = [this, shader, &camera, ¢er, radius, coplanar](const Vec3d& p) { - const Vec3d centerp = p - center; - const auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), centerp.normalized()); - shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * q * - Geometry::scale_transform({ coplanar ? centerp.norm() : radius, 1.0f, 1.0f })); - m_dimensioning.line.render(); - }; - render_extension(on_e1_side ? e.first : e.second); - } - }; + // render arc + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center)); + m_dimensioning.arc.render(); - auto render_arc = [this, shader, ¢er]() { + // render edge 1 extension + const Vec3d e11e12 = e1copy.second - e1copy.first; + const Vec3d e11center = center - e1copy.first; + const double e11center_len = e11center.norm(); + if (e11center_len > EPSILON && e11center.dot(e11e12) < 0.0) { const Camera& camera = wxGetApp().plater()->get_camera(); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center)); - m_dimensioning.arc.render(); - }; + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), edge_direction(e1copy)) * + Geometry::scale_transform({ e11center_len, 1.0f, 1.0f })); + m_dimensioning.line.render(); + } - render_edge_entension({ e11_proj , e12_proj }, true); - render_edge_entension({ e21_proj , e22_proj }, coplanar); - render_arc(); + // render edge 2 extension + const Vec3d e21center = center - e2copy.first; + const double e21center_len = e21center.norm(); + if (e21center_len > EPSILON) { + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), edge_direction(e2copy)) * + Geometry::scale_transform({ (coplanar && (force_radius == nullptr)) ? e21center_len : draw_radius, 1.0f, 1.0f })); + m_dimensioning.line.render(); + } + }; + + auto arc_edge_plane = [this, arc_edge_edge](const Edge& e, const Plane& p) { + const auto& [idx, normal, origin] = p; + const Vec3d e1e2 = e.second - e.first; + const double abs_dot = std::abs(normal.dot(edge_direction(e))); + if (abs_dot < EPSILON || std::abs(abs_dot - 1.0) < EPSILON) + return; + + const Eigen::Hyperplane plane(normal, origin); + const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); + const Vec3d inters = line.intersectionPoint(plane); + + // ensure the edge is pointing away from the intersection + Edge ecopy = e; + Vec3d e1e2copy = e1e2; + if ((ecopy.first - inters).squaredNorm() > (ecopy.second - inters).squaredNorm()) { + std::swap(ecopy.first, ecopy.second); + e1e2copy = -e1e2copy; + } + + // calculate 2nd edge (on the plane) + const Vec3d temp = normal.cross(e1e2copy); + const Vec3d edge_on_plane_unit = normal.cross(temp).normalized(); + Edge edge_on_plane = { origin, origin + e1e2copy.norm() * edge_on_plane_unit }; + + // ensure the 2nd edge is pointing in the correct direction + const Vec3d test_edge = (edge_on_plane.second - edge_on_plane.first).cross(e1e2copy); + if (test_edge.dot(temp) < 0.0) + edge_on_plane = { origin, origin - e1e2copy.norm() * edge_on_plane_unit }; + + const Vec3d e1e2copy_mid = 0.5 * (ecopy.second + ecopy.first); + const double radius = (inters - e1e2copy_mid).norm(); + arc_edge_edge(ecopy, edge_on_plane, &radius); }; auto edge_edge = [point_point, arc_edge_edge](const Edge& e1, const Edge& e2) { @@ -1011,6 +1074,11 @@ void GLGizmoMeasure::render_dimensioning() arc_edge_edge(e1, e2); }; + auto edge_plane = [point_point, arc_edge_plane](const Edge& e, const Plane& p) { + // arc + arc_edge_plane(e, p); + }; + auto edge_circle = [point_point](const Edge& e, const Circle& c) { const auto [distance, v1, v2] = distance_edge_circle(e, c); point_point(v1, v2); @@ -1088,31 +1156,41 @@ void GLGizmoMeasure::render_dimensioning() m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { point_edge(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_edge()); } - // plane-point - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - point_plane(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_plane()); - } - // circle-point - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - point_circle(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_circle()); - } // edge-edge else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { edge_edge(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_edge()); } + // edge-plane + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { + edge_plane(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_plane()); + } // edge-circle else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Circle) { edge_circle(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_circle()); } + // plane-point + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { + point_plane(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_plane()); + } + // plane-edge + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { + edge_plane(m_selected_features.second.feature->get_edge(), m_selected_features.first.feature->get_plane()); + } // plane-plane else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { plane_plane(m_selected_features.first.feature->get_plane(), m_selected_features.second.feature->get_plane()); } + // circle-point + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { + point_circle(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_circle()); + } // circle-edge else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { From 4dd005a554439e3fd87e4a34f83f4ec821fe7e5d Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 26 Sep 2022 13:17:41 +0200 Subject: [PATCH 066/250] Fixed bug in get_measurement() function --- src/libslic3r/Measure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 1a79369a3e..c2b7edd5e2 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -518,7 +518,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& const auto& [idx2, normal2, pt2] = f2.get_plane(); double angle = 0.; - if (! normal1.isApprox(normal2)) { + if (normal1.isApprox(normal2)) { // The planes are parallel, calculate distance. Eigen::Hyperplane plane(normal1, pt1); result.distance_infinite = plane.absDistance(pt2); From b71d61f0f7b895e7f63c117b2cffd90712cbbf1d Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 27 Sep 2022 10:21:57 +0200 Subject: [PATCH 067/250] Measuring - Refactoring in GLGizmoMeasure related to scene raycasters state cache --- src/slic3r/GUI/GLCanvas3D.cpp | 6 +++--- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 25 +++++++++++------------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 9 +++++++-- src/slic3r/GUI/SceneRaycaster.cpp | 25 ++++++++++++++++++++++++ src/slic3r/GUI/SceneRaycaster.hpp | 4 ++++ 5 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index b5fea57bea..ed82a3a8da 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5517,11 +5517,11 @@ void GLCanvas3D::_picking_pass() ImGui::Separator(); imgui.text("Registered for picking:"); - sprintf(buf, "Beds: %d", (int)m_scene_raycaster.beds_count()); + sprintf(buf, "Beds: %d (%d)", (int)m_scene_raycaster.beds_count(), (int)m_scene_raycaster.active_beds_count()); imgui.text(std::string(buf)); - sprintf(buf, "Volumes: %d", (int)m_scene_raycaster.volumes_count()); + sprintf(buf, "Volumes: %d (%d)", (int)m_scene_raycaster.volumes_count(), (int)m_scene_raycaster.active_volumes_count()); imgui.text(std::string(buf)); - sprintf(buf, "Gizmo elements: %d", (int)m_scene_raycaster.gizmos_count()); + sprintf(buf, "Gizmo elements: %d (%d)", (int)m_scene_raycaster.gizmos_count(), (int)m_scene_raycaster.active_gizmos_count()); imgui.text(std::string(buf)); imgui.end(); #endif // ENABLE_RAYCAST_PICKING_DEBUG diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index fc49e9883f..c511f7e501 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -372,11 +372,13 @@ void GLGizmoMeasure::on_set_state() else { m_mode = EMode::BasicSelection; // store current state of scene raycaster for later use - m_scene_raycaster_state.clear(); - m_scene_raycasters = m_parent.get_raycasters_for_picking(SceneRaycaster::EType::Volume); - if (m_scene_raycasters != nullptr) { - for (const auto& r : *m_scene_raycasters) { - m_scene_raycaster_state.emplace_back(r->is_active()); + m_scene_raycasters.clear(); + auto scene_raycasters = m_parent.get_raycasters_for_picking(SceneRaycaster::EType::Volume); + if (scene_raycasters != nullptr) { + m_scene_raycasters.reserve(scene_raycasters->size()); + for (auto r : *scene_raycasters) { + SceneRaycasterState state = { r, r->is_active() }; + m_scene_raycasters.emplace_back(state); } } } @@ -772,20 +774,15 @@ void GLGizmoMeasure::update_if_needed() void GLGizmoMeasure::disable_scene_raycasters() { - if (m_scene_raycasters != nullptr) { - for (auto r : *m_scene_raycasters) { - r->set_active(false); - } + for (auto r : m_scene_raycasters) { + r.raycaster->set_active(false); } } void GLGizmoMeasure::restore_scene_raycasters_state() { - if (m_scene_raycasters != nullptr) { - assert(m_scene_raycasters->size() == m_scene_raycaster_state.size()); - for (size_t i = 0; i < m_scene_raycasters->size(); ++i) { - (*m_scene_raycasters)[i]->set_active(m_scene_raycaster_state[i]); - } + for (auto r : m_scene_raycasters) { + r.raycaster->set_active(r.state); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 11e861cc7c..0e967472ae 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -89,8 +89,13 @@ class GLGizmoMeasure : public GLGizmoBase std::map> m_raycasters; std::optional m_curr_feature; std::optional m_curr_point_on_feature_position; - std::vector>* m_scene_raycasters{ nullptr }; - std::vector m_scene_raycaster_state; + struct SceneRaycasterState + { + std::shared_ptr raycaster{ nullptr }; + bool state{true}; + + }; + std::vector m_scene_raycasters; // These hold information to decide whether recalculation is necessary: std::vector m_volumes_matrices; diff --git a/src/slic3r/GUI/SceneRaycaster.cpp b/src/slic3r/GUI/SceneRaycaster.cpp index 49a59789e3..78cb59c1bc 100644 --- a/src/slic3r/GUI/SceneRaycaster.cpp +++ b/src/slic3r/GUI/SceneRaycaster.cpp @@ -173,6 +173,31 @@ void SceneRaycaster::render_hit(const Camera& camera) shader->stop_using(); } + +size_t SceneRaycaster::active_beds_count() const { + size_t count = 0; + for (const auto& b : m_bed) { + if (b->is_active()) + ++count; + } + return count; +} +size_t SceneRaycaster::active_volumes_count() const { + size_t count = 0; + for (const auto& v : m_volumes) { + if (v->is_active()) + ++count; + } + return count; +} +size_t SceneRaycaster::active_gizmos_count() const { + size_t count = 0; + for (const auto& g : m_gizmos) { + if (g->is_active()) + ++count; + } + return count; +} #endif // ENABLE_RAYCAST_PICKING_DEBUG std::vector>* SceneRaycaster::get_raycasters(EType type) diff --git a/src/slic3r/GUI/SceneRaycaster.hpp b/src/slic3r/GUI/SceneRaycaster.hpp index 8993c51a98..7acf82fe11 100644 --- a/src/slic3r/GUI/SceneRaycaster.hpp +++ b/src/slic3r/GUI/SceneRaycaster.hpp @@ -100,6 +100,10 @@ public: size_t beds_count() const { return m_bed.size(); } size_t volumes_count() const { return m_volumes.size(); } size_t gizmos_count() const { return m_gizmos.size(); } + + size_t active_beds_count() const; + size_t active_volumes_count() const; + size_t active_gizmos_count() const; #endif // ENABLE_RAYCAST_PICKING_DEBUG private: From 5b7e1c0677829bd84869818ca1e6207974394ec9 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 29 Sep 2022 08:43:03 +0200 Subject: [PATCH 068/250] Measuring - GLGizmoMeasure - Allow to deselect second feature by clicking on it --- src/slic3r/GUI/GLCanvas3D.cpp | 51 ++++++++++----- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 83 +++++++++++++++++++----- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 + src/slic3r/GUI/SceneRaycaster.cpp | 6 +- src/slic3r/GUI/SceneRaycaster.hpp | 3 +- 5 files changed, 108 insertions(+), 36 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index ed82a3a8da..9c69003618 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5501,28 +5501,49 @@ void GLCanvas3D::_picking_pass() } default: { break; } } - char buf[1024]; + + auto add_strings_row_to_table = [&imgui](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) { + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + imgui.text_colored(col_1_color, col_1.c_str()); + ImGui::TableSetColumnIndex(1); + imgui.text_colored(col_2_color, col_2.c_str()); + }; + if (hit.type != SceneRaycaster::EType::None) { - sprintf(buf, "Object ID: %d", hit.raycaster_id); - imgui.text(std::string(buf)); - sprintf(buf, "Type: %s", object_type.c_str()); - imgui.text(std::string(buf)); - sprintf(buf, "Position: %.3f, %.3f, %.3f", hit.position.x(), hit.position.y(), hit.position.z()); - imgui.text(std::string(buf)); - sprintf(buf, "Normal: %.3f, %.3f, %.3f", hit.normal.x(), hit.normal.y(), hit.normal.z()); - imgui.text(std::string(buf)); + if (ImGui::BeginTable("Hit", 2)) { + char buf[1024]; + add_strings_row_to_table("Object ID:", ImGuiWrapper::COL_ORANGE_LIGHT, + std::to_string(hit.raycaster_id), ImGuiWrapper::to_ImVec4(ColorRGBA::WHITE())); + add_strings_row_to_table("Type:", ImGuiWrapper::COL_ORANGE_LIGHT, + object_type, ImGuiWrapper::to_ImVec4(ColorRGBA::WHITE())); + sprintf(buf, "%.3f, %.3f, %.3f", hit.position.x(), hit.position.y(), hit.position.z()); + add_strings_row_to_table("Position:", ImGuiWrapper::COL_ORANGE_LIGHT, + std::string(buf), ImGuiWrapper::to_ImVec4(ColorRGBA::WHITE())); + sprintf(buf, "%.3f, %.3f, %.3f", hit.normal.x(), hit.normal.y(), hit.normal.z()); + add_strings_row_to_table("Normal:", ImGuiWrapper::COL_ORANGE_LIGHT, + std::string(buf), ImGuiWrapper::to_ImVec4(ColorRGBA::WHITE())); + ImGui::EndTable(); + } } else imgui.text("NO HIT"); ImGui::Separator(); imgui.text("Registered for picking:"); - sprintf(buf, "Beds: %d (%d)", (int)m_scene_raycaster.beds_count(), (int)m_scene_raycaster.active_beds_count()); - imgui.text(std::string(buf)); - sprintf(buf, "Volumes: %d (%d)", (int)m_scene_raycaster.volumes_count(), (int)m_scene_raycaster.active_volumes_count()); - imgui.text(std::string(buf)); - sprintf(buf, "Gizmo elements: %d (%d)", (int)m_scene_raycaster.gizmos_count(), (int)m_scene_raycaster.active_gizmos_count()); - imgui.text(std::string(buf)); + if (ImGui::BeginTable("Counters", 2)) { + char buf[1024]; + sprintf(buf, "%d (%d)", (int)m_scene_raycaster.beds_count(), (int)m_scene_raycaster.active_beds_count()); + add_strings_row_to_table("Beds:", ImGuiWrapper::COL_ORANGE_LIGHT, + std::string(buf), ImGuiWrapper::to_ImVec4(ColorRGBA::WHITE())); + sprintf(buf, "%d (%d)", (int)m_scene_raycaster.volumes_count(), (int)m_scene_raycaster.active_volumes_count()); + add_strings_row_to_table("Volumes:", ImGuiWrapper::COL_ORANGE_LIGHT, + std::string(buf), ImGuiWrapper::to_ImVec4(ColorRGBA::WHITE())); + sprintf(buf, "%d (%d)", (int)m_scene_raycaster.gizmos_count(), (int)m_scene_raycaster.active_gizmos_count()); + add_strings_row_to_table("Gizmo elements:", ImGuiWrapper::COL_ORANGE_LIGHT, + std::string(buf), ImGuiWrapper::to_ImVec4(ColorRGBA::WHITE())); + ImGui::EndTable(); + } imgui.end(); #endif // ENABLE_RAYCAST_PICKING_DEBUG } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index c511f7e501..5dee42ad1e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -30,6 +30,8 @@ static const int POINT_ID = 100; static const int EDGE_ID = 200; static const int CIRCLE_ID = 300; static const int PLANE_ID = 400; +static const int SELECTION_1_ID = 501; +static const int SELECTION_2_ID = 502; static const float TRIANGLE_BASE = 10.0f; static const float TRIANGLE_HEIGHT = TRIANGLE_BASE * 1.618033f; @@ -47,11 +49,11 @@ static std::string surface_feature_type_as_string(Measure::SurfaceFeatureType ty switch (type) { default: - case Measure::SurfaceFeatureType::Undef: { return L("Undefined"); } - case Measure::SurfaceFeatureType::Point: { return L("Vertex"); } - case Measure::SurfaceFeatureType::Edge: { return L("Edge"); } - case Measure::SurfaceFeatureType::Circle: { return L("Circle"); } - case Measure::SurfaceFeatureType::Plane: { return L("Plane"); } + case Measure::SurfaceFeatureType::Undef: { return _u8L("Undefined"); } + case Measure::SurfaceFeatureType::Point: { return _u8L("Vertex"); } + case Measure::SurfaceFeatureType::Edge: { return _u8L("Edge"); } + case Measure::SurfaceFeatureType::Circle: { return _u8L("Circle"); } + case Measure::SurfaceFeatureType::Plane: { return _u8L("Plane"); } } } @@ -277,20 +279,44 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) m_mouse_left_down = true; auto item_from_feature = [this]() { - const SelectedFeatures::Item item = { - (m_mode == EMode::ExtendedSelection) ? point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id) : surface_feature_type_as_string(m_curr_feature->get_type()), - (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(*m_curr_point_on_feature_position) : m_curr_feature }; + SelectedFeatures::Item item; + if (m_hover_id == SELECTION_1_ID && m_selected_features.first.feature.has_value()) + item = m_selected_features.first; + else if (m_hover_id == SELECTION_2_ID && m_selected_features.second.feature.has_value()) + item = m_selected_features.second; + else { + item = { + (m_mode == EMode::ExtendedSelection) ? point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id) : surface_feature_type_as_string(m_curr_feature->get_type()), + (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(*m_curr_point_on_feature_position) : m_curr_feature + }; + } return item; }; if (m_selected_features.first.feature.has_value()) { - const SelectedFeatures::Item item = item_from_feature(); - if (m_selected_features.first != item) - m_selected_features.second = item; - } - else - m_selected_features.first = item_from_feature(); + auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), + [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_2_ID; }); + if (it != m_selection_raycasters.end()) + m_selection_raycasters.erase(it); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, SELECTION_2_ID); + const SelectedFeatures::Item item = item_from_feature(); + if (m_selected_features.first != item) { + if (m_selected_features.second == item) + m_selected_features.second.reset(); + else { + m_selected_features.second = item; + if (m_mode == EMode::ExtendedSelection) + m_selection_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SELECTION_2_ID, *m_sphere.mesh_raycaster)); + } + } + } + else { + const SelectedFeatures::Item item = item_from_feature(); + m_selected_features.first = item; + if (m_mode == EMode::ExtendedSelection) + m_selection_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SELECTION_1_ID, *m_sphere.mesh_raycaster)); + } return true; } @@ -308,6 +334,7 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) } else if (mouse_event.RightDown() && mouse_event.CmdDown()) { m_selected_features.reset(); + m_selection_raycasters.clear(); m_imgui->set_requires_extra_frame(); } else if (mouse_event.Leaving()) @@ -332,6 +359,7 @@ void GLGizmoMeasure::data_changed() m_last_inv_zoom = 0.0f; m_last_plane_idx = -1; m_selected_features.reset(); + m_selection_raycasters.clear(); } bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) @@ -435,7 +463,11 @@ void GLGizmoMeasure::on_render() std::optional curr_feature = mouse_on_object ? m_measuring->get_feature(model_facet_idx, position_on_model.cast()) : std::nullopt; m_curr_point_on_feature_position.reset(); if (m_curr_feature != curr_feature) { - GLGizmoMeasure::on_unregister_raycasters_for_picking(); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); + m_raycasters.clear(); m_curr_feature = curr_feature; if (!m_curr_feature.has_value()) return; @@ -687,11 +719,23 @@ void GLGizmoMeasure::on_render() std::vector colors; colors.emplace_back(SELECTED_1ST_COLOR); render_feature(*m_selected_features.first.feature, colors, m_volume_matrix, inv_zoom, false); + if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point) { + auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), + [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_1_ID; }); + if (it != m_selection_raycasters.end()) + (*it)->set_transform(m_volume_matrix * Geometry::translation_transform(m_selected_features.first.feature->get_point()) * Geometry::scale_transform(inv_zoom)); + } } if (m_selected_features.second.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.second.feature)) { std::vector colors; colors.emplace_back(SELECTED_2ND_COLOR); render_feature(*m_selected_features.second.feature, colors, m_volume_matrix, inv_zoom, false); + if (m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { + auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), + [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_2_ID; }); + if (it != m_selection_raycasters.end()) + (*it)->set_transform(m_volume_matrix * Geometry::translation_transform(m_selected_features.second.feature->get_point()) * Geometry::scale_transform(inv_zoom)); + } } if (is_hovering_on_locked_feature && m_curr_point_on_feature_position.has_value()) { @@ -1269,7 +1313,7 @@ void GLGizmoMeasure::render_debug_dialog() add_strings_row_to_table(*m_imgui, "m_pt3", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(*extra_point), ImGui::GetStyleColorVec4(ImGuiCol_Text)); }; - m_imgui->begin(_L("Measure tool debug"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + m_imgui->begin(_L("Measure tool debug"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); if (!m_selected_features.first.feature.has_value() && !m_selected_features.second.feature.has_value()) m_imgui->text("Empty selection"); else { @@ -1323,7 +1367,10 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Left mouse button")); }, [this]() { - m_imgui->text_colored(ImGui::GetStyleColorVec4(ImGuiCol_Text), (m_mode == EMode::BasicSelection) ? _u8L("Select feature") : _u8L("Select point")); + m_imgui->text_colored(ImGui::GetStyleColorVec4(ImGuiCol_Text), + m_selected_features.second.feature.has_value() ? + ((m_mode == EMode::BasicSelection) ? _u8L("Select/Unselect feature") : _u8L("Select/Unselect point")) : + ((m_mode == EMode::BasicSelection) ? _u8L("Select feature") : _u8L("Select point"))); ImGui::SameLine(); const ImVec2 pos = ImGui::GetCursorScreenPos(); const float rect_size = ImGui::GetTextLineHeight(); @@ -1434,6 +1481,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit //if (m_selected_features.first.feature.has_value()) { // if (m_imgui->button(_u8L("Restart"))) { // m_selected_features.reset(); + // m_selection_raycasters.clear(); // m_imgui->set_requires_extra_frame(); // } //} @@ -1498,6 +1546,7 @@ void GLGizmoMeasure::on_unregister_raycasters_for_picking() m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo); m_parent.set_raycaster_gizmos_on_top(false); m_raycasters.clear(); + m_selection_raycasters.clear(); } } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 0e967472ae..441d91c3a2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -87,6 +87,7 @@ class GLGizmoMeasure : public GLGizmoBase Transform3d m_volume_matrix{ Transform3d::Identity() }; std::vector m_plane_models_cache; std::map> m_raycasters; + std::vector> m_selection_raycasters; std::optional m_curr_feature; std::optional m_curr_point_on_feature_position; struct SceneRaycasterState diff --git a/src/slic3r/GUI/SceneRaycaster.cpp b/src/slic3r/GUI/SceneRaycaster.cpp index 78cb59c1bc..a92c622c1b 100644 --- a/src/slic3r/GUI/SceneRaycaster.cpp +++ b/src/slic3r/GUI/SceneRaycaster.cpp @@ -37,10 +37,10 @@ std::shared_ptr SceneRaycaster::add_raycaster(EType type, in const Transform3d& trafo, bool use_back_faces) { switch (type) { - case EType::Bed: { return m_bed.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo, use_back_faces)); } + case EType::Bed: { return m_bed.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo, use_back_faces)); } case EType::Volume: { return m_volumes.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo, use_back_faces)); } - case EType::Gizmo: { return m_gizmos.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo, use_back_faces)); } - default: { assert(false); return nullptr; } + case EType::Gizmo: { return m_gizmos.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo, use_back_faces)); } + default: { assert(false); return nullptr; } }; } diff --git a/src/slic3r/GUI/SceneRaycaster.hpp b/src/slic3r/GUI/SceneRaycaster.hpp index 7acf82fe11..4a7eaab276 100644 --- a/src/slic3r/GUI/SceneRaycaster.hpp +++ b/src/slic3r/GUI/SceneRaycaster.hpp @@ -106,9 +106,10 @@ public: size_t active_gizmos_count() const; #endif // ENABLE_RAYCAST_PICKING_DEBUG + static int decode_id(EType type, int id); + private: static int encode_id(EType type, int id); - static int decode_id(EType type, int id); static int base_id(EType type); }; From ee088bf79877b18eed1b370e9d7419f13693aa70 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 29 Sep 2022 10:19:40 +0200 Subject: [PATCH 069/250] Measuring - GLGizmoMeasure - Added option to copy to clipboard the result of measurement --- src/imgui/imconfig.h | 16 +++++++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 57 ++++++++++++++++++++---- src/slic3r/GUI/ImGuiWrapper.cpp | 3 ++ 3 files changed, 68 insertions(+), 8 deletions(-) diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h index f2c3ef0837..7c79058c4c 100644 --- a/src/imgui/imconfig.h +++ b/src/imgui/imconfig.h @@ -156,6 +156,21 @@ namespace ImGui const wchar_t InfoMarker = 0x2603; const wchar_t SliderFloatEditBtnIcon = 0x2604; const wchar_t SliderFloatEditBtnPressedIcon = 0x2605; +#if ENABLE_MEASURE_GIZMO + const wchar_t ClipboardBtnIcon = 0x2606; + const wchar_t LegendTravel = 0x2701; + const wchar_t LegendWipe = 0x2702; + const wchar_t LegendRetract = 0x2703; + const wchar_t LegendDeretract = 0x2704; + const wchar_t LegendSeams = 0x2705; + const wchar_t LegendToolChanges = 0x2706; + const wchar_t LegendColorChanges = 0x2707; + const wchar_t LegendPausePrints = 0x2708; + const wchar_t LegendCustomGCodes = 0x2709; + const wchar_t LegendCOG = 0x2710; + const wchar_t LegendShells = 0x2711; + const wchar_t LegendToolMarker = 0x2712; +#else const wchar_t LegendTravel = 0x2606; const wchar_t LegendWipe = 0x2607; const wchar_t LegendRetract = 0x2608; @@ -168,6 +183,7 @@ namespace ImGui const wchar_t LegendCOG = 0x2615; const wchar_t LegendShells = 0x2616; const wchar_t LegendToolMarker = 0x2617; +#endif // ENABLE_MEASURE_GIZMO // void MyFunction(const char* name, const MyMatrix44& v); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 5dee42ad1e..c232405019 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -10,6 +10,8 @@ #include "libslic3r/Model.hpp" #include "libslic3r/PresetBundle.hpp" +#include + #include #include @@ -1251,7 +1253,7 @@ static void add_row_to_table(std::function col_1 = nullptr, std::fun col_1(); ImGui::TableSetColumnIndex(1); col_2(); -}; +} static void add_strings_row_to_table(ImGuiWrapper& imgui, const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) { @@ -1263,14 +1265,14 @@ static std::string format_double(double value) char buf[1024]; sprintf(buf, "%.3f", value); return std::string(buf); -}; +} static std::string format_vec3(const Vec3d& v) { char buf[1024]; sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", v.x(), v.y(), v.z()); return std::string(buf); -}; +} #if ENABLE_MEASURE_GIZMO_DEBUG void GLGizmoMeasure::render_debug_dialog() @@ -1486,36 +1488,75 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit // } //} + auto add_measure_row_to_table = [this](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) { + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + m_imgui->text_colored(col_1_color, col_1); + ImGui::TableSetColumnIndex(1); + m_imgui->text_colored(col_2_color, col_2); + ImGui::TableSetColumnIndex(2); + ImGuiIO& io = ImGui::GetIO(); + const ImTextureID tex_id = io.Fonts->TexID; + assert(io.Fonts->TexWidth > 0 && io.Fonts->TexHeight > 0); + float inv_tex_w = 1.0f / float(io.Fonts->TexWidth); + float inv_tex_h = 1.0f / float(io.Fonts->TexHeight); + const ImFontAtlasCustomRect* const rect = m_imgui->GetTextureCustomRect(ImGui::ClipboardBtnIcon); + const ImVec2 size = { float(rect->Width), float(rect->Height) }; + const ImVec2 uv0 = ImVec2(float(rect->X) * inv_tex_w, float(rect->Y) * inv_tex_h); + const ImVec2 uv1 = ImVec2(float(rect->X + rect->Width) * inv_tex_w, float(rect->Y + rect->Height) * inv_tex_h); + ImGui::PushStyleColor(ImGuiCol_Button, { 0.25f, 0.25f, 0.25f, 0.0f }); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 0.4f, 0.4f, 0.4f, 1.0f }); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0.25f, 0.25f, 0.25f, 1.0f }); + if (m_imgui->image_button(tex_id, size, uv0, uv1)) { + wxTheClipboard->Open(); + wxTheClipboard->SetData(new wxTextDataObject(col_1 + ": " + col_2)); + wxTheClipboard->Close(); + } + ImGui::PopStyleColor(3); + if (ImGui::IsItemHovered()) { + const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; + m_imgui->tooltip(into_u8(_L("Copy to clipboard")).c_str(), max_tooltip_width); + } + }; + if (m_selected_features.second.feature.has_value()) { const Measure::MeasurementResult measure = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature); ImGui::Separator(); if (measure.has_any_data()) { m_imgui->text(_u8L("Measure") + ":"); - if (ImGui::BeginTable("Measure", 2)) { + if (ImGui::BeginTable("Measure", 3)) { if (measure.angle.has_value()) { - add_strings_row_to_table(*m_imgui, _u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(*measure.angle)), + ImGui::PushID((void*)(intptr_t)1); + add_measure_row_to_table(_u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(*measure.angle)), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ImGui::PopID(); } if (measure.distance_infinite.has_value()) { double distance = *measure.distance_infinite; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - add_strings_row_to_table(*m_imgui, _u8L("Distance Infinite") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), + ImGui::PushID((void*)(intptr_t)2); + add_measure_row_to_table(_u8L("Distance Infinite") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ImGui::PopID(); } if (measure.distance_strict.has_value()) { double distance = *measure.distance_strict; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - add_strings_row_to_table(*m_imgui, _u8L("Distance Strict") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), + ImGui::PushID((void*)(intptr_t)3); + add_measure_row_to_table(_u8L("Distance Strict") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ImGui::PopID(); } if (measure.distance_xyz.has_value()) { Vec3d distance = *measure.distance_xyz; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - add_strings_row_to_table(*m_imgui, _u8L("Distance XYZ") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), + ImGui::PushID((void*)(intptr_t)4); + add_measure_row_to_table(_u8L("Distance XYZ") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ImGui::PopID(); } ImGui::EndTable(); } diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index fa6e2c9031..4ce9dfefc0 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -56,6 +56,9 @@ static const std::map font_icons = { {ImGui::PreferencesHoverButton, "notification_preferences_hover"}, {ImGui::SliderFloatEditBtnIcon, "edit_button" }, {ImGui::SliderFloatEditBtnPressedIcon, "edit_button_pressed" }, +#if ENABLE_MEASURE_GIZMO + {ImGui::ClipboardBtnIcon , "copy_menu" }, +#endif // ENABLE_MEASURE_GIZMO #if ENABLE_LEGEND_TOOLBAR_ICONS {ImGui::LegendTravel , "legend_travel" }, {ImGui::LegendWipe , "legend_wipe" }, From 5ad4fafbf168631c12fd5e795eba4b7ecddaf83d Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 29 Sep 2022 11:22:23 +0200 Subject: [PATCH 070/250] Measurement: moving arrow-drawing functions from frontend to the backend (1/4) --- src/libslic3r/Measure.cpp | 24 +++-- src/libslic3r/Measure.hpp | 10 +- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 126 ++++++++++++----------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 4 +- 4 files changed, 92 insertions(+), 72 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index c2b7edd5e2..a627fe62cc 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -349,7 +349,7 @@ std::optional MeasuringImpl::get_feature(size_t face_idx, const // which is needless and relatively expensive. res = get_measurement(plane.surface_features[i], point_sf); if (res.distance_strict) { // TODO: this should become an assert after all combinations are implemented. - double dist = *res.distance_strict; + double dist = res.distance_strict->dist; if (dist < feature_hover_limit && dist < min_dist) { min_dist = std::min(dist, min_dist); closest_feature_idx = i; @@ -455,8 +455,9 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& if (f1.get_type() == SurfaceFeatureType::Point) { if (f2.get_type() == SurfaceFeatureType::Point) { Vec3d diff = (f2.get_point() - f1.get_point()); - result.distance_strict = diff.norm(); + result.distance_strict = std::make_optional(DistAndPoints{diff.norm(), f1.get_point(), f2.get_point()}); result.distance_xyz = diff; + /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Edge) { const auto& [s,e] = f2.get_edge(); @@ -468,11 +469,12 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& double dist_end_sq = (proj-e).squaredNorm(); if (dist_start_sq < len_sq && dist_end_sq < len_sq) { // projection falls on the line - the strict distance is the same as infinite - result.distance_strict = std::make_optional(dist_inf); + result.distance_strict = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); // TODO } else { // the result is the closer of the endpoints - result.distance_strict = std::make_optional(std::sqrt(std::min(dist_start_sq, dist_end_sq) + dist_inf)); + bool s_is_closer = dist_start_sq < dist_end_sq; + result.distance_strict = std::make_optional(DistAndPoints{std::sqrt(std::min(dist_start_sq, dist_end_sq) + dist_inf), f1.get_point(), s_is_closer ? s : e}); } - result.distance_infinite = std::make_optional(dist_inf); + result.distance_infinite = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); // TODO /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Circle) { // Find a plane containing normal, center and the point. @@ -482,12 +484,13 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& double dist = std::sqrt(std::pow((proj - c).norm() - radius, 2.) + (f1.get_point() - proj).squaredNorm()); - result.distance_strict = std::make_optional(dist); + const Vec3d p_on_circle = c + radius * (circle_plane.projection(f1.get_point()) - c).normalized(); + result.distance_strict = std::make_optional(DistAndPoints{dist, f1.get_point(), p_on_circle}); // TODO /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { const auto& [idx, normal, pt] = f2.get_plane(); Eigen::Hyperplane plane(normal, pt); - result.distance_infinite = plane.absDistance(f1.get_point()); + result.distance_infinite = std::make_optional(DistAndPoints{plane.absDistance(f1.get_point()), f1.get_point(), plane.projection(f1.get_point())}); // TODO // TODO: result.distance_strict = } /////////////////////////////////////////////////////////////////////////// @@ -495,18 +498,23 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& /////////////////////////////////////////////////////////////////////////// } else if (f1.get_type() == SurfaceFeatureType::Edge) { if (f2.get_type() == SurfaceFeatureType::Edge) { + result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Circle) { + result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { + result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// } else if (f1.get_type() == SurfaceFeatureType::Circle) { if (f2.get_type() == SurfaceFeatureType::Circle) { + result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { + result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// @@ -521,7 +529,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& if (normal1.isApprox(normal2)) { // The planes are parallel, calculate distance. Eigen::Hyperplane plane(normal1, pt1); - result.distance_infinite = plane.absDistance(pt2); + result.distance_infinite = std::make_optional(DistAndPoints{plane.absDistance(pt2), Vec3d::Zero(), Vec3d::Zero()}); } else { // Planes are not parallel, calculate angle. angle = std::acos(std::abs(normal1.dot(normal2))); diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 5d71983f0b..6b7940f2bf 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -110,12 +110,16 @@ private: }; - +struct DistAndPoints { + double dist; + Vec3d from; + Vec3d to; +}; struct MeasurementResult { std::optional angle; - std::optional distance_infinite; - std::optional distance_strict; + std::optional distance_infinite; + std::optional distance_strict; std::optional distance_xyz; bool has_any_data() const { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index c232405019..11cd651e5c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -72,13 +72,6 @@ static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType t return ret; } -static std::tuple distance_point_plane(const Vec3d& v, const Plane& p) -{ - const auto& [idx, normal, origin] = p; - const Eigen::Hyperplane plane(normal, origin); - return std::make_tuple(plane.absDistance(v), v, plane.projection(v)); -} - static Vec3d vector_direction(const Vec3d& from, const Vec3d& to) { return (to - from).normalized(); @@ -89,21 +82,13 @@ static Vec3d edge_direction(const Edge& e) return vector_direction(e.first, e.second); } -// returns: distance, 1st vertex, 2nd vertex -static std::tuple distance_point_edge(const Vec3d& v, const Edge& e) -{ - const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); - return std::make_tuple(line.distance(v), v, line.projection(v)); -} -// returns: distance, 1st vertex, 2nd vertex -static std::tuple distance_point_circle(const Vec3d& v, const Circle& c) -{ - const auto& [center, radius, normal] = c; - const Eigen::Hyperplane plane(normal, center); - const Vec3d p_on_circle = center + radius * vector_direction(center, plane.projection(v)); - return std::make_tuple((v - p_on_circle).norm(), v, p_on_circle); -} + + + + +/* + // returns: distance, 1st vertex, 2nd vertex static std::tuple distance_edge_edge(const Edge& e1, const Edge& e2) @@ -165,6 +150,34 @@ static std::tuple distance_plane_plane(const Plane& p1, co return (std::abs(std::abs(normal1.dot(normal2)) - 1.0) < EPSILON) ? distance_point_plane(origin2, p1) : std::make_tuple(0.0, Vec3d::Zero(), Vec3d::Zero()); } +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + // returns: angle in rad, center of arc, radius of arc, whether or not the edges are coplanar // After return, the edges are oriented so that they point away from their intersection point @@ -278,6 +291,9 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) } else if (mouse_event.LeftDown()) { if (m_hover_id != -1) { + SelectedFeatures selected_features_old = m_selected_features; + + m_mouse_left_down = true; auto item_from_feature = [this]() { @@ -319,6 +335,10 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) if (m_mode == EMode::ExtendedSelection) m_selection_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SELECTION_1_ID, *m_sphere.mesh_raycaster)); } + + if (m_selected_features != selected_features_old && m_selected_features.second.feature.has_value()) + m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature); + return true; } @@ -963,8 +983,11 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.triangle.render(); }; + auto point_edge = [this, shader, point_point](const Vec3d& v, const Edge& e) { - const auto [distance, v1, v_proj] = distance_point_edge(v, e); + const double distance = m_measurement_result.distance_infinite->dist; + const Vec3d v1 = m_measurement_result.distance_infinite->from; + const Vec3d v_proj = m_measurement_result.distance_infinite->to; point_point(v1, v_proj); const Vec3d e1e2 = e.second - e.first; @@ -997,16 +1020,7 @@ void GLGizmoMeasure::render_dimensioning() } }; - auto point_plane = [point_point](const Vec3d& v, const Plane& p) { - const auto [distance, v1, v2] = distance_point_plane(v, p); - point_point(v1, v2); - }; - - auto point_circle = [point_point](const Vec3d& v, const Circle& c) { - const auto [distance, v1, v2] = distance_point_circle(v, c); - point_point(v1, v2); - }; - +/* auto arc_edge_edge = [this, shader](const Edge& e1, const Edge& e2, const double* const force_radius = nullptr) { Edge e1copy = e1; Edge e2copy = e2; @@ -1130,7 +1144,7 @@ void GLGizmoMeasure::render_dimensioning() auto plane_plane = [point_point](const Plane& p1, const Plane& p2) { const auto [distance, v1, v2] = distance_plane_plane(p1, p2); point_point(v1, v2); - }; + };*/ shader->start_using(); @@ -1174,26 +1188,26 @@ void GLGizmoMeasure::render_dimensioning() glsafe(::glDisable(GL_DEPTH_TEST)); - // point-point - if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - point_point(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_point()); + // Render the arrow between the points that the backend passed: + if (m_selected_features.second.feature.has_value()) { + const Measure::DistAndPoints& dap = m_measurement_result.distance_infinite.has_value() + ? *m_measurement_result.distance_infinite + : *m_measurement_result.distance_strict; + point_point(dap.from, dap.to); } + + // Now if one of the features is an edge, draw also the extension of the edge to where the dist is measured: + // TODO... + + // point-edge else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { point_edge(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_edge()); } - // point-plane - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { - point_plane(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_plane()); - } - // point-circle - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Circle) { - point_circle(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_circle()); - } + + + /* // edge-point else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { @@ -1214,11 +1228,6 @@ void GLGizmoMeasure::render_dimensioning() m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Circle) { edge_circle(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_circle()); } - // plane-point - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - point_plane(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_plane()); - } // plane-edge else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { @@ -1229,16 +1238,12 @@ void GLGizmoMeasure::render_dimensioning() m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { plane_plane(m_selected_features.first.feature->get_plane(), m_selected_features.second.feature->get_plane()); } - // circle-point - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - point_circle(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_circle()); - } // circle-edge else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { edge_circle(m_selected_features.second.feature->get_edge(), m_selected_features.first.feature->get_circle()); } +*/ glsafe(::glEnable(GL_DEPTH_TEST)); @@ -1520,7 +1525,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit }; if (m_selected_features.second.feature.has_value()) { - const Measure::MeasurementResult measure = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature); + const Measure::MeasurementResult& measure = m_measurement_result; + ImGui::Separator(); if (measure.has_any_data()) { m_imgui->text(_u8L("Measure") + ":"); @@ -1532,7 +1538,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::PopID(); } if (measure.distance_infinite.has_value()) { - double distance = *measure.distance_infinite; + double distance = measure.distance_infinite->dist; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; ImGui::PushID((void*)(intptr_t)2); @@ -1541,7 +1547,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::PopID(); } if (measure.distance_strict.has_value()) { - double distance = *measure.distance_strict; + double distance = measure.distance_strict->dist; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; ImGui::PushID((void*)(intptr_t)3); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 441d91c3a2..a5312ebf57 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -70,7 +70,9 @@ class GLGizmoMeasure : public GLGizmoBase }; EMode m_mode{ EMode::BasicSelection }; - std::unique_ptr m_measuring; + Measure::MeasurementResult m_measurement_result; + + std::unique_ptr m_measuring; // PIMPL PickingModel m_sphere; PickingModel m_cylinder; From 05c03e54d9172b235151f6dd2c7738ccb01b16f1 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 29 Sep 2022 12:33:20 +0200 Subject: [PATCH 071/250] Measurement: moving arrow-drawing functions from frontend to the backend (2/4) --- src/libslic3r/Measure.cpp | 35 +++++++++++++++++++++++- src/libslic3r/Measure.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index a627fe62cc..01f48579d2 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -498,7 +498,40 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& /////////////////////////////////////////////////////////////////////////// } else if (f1.get_type() == SurfaceFeatureType::Edge) { if (f2.get_type() == SurfaceFeatureType::Edge) { - result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO + + std::vector distances; + + auto add_point_edge_distance = [&distances](const Vec3d& v, const std::pair& e) { + //const auto [distance, v1, v2] = distance_point_edge(v, SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second)); + + const MeasurementResult res = get_measurement(SurfaceFeature(v), SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second, std::optional(), 0.)); + double distance = res.distance_strict->dist; + Vec3d v1 = res.distance_strict->from; + Vec3d v2 = res.distance_strict->to; + + + const Vec3d e1e2 = e.second - e.first; + const Vec3d e1v2 = v2 - e.first; + if (e1v2.dot(e1e2) >= 0.0 && e1v2.norm() < e1e2.norm()) + distances.emplace_back(distance, v, v2); + }; + + std::pair e1 = f1.get_edge(); + std::pair e2 = f2.get_edge(); + + distances.emplace_back((e2.first - e1.first).norm(), e1.first, e2.first); + distances.emplace_back((e2.second - e1.first).norm(), e1.first, e2.second); + distances.emplace_back((e2.first - e1.second).norm(), e1.second, e2.first); + distances.emplace_back((e2.second - e1.second).norm(), e1.second, e2.second); + add_point_edge_distance(e1.first, e2); + add_point_edge_distance(e1.second, e2); + add_point_edge_distance(e2.first, e1); + add_point_edge_distance(e2.second, e1); + auto it = std::min_element(distances.begin(), distances.end(), + [](const DistAndPoints& item1, const DistAndPoints& item2) { + return item1.dist < item2.dist; + }); + result.distance_infinite = std::make_optional(*it); // TODO /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Circle) { result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 6b7940f2bf..fb36b50095 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -111,6 +111,7 @@ private: struct DistAndPoints { + DistAndPoints(double dist_, Vec3d from_, Vec3d to_) : dist(dist_), from(from_), to(to_) {} double dist; Vec3d from; Vec3d to; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 11cd651e5c..222d8087a0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -90,7 +90,7 @@ static Vec3d edge_direction(const Edge& e) /* -// returns: distance, 1st vertex, 2nd vertex +// returns: distance, 1st vertex, 2nd vertexs static std::tuple distance_edge_edge(const Edge& e1, const Edge& e2) { std::vector> distances; From 699a210c31b2b6fc912236e1e9fc0df2652a3507 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 29 Sep 2022 14:50:29 +0200 Subject: [PATCH 072/250] Measurement: moving arrow-drawing functions from frontend to the backend (3/4) --- src/libslic3r/Measure.cpp | 98 ++++++- src/libslic3r/Measure.hpp | 25 +- src/libslic3r/SurfaceMesh.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 310 ++++------------------- 4 files changed, 156 insertions(+), 278 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 01f48579d2..fbf248c0f7 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -431,6 +431,67 @@ std::vector> Measuring::get_planes_triangle_indices() const +static AngleAndPoints angle_edge_edge(const std::pair& e1, const std::pair& e2) +{ + Vec3d e1_unit = (e1.second - e1.first).normalized(); + Vec3d e2_unit = (e2.second - e2.first).normalized(); + const double dot = e1_unit.dot(e2_unit); + // are edges parallel ? + if (std::abs(std::abs(dot) - 1.0) < EPSILON) + return AngleAndPoints(0.0, e1.first, Vec3d::UnitX(), Vec3d::UnitX(), 0., true); + + // project edges on the plane defined by them + Vec3d normal = e1_unit.cross(e2_unit).normalized(); + const Eigen::Hyperplane plane(normal, e1.first); + Vec3d e11_proj = plane.projection(e1.first); + Vec3d e12_proj = plane.projection(e1.second); + Vec3d e21_proj = plane.projection(e2.first); + Vec3d e22_proj = plane.projection(e2.second); + + const bool coplanar = (e2.first - e21_proj).norm() < EPSILON && (e2.second - e22_proj).norm() < EPSILON; + + // rotate the plane to become the XY plane + auto qp = Eigen::Quaternion::FromTwoVectors(normal, Vec3d::UnitZ()); + auto qp_inverse = qp.inverse(); + const Vec3d e11_rot = qp * e11_proj; + const Vec3d e12_rot = qp * e12_proj; + const Vec3d e21_rot = qp * e21_proj; + const Vec3d e22_rot = qp * e22_proj; + + // discard Z + const Vec2d e11_rot_2d = Vec2d(e11_rot.x(), e11_rot.y()); + const Vec2d e12_rot_2d = Vec2d(e12_rot.x(), e12_rot.y()); + const Vec2d e21_rot_2d = Vec2d(e21_rot.x(), e21_rot.y()); + const Vec2d e22_rot_2d = Vec2d(e22_rot.x(), e22_rot.y()); + + // find intersection (arc center) of edges in XY plane + const Eigen::Hyperplane e1_rot_2d_line = Eigen::Hyperplane::Through(e11_rot_2d, e12_rot_2d); + const Eigen::Hyperplane e2_rot_2d_line = Eigen::Hyperplane::Through(e21_rot_2d, e22_rot_2d); + const Vec2d center_rot_2d = e1_rot_2d_line.intersection(e2_rot_2d_line); + + // arc center in original coordinate + const Vec3d center = qp_inverse * Vec3d(center_rot_2d.x(), center_rot_2d.y(), e11_rot.z()); + + // ensure the edges are pointing away from the center + if ((center_rot_2d - e11_rot_2d).squaredNorm() > (center_rot_2d - e12_rot_2d).squaredNorm()) { + std::swap(e11_proj, e12_proj); + e1_unit = -e1_unit; + } + if ((center_rot_2d - e21_rot_2d).squaredNorm() > (center_rot_2d - e22_rot_2d).squaredNorm()) { + std::swap(e21_proj, e22_proj); + e2_unit = -e2_unit; + } + + // arc angle + const double angle = std::acos(std::clamp(e1_unit.dot(e2_unit), -1.0, 1.0)); + // arc radius + const Vec3d e1_proj_mid = 0.5 * (e11_proj + e12_proj); + const Vec3d e2_proj_mid = 0.5 * (e21_proj + e22_proj); + const double radius = std::min((center - e1_proj_mid).norm(), (center - e2_proj_mid).norm()); + + return AngleAndPoints(angle, center, e1_unit, e2_unit, radius, coplanar); +} + @@ -469,12 +530,12 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& double dist_end_sq = (proj-e).squaredNorm(); if (dist_start_sq < len_sq && dist_end_sq < len_sq) { // projection falls on the line - the strict distance is the same as infinite - result.distance_strict = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); // TODO + result.distance_strict = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); } else { // the result is the closer of the endpoints bool s_is_closer = dist_start_sq < dist_end_sq; result.distance_strict = std::make_optional(DistAndPoints{std::sqrt(std::min(dist_start_sq, dist_end_sq) + dist_inf), f1.get_point(), s_is_closer ? s : e}); } - result.distance_infinite = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); // TODO + result.distance_infinite = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Circle) { // Find a plane containing normal, center and the point. @@ -498,18 +559,13 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& /////////////////////////////////////////////////////////////////////////// } else if (f1.get_type() == SurfaceFeatureType::Edge) { if (f2.get_type() == SurfaceFeatureType::Edge) { - std::vector distances; auto add_point_edge_distance = [&distances](const Vec3d& v, const std::pair& e) { - //const auto [distance, v1, v2] = distance_point_edge(v, SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second)); - const MeasurementResult res = get_measurement(SurfaceFeature(v), SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second, std::optional(), 0.)); double distance = res.distance_strict->dist; - Vec3d v1 = res.distance_strict->from; Vec3d v2 = res.distance_strict->to; - const Vec3d e1e2 = e.second - e.first; const Vec3d e1v2 = v2 - e.first; if (e1v2.dot(e1e2) >= 0.0 && e1v2.norm() < e1e2.norm()) @@ -531,10 +587,32 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& [](const DistAndPoints& item1, const DistAndPoints& item2) { return item1.dist < item2.dist; }); - result.distance_infinite = std::make_optional(*it); // TODO + result.distance_infinite = std::make_optional(*it); + + result.angle = angle_edge_edge(f1.get_edge(), f2.get_edge()); /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Circle) { - result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO + const std::pair e = f1.get_edge(); + const auto& [center, radius, normal] = f2.get_circle(); + const Vec3d e1e2 = (e.second - e.first); + const Vec3d e1e2_unit = (e.second - e.first).normalized(); + + std::vector distances; + distances.emplace_back(*get_measurement(SurfaceFeature(e.first), f2).distance_strict); + distances.emplace_back(*get_measurement(SurfaceFeature(e.second), f2).distance_strict); + + const Eigen::Hyperplane plane(e1e2_unit, center); + const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); + const Vec3d inter = line.intersectionPoint(plane); + const Vec3d e1inter = inter - e.first; + if (e1inter.dot(e1e2) >= 0.0 && e1inter.norm() < e1e2.norm()) + distances.emplace_back(*get_measurement(SurfaceFeature(inter), f2).distance_strict); + + auto it = std::min_element(distances.begin(), distances.end(), + [](const DistAndPoints& item1, const DistAndPoints& item2) { + return item1.dist < item2.dist; + }); + result.distance_infinite = std::make_optional(DistAndPoints{it->dist, it->from, it->to}); /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO @@ -567,7 +645,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& // Planes are not parallel, calculate angle. angle = std::acos(std::abs(normal1.dot(normal2))); } - result.angle = angle; + result.angle = std::make_optional(AngleAndPoints(angle, Vec3d::Zero(), Vec3d::UnitX(), Vec3d::UnitX(), 0., false)); // TODO } diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index fb36b50095..b88411a9f6 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -15,12 +15,12 @@ namespace Slic3r { namespace Measure { -enum class SurfaceFeatureType { - Undef, - Point, - Edge, - Circle, - Plane +enum class SurfaceFeatureType : int { + Undef = 0, + Point = 1 << 0, + Edge = 1 << 1, + Circle = 1 << 2, + Plane = 1 << 3 }; class SurfaceFeature { @@ -117,8 +117,19 @@ struct DistAndPoints { Vec3d to; }; +struct AngleAndPoints { + AngleAndPoints(double angle_, Vec3d center_, Vec3d e1_, Vec3d e2_, double radius_, bool coplanar_) + : angle(angle_), center(center_), e1(e1_), e2(e2_), radius(radius_), coplanar(coplanar_) {} + double angle; + Vec3d center; + Vec3d e1; + Vec3d e2; + double radius; + bool coplanar; +}; + struct MeasurementResult { - std::optional angle; + std::optional angle; std::optional distance_infinite; std::optional distance_strict; std::optional distance_xyz; diff --git a/src/libslic3r/SurfaceMesh.hpp b/src/libslic3r/SurfaceMesh.hpp index a4b261ceb9..9e547eec49 100644 --- a/src/libslic3r/SurfaceMesh.hpp +++ b/src/libslic3r/SurfaceMesh.hpp @@ -2,6 +2,7 @@ #define slic3r_SurfaceMesh_hpp_ #include +#include namespace Slic3r { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 222d8087a0..e9fbd7f8c0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -16,15 +16,13 @@ #include +#include + #if ENABLE_MEASURE_GIZMO namespace Slic3r { namespace GUI { -using Edge = std::pair; -using Plane = std::tuple; -using Circle = std::tuple; - static const Slic3r::ColorRGBA SELECTED_1ST_COLOR = { 0.25f, 0.75f, 0.75f, 1.0f }; static const Slic3r::ColorRGBA SELECTED_2ND_COLOR = { 0.75f, 0.25f, 0.75f, 1.0f }; @@ -72,176 +70,9 @@ static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType t return ret; } -static Vec3d vector_direction(const Vec3d& from, const Vec3d& to) +static Vec3d edge_direction(const std::pair& e) { - return (to - from).normalized(); -} - -static Vec3d edge_direction(const Edge& e) -{ - return vector_direction(e.first, e.second); -} - - - - - - -/* - - -// returns: distance, 1st vertex, 2nd vertexs -static std::tuple distance_edge_edge(const Edge& e1, const Edge& e2) -{ - std::vector> distances; - auto add_point_edge_distance = [&distances](const Vec3d& v, const Edge& e) { - const auto [distance, v1, v2] = distance_point_edge(v, e); - const Vec3d e1e2 = e.second - e.first; - const Vec3d e1v2 = v2 - e.first; - if (e1v2.dot(e1e2) >= 0.0 && e1v2.norm() < e1e2.norm()) - distances.emplace_back(std::make_tuple(distance, v, v2)); - }; - - distances.emplace_back(std::make_tuple((e2.first - e1.first).norm(), e1.first, e2.first)); - distances.emplace_back(std::make_tuple((e2.second - e1.first).norm(), e1.first, e2.second)); - distances.emplace_back(std::make_tuple((e2.first - e1.second).norm(), e1.second, e2.first)); - distances.emplace_back(std::make_tuple((e2.second - e1.second).norm(), e1.second, e2.second)); - add_point_edge_distance(e1.first, e2); - add_point_edge_distance(e1.second, e2); - add_point_edge_distance(e2.first, e1); - add_point_edge_distance(e2.second, e1); - std::sort(distances.begin(), distances.end(), - [](const std::tuple& item1, const std::tuple& item2) { - return std::get<0>(item1) < std::get<0>(item2); - }); - return distances.front(); -} - -// returns: distance, 1st vertex, 2nd vertex -static std::tuple distance_edge_circle(const Edge& e, const Circle& c) -{ - const auto& [center, radius, normal] = c; - const Vec3d e1e2 = (e.second - e.first); - const Vec3d e1e2_unit = vector_direction(e.first, e.second); - - std::vector> distances; - distances.emplace_back(distance_point_circle(e.first, c)); - distances.emplace_back(distance_point_circle(e.second, c)); - - const Eigen::Hyperplane plane(e1e2_unit, center); - const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); - const Vec3d inter = line.intersectionPoint(plane); - const Vec3d e1inter = inter - e.first; - if (e1inter.dot(e1e2) >= 0.0 && e1inter.norm() < e1e2.norm()) - distances.emplace_back(distance_point_circle(inter, c)); - - std::sort(distances.begin(), distances.end(), - [](const std::tuple& item1, const std::tuple& item2) { - return std::get<0>(item1) < std::get<0>(item2); - }); - return distances.front(); -} - -// returns: distance, 1st vertex, 2nd vertex -static std::tuple distance_plane_plane(const Plane& p1, const Plane& p2) -{ - const auto& [idx1, normal1, origin1] = p1; - const auto& [idx2, normal2, origin2] = p2; - return (std::abs(std::abs(normal1.dot(normal2)) - 1.0) < EPSILON) ? distance_point_plane(origin2, p1) : - std::make_tuple(0.0, Vec3d::Zero(), Vec3d::Zero()); -} -*/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// returns: angle in rad, center of arc, radius of arc, whether or not the edges are coplanar -// After return, the edges are oriented so that they point away from their intersection point -static std::tuple angle_edge_edge(Edge& e1, Edge& e2) -{ - Vec3d e1_unit = edge_direction(e1); - Vec3d e2_unit = edge_direction(e2); - const double dot = e1_unit.dot(e2_unit); - // are edges parallel ? - if (std::abs(std::abs(dot) - 1.0) < EPSILON) - return std::make_tuple(0.0, e1.first, 0.0, true); - - // project edges on the plane defined by them - Vec3d normal = e1_unit.cross(e2_unit).normalized(); - const Eigen::Hyperplane plane(normal, e1.first); - Vec3d e11_proj = plane.projection(e1.first); - Vec3d e12_proj = plane.projection(e1.second); - Vec3d e21_proj = plane.projection(e2.first); - Vec3d e22_proj = plane.projection(e2.second); - - const bool coplanar = (e2.first - e21_proj).norm() < EPSILON && (e2.second - e22_proj).norm() < EPSILON; - - // rotate the plane to become the XY plane - auto qp = Eigen::Quaternion::FromTwoVectors(normal, Vec3d::UnitZ()); - auto qp_inverse = qp.inverse(); - const Vec3d e11_rot = qp * e11_proj; - const Vec3d e12_rot = qp * e12_proj; - const Vec3d e21_rot = qp * e21_proj; - const Vec3d e22_rot = qp * e22_proj; - - // discard Z - const Vec2d e11_rot_2d = Vec2d(e11_rot.x(), e11_rot.y()); - const Vec2d e12_rot_2d = Vec2d(e12_rot.x(), e12_rot.y()); - const Vec2d e21_rot_2d = Vec2d(e21_rot.x(), e21_rot.y()); - const Vec2d e22_rot_2d = Vec2d(e22_rot.x(), e22_rot.y()); - - // find intersection (arc center) of edges in XY plane - const Eigen::Hyperplane e1_rot_2d_line = Eigen::Hyperplane::Through(e11_rot_2d, e12_rot_2d); - const Eigen::Hyperplane e2_rot_2d_line = Eigen::Hyperplane::Through(e21_rot_2d, e22_rot_2d); - const Vec2d center_rot_2d = e1_rot_2d_line.intersection(e2_rot_2d_line); - - // arc center in original coordinate - const Vec3d center = qp_inverse * Vec3d(center_rot_2d.x(), center_rot_2d.y(), e11_rot.z()); - - // ensure the edges are pointing away from the center - if ((center_rot_2d - e11_rot_2d).squaredNorm() > (center_rot_2d - e12_rot_2d).squaredNorm()) { - std::swap(e1.first, e1.second); - std::swap(e11_proj, e12_proj); - e1_unit = -e1_unit; - } - if ((center_rot_2d - e21_rot_2d).squaredNorm() > (center_rot_2d - e22_rot_2d).squaredNorm()) { - std::swap(e2.first, e2.second); - std::swap(e21_proj, e22_proj); - e2_unit = -e2_unit; - } - - // arc angle - const double angle = std::acos(std::clamp(e1_unit.dot(e2_unit), -1.0, 1.0)); - // arc radius - const Vec3d e1_proj_mid = 0.5 * (e11_proj + e12_proj); - const Vec3d e2_proj_mid = 0.5 * (e21_proj + e22_proj); - const double radius = std::min((center - e1_proj_mid).norm(), (center - e2_proj_mid).norm()); - - return std::make_tuple(angle, center, radius, coplanar); + return (e.second - e.first).normalized(); } static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const std::vector>& planes_triangles, int idx) @@ -984,11 +815,9 @@ void GLGizmoMeasure::render_dimensioning() }; - auto point_edge = [this, shader, point_point](const Vec3d& v, const Edge& e) { - const double distance = m_measurement_result.distance_infinite->dist; - const Vec3d v1 = m_measurement_result.distance_infinite->from; + auto point_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { + std::pair e = f1.get_type() == Measure::SurfaceFeatureType::Edge ? f1.get_edge() : f2.get_edge(); const Vec3d v_proj = m_measurement_result.distance_infinite->to; - point_point(v1, v_proj); const Vec3d e1e2 = e.second - e.first; const Vec3d v_proje1 = v_proj - e.first; @@ -1020,21 +849,30 @@ void GLGizmoMeasure::render_dimensioning() } }; -/* - auto arc_edge_edge = [this, shader](const Edge& e1, const Edge& e2, const double* const force_radius = nullptr) { - Edge e1copy = e1; - Edge e2copy = e2; - const auto [angle, center, radius, coplanar] = angle_edge_edge(e1copy, e2copy); + auto arc_edge_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2, double* const force_radius = nullptr) { + Measure::MeasurementResult res = Measure::get_measurement(f1, f2); + const double angle = res.angle->angle; + const Vec3d center = res.angle->center; + const Vec3d e1_unit = res.angle->e1; + const Vec3d e2_unit = res.angle->e2; + const double radius = res.angle->radius; + const bool coplanar = res.angle->coplanar; - if (radius == 0.0) + std::pair e1 = m_selected_features.first.feature->get_edge(); + std::pair e2 = m_selected_features.second.feature->get_edge(); + + if ((e1.second - e1.first).dot(e1_unit) < 0.) + std::swap(e1.first, e1.second); + if ((e2.second - e2.first).dot(e2_unit) < 0.) + std::swap(e2.first, e2.second); + + if (radius == 0.) return; assert(force_radius == nullptr || *force_radius > 0.0); - const double draw_radius = (force_radius != nullptr) ? *force_radius : radius; + double draw_radius = force_radius ? *force_radius : radius; - const Vec3d e1_unit = edge_direction(e1copy); - const Vec3d e2_unit = edge_direction(e2copy); const Vec3d normal = e1_unit.cross(e2_unit).normalized(); if (!m_dimensioning.arc.is_initialized()) { @@ -1064,31 +902,33 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.arc.render(); // render edge 1 extension - const Vec3d e11e12 = e1copy.second - e1copy.first; - const Vec3d e11center = center - e1copy.first; + const Vec3d e11e12 = e1.second - e1.first; + const Vec3d e11center = center - e1.first; const double e11center_len = e11center.norm(); if (e11center_len > EPSILON && e11center.dot(e11e12) < 0.0) { const Camera& camera = wxGetApp().plater()->get_camera(); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), edge_direction(e1copy)) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), edge_direction(e1)) * Geometry::scale_transform({ e11center_len, 1.0f, 1.0f })); m_dimensioning.line.render(); } // render edge 2 extension - const Vec3d e21center = center - e2copy.first; + const Vec3d e21center = center - e2.first; const double e21center_len = e21center.norm(); if (e21center_len > EPSILON) { const Camera& camera = wxGetApp().plater()->get_camera(); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), edge_direction(e2copy)) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), edge_direction(e2)) * Geometry::scale_transform({ (coplanar && (force_radius == nullptr)) ? e21center_len : draw_radius, 1.0f, 1.0f })); m_dimensioning.line.render(); } }; + +/* auto arc_edge_plane = [this, arc_edge_edge](const Edge& e, const Plane& p) { const auto& [idx, normal, origin] = p; const Vec3d e1e2 = e.second - e.first; @@ -1122,29 +962,7 @@ void GLGizmoMeasure::render_dimensioning() const double radius = (inters - e1e2copy_mid).norm(); arc_edge_edge(ecopy, edge_on_plane, &radius); }; - - auto edge_edge = [point_point, arc_edge_edge](const Edge& e1, const Edge& e2) { - // distance - const auto [distance, v1, v2] = distance_edge_edge(e1, e2); - point_point(v1, v2); - // arc - arc_edge_edge(e1, e2); - }; - - auto edge_plane = [point_point, arc_edge_plane](const Edge& e, const Plane& p) { - // arc - arc_edge_plane(e, p); - }; - - auto edge_circle = [point_point](const Edge& e, const Circle& c) { - const auto [distance, v1, v2] = distance_edge_circle(e, c); - point_point(v1, v2); - }; - - auto plane_plane = [point_point](const Plane& p1, const Plane& p2) { - const auto [distance, v1, v2] = distance_plane_plane(p1, p2); - point_point(v1, v2); - };*/ +*/ shader->start_using(); @@ -1188,63 +1006,33 @@ void GLGizmoMeasure::render_dimensioning() glsafe(::glDisable(GL_DEPTH_TEST)); - // Render the arrow between the points that the backend passed: if (m_selected_features.second.feature.has_value()) { + // Render the arrow between the points that the backend passed: const Measure::DistAndPoints& dap = m_measurement_result.distance_infinite.has_value() ? *m_measurement_result.distance_infinite : *m_measurement_result.distance_strict; point_point(dap.from, dap.to); - } - // Now if one of the features is an edge, draw also the extension of the edge to where the dist is measured: - // TODO... + const Measure::SurfaceFeature& f1 = *m_selected_features.first.feature; + const Measure::SurfaceFeature& f2 = *m_selected_features.second.feature; + Measure::SurfaceFeatureType ft1 = f1.get_type(); + Measure::SurfaceFeatureType ft2 = f2.get_type(); - // point-edge - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { - point_edge(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_edge()); + // Where needed, draw also the extension of the edge to where the dist is measured: + if ((int(ft1) | int(ft2)) == + (int(Measure::SurfaceFeatureType::Point) | int(Measure::SurfaceFeatureType::Edge))) + point_edge(f1, f2); + + + // Now if there is an angle to show, draw the arc: + if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Edge) + arc_edge_edge(f1, f2); + //if (int(ft1) | int(ft2) == (int(Measure::SurfaceFeatureType::Edge) | int(Measure::SurfaceFeatureType::Plane))) + // arc_edge_plane(); } - /* - // edge-point - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - point_edge(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_edge()); - } - // edge-edge - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { - edge_edge(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_edge()); - } - // edge-plane - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { - edge_plane(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_plane()); - } - // edge-circle - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Circle) { - edge_circle(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_circle()); - } - // plane-edge - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { - edge_plane(m_selected_features.second.feature->get_edge(), m_selected_features.first.feature->get_plane()); - } - // plane-plane - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { - plane_plane(m_selected_features.first.feature->get_plane(), m_selected_features.second.feature->get_plane()); - } - // circle-edge - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { - edge_circle(m_selected_features.second.feature->get_edge(), m_selected_features.first.feature->get_circle()); - } -*/ - glsafe(::glEnable(GL_DEPTH_TEST)); shader->stop_using(); @@ -1533,7 +1321,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (ImGui::BeginTable("Measure", 3)) { if (measure.angle.has_value()) { ImGui::PushID((void*)(intptr_t)1); - add_measure_row_to_table(_u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(*measure.angle)), + add_measure_row_to_table(_u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(measure.angle->angle)), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } From 5091d77adb9083152e0b92da515e3b15f9ead8be Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 29 Sep 2022 16:39:39 +0200 Subject: [PATCH 073/250] Measurement: moving arrow-drawing functions from frontend to the backend (4/4) --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index e9fbd7f8c0..568d5db3a2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -849,7 +849,7 @@ void GLGizmoMeasure::render_dimensioning() } }; - auto arc_edge_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2, double* const force_radius = nullptr) { + auto arc_edge_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2, const double* force_radius = nullptr) { Measure::MeasurementResult res = Measure::get_measurement(f1, f2); const double angle = res.angle->angle; const Vec3d center = res.angle->center; @@ -928,8 +928,12 @@ void GLGizmoMeasure::render_dimensioning() }; -/* - auto arc_edge_plane = [this, arc_edge_edge](const Edge& e, const Plane& p) { + + auto arc_edge_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { + + std::pair e = f1.get_type() == Measure::SurfaceFeatureType::Edge ? f1.get_edge() : f2.get_edge(); + std::tuple p = f1.get_type() == Measure::SurfaceFeatureType::Plane ? f1.get_plane() : f2.get_plane(); + const auto& [idx, normal, origin] = p; const Vec3d e1e2 = e.second - e.first; const double abs_dot = std::abs(normal.dot(edge_direction(e))); @@ -941,7 +945,7 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d inters = line.intersectionPoint(plane); // ensure the edge is pointing away from the intersection - Edge ecopy = e; + std::pair ecopy = e; Vec3d e1e2copy = e1e2; if ((ecopy.first - inters).squaredNorm() > (ecopy.second - inters).squaredNorm()) { std::swap(ecopy.first, ecopy.second); @@ -951,7 +955,7 @@ void GLGizmoMeasure::render_dimensioning() // calculate 2nd edge (on the plane) const Vec3d temp = normal.cross(e1e2copy); const Vec3d edge_on_plane_unit = normal.cross(temp).normalized(); - Edge edge_on_plane = { origin, origin + e1e2copy.norm() * edge_on_plane_unit }; + std::pair edge_on_plane = { origin, origin + e1e2copy.norm() * edge_on_plane_unit }; // ensure the 2nd edge is pointing in the correct direction const Vec3d test_edge = (edge_on_plane.second - edge_on_plane.first).cross(e1e2copy); @@ -960,9 +964,11 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d e1e2copy_mid = 0.5 * (ecopy.second + ecopy.first); const double radius = (inters - e1e2copy_mid).norm(); - arc_edge_edge(ecopy, edge_on_plane, &radius); + arc_edge_edge(Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, ecopy.second, ecopy.first, std::optional(), 0.), + Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, edge_on_plane.second, edge_on_plane.first, std::optional(), 0.), + &radius); }; -*/ + shader->start_using(); @@ -1028,8 +1034,8 @@ void GLGizmoMeasure::render_dimensioning() // Now if there is an angle to show, draw the arc: if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Edge) arc_edge_edge(f1, f2); - //if (int(ft1) | int(ft2) == (int(Measure::SurfaceFeatureType::Edge) | int(Measure::SurfaceFeatureType::Plane))) - // arc_edge_plane(); + if (int(ft1) | int(ft2) == (int(Measure::SurfaceFeatureType::Edge) | int(Measure::SurfaceFeatureType::Plane))) + arc_edge_plane(f1, f2); } From 97e69c04f87a4b3d6d34b406c56808b8e04f27e5 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 30 Sep 2022 08:52:38 +0200 Subject: [PATCH 074/250] Fixed crashing asserts due to a bug in the just merged branch --- src/libslic3r/Measure.cpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 26 +++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index fbf248c0f7..78d3d524e7 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -646,6 +646,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& angle = std::acos(std::abs(normal1.dot(normal2))); } result.angle = std::make_optional(AngleAndPoints(angle, Vec3d::Zero(), Vec3d::UnitX(), Vec3d::UnitX(), 0., false)); // TODO + result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 568d5db3a2..6aebd0fa37 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -858,8 +858,8 @@ void GLGizmoMeasure::render_dimensioning() const double radius = res.angle->radius; const bool coplanar = res.angle->coplanar; - std::pair e1 = m_selected_features.first.feature->get_edge(); - std::pair e2 = m_selected_features.second.feature->get_edge(); + std::pair e1 = f1.get_edge(); + std::pair e2 = f2.get_edge(); if ((e1.second - e1.first).dot(e1_unit) < 0.) std::swap(e1.first, e1.second); @@ -1019,23 +1019,25 @@ void GLGizmoMeasure::render_dimensioning() : *m_measurement_result.distance_strict; point_point(dap.from, dap.to); - const Measure::SurfaceFeature& f1 = *m_selected_features.first.feature; - const Measure::SurfaceFeature& f2 = *m_selected_features.second.feature; - Measure::SurfaceFeatureType ft1 = f1.get_type(); - Measure::SurfaceFeatureType ft2 = f2.get_type(); + const Measure::SurfaceFeature* f1 = &(*m_selected_features.first.feature); + const Measure::SurfaceFeature* f2 = &(*m_selected_features.second.feature); + Measure::SurfaceFeatureType ft1 = f1->get_type(); + Measure::SurfaceFeatureType ft2 = f2->get_type(); + // Order features by type so following conditions are simple. + if (ft2 > ft2) + std::swap(ft1, ft2); // Where needed, draw also the extension of the edge to where the dist is measured: - if ((int(ft1) | int(ft2)) == - (int(Measure::SurfaceFeatureType::Point) | int(Measure::SurfaceFeatureType::Edge))) - point_edge(f1, f2); + if (ft1 == Measure::SurfaceFeatureType::Point && ft2 == Measure::SurfaceFeatureType::Edge) + point_edge(*f1, *f2); // Now if there is an angle to show, draw the arc: if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Edge) - arc_edge_edge(f1, f2); - if (int(ft1) | int(ft2) == (int(Measure::SurfaceFeatureType::Edge) | int(Measure::SurfaceFeatureType::Plane))) - arc_edge_plane(f1, f2); + arc_edge_edge(*f1, *f2); + if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Plane) + arc_edge_plane(*f1, *f2); } From 9b915bdd0985fd3deb7b99f4d3598b63fa5b3b99 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 30 Sep 2022 09:44:22 +0200 Subject: [PATCH 075/250] Measuring - GLGizmoMeasure - Visualization and selection of extra point for edges --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 28 ++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 6aebd0fa37..76d2dacd64 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -62,7 +62,7 @@ static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType t std::string ret; switch (type) { case Measure::SurfaceFeatureType::Point: { ret = _u8L("Vertex"); break; } - case Measure::SurfaceFeatureType::Edge: { ret = _u8L("Point on edge"); break; } + case Measure::SurfaceFeatureType::Edge: { ret = (hover_id == POINT_ID) ? _u8L("Center of edge") : _u8L("Point on edge"); break; } case Measure::SurfaceFeatureType::Circle: { ret = (hover_id == POINT_ID) ? _u8L("Center of circle") : _u8L("Point on circle"); break; } case Measure::SurfaceFeatureType::Plane: { ret = _u8L("Point on plane"); break; } default: { assert(false); break; } @@ -335,6 +335,8 @@ void GLGizmoMeasure::on_render() case Measure::SurfaceFeatureType::Edge: { m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); + if (m_curr_feature->get_extra_point().has_value()) + m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); break; } case Measure::SurfaceFeatureType::Circle: @@ -400,7 +402,11 @@ void GLGizmoMeasure::on_render() } case Measure::SurfaceFeatureType::Edge: { - m_curr_point_on_feature_position = m_volume_matrix.inverse() * position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); + const std::optional extra = m_curr_feature->get_extra_point(); + if (extra.has_value() && m_hover_id == POINT_ID) + m_curr_point_on_feature_position = *extra; + else + m_curr_point_on_feature_position = m_volume_matrix.inverse() * position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); break; } case Measure::SurfaceFeatureType::Plane: @@ -497,11 +503,25 @@ void GLGizmoMeasure::on_render() case Measure::SurfaceFeatureType::Edge: { const auto& [start, end] = feature.get_edge(); + // render extra point + const std::optional extra = m_curr_feature->get_extra_point(); + if (extra.has_value()) { + const Transform3d point_matrix = model_matrix * Geometry::translation_transform(*extra) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(point_matrix); + m_sphere.model.set_color(colors.front()); + m_sphere.model.render(); + if (update_raycasters) { + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(point_matrix); + } + } + // render edge const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start) * Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); set_matrix_uniforms(feature_matrix); - m_cylinder.model.set_color(colors.front()); + m_cylinder.model.set_color(colors.back()); m_cylinder.model.render(); if (update_raycasters) { auto it = m_raycasters.find(EDGE_ID); @@ -550,13 +570,13 @@ void GLGizmoMeasure::on_render() colors.emplace_back(hover_selection_color()); break; } + case Measure::SurfaceFeatureType::Edge: case Measure::SurfaceFeatureType::Circle: { colors.emplace_back((m_hover_id == POINT_ID) ? hover_selection_color() : hovering_color()); colors.emplace_back(hovering_color()); break; } - case Measure::SurfaceFeatureType::Edge: case Measure::SurfaceFeatureType::Plane: { colors.emplace_back(hovering_color()); From f7afed4bd3ba70339e77ee3b87b398ec2a1d3a16 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 30 Sep 2022 12:06:07 +0200 Subject: [PATCH 076/250] Follow-up of 9b915bdd0985fd3deb7b99f4d3598b63fa5b3b99 - Fixed crash --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 76d2dacd64..5cc4ce24e3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -504,7 +504,7 @@ void GLGizmoMeasure::on_render() { const auto& [start, end] = feature.get_edge(); // render extra point - const std::optional extra = m_curr_feature->get_extra_point(); + const std::optional extra = feature.get_extra_point(); if (extra.has_value()) { const Transform3d point_matrix = model_matrix * Geometry::translation_transform(*extra) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(point_matrix); From 8111fdfb544c139f404312533252a238a222b9dc Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 30 Sep 2022 12:54:00 +0200 Subject: [PATCH 077/250] Measuring - Added a bunch of utility functions in Measure.hpp --- src/libslic3r/Measure.cpp | 6 ++--- src/libslic3r/Measure.hpp | 32 ++++++++++++++++++++++++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 21 ++++------------ 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 78d3d524e7..b27425ea91 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -633,11 +633,11 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& } else if (f1.get_type() == SurfaceFeatureType::Plane) { assert(f2.get_type() == SurfaceFeatureType::Plane); - const auto& [idx1, normal1, pt1] = f1.get_plane(); - const auto& [idx2, normal2, pt2] = f2.get_plane(); + const auto [idx1, normal1, pt1] = f1.get_plane(); + const auto [idx2, normal2, pt2] = f2.get_plane(); double angle = 0.; - if (normal1.isApprox(normal2)) { + if (are_parallel(normal1, normal2)) { // The planes are parallel, calculate distance. Eigen::Hyperplane plane(normal1, pt1); result.distance_infinite = std::make_optional(DistAndPoints{plane.absDistance(pt2), Vec3d::Zero(), Vec3d::Zero()}); diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index b88411a9f6..4ac56a87f3 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -142,6 +142,38 @@ struct MeasurementResult { // Returns distance/angle between two SurfaceFeatures. MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b); +inline Vec3d edge_direction(const Vec3d& from, const Vec3d& to) { return (to - from).normalized(); } +inline Vec3d edge_direction(const SurfaceFeature& edge) { + assert(edge.get_type() == SurfaceFeatureType::Edge); + const auto [from, to] = edge.get_edge(); + return edge_direction(from, to); +} + +inline Vec3d plane_normal(const SurfaceFeature& plane) { + assert(plane.get_type() == SurfaceFeatureType::Plane); + return std::get<1>(plane.get_plane()); +} + +inline bool are_parallel(const Vec3d& v1, const Vec3d& v2) { return std::abs(std::abs(v1.dot(v2)) - 1.0) < EPSILON; } +inline bool are_perpendicular(const Vec3d& v1, const Vec3d& v2) { return std::abs(v1.dot(v2)) < EPSILON; } + +inline bool are_parallel(const SurfaceFeature& f1, const SurfaceFeature& f2) { + if (f1.get_type() == SurfaceFeatureType::Edge && f2.get_type() == SurfaceFeatureType::Edge) + return are_parallel(edge_direction(f1), edge_direction(f2)); + else if (f1.get_type() == SurfaceFeatureType::Edge && f2.get_type() == SurfaceFeatureType::Plane) + return are_perpendicular(edge_direction(f1), plane_normal(f2)); + else + return false; +} + +inline bool are_perpendicular(const SurfaceFeature& f1, const SurfaceFeature& f2) { + if (f1.get_type() == SurfaceFeatureType::Edge && f2.get_type() == SurfaceFeatureType::Edge) + return are_perpendicular(edge_direction(f1), edge_direction(f2)); + else if (f1.get_type() == SurfaceFeatureType::Edge && f2.get_type() == SurfaceFeatureType::Plane) + return are_parallel(edge_direction(f1), plane_normal(f2)); + else + return false; +} } // namespace Measure } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 5cc4ce24e3..421dfbedd5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -70,11 +70,6 @@ static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType t return ret; } -static Vec3d edge_direction(const std::pair& e) -{ - return (e.second - e.first).normalized(); -} - static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const std::vector>& planes_triangles, int idx) { assert(0 <= idx && idx < (int)planes_triangles.size()); @@ -123,8 +118,6 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) else if (mouse_event.LeftDown()) { if (m_hover_id != -1) { SelectedFeatures selected_features_old = m_selected_features; - - m_mouse_left_down = true; auto item_from_feature = [this]() { @@ -834,7 +827,6 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.triangle.render(); }; - auto point_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { std::pair e = f1.get_type() == Measure::SurfaceFeatureType::Edge ? f1.get_edge() : f2.get_edge(); const Vec3d v_proj = m_measurement_result.distance_infinite->to; @@ -929,7 +921,7 @@ void GLGizmoMeasure::render_dimensioning() const Camera& camera = wxGetApp().plater()->get_camera(); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), edge_direction(e1)) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e1.first, e1.second)) * Geometry::scale_transform({ e11center_len, 1.0f, 1.0f })); m_dimensioning.line.render(); } @@ -941,14 +933,12 @@ void GLGizmoMeasure::render_dimensioning() const Camera& camera = wxGetApp().plater()->get_camera(); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), edge_direction(e2)) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e2.first, e2.second)) * Geometry::scale_transform({ (coplanar && (force_radius == nullptr)) ? e21center_len : draw_radius, 1.0f, 1.0f })); m_dimensioning.line.render(); } }; - - auto arc_edge_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { std::pair e = f1.get_type() == Measure::SurfaceFeatureType::Edge ? f1.get_edge() : f2.get_edge(); @@ -956,8 +946,8 @@ void GLGizmoMeasure::render_dimensioning() const auto& [idx, normal, origin] = p; const Vec3d e1e2 = e.second - e.first; - const double abs_dot = std::abs(normal.dot(edge_direction(e))); - if (abs_dot < EPSILON || std::abs(abs_dot - 1.0) < EPSILON) + const double abs_dot = std::abs(normal.dot(Measure::edge_direction(f1))); + if (Measure::are_parallel(f1, f2) || Measure::are_perpendicular(f1, f2)) return; const Eigen::Hyperplane plane(normal, origin); @@ -1052,11 +1042,10 @@ void GLGizmoMeasure::render_dimensioning() if (ft1 == Measure::SurfaceFeatureType::Point && ft2 == Measure::SurfaceFeatureType::Edge) point_edge(*f1, *f2); - // Now if there is an angle to show, draw the arc: if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Edge) arc_edge_edge(*f1, *f2); - if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Plane) + else if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Plane) arc_edge_plane(*f1, *f2); } From 0ef811556408ecbf0d41058563d51b8c86166005 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 30 Sep 2022 13:18:17 +0200 Subject: [PATCH 078/250] Measuring - Refactoring and bug fixing in GLGizmoMeasure::render_dimensioning() --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 36 +++++++++++------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 421dfbedd5..9a62a8c39f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -828,7 +828,8 @@ void GLGizmoMeasure::render_dimensioning() }; auto point_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { - std::pair e = f1.get_type() == Measure::SurfaceFeatureType::Edge ? f1.get_edge() : f2.get_edge(); + assert(f1.get_type() == Measure::SurfaceFeatureType::Point && f2.get_type() == Measure::SurfaceFeatureType::Edge); + const std::pair e = f2.get_edge(); const Vec3d v_proj = m_measurement_result.distance_infinite->to; const Vec3d e1e2 = e.second - e.first; @@ -862,7 +863,8 @@ void GLGizmoMeasure::render_dimensioning() }; auto arc_edge_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2, const double* force_radius = nullptr) { - Measure::MeasurementResult res = Measure::get_measurement(f1, f2); + assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Edge); + const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); const double angle = res.angle->angle; const Vec3d center = res.angle->center; const Vec3d e1_unit = res.angle->e1; @@ -940,13 +942,9 @@ void GLGizmoMeasure::render_dimensioning() }; auto arc_edge_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { - - std::pair e = f1.get_type() == Measure::SurfaceFeatureType::Edge ? f1.get_edge() : f2.get_edge(); - std::tuple p = f1.get_type() == Measure::SurfaceFeatureType::Plane ? f1.get_plane() : f2.get_plane(); - - const auto& [idx, normal, origin] = p; - const Vec3d e1e2 = e.second - e.first; - const double abs_dot = std::abs(normal.dot(Measure::edge_direction(f1))); + assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Plane); + std::pair e = f1.get_edge(); + const auto [idx, normal, origin] = f2.get_plane(); if (Measure::are_parallel(f1, f2) || Measure::are_perpendicular(f1, f2)) return; @@ -956,21 +954,20 @@ void GLGizmoMeasure::render_dimensioning() // ensure the edge is pointing away from the intersection std::pair ecopy = e; - Vec3d e1e2copy = e1e2; - if ((ecopy.first - inters).squaredNorm() > (ecopy.second - inters).squaredNorm()) { + if ((ecopy.first - inters).squaredNorm() > (ecopy.second - inters).squaredNorm()) std::swap(ecopy.first, ecopy.second); - e1e2copy = -e1e2copy; - } // calculate 2nd edge (on the plane) - const Vec3d temp = normal.cross(e1e2copy); + const Vec3d e1e2 = ecopy.second - ecopy.first; + const double e1e2_len = e1e2.norm(); + const Vec3d temp = normal.cross(e1e2); const Vec3d edge_on_plane_unit = normal.cross(temp).normalized(); - std::pair edge_on_plane = { origin, origin + e1e2copy.norm() * edge_on_plane_unit }; + std::pair edge_on_plane = { origin, origin + e1e2_len * edge_on_plane_unit }; // ensure the 2nd edge is pointing in the correct direction - const Vec3d test_edge = (edge_on_plane.second - edge_on_plane.first).cross(e1e2copy); + const Vec3d test_edge = (edge_on_plane.second - edge_on_plane.first).cross(e1e2); if (test_edge.dot(temp) < 0.0) - edge_on_plane = { origin, origin - e1e2copy.norm() * edge_on_plane_unit }; + edge_on_plane = { origin, origin - e1e2_len * edge_on_plane_unit }; const Vec3d e1e2copy_mid = 0.5 * (ecopy.second + ecopy.first); const double radius = (inters - e1e2copy_mid).norm(); @@ -1035,8 +1032,10 @@ void GLGizmoMeasure::render_dimensioning() Measure::SurfaceFeatureType ft2 = f2->get_type(); // Order features by type so following conditions are simple. - if (ft2 > ft2) + if (ft1 > ft2) { std::swap(ft1, ft2); + std::swap(f1, f2); + } // Where needed, draw also the extension of the edge to where the dist is measured: if (ft1 == Measure::SurfaceFeatureType::Point && ft2 == Measure::SurfaceFeatureType::Edge) @@ -1048,7 +1047,6 @@ void GLGizmoMeasure::render_dimensioning() else if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Plane) arc_edge_plane(*f1, *f2); } - glsafe(::glEnable(GL_DEPTH_TEST)); From 6be56413f6ad36d0fa5aebc5d3d72b5f501018b1 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 30 Sep 2022 14:13:17 +0200 Subject: [PATCH 079/250] Measuring - Some refactoring --- src/libslic3r/Measure.cpp | 21 ++++++++++----------- src/libslic3r/Measure.hpp | 7 +++++-- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 18 ++++++++++-------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index b27425ea91..ff07aa0810 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -250,7 +250,7 @@ void MeasuringImpl::extract_features() // Add the circle and remember indices into borders. const auto& [center, radius] = get_center_and_radius(border, start_idx, i, trafo); circles_idxs.emplace_back(start_idx, i); - circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::optional(), radius)); + circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius)); circle = false; } } @@ -269,7 +269,7 @@ void MeasuringImpl::extract_features() const Vec3d center = std::get<0>(circles[i].get_circle()); for (int j=(int)circles_idxs[i].first + 1; j<=(int)circles_idxs[i].second; ++j) plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, - border[j-1], border[j], std::make_optional(center), 0.)); + border[j - 1], border[j], std::make_optional(center))); } else { // This will be handled just like a regular edge. circles_idxs.erase(circles_idxs.begin() + i); @@ -288,8 +288,8 @@ void MeasuringImpl::extract_features() for (int i=1; i (int)circles_idxs[cidx].first) i = circles_idxs[cidx++].second; - else plane.surface_features.emplace_back(SurfaceFeature( - SurfaceFeatureType::Edge, border[i-1], border[i], std::optional(), 0.)); + else + plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[i - 1], border[i])); } // FIXME Throw away / do not create edges which are parts of circles or @@ -307,7 +307,7 @@ void MeasuringImpl::extract_features() // The last surface feature is the plane itself. plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Plane, - plane.normal, plane.borders.front().front(), std::optional(), i + 0.0001)); + plane.normal, plane.borders.front().front(), std::nullopt, i + 0.0001)); plane.borders.clear(); plane.borders.shrink_to_fit(); @@ -433,13 +433,12 @@ std::vector> Measuring::get_planes_triangle_indices() const static AngleAndPoints angle_edge_edge(const std::pair& e1, const std::pair& e2) { - Vec3d e1_unit = (e1.second - e1.first).normalized(); - Vec3d e2_unit = (e2.second - e2.first).normalized(); - const double dot = e1_unit.dot(e2_unit); - // are edges parallel ? - if (std::abs(std::abs(dot) - 1.0) < EPSILON) + if (are_parallel(e1, e2)) return AngleAndPoints(0.0, e1.first, Vec3d::UnitX(), Vec3d::UnitX(), 0., true); + Vec3d e1_unit = edge_direction(e1.first, e1.second); + Vec3d e2_unit = edge_direction(e2.first, e2.second); + // project edges on the plane defined by them Vec3d normal = e1_unit.cross(e2_unit).normalized(); const Eigen::Hyperplane plane(normal, e1.first); @@ -562,7 +561,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& std::vector distances; auto add_point_edge_distance = [&distances](const Vec3d& v, const std::pair& e) { - const MeasurementResult res = get_measurement(SurfaceFeature(v), SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second, std::optional(), 0.)); + const MeasurementResult res = get_measurement(SurfaceFeature(v), SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second)); double distance = res.distance_strict->dist; Vec3d v2 = res.distance_strict->to; diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 4ac56a87f3..1c51289e8d 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -25,8 +25,8 @@ enum class SurfaceFeatureType : int { class SurfaceFeature { public: - SurfaceFeature(SurfaceFeatureType type, const Vec3d& pt1, const Vec3d& pt2, std::optional pt3, double value) - : m_type{type}, m_pt1{pt1}, m_pt2{pt2}, m_pt3{pt3}, m_value{value} {} + SurfaceFeature(SurfaceFeatureType type, const Vec3d& pt1, const Vec3d& pt2, std::optional pt3 = std::nullopt, double value = 0.0) + : m_type{ type }, m_pt1{ pt1 }, m_pt2{ pt2 }, m_pt3{ pt3 }, m_value{ value } {} explicit SurfaceFeature(const Vec3d& pt) : m_type{SurfaceFeatureType::Point}, m_pt1{pt} {} @@ -157,6 +157,9 @@ inline Vec3d plane_normal(const SurfaceFeature& plane) { inline bool are_parallel(const Vec3d& v1, const Vec3d& v2) { return std::abs(std::abs(v1.dot(v2)) - 1.0) < EPSILON; } inline bool are_perpendicular(const Vec3d& v1, const Vec3d& v2) { return std::abs(v1.dot(v2)) < EPSILON; } +inline bool are_parallel(const std::pair& e1, const std::pair& e2) { + return are_parallel(e1.second - e1.first, e2.second - e2.first); +} inline bool are_parallel(const SurfaceFeature& f1, const SurfaceFeature& f2) { if (f1.get_type() == SurfaceFeatureType::Edge && f2.get_type() == SurfaceFeatureType::Edge) return are_parallel(edge_direction(f1), edge_direction(f2)); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 9a62a8c39f..d6488b83a9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -887,8 +887,6 @@ void GLGizmoMeasure::render_dimensioning() double draw_radius = force_radius ? *force_radius : radius; - const Vec3d normal = e1_unit.cross(e2_unit).normalized(); - if (!m_dimensioning.arc.is_initialized()) { const unsigned int resolution = std::max(2, 64 * angle / double(PI)); GLModel::Geometry init_data; @@ -898,6 +896,7 @@ void GLGizmoMeasure::render_dimensioning() init_data.reserve_indices(resolution + 1); // vertices + indices + const Vec3d normal = e1_unit.cross(e2_unit).normalized(); const double step = angle / double(resolution); for (unsigned int i = 0; i <= resolution; ++i) { const double a = step * double(i); @@ -943,16 +942,19 @@ void GLGizmoMeasure::render_dimensioning() auto arc_edge_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Plane); - std::pair e = f1.get_edge(); - const auto [idx, normal, origin] = f2.get_plane(); if (Measure::are_parallel(f1, f2) || Measure::are_perpendicular(f1, f2)) return; + const std::pair e = f1.get_edge(); + const auto [idx, normal, origin] = f2.get_plane(); + + // ensure the edge is pointing away from the intersection + // 1st calculate instersection between edge and plane const Eigen::Hyperplane plane(normal, origin); const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); const Vec3d inters = line.intersectionPoint(plane); - // ensure the edge is pointing away from the intersection + // then verify edge direction and revert it, if needed std::pair ecopy = e; if ((ecopy.first - inters).squaredNorm() > (ecopy.second - inters).squaredNorm()) std::swap(ecopy.first, ecopy.second); @@ -971,9 +973,9 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d e1e2copy_mid = 0.5 * (ecopy.second + ecopy.first); const double radius = (inters - e1e2copy_mid).norm(); - arc_edge_edge(Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, ecopy.second, ecopy.first, std::optional(), 0.), - Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, edge_on_plane.second, edge_on_plane.first, std::optional(), 0.), - &radius); + arc_edge_edge(Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, ecopy.first, ecopy.second), + Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, edge_on_plane.first, edge_on_plane.second), + &radius); }; From 7cdc7ac5357c6a89fb2fa1bde0f2000346c5a8b1 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 30 Sep 2022 14:35:39 +0200 Subject: [PATCH 080/250] Measuring - struct AngleAndPoints reworked as struct AngleAndEdges --- src/libslic3r/Measure.cpp | 14 +++++++------- src/libslic3r/Measure.hpp | 20 +++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 15 +++++---------- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index ff07aa0810..b9fb0f3448 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -427,14 +427,12 @@ std::vector> Measuring::get_planes_triangle_indices() const } +const AngleAndEdges AngleAndEdges::Dummy = { 0.0, Vec3d::Zero(), { Vec3d::Zero(), Vec3d::Zero() }, { Vec3d::Zero(), Vec3d::Zero() }, 0.0, true }; - - - -static AngleAndPoints angle_edge_edge(const std::pair& e1, const std::pair& e2) +static AngleAndEdges angle_edge_edge(std::pair e1, std::pair e2) { if (are_parallel(e1, e2)) - return AngleAndPoints(0.0, e1.first, Vec3d::UnitX(), Vec3d::UnitX(), 0., true); + return AngleAndEdges::Dummy; Vec3d e1_unit = edge_direction(e1.first, e1.second); Vec3d e2_unit = edge_direction(e2.first, e2.second); @@ -474,10 +472,12 @@ static AngleAndPoints angle_edge_edge(const std::pair& e1, const s // ensure the edges are pointing away from the center if ((center_rot_2d - e11_rot_2d).squaredNorm() > (center_rot_2d - e12_rot_2d).squaredNorm()) { std::swap(e11_proj, e12_proj); + std::swap(e1.first, e1.second); e1_unit = -e1_unit; } if ((center_rot_2d - e21_rot_2d).squaredNorm() > (center_rot_2d - e22_rot_2d).squaredNorm()) { std::swap(e21_proj, e22_proj); + std::swap(e2.first, e2.second); e2_unit = -e2_unit; } @@ -488,7 +488,7 @@ static AngleAndPoints angle_edge_edge(const std::pair& e1, const s const Vec3d e2_proj_mid = 0.5 * (e21_proj + e22_proj); const double radius = std::min((center - e1_proj_mid).norm(), (center - e2_proj_mid).norm()); - return AngleAndPoints(angle, center, e1_unit, e2_unit, radius, coplanar); + return { angle, center, e1, e2, radius, coplanar }; } @@ -644,7 +644,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& // Planes are not parallel, calculate angle. angle = std::acos(std::abs(normal1.dot(normal2))); } - result.angle = std::make_optional(AngleAndPoints(angle, Vec3d::Zero(), Vec3d::UnitX(), Vec3d::UnitX(), 0., false)); // TODO + result.angle = std::make_optional(AngleAndEdges(angle, Vec3d::Zero(), { Vec3d::Zero(), Vec3d::Zero() }, { Vec3d::Zero(), Vec3d::Zero() }, 0., false)); // TODO result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO } diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 1c51289e8d..c59c9bbbc7 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -26,7 +26,7 @@ enum class SurfaceFeatureType : int { class SurfaceFeature { public: SurfaceFeature(SurfaceFeatureType type, const Vec3d& pt1, const Vec3d& pt2, std::optional pt3 = std::nullopt, double value = 0.0) - : m_type{ type }, m_pt1{ pt1 }, m_pt2{ pt2 }, m_pt3{ pt3 }, m_value{ value } {} + : m_type(type), m_pt1(pt1), m_pt2(pt2), m_pt3(pt3), m_value(value) {} explicit SurfaceFeature(const Vec3d& pt) : m_type{SurfaceFeatureType::Point}, m_pt1{pt} {} @@ -117,19 +117,21 @@ struct DistAndPoints { Vec3d to; }; -struct AngleAndPoints { - AngleAndPoints(double angle_, Vec3d center_, Vec3d e1_, Vec3d e2_, double radius_, bool coplanar_) - : angle(angle_), center(center_), e1(e1_), e2(e2_), radius(radius_), coplanar(coplanar_) {} +struct AngleAndEdges { + AngleAndEdges(double angle_, const Vec3d& center_, const std::pair& e1_, const std::pair& e2_, double radius_, bool coplanar_) + : angle(angle_), center(center_), e1(e1_), e2(e2_), radius(radius_), coplanar(coplanar_) {} double angle; Vec3d center; - Vec3d e1; - Vec3d e2; + std::pair e1; + std::pair e2; double radius; bool coplanar; + + static const AngleAndEdges Dummy; }; struct MeasurementResult { - std::optional angle; + std::optional angle; std::optional distance_infinite; std::optional distance_strict; std::optional distance_xyz; @@ -143,10 +145,10 @@ struct MeasurementResult { MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b); inline Vec3d edge_direction(const Vec3d& from, const Vec3d& to) { return (to - from).normalized(); } +inline Vec3d edge_direction(const std::pair& e) { return edge_direction(e.first, e.second); } inline Vec3d edge_direction(const SurfaceFeature& edge) { assert(edge.get_type() == SurfaceFeatureType::Edge); - const auto [from, to] = edge.get_edge(); - return edge_direction(from, to); + return edge_direction(edge.get_edge()); } inline Vec3d plane_normal(const SurfaceFeature& plane) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index d6488b83a9..138e8c54a3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -867,19 +867,11 @@ void GLGizmoMeasure::render_dimensioning() const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); const double angle = res.angle->angle; const Vec3d center = res.angle->center; - const Vec3d e1_unit = res.angle->e1; - const Vec3d e2_unit = res.angle->e2; + const std::pair e1 = res.angle->e1; + const std::pair e2 = res.angle->e2; const double radius = res.angle->radius; const bool coplanar = res.angle->coplanar; - std::pair e1 = f1.get_edge(); - std::pair e2 = f2.get_edge(); - - if ((e1.second - e1.first).dot(e1_unit) < 0.) - std::swap(e1.first, e1.second); - if ((e2.second - e2.first).dot(e2_unit) < 0.) - std::swap(e2.first, e2.second); - if (radius == 0.) return; @@ -887,6 +879,9 @@ void GLGizmoMeasure::render_dimensioning() double draw_radius = force_radius ? *force_radius : radius; + const Vec3d e1_unit = Measure::edge_direction(e1); + const Vec3d e2_unit = Measure::edge_direction(e2); + if (!m_dimensioning.arc.is_initialized()) { const unsigned int resolution = std::max(2, 64 * angle / double(PI)); GLModel::Geometry init_data; From 6f63a69e04b507749e056d58d4de3d511cd8c678 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 30 Sep 2022 15:50:31 +0200 Subject: [PATCH 081/250] Measuring - Calculation of angle between edge and plane moved to backend --- src/libslic3r/Measure.cpp | 48 ++++++++++++++++++++-- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 52 ++++++------------------ 2 files changed, 56 insertions(+), 44 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index b9fb0f3448..f2cbb9f640 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -429,7 +429,7 @@ std::vector> Measuring::get_planes_triangle_indices() const const AngleAndEdges AngleAndEdges::Dummy = { 0.0, Vec3d::Zero(), { Vec3d::Zero(), Vec3d::Zero() }, { Vec3d::Zero(), Vec3d::Zero() }, 0.0, true }; -static AngleAndEdges angle_edge_edge(std::pair e1, std::pair e2) +static AngleAndEdges angle_edge_edge(const std::pair& e1, const std::pair& e2) { if (are_parallel(e1, e2)) return AngleAndEdges::Dummy; @@ -470,14 +470,16 @@ static AngleAndEdges angle_edge_edge(std::pair e1, std::pair out_e1 = e1; + std::pair out_e2 = e2; if ((center_rot_2d - e11_rot_2d).squaredNorm() > (center_rot_2d - e12_rot_2d).squaredNorm()) { std::swap(e11_proj, e12_proj); - std::swap(e1.first, e1.second); + std::swap(out_e1.first, out_e1.second); e1_unit = -e1_unit; } if ((center_rot_2d - e21_rot_2d).squaredNorm() > (center_rot_2d - e22_rot_2d).squaredNorm()) { std::swap(e21_proj, e22_proj); - std::swap(e2.first, e2.second); + std::swap(out_e2.first, out_e2.second); e2_unit = -e2_unit; } @@ -488,9 +490,46 @@ static AngleAndEdges angle_edge_edge(std::pair e1, std::pair& e, const std::tuple& p) +{ + const auto& [idx, normal, origin] = p; + const Vec3d e1e2_unit = edge_direction(e); + if (are_parallel(e1e2_unit, normal) || are_perpendicular(e1e2_unit, normal)) + return AngleAndEdges::Dummy; + + // ensure the edge is pointing away from the intersection + // 1st calculate instersection between edge and plane + const Eigen::Hyperplane plane(normal, origin); + const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); + const Vec3d inters = line.intersectionPoint(plane); + + // then verify edge direction and revert it, if needed + Vec3d e1 = e.first; + Vec3d e2 = e.second; + if ((e1 - inters).squaredNorm() > (e2 - inters).squaredNorm()) + std::swap(e1, e2); + + const Vec3d e1e2 = e2 - e1; + const double e1e2_len = e1e2.norm(); + + // calculate 2nd edge (on the plane) + const Vec3d temp = normal.cross(e1e2); + const Vec3d edge_on_plane_unit = normal.cross(temp).normalized(); + std::pair edge_on_plane = { origin, origin + e1e2_len * edge_on_plane_unit }; + + // ensure the 2nd edge is pointing in the correct direction + const Vec3d test_edge = (edge_on_plane.second - edge_on_plane.first).cross(e1e2); + if (test_edge.dot(temp) < 0.0) + edge_on_plane = { origin, origin - e1e2_len * edge_on_plane_unit }; + + AngleAndEdges ret = angle_edge_edge({ e1, e2 }, edge_on_plane); + const Vec3d e1e2copy_mid = 0.5 * (e1 + e2); + ret.radius = (inters - e1e2copy_mid).norm(); + return ret; +} @@ -615,6 +654,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO + result.angle = angle_edge_plane(f1.get_edge(), f2.get_plane()); } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 138e8c54a3..db015bf1c2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -862,22 +862,20 @@ void GLGizmoMeasure::render_dimensioning() } }; - auto arc_edge_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2, const double* force_radius = nullptr) { + auto arc_edge_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2, double radius = 0.0) { assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Edge); const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); const double angle = res.angle->angle; const Vec3d center = res.angle->center; const std::pair e1 = res.angle->e1; const std::pair e2 = res.angle->e2; - const double radius = res.angle->radius; + const double calc_radius = res.angle->radius; const bool coplanar = res.angle->coplanar; - if (radius == 0.) + if (calc_radius == 0.0) return; - assert(force_radius == nullptr || *force_radius > 0.0); - - double draw_radius = force_radius ? *force_radius : radius; + const double draw_radius = (radius > 0.0) ? radius : calc_radius; const Vec3d e1_unit = Measure::edge_direction(e1); const Vec3d e2_unit = Measure::edge_direction(e2); @@ -930,50 +928,24 @@ void GLGizmoMeasure::render_dimensioning() shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e2.first, e2.second)) * - Geometry::scale_transform({ (coplanar && (force_radius == nullptr)) ? e21center_len : draw_radius, 1.0f, 1.0f })); + Geometry::scale_transform({ (coplanar && radius > 0.0) ? e21center_len : draw_radius, 1.0f, 1.0f })); m_dimensioning.line.render(); } }; auto arc_edge_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Plane); - if (Measure::are_parallel(f1, f2) || Measure::are_perpendicular(f1, f2)) + const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); + const std::pair e1 = res.angle->e1; + const std::pair e2 = res.angle->e2; + const double calc_radius = res.angle->radius; + if (calc_radius == 0.0) return; - const std::pair e = f1.get_edge(); - const auto [idx, normal, origin] = f2.get_plane(); - - // ensure the edge is pointing away from the intersection - // 1st calculate instersection between edge and plane - const Eigen::Hyperplane plane(normal, origin); - const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); - const Vec3d inters = line.intersectionPoint(plane); - - // then verify edge direction and revert it, if needed - std::pair ecopy = e; - if ((ecopy.first - inters).squaredNorm() > (ecopy.second - inters).squaredNorm()) - std::swap(ecopy.first, ecopy.second); - - // calculate 2nd edge (on the plane) - const Vec3d e1e2 = ecopy.second - ecopy.first; - const double e1e2_len = e1e2.norm(); - const Vec3d temp = normal.cross(e1e2); - const Vec3d edge_on_plane_unit = normal.cross(temp).normalized(); - std::pair edge_on_plane = { origin, origin + e1e2_len * edge_on_plane_unit }; - - // ensure the 2nd edge is pointing in the correct direction - const Vec3d test_edge = (edge_on_plane.second - edge_on_plane.first).cross(e1e2); - if (test_edge.dot(temp) < 0.0) - edge_on_plane = { origin, origin - e1e2_len * edge_on_plane_unit }; - - const Vec3d e1e2copy_mid = 0.5 * (ecopy.second + ecopy.first); - const double radius = (inters - e1e2copy_mid).norm(); - arc_edge_edge(Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, ecopy.first, ecopy.second), - Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, edge_on_plane.first, edge_on_plane.second), - &radius); + arc_edge_edge(Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, e1.first, e1.second), + Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, e2.first, e2.second), calc_radius); }; - shader->start_using(); if (!m_dimensioning.line.is_initialized()) { From edc90170f4f79bd4200375ccbbd29f7e5e8c31cf Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 3 Oct 2022 09:14:47 +0200 Subject: [PATCH 082/250] Measuring - Gizmo measure shows dimensioning for angle plane-plane --- src/libslic3r/Measure.cpp | 54 ++++++++++++++++++++++-- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 15 +++++++ 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index f2cbb9f640..4d37ea712c 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -306,8 +306,17 @@ void MeasuringImpl::extract_features() } // The last surface feature is the plane itself. + Vec3d cog = Vec3d::Zero(); + size_t counter = 0; + for (const std::vector& b : plane.borders) { + for (size_t i = 1; i < b.size(); ++i) { + cog += b[i]; + ++counter; + } + } + cog /= double(counter); plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Plane, - plane.normal, plane.borders.front().front(), std::nullopt, i + 0.0001)); + plane.normal, cog, std::optional(), i + 0.0001)); plane.borders.clear(); plane.borders.shrink_to_fit(); @@ -526,11 +535,48 @@ static AngleAndEdges angle_edge_plane(const std::pair& e, const st edge_on_plane = { origin, origin - e1e2_len * edge_on_plane_unit }; AngleAndEdges ret = angle_edge_edge({ e1, e2 }, edge_on_plane); - const Vec3d e1e2copy_mid = 0.5 * (e1 + e2); - ret.radius = (inters - e1e2copy_mid).norm(); + ret.radius = (inters - 0.5 * (e1 + e2)).norm(); return ret; } +static AngleAndEdges angle_plane_plane(const std::tuple& p1, const std::tuple& p2) +{ + const auto& [idx1, normal1, origin1] = p1; + const auto& [idx2, normal2, origin2] = p2; + + // are planes parallel ? + if (are_parallel(normal1, normal2)) + return AngleAndEdges::Dummy; + + auto intersection_plane_plane = [](const Vec3d& n1, const Vec3d& o1, const Vec3d& n2, const Vec3d& o2) { + Eigen::MatrixXd m(2, 3); + m << n1.x(), n1.y(), n1.z(), n2.x(), n2.y(), n2.z(); + Eigen::VectorXd b(2); + b << o1.dot(n1), o2.dot(n2); + Eigen::VectorXd x = m.colPivHouseholderQr().solve(b); + return std::make_pair(n1.cross(n2).normalized(), Vec3d(x(0), x(1), x(2))); + }; + + // Calculate intersection line between planes + const auto [intersection_line_direction, intersection_line_origin] = intersection_plane_plane(normal1, origin1, normal2, origin2); + + // Project planes' origin on intersection line + const Eigen::ParametrizedLine intersection_line = Eigen::ParametrizedLine(intersection_line_origin, intersection_line_direction); + const Vec3d origin1_proj = intersection_line.projection(origin1); + const Vec3d origin2_proj = intersection_line.projection(origin2); + + // Calculate edges on planes + const Vec3d edge_on_plane1_unit = (origin1 - origin1_proj).normalized(); + const Vec3d edge_on_plane2_unit = (origin2 - origin2_proj).normalized(); + const double edges_angle = std::acos(std::clamp(edge_on_plane1_unit.dot(edge_on_plane2_unit), -1.0, 1.0)); + const double radius = std::max(10.0, std::max((origin1 - origin1_proj).norm(), (origin2 - origin2_proj).norm())); + const std::pair edge_on_plane1 = { origin1_proj + radius * edge_on_plane1_unit, origin1_proj + 2.0 * radius * edge_on_plane1_unit }; + const std::pair edge_on_plane2 = { origin2_proj + radius * edge_on_plane2_unit, origin2_proj + 2.0 * radius * edge_on_plane2_unit }; + + AngleAndEdges ret = angle_edge_edge(edge_on_plane1, edge_on_plane2); + ret.radius = radius; + return ret; +} @@ -684,7 +730,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& // Planes are not parallel, calculate angle. angle = std::acos(std::abs(normal1.dot(normal2))); } - result.angle = std::make_optional(AngleAndEdges(angle, Vec3d::Zero(), { Vec3d::Zero(), Vec3d::Zero() }, { Vec3d::Zero(), Vec3d::Zero() }, 0., false)); // TODO + result.angle = angle_plane_plane(f1.get_plane(), f2.get_plane()); result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index db015bf1c2..b790e43306 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -946,6 +946,19 @@ void GLGizmoMeasure::render_dimensioning() Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, e2.first, e2.second), calc_radius); }; + auto arc_plane_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { + assert(f1.get_type() == Measure::SurfaceFeatureType::Plane && f2.get_type() == Measure::SurfaceFeatureType::Plane); + const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); + const std::pair e1 = res.angle->e1; + const std::pair e2 = res.angle->e2; + const double calc_radius = res.angle->radius; + if (calc_radius == 0.0) + return; + + arc_edge_edge(Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, e1.first, e1.second), + Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, e2.first, e2.second), calc_radius); + }; + shader->start_using(); if (!m_dimensioning.line.is_initialized()) { @@ -1015,6 +1028,8 @@ void GLGizmoMeasure::render_dimensioning() arc_edge_edge(*f1, *f2); else if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Plane) arc_edge_plane(*f1, *f2); + else if (ft1 == Measure::SurfaceFeatureType::Plane && ft2 == Measure::SurfaceFeatureType::Plane) + arc_plane_plane(*f1, *f2); } glsafe(::glEnable(GL_DEPTH_TEST)); From 2e81200db039e0bf3c895f9a9984badb703a4af9 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 3 Oct 2022 10:50:38 +0200 Subject: [PATCH 083/250] Measuring - Gizmo measure shows value of distance dimensioning in 3D scene --- src/libslic3r/Measure.cpp | 8 ++-- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 51 ++++++++++++++++-------- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 4d37ea712c..529c6f1231 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -663,10 +663,10 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& distances.emplace_back((e2.second - e1.first).norm(), e1.first, e2.second); distances.emplace_back((e2.first - e1.second).norm(), e1.second, e2.first); distances.emplace_back((e2.second - e1.second).norm(), e1.second, e2.second); - add_point_edge_distance(e1.first, e2); - add_point_edge_distance(e1.second, e2); - add_point_edge_distance(e2.first, e1); - add_point_edge_distance(e2.second, e1); +// add_point_edge_distance(e1.first, e2); +// add_point_edge_distance(e1.second, e2); +// add_point_edge_distance(e2.first, e1); +// add_point_edge_distance(e2.second, e1); auto it = std::min_element(distances.begin(), distances.end(), [](const DistAndPoints& item1, const DistAndPoints& item2) { return item1.dist < item2.dist; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index b790e43306..4efaf67d78 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -44,6 +44,20 @@ static const std::string CTRL_STR = #endif //__APPLE__ ; +static std::string format_double(double value) +{ + char buf[1024]; + sprintf(buf, "%.3f", value); + return std::string(buf); +} + +static std::string format_vec3(const Vec3d& v) +{ + char buf[1024]; + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", v.x(), v.y(), v.z()); + return std::string(buf); +} + static std::string surface_feature_type_as_string(Measure::SurfaceFeatureType type) { switch (type) @@ -778,7 +792,7 @@ void GLGizmoMeasure::render_dimensioning() if (shader == nullptr) return; - auto point_point = [this, shader](const Vec3d& v1, const Vec3d& v2) { + auto point_point = [this, shader](const Vec3d& v1, const Vec3d& v2, float distance) { if (v1.isApprox(v2)) return; @@ -825,6 +839,23 @@ void GLGizmoMeasure::render_dimensioning() ss_to_ndc_matrix * Geometry::translation_transform(v2ss_3) * q21ss : ss_to_ndc_matrix * Geometry::translation_transform(v2ss_3) * q12ss); m_dimensioning.triangle.render(); + + if (distance > 0.0) { + const Vec2d label_position = 0.5 * (v1ss + v2ss); + m_imgui->set_next_window_pos(label_position.x(), viewport[3] - label_position.y(), ImGuiCond_Always, 0.0f, 1.0f); + m_imgui->set_next_window_bg_alpha(0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + m_imgui->begin(_L("##distance"), ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); + ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); + std::string txt = format_double(distance) + " "; + if (wxGetApp().app_config->get("use_inches") == "1") + txt += _u8L("in"); + else + txt += _u8L("mm"); + m_imgui->text(txt); + m_imgui->end(); + ImGui::PopStyleVar(); + } }; auto point_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { @@ -872,7 +903,7 @@ void GLGizmoMeasure::render_dimensioning() const double calc_radius = res.angle->radius; const bool coplanar = res.angle->coplanar; - if (calc_radius == 0.0) + if (std::abs(angle) < EPSILON || std::abs(calc_radius) < EPSILON) return; const double draw_radius = (radius > 0.0) ? radius : calc_radius; @@ -1006,7 +1037,7 @@ void GLGizmoMeasure::render_dimensioning() const Measure::DistAndPoints& dap = m_measurement_result.distance_infinite.has_value() ? *m_measurement_result.distance_infinite : *m_measurement_result.distance_strict; - point_point(dap.from, dap.to); + point_point(dap.from, dap.to, dap.dist); const Measure::SurfaceFeature* f1 = &(*m_selected_features.first.feature); const Measure::SurfaceFeature* f2 = &(*m_selected_features.second.feature); @@ -1052,20 +1083,6 @@ static void add_strings_row_to_table(ImGuiWrapper& imgui, const std::string& col add_row_to_table([&]() { imgui.text_colored(col_1_color, col_1); }, [&]() { imgui.text_colored(col_2_color, col_2); }); }; -static std::string format_double(double value) -{ - char buf[1024]; - sprintf(buf, "%.3f", value); - return std::string(buf); -} - -static std::string format_vec3(const Vec3d& v) -{ - char buf[1024]; - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", v.x(), v.y(), v.z()); - return std::string(buf); -} - #if ENABLE_MEASURE_GIZMO_DEBUG void GLGizmoMeasure::render_debug_dialog() { From 1f5859deb1af3fb1e5b76cc29434c257df63c991 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 3 Oct 2022 11:36:08 +0200 Subject: [PATCH 084/250] Measuring - Gizmo measure shows value of angle dimensioning in 3D scene --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 63 ++++++++++++++---------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 4efaf67d78..8a4cd17d94 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -840,22 +840,18 @@ void GLGizmoMeasure::render_dimensioning() ss_to_ndc_matrix * Geometry::translation_transform(v2ss_3) * q12ss); m_dimensioning.triangle.render(); - if (distance > 0.0) { - const Vec2d label_position = 0.5 * (v1ss + v2ss); - m_imgui->set_next_window_pos(label_position.x(), viewport[3] - label_position.y(), ImGuiCond_Always, 0.0f, 1.0f); - m_imgui->set_next_window_bg_alpha(0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); - m_imgui->begin(_L("##distance"), ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); - ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); - std::string txt = format_double(distance) + " "; - if (wxGetApp().app_config->get("use_inches") == "1") - txt += _u8L("in"); - else - txt += _u8L("mm"); - m_imgui->text(txt); - m_imgui->end(); - ImGui::PopStyleVar(); - } + const Vec2d label_position = 0.5 * (v1ss + v2ss); + m_imgui->set_next_window_pos(label_position.x(), viewport[3] - label_position.y(), ImGuiCond_Always, 0.0f, 1.0f); + m_imgui->set_next_window_bg_alpha(0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + m_imgui->begin(_L("##distance"), ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); + ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); + const bool use_inches = wxGetApp().app_config->get("use_inches") == "1"; + const std::string txt = use_inches ? format_double(ObjectManipulation::mm_to_in * distance) + " " + _u8L("in") : + format_double(distance) + " " + _u8L("mm"); + m_imgui->text(txt); + m_imgui->end(); + ImGui::PopStyleVar(); }; auto point_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { @@ -911,8 +907,11 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d e1_unit = Measure::edge_direction(e1); const Vec3d e2_unit = Measure::edge_direction(e2); + const unsigned int resolution = std::max(2, 64 * angle / double(PI)); + const double step = angle / double(resolution); + const Vec3d normal = e1_unit.cross(e2_unit).normalized(); + if (!m_dimensioning.arc.is_initialized()) { - const unsigned int resolution = std::max(2, 64 * angle / double(PI)); GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3 }; init_data.color = ColorRGBA::WHITE(); @@ -920,8 +919,6 @@ void GLGizmoMeasure::render_dimensioning() init_data.reserve_indices(resolution + 1); // vertices + indices - const Vec3d normal = e1_unit.cross(e2_unit).normalized(); - const double step = angle / double(resolution); for (unsigned int i = 0; i <= resolution; ++i) { const double a = step * double(i); const Vec3d v = draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(a, normal)) * e1_unit); @@ -943,8 +940,6 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d e11center = center - e1.first; const double e11center_len = e11center.norm(); if (e11center_len > EPSILON && e11center.dot(e11e12) < 0.0) { - const Camera& camera = wxGetApp().plater()->get_camera(); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e1.first, e1.second)) * Geometry::scale_transform({ e11center_len, 1.0f, 1.0f })); @@ -955,13 +950,29 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d e21center = center - e2.first; const double e21center_len = e21center.norm(); if (e21center_len > EPSILON) { - const Camera& camera = wxGetApp().plater()->get_camera(); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e2.first, e2.second)) * Geometry::scale_transform({ (coplanar && radius > 0.0) ? e21center_len : draw_radius, 1.0f, 1.0f })); m_dimensioning.line.render(); } + + // world coordinates + const Vec3d label_position_world = Geometry::translation_transform(center) * (draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(step * 0.5 * double(resolution), normal)) * e1_unit)); + + // screen coordinates + const std::array& viewport = camera.get_viewport(); + const Vec2d label_position_ss = DimensioningHelper::model_to_ss(label_position_world, m_volume_matrix, + camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix(), viewport); + + m_imgui->set_next_window_pos(label_position_ss.x(), viewport[3] - label_position_ss.y(), ImGuiCond_Always, 0.0f, 1.0f); + m_imgui->set_next_window_bg_alpha(0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + m_imgui->begin(_L("##angle"), ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); + ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); + std::string txt = format_double(Geometry::rad2deg(angle)) + "°"; + m_imgui->text(txt); + m_imgui->end(); + ImGui::PopStyleVar(); }; auto arc_edge_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { @@ -1341,7 +1352,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } - if (measure.distance_infinite.has_value()) { + if (measure.distance_infinite.has_value() && measure.distance_infinite->dist > 0.0) { double distance = measure.distance_infinite->dist; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; @@ -1350,7 +1361,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } - if (measure.distance_strict.has_value()) { + if (measure.distance_strict.has_value() && measure.distance_strict->dist > 0.0) { double distance = measure.distance_strict->dist; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; @@ -1359,7 +1370,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } - if (measure.distance_xyz.has_value()) { + if (measure.distance_xyz.has_value() && measure.distance_xyz->norm() > EPSILON) { Vec3d distance = *measure.distance_xyz; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; From a5a4fc4dcfb3e5f4ea267e137e70e49b89499d1f Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 3 Oct 2022 12:54:22 +0200 Subject: [PATCH 085/250] Measuring - Gizmo measure shows arrows at endpoints of angle dimensioning --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 35 ++++++++++++++++++------ 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 8a4cd17d94..f55874071d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -929,13 +929,30 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.arc.init_from(std::move(init_data)); } - // render arc + // arc const Camera& camera = wxGetApp().plater()->get_camera(); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center)); m_dimensioning.arc.render(); - // render edge 1 extension + // arrows + auto render_arrow = [this, shader, &camera, &normal, ¢er, &e1_unit, draw_radius, step, resolution](unsigned int endpoint_id) { + const double angle = (endpoint_id == 1) ? 0.0 : step * double(resolution); + const Vec3d position_model = Geometry::translation_transform(center) * (draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(angle, normal)) * e1_unit)); + const Vec3d direction_model = (endpoint_id == 1) ? -normal.cross(position_model - center).normalized() : normal.cross(position_model - center).normalized(); + const Transform3d view_model_matrix = camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(position_model) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), direction_model) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal) * + Geometry::scale_transform(camera.get_inv_zoom()); + shader->set_uniform("view_model_matrix", view_model_matrix); + m_dimensioning.triangle.render(); + }; + + glsafe(::glDisable(GL_CULL_FACE)); + render_arrow(1); + render_arrow(2); + glsafe(::glEnable(GL_CULL_FACE)); + + // edge 1 extension const Vec3d e11e12 = e1.second - e1.first; const Vec3d e11center = center - e1.first; const double e11center_len = e11center.norm(); @@ -946,7 +963,7 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.line.render(); } - // render edge 2 extension + // edge 2 extension const Vec3d e21center = center - e2.first; const double e21center_len = e21center.norm(); if (e21center_len > EPSILON) { @@ -956,12 +973,13 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.line.render(); } - // world coordinates - const Vec3d label_position_world = Geometry::translation_transform(center) * (draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(step * 0.5 * double(resolution), normal)) * e1_unit)); + // label + // label model coordinates + const Vec3d label_position_model = Geometry::translation_transform(center) * (draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(step * 0.5 * double(resolution), normal)) * e1_unit)); - // screen coordinates + // label screen coordinates const std::array& viewport = camera.get_viewport(); - const Vec2d label_position_ss = DimensioningHelper::model_to_ss(label_position_world, m_volume_matrix, + const Vec2d label_position_ss = DimensioningHelper::model_to_ss(label_position_model, m_volume_matrix, camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix(), viewport); m_imgui->set_next_window_pos(label_position_ss.x(), viewport[3] - label_position_ss.y(), ImGuiCond_Always, 0.0f, 1.0f); @@ -969,8 +987,7 @@ void GLGizmoMeasure::render_dimensioning() ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); m_imgui->begin(_L("##angle"), ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); - std::string txt = format_double(Geometry::rad2deg(angle)) + "°"; - m_imgui->text(txt); + m_imgui->text(format_double(Geometry::rad2deg(angle)) + "°"); m_imgui->end(); ImGui::PopStyleVar(); }; From 2678ccef40ca6f50daf41e77d755e50cee782688 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 3 Oct 2022 13:53:14 +0200 Subject: [PATCH 086/250] Follow-up of a5a4fc4dcfb3e5f4ea267e137e70e49b89499d1f - Fixed arrows orientations --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index f55874071d..ff59ba0a5c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -940,9 +940,10 @@ void GLGizmoMeasure::render_dimensioning() const double angle = (endpoint_id == 1) ? 0.0 : step * double(resolution); const Vec3d position_model = Geometry::translation_transform(center) * (draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(angle, normal)) * e1_unit)); const Vec3d direction_model = (endpoint_id == 1) ? -normal.cross(position_model - center).normalized() : normal.cross(position_model - center).normalized(); + const auto qz = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); + const auto qx = Eigen::Quaternion::FromTwoVectors(qz * Vec3d::UnitX(), direction_model); const Transform3d view_model_matrix = camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(position_model) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), direction_model) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal) * - Geometry::scale_transform(camera.get_inv_zoom()); + qx * qz * Geometry::scale_transform(camera.get_inv_zoom()); shader->set_uniform("view_model_matrix", view_model_matrix); m_dimensioning.triangle.render(); }; From ccfce4db7b039a38e6ceca168f503b7142ee8cfd Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 3 Oct 2022 13:59:11 +0200 Subject: [PATCH 087/250] Fixed warnings --- src/libslic3r/Measure.cpp | 21 ++++++++++----------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 4 ++-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 529c6f1231..cce63e6465 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -568,7 +568,6 @@ static AngleAndEdges angle_plane_plane(const std::tuple& p1, // Calculate edges on planes const Vec3d edge_on_plane1_unit = (origin1 - origin1_proj).normalized(); const Vec3d edge_on_plane2_unit = (origin2 - origin2_proj).normalized(); - const double edges_angle = std::acos(std::clamp(edge_on_plane1_unit.dot(edge_on_plane2_unit), -1.0, 1.0)); const double radius = std::max(10.0, std::max((origin1 - origin1_proj).norm(), (origin2 - origin2_proj).norm())); const std::pair edge_on_plane1 = { origin1_proj + radius * edge_on_plane1_unit, origin1_proj + 2.0 * radius * edge_on_plane1_unit }; const std::pair edge_on_plane2 = { origin2_proj + radius * edge_on_plane2_unit, origin2_proj + 2.0 * radius * edge_on_plane2_unit }; @@ -645,16 +644,16 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& if (f2.get_type() == SurfaceFeatureType::Edge) { std::vector distances; - auto add_point_edge_distance = [&distances](const Vec3d& v, const std::pair& e) { - const MeasurementResult res = get_measurement(SurfaceFeature(v), SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second)); - double distance = res.distance_strict->dist; - Vec3d v2 = res.distance_strict->to; - - const Vec3d e1e2 = e.second - e.first; - const Vec3d e1v2 = v2 - e.first; - if (e1v2.dot(e1e2) >= 0.0 && e1v2.norm() < e1e2.norm()) - distances.emplace_back(distance, v, v2); - }; +// auto add_point_edge_distance = [&distances](const Vec3d& v, const std::pair& e) { +// const MeasurementResult res = get_measurement(SurfaceFeature(v), SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second)); +// double distance = res.distance_strict->dist; +// Vec3d v2 = res.distance_strict->to; +// +// const Vec3d e1e2 = e.second - e.first; +// const Vec3d e1v2 = v2 - e.first; +// if (e1v2.dot(e1e2) >= 0.0 && e1v2.norm() < e1e2.norm()) +// distances.emplace_back(distance, v, v2); +// }; std::pair e1 = f1.get_edge(); std::pair e2 = f2.get_edge(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index ff59ba0a5c..13415877f9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -993,7 +993,7 @@ void GLGizmoMeasure::render_dimensioning() ImGui::PopStyleVar(); }; - auto arc_edge_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { + auto arc_edge_plane = [arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Plane); const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); const std::pair e1 = res.angle->e1; @@ -1006,7 +1006,7 @@ void GLGizmoMeasure::render_dimensioning() Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, e2.first, e2.second), calc_radius); }; - auto arc_plane_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { + auto arc_plane_plane = [arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { assert(f1.get_type() == Measure::SurfaceFeatureType::Plane && f2.get_type() == Measure::SurfaceFeatureType::Plane); const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); const std::pair e1 = res.angle->e1; From 99e239301ae7078793a0dfc3c71f025cd02fbd95 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 4 Oct 2022 08:17:43 +0200 Subject: [PATCH 088/250] Measuring - Fixes in plane-plane measurement - Measurements validation - Fixes in dimensioning rendering --- src/libslic3r/Measure.cpp | 20 +++++++++++--------- src/libslic3r/Measure.hpp | 4 ++++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 20 ++++++++++++-------- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index cce63e6465..2905f82553 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -719,21 +719,23 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& const auto [idx1, normal1, pt1] = f1.get_plane(); const auto [idx2, normal2, pt2] = f2.get_plane(); - double angle = 0.; if (are_parallel(normal1, normal2)) { // The planes are parallel, calculate distance. - Eigen::Hyperplane plane(normal1, pt1); - result.distance_infinite = std::make_optional(DistAndPoints{plane.absDistance(pt2), Vec3d::Zero(), Vec3d::Zero()}); - } else { - // Planes are not parallel, calculate angle. - angle = std::acos(std::abs(normal1.dot(normal2))); + const Eigen::Hyperplane plane(normal1, pt1); + result.distance_infinite = std::make_optional(DistAndPoints{ plane.absDistance(pt2), pt2, plane.projection(pt2) }); // TODO } - result.angle = angle_plane_plane(f1.get_plane(), f2.get_plane()); - result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO + else + result.angle = angle_plane_plane(f1.get_plane(), f2.get_plane()); } - + // validation + if (result.distance_infinite.has_value() && result.distance_infinite->dist < EPSILON) + result.distance_infinite.reset(); + if (result.distance_strict.has_value() && result.distance_strict->dist < EPSILON) + result.distance_strict.reset(); + if (result.angle.has_value() && std::abs(result.angle->angle) < EPSILON) + result.angle.reset(); return result; } diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index c59c9bbbc7..df148da761 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -136,6 +136,10 @@ struct MeasurementResult { std::optional distance_strict; std::optional distance_xyz; + bool has_distance_data() const { + return distance_infinite.has_value() || distance_strict.has_value(); + } + bool has_any_data() const { return angle.has_value() || distance_infinite.has_value() || distance_strict.has_value() || distance_xyz.has_value(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 13415877f9..5c467e0203 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1062,11 +1062,14 @@ void GLGizmoMeasure::render_dimensioning() glsafe(::glDisable(GL_DEPTH_TEST)); if (m_selected_features.second.feature.has_value()) { - // Render the arrow between the points that the backend passed: - const Measure::DistAndPoints& dap = m_measurement_result.distance_infinite.has_value() - ? *m_measurement_result.distance_infinite - : *m_measurement_result.distance_strict; - point_point(dap.from, dap.to, dap.dist); + const bool has_distance = m_measurement_result.has_distance_data(); + if (has_distance) { + // Render the arrow between the points that the backend passed: + const Measure::DistAndPoints& dap = m_measurement_result.distance_infinite.has_value() + ? *m_measurement_result.distance_infinite + : *m_measurement_result.distance_strict; + point_point(dap.from, dap.to, dap.dist); + } const Measure::SurfaceFeature* f1 = &(*m_selected_features.first.feature); const Measure::SurfaceFeature* f2 = &(*m_selected_features.second.feature); @@ -1080,7 +1083,7 @@ void GLGizmoMeasure::render_dimensioning() } // Where needed, draw also the extension of the edge to where the dist is measured: - if (ft1 == Measure::SurfaceFeatureType::Point && ft2 == Measure::SurfaceFeatureType::Edge) + if (has_distance && ft1 == Measure::SurfaceFeatureType::Point && ft2 == Measure::SurfaceFeatureType::Edge) point_edge(*f1, *f2); // Now if there is an angle to show, draw the arc: @@ -1370,7 +1373,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } - if (measure.distance_infinite.has_value() && measure.distance_infinite->dist > 0.0) { + if (measure.distance_infinite.has_value()) { double distance = measure.distance_infinite->dist; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; @@ -1379,7 +1382,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } - if (measure.distance_strict.has_value() && measure.distance_strict->dist > 0.0) { + if (measure.distance_strict.has_value() && + (!measure.distance_infinite.has_value() || std::abs(measure.distance_strict->dist - measure.distance_infinite->dist) > EPSILON)) { double distance = measure.distance_strict->dist; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; From cba2113bbbab540c55574edef1372086338b8836 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 4 Oct 2022 08:45:39 +0200 Subject: [PATCH 089/250] Measuring - Refactoring in GLGizmoMeasure imgui dialog related to units --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 5c467e0203..84b4fc0a97 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1232,7 +1232,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } const bool use_inches = wxGetApp().app_config->get("use_inches") == "1"; - const std::string units = use_inches ? _u8L(" (in)") : _u8L(" (mm)"); + const std::string units = use_inches ? " " + _u8L("in") : " " + _u8L("mm"); if (m_curr_feature.has_value()) { const Measure::SurfaceFeatureType feature_type = m_curr_feature->get_type(); @@ -1263,7 +1263,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } add_strings_row_to_table(*m_imgui, _u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, _u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, _u8L("Length") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Length"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } case Measure::SurfaceFeatureType::Circle: @@ -1276,7 +1276,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit radius = ObjectManipulation::mm_to_in * radius; } add_strings_row_to_table(*m_imgui, _u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, _u8L("Radius") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Radius"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } @@ -1369,7 +1369,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (ImGui::BeginTable("Measure", 3)) { if (measure.angle.has_value()) { ImGui::PushID((void*)(intptr_t)1); - add_measure_row_to_table(_u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(measure.angle->angle)), + add_measure_row_to_table(_u8L("Angle"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(measure.angle->angle)) + "°", ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } @@ -1378,7 +1378,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (use_inches) distance = ObjectManipulation::mm_to_in * distance; ImGui::PushID((void*)(intptr_t)2); - add_measure_row_to_table(_u8L("Distance Infinite") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), + add_measure_row_to_table(_u8L("Distance Infinite"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } @@ -1388,7 +1388,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (use_inches) distance = ObjectManipulation::mm_to_in * distance; ImGui::PushID((void*)(intptr_t)3); - add_measure_row_to_table(_u8L("Distance Strict") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), + add_measure_row_to_table(_u8L("Distance Strict"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } @@ -1397,7 +1397,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (use_inches) distance = ObjectManipulation::mm_to_in * distance; ImGui::PushID((void*)(intptr_t)4); - add_measure_row_to_table(_u8L("Distance XYZ") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), + add_measure_row_to_table(_u8L("Distance XYZ"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } From 8fd8bada373da8c823dbe2b47811b465856fe617 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 4 Oct 2022 11:26:11 +0200 Subject: [PATCH 090/250] Measuring - Gizmo measure shows dimensioning for distance plane-circle --- src/libslic3r/Measure.cpp | 58 +++++++++++++++++------- src/libslic3r/Measure.hpp | 5 +- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 2905f82553..852e9268cc 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -47,6 +47,7 @@ public: std::vector get_all_features() const; std::optional get_feature(size_t face_idx, const Vec3d& point) const; std::vector> get_planes_triangle_indices() const; + const std::vector& get_plane_features(unsigned int plane_id) const; private: void update_planes(); @@ -398,6 +399,11 @@ std::vector> MeasuringImpl::get_planes_triangle_indices() const return out; } +const std::vector& MeasuringImpl::get_plane_features(unsigned int plane_id) const +{ + assert(plane_id < m_planes.size()); + return m_planes[plane_id].surface_features; +} @@ -435,6 +441,10 @@ std::vector> Measuring::get_planes_triangle_indices() const return priv->get_planes_triangle_indices(); } +const std::vector& Measuring::get_plane_features(unsigned int plane_id) const +{ + return priv->get_plane_features(plane_id); +} const AngleAndEdges AngleAndEdges::Dummy = { 0.0, Vec3d::Zero(), { Vec3d::Zero(), Vec3d::Zero() }, { Vec3d::Zero(), Vec3d::Zero() }, 0.0, true }; @@ -583,7 +593,7 @@ static AngleAndEdges angle_plane_plane(const std::tuple& p1, -MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b) +MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b, const Measuring* measuring) { assert(a.get_type() != SurfaceFeatureType::Undef && b.get_type() != SurfaceFeatureType::Undef); @@ -604,25 +614,25 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Edge) { - const auto& [s,e] = f2.get_edge(); - Eigen::ParametrizedLine line(s, (e-s).normalized()); - double dist_inf = line.distance(f1.get_point()); - Vec3d proj = line.projection(f1.get_point()); - double len_sq = (e-s).squaredNorm(); - double dist_start_sq = (proj-s).squaredNorm(); - double dist_end_sq = (proj-e).squaredNorm(); + const auto [s,e] = f2.get_edge(); + const Eigen::ParametrizedLine line(s, (e-s).normalized()); + const double dist_inf = line.distance(f1.get_point()); + const Vec3d proj = line.projection(f1.get_point()); + const double len_sq = (e-s).squaredNorm(); + const double dist_start_sq = (proj-s).squaredNorm(); + const double dist_end_sq = (proj-e).squaredNorm(); if (dist_start_sq < len_sq && dist_end_sq < len_sq) { // projection falls on the line - the strict distance is the same as infinite result.distance_strict = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); } else { // the result is the closer of the endpoints - bool s_is_closer = dist_start_sq < dist_end_sq; - result.distance_strict = std::make_optional(DistAndPoints{std::sqrt(std::min(dist_start_sq, dist_end_sq) + dist_inf), f1.get_point(), s_is_closer ? s : e}); + const bool s_is_closer = dist_start_sq < dist_end_sq; + result.distance_strict = std::make_optional(DistAndPoints{std::sqrt(std::min(dist_start_sq, dist_end_sq) + sqr(dist_inf)), f1.get_point(), s_is_closer ? s : e}); } result.distance_infinite = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Circle) { // Find a plane containing normal, center and the point. - const auto& [c, radius, n] = f2.get_circle(); + const auto [c, radius, n] = f2.get_circle(); Eigen::Hyperplane circle_plane(n, c); Vec3d proj = circle_plane.projection(f1.get_point()); double dist = std::sqrt(std::pow((proj - c).norm() - radius, 2.) + @@ -632,7 +642,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& result.distance_strict = std::make_optional(DistAndPoints{dist, f1.get_point(), p_on_circle}); // TODO /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { - const auto& [idx, normal, pt] = f2.get_plane(); + const auto [idx, normal, pt] = f2.get_plane(); Eigen::Hyperplane plane(normal, pt); result.distance_infinite = std::make_optional(DistAndPoints{plane.absDistance(f1.get_point()), f1.get_point(), plane.projection(f1.get_point())}); // TODO // TODO: result.distance_strict = @@ -678,7 +688,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& const std::pair e = f1.get_edge(); const auto& [center, radius, normal] = f2.get_circle(); const Vec3d e1e2 = (e.second - e.first); - const Vec3d e1e2_unit = (e.second - e.first).normalized(); + const Vec3d e1e2_unit = e1e2.normalized(); std::vector distances; distances.emplace_back(*get_measurement(SurfaceFeature(e.first), f2).distance_strict); @@ -709,14 +719,30 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { - result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO + assert(measuring != nullptr); + + const auto [center, radius, normal1] = f1.get_circle(); + const auto [idx2, normal2, origin2] = f2.get_plane(); + + const bool coplanar = are_parallel(normal1, normal2) && Eigen::Hyperplane(normal1, center).absDistance(origin2) < EPSILON; + if (!coplanar) { + const std::vector& plane_features = measuring->get_plane_features(idx2); + std::vector distances; + for (const SurfaceFeature& sf : plane_features) { + if (sf.get_type() == SurfaceFeatureType::Edge) + distances.push_back(*get_measurement(sf, f1).distance_infinite); + } + auto it = std::min_element(distances.begin(), distances.end(), + [](const DistAndPoints& item1, const DistAndPoints& item2) { + return item1.dist < item2.dist; + }); + result.distance_infinite = std::make_optional(DistAndPoints{ it->dist, it->from, it->to }); + } } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// } else if (f1.get_type() == SurfaceFeatureType::Plane) { - assert(f2.get_type() == SurfaceFeatureType::Plane); - const auto [idx1, normal1, pt1] = f1.get_plane(); const auto [idx2, normal2, pt2] = f2.get_plane(); diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index df148da761..2e17eea5c5 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -105,6 +105,9 @@ public: // call too often. std::vector> get_planes_triangle_indices() const; + // Returns the surface features of the plane with the given index + const std::vector& get_plane_features(unsigned int plane_id) const; + private: std::unique_ptr priv; }; @@ -146,7 +149,7 @@ struct MeasurementResult { }; // Returns distance/angle between two SurfaceFeatures. -MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b); +MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b, const Measuring* measuring = nullptr); inline Vec3d edge_direction(const Vec3d& from, const Vec3d& to) { return (to - from).normalized(); } inline Vec3d edge_direction(const std::pair& e) { return edge_direction(e.first, e.second); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 84b4fc0a97..31ce08fa74 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -175,7 +175,7 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) } if (m_selected_features != selected_features_old && m_selected_features.second.feature.has_value()) - m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature); + m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); return true; } From 836b45a2ed01ce07061685911efe3831d926cf32 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 4 Oct 2022 12:36:38 +0200 Subject: [PATCH 091/250] Measuring - Gizmo measure shows dimensioning for distance edge-plane --- src/libslic3r/Measure.cpp | 63 +++++++++++++++++++++--- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 39 ++++++++------- 2 files changed, 77 insertions(+), 25 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 852e9268cc..ea68503254 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -708,7 +708,45 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& result.distance_infinite = std::make_optional(DistAndPoints{it->dist, it->from, it->to}); /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { - result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO + assert(measuring != nullptr); + + const auto [from, to] = f1.get_edge(); + const auto [idx, normal, origin] = f2.get_plane(); + + const Vec3d edge_unit = (to - from).normalized(); + if (are_perpendicular(edge_unit, normal)) { + std::vector distances; + const Eigen::Hyperplane plane(normal, origin); + distances.push_back(DistAndPoints{ plane.absDistance(from), from, plane.projection(from) }); + distances.push_back(DistAndPoints{ plane.absDistance(to), to, plane.projection(to) }); + auto it = std::min_element(distances.begin(), distances.end(), + [](const DistAndPoints& item1, const DistAndPoints& item2) { + return item1.dist < item2.dist; + }); + result.distance_infinite = std::make_optional(DistAndPoints{ it->dist, it->from, it->to }); + } + else { + const std::vector& plane_features = measuring->get_plane_features(idx); + std::vector distances; + for (const SurfaceFeature& sf : plane_features) { + if (sf.get_type() == SurfaceFeatureType::Edge) { + const auto m = get_measurement(sf, f1); + if (!m.distance_infinite.has_value()) { + distances.clear(); + break; + } + else + distances.push_back(*m.distance_infinite); + } + } + if (!distances.empty()) { + auto it = std::min_element(distances.begin(), distances.end(), + [](const DistAndPoints& item1, const DistAndPoints& item2) { + return item1.dist < item2.dist; + }); + result.distance_infinite = std::make_optional(DistAndPoints{ it->dist, it->from, it->to }); + } + } result.angle = angle_edge_plane(f1.get_edge(), f2.get_plane()); } /////////////////////////////////////////////////////////////////////////// @@ -729,14 +767,23 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& const std::vector& plane_features = measuring->get_plane_features(idx2); std::vector distances; for (const SurfaceFeature& sf : plane_features) { - if (sf.get_type() == SurfaceFeatureType::Edge) - distances.push_back(*get_measurement(sf, f1).distance_infinite); + if (sf.get_type() == SurfaceFeatureType::Edge) { + const auto m = get_measurement(sf, f1); + if (!m.distance_infinite.has_value()) { + distances.clear(); + break; + } + else + distances.push_back(*m.distance_infinite); + } + } + if (!distances.empty()) { + auto it = std::min_element(distances.begin(), distances.end(), + [](const DistAndPoints& item1, const DistAndPoints& item2) { + return item1.dist < item2.dist; + }); + result.distance_infinite = std::make_optional(DistAndPoints{ it->dist, it->from, it->to }); } - auto it = std::min_element(distances.begin(), distances.end(), - [](const DistAndPoints& item1, const DistAndPoints& item2) { - return item1.dist < item2.dist; - }); - result.distance_infinite = std::make_optional(DistAndPoints{ it->dist, it->from, it->to }); } } /////////////////////////////////////////////////////////////////////////// diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 31ce08fa74..051a7ee40a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -891,13 +891,15 @@ void GLGizmoMeasure::render_dimensioning() auto arc_edge_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2, double radius = 0.0) { assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Edge); - const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); - const double angle = res.angle->angle; - const Vec3d center = res.angle->center; - const std::pair e1 = res.angle->e1; - const std::pair e2 = res.angle->e2; - const double calc_radius = res.angle->radius; - const bool coplanar = res.angle->coplanar; + if (!m_measurement_result.angle.has_value()) + return; + + const double angle = m_measurement_result.angle->angle; + const Vec3d center = m_measurement_result.angle->center; + const std::pair e1 = m_measurement_result.angle->e1; + const std::pair e2 = m_measurement_result.angle->e2; + const double calc_radius = m_measurement_result.angle->radius; + const bool coplanar = m_measurement_result.angle->coplanar; if (std::abs(angle) < EPSILON || std::abs(calc_radius) < EPSILON) return; @@ -993,12 +995,15 @@ void GLGizmoMeasure::render_dimensioning() ImGui::PopStyleVar(); }; - auto arc_edge_plane = [arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { + auto arc_edge_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Plane); - const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); - const std::pair e1 = res.angle->e1; - const std::pair e2 = res.angle->e2; - const double calc_radius = res.angle->radius; + if (!m_measurement_result.angle.has_value()) + return; + + const std::pair e1 = m_measurement_result.angle->e1; + const std::pair e2 = m_measurement_result.angle->e2; + const double calc_radius = m_measurement_result.angle->radius; + if (calc_radius == 0.0) return; @@ -1006,12 +1011,12 @@ void GLGizmoMeasure::render_dimensioning() Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, e2.first, e2.second), calc_radius); }; - auto arc_plane_plane = [arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { + auto arc_plane_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { assert(f1.get_type() == Measure::SurfaceFeatureType::Plane && f2.get_type() == Measure::SurfaceFeatureType::Plane); - const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); - const std::pair e1 = res.angle->e1; - const std::pair e2 = res.angle->e2; - const double calc_radius = res.angle->radius; + const std::pair e1 = m_measurement_result.angle->e1; + const std::pair e2 = m_measurement_result.angle->e2; + const double calc_radius = m_measurement_result.angle->radius; + if (calc_radius == 0.0) return; From 19222137253a2ef453927820b15e3b646cfebc50 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 6 Oct 2022 14:23:45 +0200 Subject: [PATCH 092/250] Measuring: prototype for uniformly scale a volume by editing the value of the shown distance --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 111 ++++++++++++++++------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 + src/slic3r/GUI/ImGuiWrapper.cpp | 63 ++++++------- src/slic3r/GUI/ImGuiWrapper.hpp | 4 +- 4 files changed, 110 insertions(+), 69 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 051a7ee40a..3e83418ef4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -220,6 +220,7 @@ void GLGizmoMeasure::data_changed() m_last_plane_idx = -1; m_selected_features.reset(); m_selection_raycasters.clear(); + m_editing_distance = false; } bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) @@ -256,6 +257,7 @@ void GLGizmoMeasure::on_set_state() m_curr_feature.reset(); m_curr_point_on_feature_position.reset(); restore_scene_raycasters_state(); + m_editing_distance = false; } else { m_mode = EMode::BasicSelection; @@ -840,18 +842,79 @@ void GLGizmoMeasure::render_dimensioning() ss_to_ndc_matrix * Geometry::translation_transform(v2ss_3) * q12ss); m_dimensioning.triangle.render(); + const bool use_inches = wxGetApp().app_config->get("use_inches") == "1"; + const double value = use_inches ? ObjectManipulation::mm_to_in * distance : distance; + const std::string value_str = format_double(value); + const std::string units = use_inches ? _u8L("in") : _u8L("mm"); + const float value_str_width = 20.0f + ImGui::CalcTextSize(value_str.c_str()).x; + static double edit_value = 0.0; + const Vec2d label_position = 0.5 * (v1ss + v2ss); m_imgui->set_next_window_pos(label_position.x(), viewport[3] - label_position.y(), ImGuiCond_Always, 0.0f, 1.0f); m_imgui->set_next_window_bg_alpha(0.0f); + + if (!m_editing_distance) { + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 1.0f, 1.0f }); + m_imgui->begin(std::string("distance"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration); + ImGui::AlignTextToFramePadding(); + m_imgui->text(value_str + " " + units); + ImGui::SameLine(); + if (m_imgui->image_button(ImGui::SliderFloatEditBtnIcon, _L("Edit to scale"))) { + m_editing_distance = true; + edit_value = value; + m_imgui->requires_extra_frame(); + } + m_imgui->end(); + ImGui::PopStyleVar(3); + } + + auto perform_scale = [this, value](double new_value, double old_value) { + if (new_value == old_value || new_value <= 0.0) + return; + + const double ratio = new_value / old_value; + wxGetApp().plater()->take_snapshot(_L("Scale")); + + TransformationType type; + type.set_world(); + type.set_relative(); + type.set_joint(); + + // apply scale + Selection& selection = m_parent.get_selection(); + selection.setup_cache(); + selection.scale(ratio * Vec3d::Ones(), type); + wxGetApp().plater()->canvas3D()->do_scale(""); // avoid storing another snapshot + wxGetApp().obj_manipul()->set_dirty(); + }; + + if (m_editing_distance && !ImGui::IsPopupOpen("distance_popup")) + ImGui::OpenPopup("distance_popup"); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); - m_imgui->begin(_L("##distance"), ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); - ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); - const bool use_inches = wxGetApp().app_config->get("use_inches") == "1"; - const std::string txt = use_inches ? format_double(ObjectManipulation::mm_to_in * distance) + " " + _u8L("in") : - format_double(distance) + " " + _u8L("mm"); - m_imgui->text(txt); - m_imgui->end(); - ImGui::PopStyleVar(); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 1.0f, 1.0f }); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 4.0f, 0.0f }); + if (ImGui::BeginPopupModal("distance_popup", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration)) { + ImGui::PushItemWidth(value_str_width); + if (ImGui::InputDouble("##distance", &edit_value, 0.0f, 0.0f, "%.3f")) { + } + ImGui::SameLine(); + if (m_imgui->button(_u8L("Scale"))) { + perform_scale(edit_value, value); + m_editing_distance = false; + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (m_imgui->button(_u8L("Cancel"))) { + m_editing_distance = false; + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + ImGui::PopStyleVar(4); }; auto point_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { @@ -1194,7 +1257,10 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit static float last_y = 0.0f; static float last_h = 0.0f; - m_imgui->begin(_L("Measure tool"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + if (m_editing_distance) + return; + + m_imgui->begin(_u8L("Measure tool"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); // adjust window position to avoid overlap the view toolbar const float win_h = ImGui::GetWindowHeight(); @@ -1341,28 +1407,11 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::TableSetColumnIndex(1); m_imgui->text_colored(col_2_color, col_2); ImGui::TableSetColumnIndex(2); - ImGuiIO& io = ImGui::GetIO(); - const ImTextureID tex_id = io.Fonts->TexID; - assert(io.Fonts->TexWidth > 0 && io.Fonts->TexHeight > 0); - float inv_tex_w = 1.0f / float(io.Fonts->TexWidth); - float inv_tex_h = 1.0f / float(io.Fonts->TexHeight); - const ImFontAtlasCustomRect* const rect = m_imgui->GetTextureCustomRect(ImGui::ClipboardBtnIcon); - const ImVec2 size = { float(rect->Width), float(rect->Height) }; - const ImVec2 uv0 = ImVec2(float(rect->X) * inv_tex_w, float(rect->Y) * inv_tex_h); - const ImVec2 uv1 = ImVec2(float(rect->X + rect->Width) * inv_tex_w, float(rect->Y + rect->Height) * inv_tex_h); - ImGui::PushStyleColor(ImGuiCol_Button, { 0.25f, 0.25f, 0.25f, 0.0f }); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 0.4f, 0.4f, 0.4f, 1.0f }); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0.25f, 0.25f, 0.25f, 1.0f }); - if (m_imgui->image_button(tex_id, size, uv0, uv1)) { + if (m_imgui->image_button(ImGui::ClipboardBtnIcon, _L("Copy to clipboard"))) { wxTheClipboard->Open(); wxTheClipboard->SetData(new wxTextDataObject(col_1 + ": " + col_2)); wxTheClipboard->Close(); } - ImGui::PopStyleColor(3); - if (ImGui::IsItemHovered()) { - const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; - m_imgui->tooltip(into_u8(_L("Copy to clipboard")).c_str(), max_tooltip_width); - } }; if (m_selected_features.second.feature.has_value()) { @@ -1373,7 +1422,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit m_imgui->text(_u8L("Measure") + ":"); if (ImGui::BeginTable("Measure", 3)) { if (measure.angle.has_value()) { - ImGui::PushID((void*)(intptr_t)1); + ImGui::PushID("ClipboardAngle"); add_measure_row_to_table(_u8L("Angle"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(measure.angle->angle)) + "°", ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); @@ -1382,7 +1431,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit double distance = measure.distance_infinite->dist; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - ImGui::PushID((void*)(intptr_t)2); + ImGui::PushID("ClipboardDistanceInfinite"); add_measure_row_to_table(_u8L("Distance Infinite"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); @@ -1392,7 +1441,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit double distance = measure.distance_strict->dist; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - ImGui::PushID((void*)(intptr_t)3); + ImGui::PushID("ClipboardDistanceStrict"); add_measure_row_to_table(_u8L("Distance Strict"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); @@ -1401,7 +1450,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit Vec3d distance = *measure.distance_xyz; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - ImGui::PushID((void*)(intptr_t)4); + ImGui::PushID("ClipboardDistanceXYZ"); add_measure_row_to_table(_u8L("Distance XYZ"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index a5312ebf57..bba23fb6b8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -118,6 +118,7 @@ class GLGizmoMeasure : public GLGizmoBase KeyAutoRepeatFilter m_ctrl_kar_filter; SelectedFeatures m_selected_features; + bool m_editing_distance{ false }; void update_if_needed(); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 4ce9dfefc0..74e125053e 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -431,36 +431,6 @@ bool ImGuiWrapper::draw_radio_button(const std::string& name, float size, bool a } #endif // ENABLE_PREVIEW_LAYOUT -bool ImGuiWrapper::input_double(const std::string &label, const double &value, const std::string &format) -{ - return ImGui::InputDouble(label.c_str(), const_cast(&value), 0.0f, 0.0f, format.c_str(), ImGuiInputTextFlags_CharsDecimal); -} - -bool ImGuiWrapper::input_double(const wxString &label, const double &value, const std::string &format) -{ - auto label_utf8 = into_u8(label); - return input_double(label_utf8, value, format); -} - -bool ImGuiWrapper::input_vec3(const std::string &label, const Vec3d &value, float width, const std::string &format) -{ - bool value_changed = false; - - ImGui::BeginGroup(); - - for (int i = 0; i < 3; ++i) - { - std::string item_label = (i == 0) ? "X" : ((i == 1) ? "Y" : "Z"); - ImGui::PushID(i); - ImGui::PushItemWidth(width); - value_changed |= ImGui::InputDouble(item_label.c_str(), const_cast(&value(i)), 0.0f, 0.0f, format.c_str()); - ImGui::PopID(); - } - ImGui::EndGroup(); - - return value_changed; -} - bool ImGuiWrapper::checkbox(const wxString &label, bool &value) { auto label_utf8 = into_u8(label); @@ -519,20 +489,20 @@ void ImGuiWrapper::text_wrapped(const wxString &label, float wrap_width) void ImGuiWrapper::tooltip(const char *label, float wrap_width) { + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 4.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 8.0f, 8.0f }); ImGui::BeginTooltip(); ImGui::PushTextWrapPos(wrap_width); ImGui::TextUnformatted(label); ImGui::PopTextWrapPos(); ImGui::EndTooltip(); + ImGui::PopStyleVar(3); } void ImGuiWrapper::tooltip(const wxString &label, float wrap_width) { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(wrap_width); - ImGui::TextUnformatted(label.ToUTF8().data()); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); + tooltip(label.ToUTF8().data(), wrap_width); } ImVec2 ImGuiWrapper::get_slider_icon_size() const @@ -684,6 +654,29 @@ bool ImGuiWrapper::image_button(ImTextureID user_texture_id, const ImVec2& size, return image_button_ex(id, user_texture_id, size, uv0, uv1, padding, bg_col, tint_col, flags); } +bool ImGuiWrapper::image_button(const wchar_t icon, const wxString& tooltip) +{ + const ImGuiIO& io = ImGui::GetIO(); + const ImTextureID tex_id = io.Fonts->TexID; + assert(io.Fonts->TexWidth > 0 && io.Fonts->TexHeight > 0); + const float inv_tex_w = 1.0f / float(io.Fonts->TexWidth); + const float inv_tex_h = 1.0f / float(io.Fonts->TexHeight); + const ImFontAtlasCustomRect* const rect = GetTextureCustomRect(icon); + const ImVec2 size = { float(rect->Width), float(rect->Height) }; + const ImVec2 uv0 = ImVec2(float(rect->X) * inv_tex_w, float(rect->Y) * inv_tex_h); + const ImVec2 uv1 = ImVec2(float(rect->X + rect->Width) * inv_tex_w, float(rect->Y + rect->Height) * inv_tex_h); + ImGui::PushStyleColor(ImGuiCol_Button, { 0.25f, 0.25f, 0.25f, 0.0f }); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 0.4f, 0.4f, 0.4f, 1.0f }); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0.25f, 0.25f, 0.25f, 1.0f }); + const bool res = image_button(tex_id, size, uv0, uv1); + ImGui::PopStyleColor(3); + + if (!tooltip.empty() && ImGui::IsItemHovered()) + this->tooltip(tooltip, ImGui::GetFontSize() * 20.0f); + + return res; +} + bool ImGuiWrapper::combo(const wxString& label, const std::vector& options, int& selection, ImGuiComboFlags flags) { // this is to force the label to the left of the widget: diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index f461bc970a..f75200b071 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -95,9 +95,6 @@ public: #if ENABLE_PREVIEW_LAYOUT bool draw_radio_button(const std::string& name, float size, bool active, std::function draw_callback); #endif // ENABLE_PREVIEW_LAYOUT - bool input_double(const std::string &label, const double &value, const std::string &format = "%.3f"); - bool input_double(const wxString &label, const double &value, const std::string &format = "%.3f"); - bool input_vec3(const std::string &label, const Vec3d &value, float width, const std::string &format = "%.3f"); bool checkbox(const wxString &label, bool &value); void text(const char *label); void text(const std::string &label); @@ -118,6 +115,7 @@ public: bool slider_float(const wxString& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true, const wxString& tooltip = {}, bool show_edit_btn = true); bool image_button(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0.0, 0.0), const ImVec2& uv1 = ImVec2(1.0, 1.0), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0.0, 0.0, 0.0, 0.0), const ImVec4& tint_col = ImVec4(1.0, 1.0, 1.0, 1.0), ImGuiButtonFlags flags = 0); + bool image_button(const wchar_t icon, const wxString& tooltip = L""); // Use selection = -1 to not mark any option as selected bool combo(const wxString& label, const std::vector& options, int& selection, ImGuiComboFlags flags = 0); From 8312dc24547df8e622bde814efb1b3e0b15bab40 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 6 Oct 2022 14:47:25 +0200 Subject: [PATCH 093/250] Measuring: Fixed rendering of point features when the object is scaled --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 157 ++++++++++++----------- 1 file changed, 79 insertions(+), 78 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 3e83418ef4..a6efc09e78 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -467,93 +467,94 @@ void GLGizmoMeasure::on_render() auto render_feature = [this, set_matrix_uniforms](const Measure::SurfaceFeature& feature, const std::vector& colors, const Transform3d& model_matrix, float inv_zoom, bool update_raycasters) { - switch (feature.get_type()) - { - default: { assert(false); break; } - case Measure::SurfaceFeatureType::Point: - { - const Vec3d& position = feature.get_point(); - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); - set_matrix_uniforms(feature_matrix); - m_sphere.model.set_color(colors.front()); - m_sphere.model.render(); - if (update_raycasters) { - auto it = m_raycasters.find(POINT_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(feature_matrix); - } - break; - } - case Measure::SurfaceFeatureType::Circle: - { - const auto& [center, radius, normal] = feature.get_circle(); - // render center - const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); - set_matrix_uniforms(center_matrix); - m_sphere.model.set_color(colors.front()); - m_sphere.model.render(); - if (update_raycasters) { - auto it = m_raycasters.find(POINT_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(center_matrix); - } - // render circle - const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); - set_matrix_uniforms(circle_matrix); - m_circle.model.set_color(colors.back()); - m_circle.model.render(); - if (update_raycasters) { - auto it = m_raycasters.find(CIRCLE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(circle_matrix); - } - break; - } - case Measure::SurfaceFeatureType::Edge: - { - const auto& [start, end] = feature.get_edge(); - // render extra point - const std::optional extra = feature.get_extra_point(); - if (extra.has_value()) { - const Transform3d point_matrix = model_matrix * Geometry::translation_transform(*extra) * Geometry::scale_transform(inv_zoom); - set_matrix_uniforms(point_matrix); + const Transform3d model_matrix_scale_inverse = Geometry::Transformation(model_matrix).get_scaling_factor_matrix().inverse(); + switch (feature.get_type()) + { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + const Vec3d& position = feature.get_point(); + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * model_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(feature_matrix); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); if (update_raycasters) { auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(point_matrix); + it->second->set_transform(feature_matrix); } + break; } - // render edge - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start) * - Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); - set_matrix_uniforms(feature_matrix); - m_cylinder.model.set_color(colors.back()); - m_cylinder.model.render(); - if (update_raycasters) { - auto it = m_raycasters.find(EDGE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(feature_matrix); + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, normal] = feature.get_circle(); + // render center + const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * model_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(center_matrix); + m_sphere.model.set_color(colors.front()); + m_sphere.model.render(); + if (update_raycasters) { + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(center_matrix); + } + // render circle + const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); + set_matrix_uniforms(circle_matrix); + m_circle.model.set_color(colors.back()); + m_circle.model.render(); + if (update_raycasters) { + auto it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(circle_matrix); + } + break; + } + case Measure::SurfaceFeatureType::Edge: + { + const auto& [start, end] = feature.get_edge(); + // render extra point + const std::optional extra = feature.get_extra_point(); + if (extra.has_value()) { + const Transform3d point_matrix = model_matrix * Geometry::translation_transform(*extra) * model_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(point_matrix); + m_sphere.model.set_color(colors.front()); + m_sphere.model.render(); + if (update_raycasters) { + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(point_matrix); + } + } + // render edge + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start) * + Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); + set_matrix_uniforms(feature_matrix); + m_cylinder.model.set_color(colors.back()); + m_cylinder.model.render(); + if (update_raycasters) { + auto it = m_raycasters.find(EDGE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); + } + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto& [idx, normal, pt] = feature.get_plane(); + assert(idx < m_plane_models_cache.size()); + set_matrix_uniforms(model_matrix); + m_plane_models_cache[idx].set_color(colors.front()); + m_plane_models_cache[idx].render(); + if (update_raycasters) { + auto it = m_raycasters.find(PLANE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(model_matrix); + } + break; } - break; - } - case Measure::SurfaceFeatureType::Plane: - { - const auto& [idx, normal, pt] = feature.get_plane(); - assert(idx < m_plane_models_cache.size()); - set_matrix_uniforms(model_matrix); - m_plane_models_cache[idx].set_color(colors.front()); - m_plane_models_cache[idx].render(); - if (update_raycasters) { - auto it = m_raycasters.find(PLANE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(model_matrix); } - break; - } - } }; auto hover_selection_color = [this]() { From 1a0294e892476324936907eb8028a43c93c12b7b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 7 Oct 2022 08:40:23 +0200 Subject: [PATCH 094/250] Measuring - Gizmo measure disabled for scaled volumes --- src/libslic3r/Technologies.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 903612f29b..1d13d92f10 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -78,6 +78,7 @@ #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) // Enable Measure Gizmo #define ENABLE_MEASURE_GIZMO (1 && ENABLE_RAYCAST_PICKING) +#define DISABLE_MEASURE_GIZMO_FOR_SCALED_VOLUMES (1 && ENABLE_MEASURE_GIZMO) #define ENABLE_MEASURE_GIZMO_DEBUG (0 && ENABLE_MEASURE_GIZMO) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index a6efc09e78..f2638d0588 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -290,8 +290,12 @@ bool GLGizmoMeasure::on_is_activable() const bool res = (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) ? selection.is_single_full_instance() : selection.is_single_volume() || selection.is_single_volume_instance(); - if (res) + if (res) { res &= !selection.get_first_volume()->is_sinking(); +#if DISABLE_MEASURE_GIZMO_FOR_SCALED_VOLUMES + res &= Geometry::Transformation(selection.get_first_volume()->world_matrix()).get_scaling_factor().isApprox(Vec3d::Ones()); +#endif // DISABLE_MEASURE_GIZMO_FOR_SCALED_VOLUMES + } return res; } From 5ebfa73f374265ec1f035ac7d1c66d587b990530 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 7 Oct 2022 09:57:13 +0200 Subject: [PATCH 095/250] Measuring - Gizmo measure - Disable background fadeout animation when showing imgui modal dialog to edit distance --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 1 + src/slic3r/GUI/ImGuiWrapper.cpp | 7 +++++++ src/slic3r/GUI/ImGuiWrapper.hpp | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index f2638d0588..d18584a870 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -903,6 +903,7 @@ void GLGizmoMeasure::render_dimensioning() ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 1.0f, 1.0f }); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 4.0f, 0.0f }); if (ImGui::BeginPopupModal("distance_popup", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration)) { + m_imgui->disable_background_fadeout_animation(); ImGui::PushItemWidth(value_str_width); if (ImGui::InputDouble("##distance", &edit_value, 0.0f, 0.0f, "%.3f")) { } diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 74e125053e..7484724097 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -1145,6 +1145,13 @@ ImFontAtlasCustomRect* ImGuiWrapper::GetTextureCustomRect(const wchar_t& tex_id) } #endif // ENABLE_LEGEND_TOOLBAR_ICONS +#if ENABLE_MEASURE_GIZMO +void ImGuiWrapper::disable_background_fadeout_animation() +{ + GImGui->DimBgRatio = 1.0f; +} +#endif // ENABLE_MEASURE_GIZMO + ImU32 ImGuiWrapper::to_ImU32(const ColorRGBA& color) { return ImGui::GetColorU32({ color.r(), color.g(), color.b(), color.a() }); diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index f75200b071..bf4018fb15 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -136,6 +136,10 @@ public: void set_requires_extra_frame() { m_requires_extra_frame = true; } void reset_requires_extra_frame() { m_requires_extra_frame = false; } +#if ENABLE_MEASURE_GIZMO + void disable_background_fadeout_animation(); +#endif // ENABLE_MEASURE_GIZMO + static ImU32 to_ImU32(const ColorRGBA& color); static ImVec4 to_ImVec4(const ColorRGBA& color); static ColorRGBA from_ImU32(const ImU32& color); From 0fd01f36bdf3f3a6bd0b4a564f06b10e5cce9367 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 7 Oct 2022 10:42:01 +0200 Subject: [PATCH 096/250] Measuring - Gizmo measure - Handle [Enter] and [Esc] keys input events in imgui modal dialog to edit distance --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 78 +++++++++++++----------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index d18584a870..3e1d9824d4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -848,10 +848,10 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.triangle.render(); const bool use_inches = wxGetApp().app_config->get("use_inches") == "1"; - const double value = use_inches ? ObjectManipulation::mm_to_in * distance : distance; - const std::string value_str = format_double(value); + const double curr_value = use_inches ? ObjectManipulation::mm_to_in * distance : distance; + const std::string curr_value_str = format_double(curr_value); const std::string units = use_inches ? _u8L("in") : _u8L("mm"); - const float value_str_width = 20.0f + ImGui::CalcTextSize(value_str.c_str()).x; + const float value_str_width = 20.0f + ImGui::CalcTextSize(curr_value_str.c_str()).x; static double edit_value = 0.0; const Vec2d label_position = 0.5 * (v1ss + v2ss); @@ -864,37 +864,17 @@ void GLGizmoMeasure::render_dimensioning() ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 1.0f, 1.0f }); m_imgui->begin(std::string("distance"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration); ImGui::AlignTextToFramePadding(); - m_imgui->text(value_str + " " + units); + m_imgui->text(curr_value_str + " " + units); ImGui::SameLine(); if (m_imgui->image_button(ImGui::SliderFloatEditBtnIcon, _L("Edit to scale"))) { m_editing_distance = true; - edit_value = value; + edit_value = curr_value; m_imgui->requires_extra_frame(); } m_imgui->end(); ImGui::PopStyleVar(3); } - auto perform_scale = [this, value](double new_value, double old_value) { - if (new_value == old_value || new_value <= 0.0) - return; - - const double ratio = new_value / old_value; - wxGetApp().plater()->take_snapshot(_L("Scale")); - - TransformationType type; - type.set_world(); - type.set_relative(); - type.set_joint(); - - // apply scale - Selection& selection = m_parent.get_selection(); - selection.setup_cache(); - selection.scale(ratio * Vec3d::Ones(), type); - wxGetApp().plater()->canvas3D()->do_scale(""); // avoid storing another snapshot - wxGetApp().obj_manipul()->set_dirty(); - }; - if (m_editing_distance && !ImGui::IsPopupOpen("distance_popup")) ImGui::OpenPopup("distance_popup"); @@ -903,21 +883,51 @@ void GLGizmoMeasure::render_dimensioning() ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 1.0f, 1.0f }); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 4.0f, 0.0f }); if (ImGui::BeginPopupModal("distance_popup", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration)) { + auto perform_scale = [this](double new_value, double old_value) { + if (new_value == old_value || new_value <= 0.0) + return; + + const double ratio = new_value / old_value; + wxGetApp().plater()->take_snapshot(_L("Scale")); + + TransformationType type; + type.set_world(); + type.set_relative(); + type.set_joint(); + + // apply scale + Selection& selection = m_parent.get_selection(); + selection.setup_cache(); + selection.scale(ratio * Vec3d::Ones(), type); + wxGetApp().plater()->canvas3D()->do_scale(""); // avoid storing another snapshot + wxGetApp().obj_manipul()->set_dirty(); + }; + auto action_exit = [this]() { + m_editing_distance = false; + ImGui::CloseCurrentPopup(); + }; + auto action_scale = [this, perform_scale, action_exit](double new_value, double old_value) { + perform_scale(new_value, old_value); + action_exit(); + }; + m_imgui->disable_background_fadeout_animation(); ImGui::PushItemWidth(value_str_width); if (ImGui::InputDouble("##distance", &edit_value, 0.0f, 0.0f, "%.3f")) { } + + // handle keys input + if (ImGui::IsKeyPressedMap(ImGuiKey_Enter) || ImGui::IsKeyPressedMap(ImGuiKey_KeyPadEnter)) + action_scale(edit_value, curr_value); + else if (ImGui::IsKeyPressedMap(ImGuiKey_Escape)) + action_exit(); + ImGui::SameLine(); - if (m_imgui->button(_u8L("Scale"))) { - perform_scale(edit_value, value); - m_editing_distance = false; - ImGui::CloseCurrentPopup(); - } + if (m_imgui->button(_u8L("Scale"))) + action_scale(edit_value, curr_value); ImGui::SameLine(); - if (m_imgui->button(_u8L("Cancel"))) { - m_editing_distance = false; - ImGui::CloseCurrentPopup(); - } + if (m_imgui->button(_u8L("Cancel"))) + action_exit(); ImGui::EndPopup(); } ImGui::PopStyleVar(4); From 2fb59e66c2b6f07a25cfa873fdeb1d820b2d78c4 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 7 Oct 2022 12:42:30 +0200 Subject: [PATCH 097/250] easuring - Gizmo measure - Reworked imgui dialog layout to avoid change in size in dependence of hovered or selected features --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 266 +++++++++++++---------- 1 file changed, 151 insertions(+), 115 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 3e1d9824d4..15d6ea761f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -63,7 +63,7 @@ static std::string surface_feature_type_as_string(Measure::SurfaceFeatureType ty switch (type) { default: - case Measure::SurfaceFeatureType::Undef: { return _u8L("Undefined"); } + case Measure::SurfaceFeatureType::Undef: { return _u8L("No feature"); } case Measure::SurfaceFeatureType::Point: { return _u8L("Vertex"); } case Measure::SurfaceFeatureType::Edge: { return _u8L("Edge"); } case Measure::SurfaceFeatureType::Circle: { return _u8L("Circle"); } @@ -1292,6 +1292,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } if (ImGui::BeginTable("Commands", 2)) { + unsigned int row_count = 1; add_row_to_table( [this]() { m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Left mouse button")); @@ -1310,93 +1311,121 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } ); - if (m_selected_features.first.feature.has_value()) + if (m_selected_features.first.feature.has_value()) { add_strings_row_to_table(*m_imgui, CTRL_STR + "+" + _u8L("Right mouse button"), ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ++row_count; + } - if (m_mode == EMode::BasicSelection && m_hover_id != -1) + if (m_mode == EMode::BasicSelection && m_hover_id != -1) { add_strings_row_to_table(*m_imgui, CTRL_STR, ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable point selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ++row_count; + } + + // add dummy rows to keep dialog size fixed + for (unsigned int i = row_count; i < 3; ++i) { + add_strings_row_to_table(*m_imgui, " ", ImGuiWrapper::COL_ORANGE_LIGHT, " ", ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + ImGui::EndTable(); } const bool use_inches = wxGetApp().app_config->get("use_inches") == "1"; const std::string units = use_inches ? " " + _u8L("in") : " " + _u8L("mm"); - if (m_curr_feature.has_value()) { - const Measure::SurfaceFeatureType feature_type = m_curr_feature->get_type(); + const Measure::SurfaceFeatureType feature_type = m_curr_feature.has_value() ? m_curr_feature->get_type() : Measure::SurfaceFeatureType::Undef; + bool data_text_set = false; + ImGui::Separator(); + if (feature_type != Measure::SurfaceFeatureType::Undef) { if (m_mode == EMode::BasicSelection) { - if (feature_type != Measure::SurfaceFeatureType::Undef) { - ImGui::Separator(); - m_imgui->text(surface_feature_type_as_string(feature_type) + ":"); - if (ImGui::BeginTable("Data", 2)) { - switch (feature_type) - { - default: { assert(false); break; } - case Measure::SurfaceFeatureType::Point: - { - Vec3d position = m_volume_matrix * m_curr_feature->get_point(); - if (use_inches) - position = ObjectManipulation::mm_to_in * position; - add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - break; - } - case Measure::SurfaceFeatureType::Edge: - { - auto [from, to] = m_curr_feature->get_edge(); - from = m_volume_matrix * from; - to = m_volume_matrix * to; - if (use_inches) { - from = ObjectManipulation::mm_to_in * from; - to = ObjectManipulation::mm_to_in * to; - } - add_strings_row_to_table(*m_imgui, _u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, _u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, _u8L("Length"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); - break; - } - case Measure::SurfaceFeatureType::Circle: - { - auto [center, radius, normal] = m_curr_feature->get_circle(); - center = m_volume_matrix * center; - normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; - if (use_inches) { - center = ObjectManipulation::mm_to_in * center; - radius = ObjectManipulation::mm_to_in * radius; - } - add_strings_row_to_table(*m_imgui, _u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, _u8L("Radius"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - auto [idx, normal, origin] = m_curr_feature->get_plane(); - origin = m_volume_matrix * origin; - normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; - if (use_inches) - origin = ObjectManipulation::mm_to_in * origin; - add_strings_row_to_table(*m_imgui, _u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - break; - } - } - ImGui::EndTable(); - } - } + m_imgui->text(surface_feature_type_as_string(feature_type)); + data_text_set = true; } else if (m_mode == EMode::ExtendedSelection) { if (m_hover_id != -1 && m_curr_point_on_feature_position.has_value()) { - ImGui::Separator(); - m_imgui->text(point_on_feature_type_as_string(feature_type, m_hover_id) + ":"); - if (ImGui::BeginTable("Data", 2)) { - Vec3d position = m_volume_matrix * *m_curr_point_on_feature_position; - if (use_inches) - position = ObjectManipulation::mm_to_in * position; - add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - ImGui::EndTable(); - } + m_imgui->text(point_on_feature_type_as_string(feature_type, m_hover_id)); + data_text_set = true; } } } + if (!data_text_set) + m_imgui->text(_u8L("No feature")); + + const unsigned int max_data_row_count = 3; + unsigned int data_row_count = 0; + if (ImGui::BeginTable("Data", 2)) { + if (m_mode == EMode::BasicSelection) { + switch (feature_type) + { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + Vec3d position = m_volume_matrix * m_curr_feature->get_point(); + if (use_inches) + position = ObjectManipulation::mm_to_in * position; + add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + data_row_count = 1; + break; + } + case Measure::SurfaceFeatureType::Edge: + { + auto [from, to] = m_curr_feature->get_edge(); + from = m_volume_matrix * from; + to = m_volume_matrix * to; + if (use_inches) { + from = ObjectManipulation::mm_to_in * from; + to = ObjectManipulation::mm_to_in * to; + } + add_strings_row_to_table(*m_imgui, _u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Length"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); + data_row_count = 3; + break; + } + case Measure::SurfaceFeatureType::Circle: + { + auto [center, radius, normal] = m_curr_feature->get_circle(); + center = m_volume_matrix * center; + normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + if (use_inches) { + center = ObjectManipulation::mm_to_in * center; + radius = ObjectManipulation::mm_to_in * radius; + } + add_strings_row_to_table(*m_imgui, _u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Radius"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + data_row_count = 3; + break; + } + case Measure::SurfaceFeatureType::Plane: + { + auto [idx, normal, origin] = m_curr_feature->get_plane(); + origin = m_volume_matrix * origin; + normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + if (use_inches) + origin = ObjectManipulation::mm_to_in * origin; + add_strings_row_to_table(*m_imgui, _u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + data_row_count = 2; + break; + } + } + } + else { + if (m_hover_id != -1 && m_curr_point_on_feature_position.has_value()) { + Vec3d position = m_volume_matrix * *m_curr_point_on_feature_position; + if (use_inches) + position = ObjectManipulation::mm_to_in * position; + add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + data_row_count = 1; + } + } + + // add dummy rows to keep dialog size fixed + for (unsigned int i = data_row_count; i < max_data_row_count; ++i) { + add_strings_row_to_table(*m_imgui, " ", ImGuiWrapper::COL_ORANGE_LIGHT, " ", ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + ImGui::EndTable(); + } ImGui::Separator(); const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; @@ -1430,52 +1459,59 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } }; - if (m_selected_features.second.feature.has_value()) { - const Measure::MeasurementResult& measure = m_measurement_result; + ImGui::Separator(); + m_imgui->text(_u8L("Measure")); - ImGui::Separator(); - if (measure.has_any_data()) { - m_imgui->text(_u8L("Measure") + ":"); - if (ImGui::BeginTable("Measure", 3)) { - if (measure.angle.has_value()) { - ImGui::PushID("ClipboardAngle"); - add_measure_row_to_table(_u8L("Angle"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(measure.angle->angle)) + "°", - ImGui::GetStyleColorVec4(ImGuiCol_Text)); - ImGui::PopID(); - } - if (measure.distance_infinite.has_value()) { - double distance = measure.distance_infinite->dist; - if (use_inches) - distance = ObjectManipulation::mm_to_in * distance; - ImGui::PushID("ClipboardDistanceInfinite"); - add_measure_row_to_table(_u8L("Distance Infinite"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, - ImGui::GetStyleColorVec4(ImGuiCol_Text)); - ImGui::PopID(); - } - if (measure.distance_strict.has_value() && - (!measure.distance_infinite.has_value() || std::abs(measure.distance_strict->dist - measure.distance_infinite->dist) > EPSILON)) { - double distance = measure.distance_strict->dist; - if (use_inches) - distance = ObjectManipulation::mm_to_in * distance; - ImGui::PushID("ClipboardDistanceStrict"); - add_measure_row_to_table(_u8L("Distance Strict"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, - ImGui::GetStyleColorVec4(ImGuiCol_Text)); - ImGui::PopID(); - } - if (measure.distance_xyz.has_value() && measure.distance_xyz->norm() > EPSILON) { - Vec3d distance = *measure.distance_xyz; - if (use_inches) - distance = ObjectManipulation::mm_to_in * distance; - ImGui::PushID("ClipboardDistanceXYZ"); - add_measure_row_to_table(_u8L("Distance XYZ"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), - ImGui::GetStyleColorVec4(ImGuiCol_Text)); - ImGui::PopID(); - } - ImGui::EndTable(); + const unsigned int max_measure_row_count = 2; + unsigned int measure_row_count = 0; + if (ImGui::BeginTable("Measure", 4)) { + if (m_selected_features.second.feature.has_value()) { + const Measure::MeasurementResult& measure = m_measurement_result; + if (measure.angle.has_value()) { + ImGui::PushID("ClipboardAngle"); + add_measure_row_to_table(_u8L("Angle"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(measure.angle->angle)) + "°", + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ++measure_row_count; + ImGui::PopID(); + } + if (measure.distance_infinite.has_value()) { + double distance = measure.distance_infinite->dist; + if (use_inches) + distance = ObjectManipulation::mm_to_in * distance; + ImGui::PushID("ClipboardDistanceInfinite"); + add_measure_row_to_table(_u8L("Distance Infinite"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ++measure_row_count; + ImGui::PopID(); + } + if (measure.distance_strict.has_value() && + (!measure.distance_infinite.has_value() || std::abs(measure.distance_strict->dist - measure.distance_infinite->dist) > EPSILON)) { + double distance = measure.distance_strict->dist; + if (use_inches) + distance = ObjectManipulation::mm_to_in * distance; + ImGui::PushID("ClipboardDistanceStrict"); + add_measure_row_to_table(_u8L("Distance Strict"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ++measure_row_count; + ImGui::PopID(); + } + if (measure.distance_xyz.has_value() && measure.distance_xyz->norm() > EPSILON) { + Vec3d distance = *measure.distance_xyz; + if (use_inches) + distance = ObjectManipulation::mm_to_in * distance; + ImGui::PushID("ClipboardDistanceXYZ"); + add_measure_row_to_table(_u8L("Distance XYZ"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ++measure_row_count; + ImGui::PopID(); } } - else - m_imgui->text(_u8L("No measure available")); + + // add dummy rows to keep dialog size fixed + for (unsigned int i = measure_row_count; i < max_measure_row_count; ++i) { + add_strings_row_to_table(*m_imgui, " ", ImGuiWrapper::COL_ORANGE_LIGHT, " ", ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + ImGui::EndTable(); } if (last_feature != m_curr_feature || last_mode != m_mode || last_selected_features != m_selected_features) { From f0925e74f720a5f8da61f63c08190294b2cb2c97 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 10 Oct 2022 08:29:51 +0200 Subject: [PATCH 098/250] Follow-up of 2fb59e66c2b6f07a25cfa873fdeb1d820b2d78c4 - Removed obsolete assert --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 15d6ea761f..79a800bf2e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1356,7 +1356,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (m_mode == EMode::BasicSelection) { switch (feature_type) { - default: { assert(false); break; } + default: { break; } case Measure::SurfaceFeatureType::Point: { Vec3d position = m_volume_matrix * m_curr_feature->get_point(); From 614b1581a662952d5d282427e6fd353b007d610f Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 10 Oct 2022 09:46:12 +0200 Subject: [PATCH 099/250] Measuring - Gizmo measure - Auto-select text when opening imgui modal dialog to edit distance --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 10 ++++++++++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 + 2 files changed, 11 insertions(+) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 79a800bf2e..b4c35b1563 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -221,6 +221,7 @@ void GLGizmoMeasure::data_changed() m_selected_features.reset(); m_selection_raycasters.clear(); m_editing_distance = false; + m_is_editing_distance_first_frame = true; } bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) @@ -258,6 +259,7 @@ void GLGizmoMeasure::on_set_state() m_curr_point_on_feature_position.reset(); restore_scene_raycasters_state(); m_editing_distance = false; + m_is_editing_distance_first_frame = true; } else { m_mode = EMode::BasicSelection; @@ -904,6 +906,7 @@ void GLGizmoMeasure::render_dimensioning() }; auto action_exit = [this]() { m_editing_distance = false; + m_is_editing_distance_first_frame = true; ImGui::CloseCurrentPopup(); }; auto action_scale = [this, perform_scale, action_exit](double new_value, double old_value) { @@ -916,6 +919,13 @@ void GLGizmoMeasure::render_dimensioning() if (ImGui::InputDouble("##distance", &edit_value, 0.0f, 0.0f, "%.3f")) { } + // trick to auto-select text in the input widgets on 1st frame + if (m_is_editing_distance_first_frame) { + ImGui::SetKeyboardFocusHere(0); + m_is_editing_distance_first_frame = false; + m_imgui->set_requires_extra_frame(); + } + // handle keys input if (ImGui::IsKeyPressedMap(ImGuiKey_Enter) || ImGui::IsKeyPressedMap(ImGuiKey_KeyPadEnter)) action_scale(edit_value, curr_value); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index bba23fb6b8..9db2a73aa3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -119,6 +119,7 @@ class GLGizmoMeasure : public GLGizmoBase SelectedFeatures m_selected_features; bool m_editing_distance{ false }; + bool m_is_editing_distance_first_frame{ true }; void update_if_needed(); From 6cee261f3969f0070ade5985940d92fad44cdd89 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 10 Oct 2022 10:12:14 +0200 Subject: [PATCH 100/250] Follow-up of 8312dc24547df8e622bde814efb1b3e0b15bab40 - Fixed rendering of point on locked features when the object is scaled --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 34 ++++++++++++------------ src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 + 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index b4c35b1563..1976cbcdab 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -317,7 +317,6 @@ void GLGizmoMeasure::on_render() (selection.is_single_volume() || selection.is_single_volume_instance())) { update_if_needed(); - m_volume_matrix = selection.get_first_volume()->world_matrix(); const Camera& camera = wxGetApp().plater()->get_camera(); const float inv_zoom = (float)camera.get_inv_zoom(); @@ -397,7 +396,6 @@ void GLGizmoMeasure::on_render() Vec3f n; const Transform3d& trafo = it->second->get_transform(); bool res = it->second->get_raycaster()->closest_hit(m_mouse_pos, trafo, camera, p, n); - assert(res); if (res) { if (callback) p = callback(p); @@ -472,15 +470,14 @@ void GLGizmoMeasure::on_render() }; auto render_feature = [this, set_matrix_uniforms](const Measure::SurfaceFeature& feature, const std::vector& colors, - const Transform3d& model_matrix, float inv_zoom, bool update_raycasters) { - const Transform3d model_matrix_scale_inverse = Geometry::Transformation(model_matrix).get_scaling_factor_matrix().inverse(); + float inv_zoom, bool update_raycasters) { switch (feature.get_type()) { default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { const Vec3d& position = feature.get_point(); - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * model_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); + const Transform3d feature_matrix = m_volume_matrix * Geometry::translation_transform(position) * m_volume_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(feature_matrix); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); @@ -495,7 +492,7 @@ void GLGizmoMeasure::on_render() { const auto& [center, radius, normal] = feature.get_circle(); // render center - const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * model_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); + const Transform3d center_matrix = m_volume_matrix * Geometry::translation_transform(center) * m_volume_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(center_matrix); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); @@ -505,7 +502,7 @@ void GLGizmoMeasure::on_render() it->second->set_transform(center_matrix); } // render circle - const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); + const Transform3d circle_matrix = m_volume_matrix * Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); set_matrix_uniforms(circle_matrix); m_circle.model.set_color(colors.back()); m_circle.model.render(); @@ -522,7 +519,7 @@ void GLGizmoMeasure::on_render() // render extra point const std::optional extra = feature.get_extra_point(); if (extra.has_value()) { - const Transform3d point_matrix = model_matrix * Geometry::translation_transform(*extra) * model_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); + const Transform3d point_matrix = m_volume_matrix * Geometry::translation_transform(*extra) * m_volume_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(point_matrix); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); @@ -533,16 +530,16 @@ void GLGizmoMeasure::on_render() } } // render edge - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * + const Transform3d edge_matrix = m_volume_matrix * Geometry::translation_transform(start) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start) * Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); - set_matrix_uniforms(feature_matrix); + set_matrix_uniforms(edge_matrix); m_cylinder.model.set_color(colors.back()); m_cylinder.model.render(); if (update_raycasters) { auto it = m_raycasters.find(EDGE_ID); if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(feature_matrix); + it->second->set_transform(edge_matrix); } break; } @@ -550,13 +547,13 @@ void GLGizmoMeasure::on_render() { const auto& [idx, normal, pt] = feature.get_plane(); assert(idx < m_plane_models_cache.size()); - set_matrix_uniforms(model_matrix); + set_matrix_uniforms(m_volume_matrix); m_plane_models_cache[idx].set_color(colors.front()); m_plane_models_cache[idx].render(); if (update_raycasters) { auto it = m_raycasters.find(PLANE_ID); if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(model_matrix); + it->second->set_transform(m_volume_matrix); } break; } @@ -601,13 +598,13 @@ void GLGizmoMeasure::on_render() } } - render_feature(*m_curr_feature, colors, m_volume_matrix, inv_zoom, true); + render_feature(*m_curr_feature, colors, inv_zoom, true); } if (m_selected_features.first.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.first.feature)) { std::vector colors; colors.emplace_back(SELECTED_1ST_COLOR); - render_feature(*m_selected_features.first.feature, colors, m_volume_matrix, inv_zoom, false); + render_feature(*m_selected_features.first.feature, colors, inv_zoom, false); if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point) { auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_1_ID; }); @@ -618,7 +615,7 @@ void GLGizmoMeasure::on_render() if (m_selected_features.second.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.second.feature)) { std::vector colors; colors.emplace_back(SELECTED_2ND_COLOR); - render_feature(*m_selected_features.second.feature, colors, m_volume_matrix, inv_zoom, false); + render_feature(*m_selected_features.second.feature, colors, inv_zoom, false); if (m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_2_ID; }); @@ -629,7 +626,7 @@ void GLGizmoMeasure::on_render() if (is_hovering_on_locked_feature && m_curr_point_on_feature_position.has_value()) { if (m_hover_id != POINT_ID) { - const Transform3d matrix = m_volume_matrix * Geometry::translation_transform(*m_curr_point_on_feature_position) * Geometry::scale_transform(inv_zoom); + const Transform3d matrix = m_volume_matrix * Geometry::translation_transform(*m_curr_point_on_feature_position) * m_volume_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(matrix); m_sphere.model.set_color(hover_selection_color()); m_sphere.model.render(); @@ -675,6 +672,9 @@ void GLGizmoMeasure::update_if_needed() } m_old_model_object = object; m_old_model_volume = volume; + + m_volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); + m_volume_matrix_scale_inverse = Geometry::Transformation(m_volume_matrix).get_scaling_factor_matrix().inverse(); }; const ModelObject* mo = m_c->selection_info()->model_object(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 9db2a73aa3..fd93ba4aac 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -87,6 +87,7 @@ class GLGizmoMeasure : public GLGizmoBase Dimensioning m_dimensioning; Transform3d m_volume_matrix{ Transform3d::Identity() }; + Transform3d m_volume_matrix_scale_inverse{ Transform3d::Identity() }; std::vector m_plane_models_cache; std::map> m_raycasters; std::vector> m_selection_raycasters; From 2972493f5fb66a418c61ca5c3d9f16901187a0b1 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 11 Oct 2022 10:47:20 +0200 Subject: [PATCH 101/250] Measuring: Gizmo measure shows dimensioning for distance circle-circle --- src/libslic3r/CMakeLists.txt | 1 + src/libslic3r/Measure.cpp | 241 +++++++++++++++++++- src/libslic3r/Measure.hpp | 4 + src/libslic3r/MeasureUtils.hpp | 390 +++++++++++++++++++++++++++++++++ 4 files changed, 632 insertions(+), 4 deletions(-) create mode 100644 src/libslic3r/MeasureUtils.hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index cdf61407f2..e91a2186c0 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -182,6 +182,7 @@ set(SLIC3R_SOURCES MeshNormals.cpp Measure.hpp Measure.cpp + MeasureUtils.hpp CustomGCode.cpp CustomGCode.hpp Arrange.hpp diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index ea68503254..27a4f8a90d 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -1,10 +1,11 @@ #include "libslic3r/libslic3r.h" #include "Measure.hpp" +#include "MeasureUtils.hpp" #include "libslic3r/Geometry/Circle.hpp" #include "libslic3r/SurfaceMesh.hpp" - +#if ENABLE_MEASURE_GIZMO namespace Slic3r { namespace Measure { @@ -13,8 +14,6 @@ namespace Measure { constexpr double feature_hover_limit = 0.5; // how close to a feature the mouse must be to highlight it constexpr double edge_endpoint_limit = 0.5; // how close to an edge endpoint the mouse ... - - static std::pair get_center_and_radius(const std::vector& border, int start_idx, int end_idx, const Transform3d& trafo) { Vec2ds pts; @@ -754,7 +753,238 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& /////////////////////////////////////////////////////////////////////////// } else if (f1.get_type() == SurfaceFeatureType::Circle) { if (f2.get_type() == SurfaceFeatureType::Circle) { - result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO + const auto [c0, r0, n0] = f1.get_circle(); + const auto [c1, r1, n1] = f2.get_circle(); + + // The following code is an adaptation of the algorithm found in: + // https://github.com/davideberly/GeometricTools/blob/master/GTE/Mathematics/DistCircle3Circle3.h + // and described in: + // https://www.geometrictools.com/Documentation/DistanceToCircle3.pdf + + struct ClosestInfo + { + double sqrDistance{ 0.0 }; + Vec3d circle0Closest{ Vec3d::Zero() }; + Vec3d circle1Closest{ Vec3d::Zero() }; + + inline bool operator < (const ClosestInfo& other) const { return sqrDistance < other.sqrDistance; } + }; + std::array candidates{}; + + const double zero = 0.0; + + const Vec3d D = c1 - c0; + + if (!are_parallel(n0, n1)) { + auto orthonormal_basis = [](const Vec3d& v) { + std::array ret; + ret[2] = v.normalized(); + int index; + ret[2].maxCoeff(&index); + switch (index) + { + case 0: { ret[0] = Vec3d(ret[2].y(), -ret[2].x(), 0.0).normalized(); break; } + case 1: { ret[0] = Vec3d(0.0, ret[2].z(), -ret[2].y()).normalized(); break; } + case 2: { ret[0] = Vec3d(-ret[2].z(), 0.0, ret[2].x()).normalized(); break; } + } + ret[1] = ret[2].cross(ret[0]).normalized(); + return ret; + }; + + // Get parameters for constructing the degree-8 polynomial phi. + const double one = 1.0; + const double two = 2.0; + const double r0sqr = sqr(r0); + const double r1sqr = sqr(r1); + + // Compute U1 and V1 for the plane of circle1. + const std::array basis = orthonormal_basis(n1); + const Vec3d U1 = basis[0]; + const Vec3d V1 = basis[1]; + + // Construct the polynomial phi(cos(theta)). + const Vec3d N0xD = n0.cross(D); + const Vec3d N0xU1 = n0.cross(U1); + const Vec3d N0xV1 = n0.cross(V1); + const double a0 = r1 * D.dot(U1); + const double a1 = r1 * D.dot(V1); + const double a2 = N0xD.dot(N0xD); + const double a3 = r1 * N0xD.dot(N0xU1); + const double a4 = r1 * N0xD.dot(N0xV1); + const double a5 = r1sqr * N0xU1.dot(N0xU1); + const double a6 = r1sqr * N0xU1.dot(N0xV1); + const double a7 = r1sqr * N0xV1.dot(N0xV1); + Polynomial1 p0{ a2 + a7, two * a3, a5 - a7 }; + Polynomial1 p1{ two * a4, two * a6 }; + Polynomial1 p2{ zero, a1 }; + Polynomial1 p3{ -a0 }; + Polynomial1 p4{ -a6, a4, two * a6 }; + Polynomial1 p5{ -a3, a7 - a5 }; + Polynomial1 tmp0{ one, zero, -one }; + Polynomial1 tmp1 = p2 * p2 + tmp0 * p3 * p3; + Polynomial1 tmp2 = two * p2 * p3; + Polynomial1 tmp3 = p4 * p4 + tmp0 * p5 * p5; + Polynomial1 tmp4 = two * p4 * p5; + Polynomial1 p6 = p0 * tmp1 + tmp0 * p1 * tmp2 - r0sqr * tmp3; + Polynomial1 p7 = p0 * tmp2 + p1 * tmp1 - r0sqr * tmp4; + + // Parameters for polynomial root finding. The roots[] array + // stores the roots. We need only the unique ones, which is + // the responsibility of the set uniqueRoots. The pairs[] + // array stores the (cosine,sine) information mentioned in the + // PDF. TODO: Choose the maximum number of iterations for root + // finding based on specific polynomial data? + const uint32_t maxIterations = 128; + int32_t degree = 0; + size_t numRoots = 0; + std::array roots{}; + std::set uniqueRoots{}; + size_t numPairs = 0; + std::array, 16> pairs{}; + double temp = zero; + double sn = zero; + + if (p7.GetDegree() > 0 || p7[0] != zero) { + // H(cs,sn) = p6(cs) + sn * p7(cs) + Polynomial1 phi = p6 * p6 - tmp0 * p7 * p7; + degree = static_cast(phi.GetDegree()); + assert(degree > 0); + numRoots = RootsPolynomial::Find(degree, &phi[0], maxIterations, roots.data()); + for (size_t i = 0; i < numRoots; ++i) { + uniqueRoots.insert(roots[i]); + } + + for (auto const& cs : uniqueRoots) { + if (std::fabs(cs) <= one) { + temp = p7(cs); + if (temp != zero) { + sn = -p6(cs) / temp; + pairs[numPairs++] = std::make_pair(cs, sn); + } + else { + temp = std::max(one - sqr(cs), zero); + sn = std::sqrt(temp); + pairs[numPairs++] = std::make_pair(cs, sn); + if (sn != zero) + pairs[numPairs++] = std::make_pair(cs, -sn); + } + } + } + } + else { + // H(cs,sn) = p6(cs) + degree = static_cast(p6.GetDegree()); + assert(degree > 0); + numRoots = RootsPolynomial::Find(degree, &p6[0], maxIterations, roots.data()); + for (size_t i = 0; i < numRoots; ++i) { + uniqueRoots.insert(roots[i]); + } + + for (auto const& cs : uniqueRoots) { + if (std::fabs(cs) <= one) { + temp = std::max(one - sqr(cs), zero); + sn = std::sqrt(temp); + pairs[numPairs++] = std::make_pair(cs, sn); + if (sn != zero) + pairs[numPairs++] = std::make_pair(cs, -sn); + } + } + } + + for (size_t i = 0; i < numPairs; ++i) { + ClosestInfo& info = candidates[i]; + Vec3d delta = D + r1 * (pairs[i].first * U1 + pairs[i].second * V1); + info.circle1Closest = c0 + delta; + const double N0dDelta = n0.dot(delta); + const double lenN0xDelta = n0.cross(delta).norm(); + if (lenN0xDelta > 0.0) { + const double diff = lenN0xDelta - r0; + info.sqrDistance = sqr(N0dDelta) + sqr(diff); + delta -= N0dDelta * n0; + delta.normalize(); + info.circle0Closest = c0 + r0 * delta; + } + else { + const Vec3d r0U0 = r0 * get_orthogonal(n0, true); + const Vec3d diff = delta - r0U0; + info.sqrDistance = diff.dot(diff); + info.circle0Closest = c0 + r0U0; + } + } + + std::sort(candidates.begin(), candidates.begin() + numPairs); + } + else { + ClosestInfo& info = candidates[0]; + + const double N0dD = n0.dot(D); + const Vec3d normProj = N0dD * n0; + const Vec3d compProj = D - normProj; + Vec3d U = compProj; + const double d = U.norm(); + U.normalize(); + + // The configuration is determined by the relative location of the + // intervals of projection of the circles on to the D-line. + // Circle0 projects to [-r0,r0] and circle1 projects to + // [d-r1,d+r1]. + const double dmr1 = d - r1; + double distance; + if (dmr1 >= r0) { + // d >= r0 + r1 + // The circles are separated (d > r0 + r1) or tangent with one + // outside the other (d = r0 + r1). + distance = dmr1 - r0; + info.circle0Closest = c0 + r0 * U; + info.circle1Closest = c1 - r1 * U; + } + else { + // d < r0 + r1 + // The cases implicitly use the knowledge that d >= 0. + const double dpr1 = d + r1; + if (dpr1 <= r0) { + // Circle1 is inside circle0. + distance = r0 - dpr1; + if (d > 0.0) { + info.circle0Closest = c0 + r0 * U; + info.circle1Closest = c1 + r1 * U; + } + else { + // The circles are concentric, so U = (0,0,0). + // Construct a vector perpendicular to N0 to use for + // closest points. + U = get_orthogonal(n0, true); + info.circle0Closest = c0 + r0 * U; + info.circle1Closest = c1 + r1 * U; + } + } + else if (dmr1 <= -r0) { + // Circle0 is inside circle1. + distance = -r0 - dmr1; + if (d > 0.0) { + info.circle0Closest = c0 - r0 * U; + info.circle1Closest = c1 - r1 * U; + } + else { + // The circles are concentric, so U = (0,0,0). + // Construct a vector perpendicular to N0 to use for + // closest points. + U = get_orthogonal(n0, true); + info.circle0Closest = c0 + r0 * U; + info.circle1Closest = c1 + r1 * U; + } + } + else { + distance = (c1 - c0).norm(); + info.circle0Closest = c0; + info.circle1Closest = c1; + } + } + + info.sqrDistance = distance * distance + N0dD * N0dD; + } + + result.distance_infinite = std::make_optional(DistAndPoints{ std::sqrt(candidates[0].sqrDistance), candidates[0].circle0Closest, candidates[0].circle1Closest }); // TODO /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { assert(measuring != nullptr); @@ -823,3 +1053,6 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& } // namespace Measure } // namespace Slic3r + + +#endif // ENABLE_MEASURE_GIZMO diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 2e17eea5c5..f310d8f9fa 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -1,6 +1,8 @@ #ifndef Slic3r_Measure_hpp_ #define Slic3r_Measure_hpp_ +#if ENABLE_MEASURE_GIZMO + #include #include @@ -191,3 +193,5 @@ inline bool are_perpendicular(const SurfaceFeature& f1, const SurfaceFeature& f2 } // namespace Slic3r #endif // Slic3r_Measure_hpp_ + +#endif // ENABLE_MEASURE_GIZMO diff --git a/src/libslic3r/MeasureUtils.hpp b/src/libslic3r/MeasureUtils.hpp new file mode 100644 index 0000000000..4f84624eac --- /dev/null +++ b/src/libslic3r/MeasureUtils.hpp @@ -0,0 +1,390 @@ +#ifndef Slic3r_MeasureUtils_hpp_ +#define Slic3r_MeasureUtils_hpp_ + +#if ENABLE_MEASURE_GIZMO + +#include + +namespace Slic3r { +namespace Measure { + +// Utility class used to calculate distance circle-circle +// Adaptation of code found in: +// https://github.com/davideberly/GeometricTools/blob/master/GTE/Mathematics/Polynomial1.h + +class Polynomial1 +{ +public: + Polynomial1(std::initializer_list values) + { + // C++ 11 will call the default constructor for + // Polynomial1 p{}, so it is guaranteed that + // values.size() > 0. + m_coefficient.resize(values.size()); + std::copy(values.begin(), values.end(), m_coefficient.begin()); + EliminateLeadingZeros(); + } + + // Construction and destruction. The first constructor creates a + // polynomial of the specified degree but sets all coefficients to + // zero (to ensure initialization). You are responsible for setting + // the coefficients, presumably with the degree-term set to a nonzero + // number. In the second constructor, the degree is the number of + // initializers plus 1, but then adjusted so that coefficient[degree] + // is not zero (unless all initializer values are zero). + explicit Polynomial1(uint32_t degree) + : m_coefficient(static_cast(degree) + 1, 0.0) + {} + + // Eliminate any leading zeros in the polynomial, except in the case + // the degree is 0 and the coefficient is 0. The elimination is + // necessary when arithmetic operations cause a decrease in the degree + // of the result. For example, (1 + x + x^2) + (1 + 2*x - x^2) = + // (2 + 3*x). The inputs both have degree 2, so the result is created + // with degree 2. After the addition we find that the degree is in + // fact 1 and resize the array of coefficients. This function is + // called internally by the arithmetic operators, but it is exposed in + // the public interface in case you need it for your own purposes. + void EliminateLeadingZeros() + { + const size_t size = m_coefficient.size(); + if (size > 1) { + const double zero = 0.0; + int32_t leading; + for (leading = static_cast(size) - 1; leading > 0; --leading) { + if (m_coefficient[leading] != zero) + break; + } + + m_coefficient.resize(++leading); + } + } + + // Set all coefficients to the specified value. + void SetCoefficients(double value) + { + std::fill(m_coefficient.begin(), m_coefficient.end(), value); + } + + inline uint32_t GetDegree() const + { + // By design, m_coefficient.size() > 0. + return static_cast(m_coefficient.size() - 1); + } + + inline const double& operator[](uint32_t i) const { return m_coefficient[i]; } + inline double& operator[](uint32_t i) { return m_coefficient[i]; } + + // Evaluate the polynomial. If the polynomial is invalid, the + // function returns zero. + double operator()(double t) const + { + int32_t i = static_cast(m_coefficient.size()); + double result = m_coefficient[--i]; + for (--i; i >= 0; --i) { + result *= t; + result += m_coefficient[i]; + } + return result; + } + +protected: + // The class is designed so that m_coefficient.size() >= 1. + std::vector m_coefficient; +}; + +Polynomial1 operator * (const Polynomial1& p0, const Polynomial1& p1) +{ + const uint32_t p0Degree = p0.GetDegree(); + const uint32_t p1Degree = p1.GetDegree(); + Polynomial1 result(p0Degree + p1Degree); + result.SetCoefficients(0.0); + for (uint32_t i0 = 0; i0 <= p0Degree; ++i0) { + for (uint32_t i1 = 0; i1 <= p1Degree; ++i1) { + result[i0 + i1] += p0[i0] * p1[i1]; + } + } + return result; +} + +Polynomial1 operator + (const Polynomial1& p0, const Polynomial1& p1) +{ + const uint32_t p0Degree = p0.GetDegree(); + const uint32_t p1Degree = p1.GetDegree(); + uint32_t i; + if (p0Degree >= p1Degree) { + Polynomial1 result(p0Degree); + for (i = 0; i <= p1Degree; ++i) { + result[i] = p0[i] + p1[i]; + } + for (/**/; i <= p0Degree; ++i) { + result[i] = p0[i]; + } + result.EliminateLeadingZeros(); + return result; + } + else { + Polynomial1 result(p1Degree); + for (i = 0; i <= p0Degree; ++i) { + result[i] = p0[i] + p1[i]; + } + for (/**/; i <= p1Degree; ++i) { + result[i] = p1[i]; + } + result.EliminateLeadingZeros(); + return result; + } +} + +Polynomial1 operator - (const Polynomial1& p0, const Polynomial1& p1) +{ + const uint32_t p0Degree = p0.GetDegree(); + const uint32_t p1Degree = p1.GetDegree(); + uint32_t i; + if (p0Degree >= p1Degree) { + Polynomial1 result(p0Degree); + for (i = 0; i <= p1Degree; ++i) { + result[i] = p0[i] - p1[i]; + } + for (/**/; i <= p0Degree; ++i) { + result[i] = p0[i]; + } + result.EliminateLeadingZeros(); + return result; + } + else { + Polynomial1 result(p1Degree); + for (i = 0; i <= p0Degree; ++i) { + result[i] = p0[i] - p1[i]; + } + for (/**/; i <= p1Degree; ++i) { + result[i] = -p1[i]; + } + result.EliminateLeadingZeros(); + return result; + } +} + +Polynomial1 operator * (double scalar, const Polynomial1& p) +{ + const uint32_t degree = p.GetDegree(); + Polynomial1 result(degree); + for (uint32_t i = 0; i <= degree; ++i) { + result[i] = scalar * p[i]; + } + return result; +} + +// Utility class used to calculate distance circle-circle +// Adaptation of code found in: +// https://github.com/davideberly/GeometricTools/blob/master/GTE/Mathematics/RootsPolynomial.h + +class RootsPolynomial +{ +public: + // General equations: sum_{i=0}^{d} c(i)*t^i = 0. The input array 'c' + // must have at least d+1 elements and the output array 'root' must + // have at least d elements. + + // Find the roots on (-infinity,+infinity). + static int32_t Find(int32_t degree, const double* c, uint32_t maxIterations, double* roots) + { + if (degree >= 0 && c != nullptr) { + const double zero = 0.0; + while (degree >= 0 && c[degree] == zero) { + --degree; + } + + if (degree > 0) { + // Compute the Cauchy bound. + const double one = 1.0; + const double invLeading = one / c[degree]; + double maxValue = zero; + for (int32_t i = 0; i < degree; ++i) { + const double value = std::fabs(c[i] * invLeading); + if (value > maxValue) + maxValue = value; + } + const double bound = one + maxValue; + + return FindRecursive(degree, c, -bound, bound, maxIterations, roots); + } + else if (degree == 0) + // The polynomial is a nonzero constant. + return 0; + else { + // The polynomial is identically zero. + roots[0] = zero; + return 1; + } + } + else + // Invalid degree or c. + return 0; + } + + // If you know that p(tmin) * p(tmax) <= 0, then there must be at + // least one root in [tmin, tmax]. Compute it using bisection. + static bool Find(int32_t degree, const double* c, double tmin, double tmax, uint32_t maxIterations, double& root) + { + const double zero = 0.0; + double pmin = Evaluate(degree, c, tmin); + if (pmin == zero) { + root = tmin; + return true; + } + double pmax = Evaluate(degree, c, tmax); + if (pmax == zero) { + root = tmax; + return true; + } + + if (pmin * pmax > zero) + // It is not known whether the interval bounds a root. + return false; + + if (tmin >= tmax) + // Invalid ordering of interval endpoitns. + return false; + + for (uint32_t i = 1; i <= maxIterations; ++i) { + root = 0.5 * (tmin + tmax); + + // This test is designed for 'float' or 'double' when tmin + // and tmax are consecutive floating-point numbers. + if (root == tmin || root == tmax) + break; + + const double p = Evaluate(degree, c, root); + const double product = p * pmin; + if (product < zero) { + tmax = root; + pmax = p; + } + else if (product > zero) { + tmin = root; + pmin = p; + } + else + break; + } + + return true; + } + + // Support for the Find functions. + static int32_t FindRecursive(int32_t degree, double const* c, double tmin, double tmax, uint32_t maxIterations, double* roots) + { + // The base of the recursion. + const double zero = 0.0; + double root = zero; + if (degree == 1) { + int32_t numRoots; + if (c[1] != zero) { + root = -c[0] / c[1]; + numRoots = 1; + } + else if (c[0] == zero) { + root = zero; + numRoots = 1; + } + else + numRoots = 0; + + if (numRoots > 0 && tmin <= root && root <= tmax) { + roots[0] = root; + return 1; + } + return 0; + } + + // Find the roots of the derivative polynomial scaled by 1/degree. + // The scaling avoids the factorial growth in the coefficients; + // for example, without the scaling, the high-order term x^d + // becomes (d!)*x through multiple differentiations. With the + // scaling we instead get x. This leads to better numerical + // behavior of the root finder. + const int32_t derivDegree = degree - 1; + std::vector derivCoeff(static_cast(derivDegree) + 1); + std::vector derivRoots(derivDegree); + for (int32_t i = 0, ip1 = 1; i <= derivDegree; ++i, ++ip1) { + derivCoeff[i] = c[ip1] * (double)(ip1) / (double)degree; + } + const int32_t numDerivRoots = FindRecursive(degree - 1, &derivCoeff[0], tmin, tmax, maxIterations, &derivRoots[0]); + + int32_t numRoots = 0; + if (numDerivRoots > 0) { + // Find root on [tmin,derivRoots[0]]. + if (Find(degree, c, tmin, derivRoots[0], maxIterations, root)) + roots[numRoots++] = root; + + // Find root on [derivRoots[i],derivRoots[i+1]]. + for (int32_t i = 0, ip1 = 1; i <= numDerivRoots - 2; ++i, ++ip1) { + if (Find(degree, c, derivRoots[i], derivRoots[ip1], maxIterations, root)) + roots[numRoots++] = root; + } + + // Find root on [derivRoots[numDerivRoots-1],tmax]. + if (Find(degree, c, derivRoots[static_cast(numDerivRoots) - 1], tmax, maxIterations, root)) + roots[numRoots++] = root; + } + else { + // The polynomial is monotone on [tmin,tmax], so has at most one root. + if (Find(degree, c, tmin, tmax, maxIterations, root)) + roots[numRoots++] = root; + } + return numRoots; + } + + static double Evaluate(int32_t degree, const double* c, double t) + { + int32_t i = degree; + double result = c[i]; + while (--i >= 0) { + result = t * result + c[i]; + } + return result; + } +}; + +// Adaptation of code found in: +// https://github.com/davideberly/GeometricTools/blob/master/GTE/Mathematics/Vector.h + +// Construct a single vector orthogonal to the nonzero input vector. If +// the maximum absolute component occurs at index i, then the orthogonal +// vector U has u[i] = v[i+1], u[i+1] = -v[i], and all other components +// zero. The index addition i+1 is computed modulo N. +Vec3d get_orthogonal(const Vec3d& v, bool unitLength) +{ + double cmax = std::fabs(v[0]); + int32_t imax = 0; + for (int32_t i = 1; i < 3; ++i) { + double c = std::fabs(v[i]); + if (c > cmax) { + cmax = c; + imax = i; + } + } + + Vec3d result = Vec3d::Zero(); + int32_t inext = imax + 1; + if (inext == 3) + inext = 0; + + result[imax] = v[inext]; + result[inext] = -v[imax]; + if (unitLength) { + const double sqrDistance = result[imax] * result[imax] + result[inext] * result[inext]; + const double invLength = 1.0 / std::sqrt(sqrDistance); + result[imax] *= invLength; + result[inext] *= invLength; + } + return result; +} + +} // namespace Slic3r +} // namespace Measure + +#endif // Slic3r_MeasureUtils_hpp_ + +#endif // ENABLE_MEASURE_GIZMO From e3fd2ca48413dbcf746de4294315e955c320d944 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 11 Oct 2022 11:41:15 +0200 Subject: [PATCH 102/250] Fixed warning --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 1976cbcdab..0d53c69385 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -909,7 +909,7 @@ void GLGizmoMeasure::render_dimensioning() m_is_editing_distance_first_frame = true; ImGui::CloseCurrentPopup(); }; - auto action_scale = [this, perform_scale, action_exit](double new_value, double old_value) { + auto action_scale = [perform_scale, action_exit](double new_value, double old_value) { perform_scale(new_value, old_value); action_exit(); }; From 2a7611ebafadde4d8366ef86f77465fad14891d1 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 11 Oct 2022 13:38:07 +0200 Subject: [PATCH 103/250] Measuring: Gizmo measure - Fixed rendering of selected circle features --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 34 ++++++++++++++---------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 0d53c69385..db33135dda 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -329,7 +329,8 @@ void GLGizmoMeasure::on_render() if (m_mode == EMode::BasicSelection) { std::optional curr_feature = mouse_on_object ? m_measuring->get_feature(model_facet_idx, position_on_model.cast()) : std::nullopt; m_curr_point_on_feature_position.reset(); - if (m_curr_feature != curr_feature) { + if (m_curr_feature != curr_feature || + (curr_feature.has_value() && curr_feature->get_type() == Measure::SurfaceFeatureType::Circle && (m_curr_feature != curr_feature || m_last_inv_zoom != inv_zoom))) { m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID); m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID); m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID); @@ -470,7 +471,7 @@ void GLGizmoMeasure::on_render() }; auto render_feature = [this, set_matrix_uniforms](const Measure::SurfaceFeature& feature, const std::vector& colors, - float inv_zoom, bool update_raycasters) { + float inv_zoom, bool update_raycasters_transform) { switch (feature.get_type()) { default: { assert(false); break; } @@ -481,7 +482,7 @@ void GLGizmoMeasure::on_render() set_matrix_uniforms(feature_matrix); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); - if (update_raycasters) { + if (update_raycasters_transform) { auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) it->second->set_transform(feature_matrix); @@ -496,7 +497,7 @@ void GLGizmoMeasure::on_render() set_matrix_uniforms(center_matrix); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); - if (update_raycasters) { + if (update_raycasters_transform) { auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) it->second->set_transform(center_matrix); @@ -504,13 +505,20 @@ void GLGizmoMeasure::on_render() // render circle const Transform3d circle_matrix = m_volume_matrix * Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); set_matrix_uniforms(circle_matrix); - m_circle.model.set_color(colors.back()); - m_circle.model.render(); - if (update_raycasters) { + if (update_raycasters_transform) { + m_circle.model.set_color(colors.back()); + m_circle.model.render(); auto it = m_raycasters.find(CIRCLE_ID); if (it != m_raycasters.end() && it->second != nullptr) it->second->set_transform(circle_matrix); } + else { + GLModel circle; + GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); + circle.init_from(std::move(circle_geometry)); + circle.set_color(colors.back()); + circle.render(); + } break; } case Measure::SurfaceFeatureType::Edge: @@ -523,7 +531,7 @@ void GLGizmoMeasure::on_render() set_matrix_uniforms(point_matrix); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); - if (update_raycasters) { + if (update_raycasters_transform) { auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) it->second->set_transform(point_matrix); @@ -536,7 +544,7 @@ void GLGizmoMeasure::on_render() set_matrix_uniforms(edge_matrix); m_cylinder.model.set_color(colors.back()); m_cylinder.model.render(); - if (update_raycasters) { + if (update_raycasters_transform) { auto it = m_raycasters.find(EDGE_ID); if (it != m_raycasters.end() && it->second != nullptr) it->second->set_transform(edge_matrix); @@ -550,7 +558,7 @@ void GLGizmoMeasure::on_render() set_matrix_uniforms(m_volume_matrix); m_plane_models_cache[idx].set_color(colors.front()); m_plane_models_cache[idx].render(); - if (update_raycasters) { + if (update_raycasters_transform) { auto it = m_raycasters.find(PLANE_ID); if (it != m_raycasters.end() && it->second != nullptr) it->second->set_transform(m_volume_matrix); @@ -602,8 +610,7 @@ void GLGizmoMeasure::on_render() } if (m_selected_features.first.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.first.feature)) { - std::vector colors; - colors.emplace_back(SELECTED_1ST_COLOR); + const std::vector colors = { SELECTED_1ST_COLOR }; render_feature(*m_selected_features.first.feature, colors, inv_zoom, false); if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point) { auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), @@ -613,8 +620,7 @@ void GLGizmoMeasure::on_render() } } if (m_selected_features.second.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.second.feature)) { - std::vector colors; - colors.emplace_back(SELECTED_2ND_COLOR); + const std::vector colors = { SELECTED_2ND_COLOR }; render_feature(*m_selected_features.second.feature, colors, inv_zoom, false); if (m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), From ac167e29adce1c3cc63bd3188d470fa94ec87e1d Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 3 Jun 2022 12:53:02 +0200 Subject: [PATCH 104/250] First implementation of SurfaceMesh --- src/libslic3r/CMakeLists.txt | 1 + src/libslic3r/SurfaceMesh.hpp | 151 ++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 src/libslic3r/SurfaceMesh.hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index a118f6ef39..ac1abe5375 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -253,6 +253,7 @@ set(SLIC3R_SOURCES Surface.hpp SurfaceCollection.cpp SurfaceCollection.hpp + SurfaceMesh.hpp SVG.cpp SVG.hpp Technologies.hpp diff --git a/src/libslic3r/SurfaceMesh.hpp b/src/libslic3r/SurfaceMesh.hpp new file mode 100644 index 0000000000..47d5ed0dcc --- /dev/null +++ b/src/libslic3r/SurfaceMesh.hpp @@ -0,0 +1,151 @@ +#ifndef slic3r_SurfaceMesh_hpp_ +#define slic3r_SurfaceMesh_hpp_ + +#include + +namespace Slic3r { + +class TriangleMesh; + + + +enum Face_index : int; + +class Halfedge_index { + friend class SurfaceMesh; + +public: + Halfedge_index() : m_face(Face_index(-1)), m_side(0) {} + Face_index face() const { return m_face; } + bool is_invalid() const { return int(m_face) < 0; } + bool operator!=(const Halfedge_index& rhs) const { return ! ((*this) == rhs); } + bool operator==(const Halfedge_index& rhs) const { return m_face == rhs.m_face && m_side == rhs.m_side; } + +private: + Halfedge_index(int face_idx, unsigned char side_idx) : m_face(Face_index(face_idx)), m_side(side_idx) {} + + Face_index m_face; + unsigned char m_side; +}; + + + +class Vertex_index { + friend class SurfaceMesh; + +public: + Vertex_index() : m_face(Face_index(-1)), m_vertex_idx(0) {} + bool is_invalid() const { return int(m_face) < 0; } + bool operator==(const Vertex_index& rhs) const = delete; // Use SurfaceMesh::is_same_vertex. + +private: + Vertex_index(int face_idx, unsigned char vertex_idx) : m_face(Face_index(face_idx)), m_vertex_idx(vertex_idx) {} + + Face_index m_face; + unsigned char m_vertex_idx; +}; + + + +class SurfaceMesh { +public: + explicit SurfaceMesh(const indexed_triangle_set& its) + : m_its(its), + m_face_neighbors(its_face_neighbors_par(its)) + {} + SurfaceMesh(const SurfaceMesh&) = delete; + SurfaceMesh& operator=(const SurfaceMesh&) = delete; + + Vertex_index source(Halfedge_index h) const { assert(! h.is_invalid()); return Vertex_index(h.m_face, h.m_side); } + Vertex_index target(Halfedge_index h) const { assert(! h.is_invalid()); return Vertex_index(h.m_face, h.m_side == 2 ? 0 : h.m_side + 1); } + Face_index face(Halfedge_index h) const { assert(! h.is_invalid()); return h.m_face; } + + Halfedge_index next(Halfedge_index h) const { assert(! h.is_invalid()); h.m_side = (h.m_side + 1) % 3; return h; } + Halfedge_index prev(Halfedge_index h) const { assert(! h.is_invalid()); h.m_side = (h.m_side == 0 ? 2 : h.m_side - 1); return h; } + Halfedge_index halfedge(Vertex_index v) const { return Halfedge_index(v.m_face, (v.m_vertex_idx == 0 ? 2 : v.m_vertex_idx - 1)); } + Halfedge_index halfedge(Face_index f) const { return Halfedge_index(f, 0); } + Halfedge_index opposite(Halfedge_index h) const { + if (h.is_invalid()) + return h; + + int face_idx = m_face_neighbors[h.m_face][h.m_side]; + Halfedge_index h_candidate = halfedge(Face_index(face_idx)); + + if (h_candidate.is_invalid()) + return Halfedge_index(); // invalid + + for (int i=0; i<3; ++i) { + if (is_same_vertex(source(h_candidate), target(h))) { + // Meshes in PrusaSlicer should be fixed enough for the following not to happen. + assert(is_same_vertex(target(h_candidate), source(h))); + return h_candidate; + } + h_candidate = next(h_candidate); + } + return Halfedge_index(); // invalid + } + + Halfedge_index next_around_target(Halfedge_index h) const { return opposite(next(h)); } + Halfedge_index prev_around_target(Halfedge_index h) const { Halfedge_index op = opposite(h); return (op.is_invalid() ? Halfedge_index() : prev(op)); } + Halfedge_index next_around_source(Halfedge_index h) const { Halfedge_index op = opposite(h); return (op.is_invalid() ? Halfedge_index() : next(op)); } + Halfedge_index prev_around_source(Halfedge_index h) const { return opposite(prev(h)); } + Halfedge_index halfedge(Vertex_index source, Vertex_index target) const + { + Halfedge_index hi(source.m_face, source.m_vertex_idx); + assert(! hi.is_invalid()); + + const Vertex_index orig_target = this->target(hi); + Vertex_index current_target = orig_target; + + while (! is_same_vertex(current_target, target)) { + hi = next_around_source(hi); + if (hi.is_invalid()) + break; + current_target = this->target(hi); + if (is_same_vertex(current_target, orig_target)) + return Halfedge_index(); // invalid + } + + return hi; + } + + const stl_vertex& point(Vertex_index v) const { return m_its.vertices[m_its.indices[v.m_face][v.m_vertex_idx]]; } + + size_t degree(Vertex_index v) const + { + Halfedge_index h_first = halfedge(v); + Halfedge_index h = next_around_target(h_first); + size_t degree = 2; + while (! h.is_invalid() && h != h_first) { + h = next_around_target(h); + ++degree; + } + return h.is_invalid() ? 0 : degree - 1; + } + + size_t degree(Face_index f) const { + size_t total = 0; + for (unsigned char i=0; i<3; ++i) { + size_t d = degree(Vertex_index(f, i)); + if (d == 0) + return 0; + total += d; + } + assert(total - 6 >= 0); + return total - 6; // we counted 3 halfedges from f, and one more for each neighbor + } + + bool is_border(Halfedge_index h) const { return m_face_neighbors[h.m_face][h.m_side] == -1; } + + bool is_same_vertex(const Vertex_index& a, const Vertex_index& b) const { return m_its.indices[a.m_face][a.m_vertex_idx] == m_its.indices[b.m_face][b.m_vertex_idx]; } + + + +private: + const std::vector m_face_neighbors; + const indexed_triangle_set& m_its; +}; + +} //namespace Slic3r + +#endif // slic3r_SurfaceMesh_hpp_ From 05e2a831f44d56ab2a7cd5d36ff92f58a185929f Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 3 Jun 2022 12:53:34 +0200 Subject: [PATCH 105/250] Added some unit tests (SurfaceMesh) --- tests/libslic3r/CMakeLists.txt | 1 + tests/libslic3r/test_surface_mesh.cpp | 122 ++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 tests/libslic3r/test_surface_mesh.cpp diff --git a/tests/libslic3r/CMakeLists.txt b/tests/libslic3r/CMakeLists.txt index a787208074..ed7d8a92be 100644 --- a/tests/libslic3r/CMakeLists.txt +++ b/tests/libslic3r/CMakeLists.txt @@ -26,6 +26,7 @@ add_executable(${_TEST_NAME}_tests test_voronoi.cpp test_optimizers.cpp test_png_io.cpp + test_surface_mesh.cpp test_timeutils.cpp test_indexed_triangle_set.cpp test_astar.cpp diff --git a/tests/libslic3r/test_surface_mesh.cpp b/tests/libslic3r/test_surface_mesh.cpp new file mode 100644 index 0000000000..34ff356679 --- /dev/null +++ b/tests/libslic3r/test_surface_mesh.cpp @@ -0,0 +1,122 @@ +#include +#include + + +#include + +using namespace Slic3r; + + +// Generate a broken cube mesh. Face 8 is inverted, face 11 is missing. +indexed_triangle_set its_make_cube_broken(double xd, double yd, double zd) +{ + auto x = float(xd), y = float(yd), z = float(zd); + return { + { {0, 1, 2}, {0, 2, 3}, {4, 5, 6}, {4, 6, 7}, + {0, 4, 7}, {0, 7, 1}, {1, 7, 6}, {1, 6, 2}, + {2, 5, 6}, {2, 5, 3}, {4, 0, 3} /*missing face*/ }, + { {x, y, 0}, {x, 0, 0}, {0, 0, 0}, {0, y, 0}, + {x, y, z}, {0, y, z}, {0, 0, z}, {x, 0, z} } + }; +} + + + +TEST_CASE("SurfaceMesh on a cube", "[SurfaceMesh]") { + indexed_triangle_set cube = its_make_cube(1., 1., 1.); + SurfaceMesh sm(cube); + const Halfedge_index hi_first = sm.halfedge(Face_index(0)); + Halfedge_index hi = hi_first; + + REQUIRE(! hi_first.is_invalid()); + + SECTION("next / prev halfedge") { + hi = sm.next(hi); + REQUIRE(hi != hi_first); + hi = sm.next(hi); + hi = sm.next(hi); + REQUIRE(hi == hi_first); + hi = sm.prev(hi); + REQUIRE(hi != hi_first); + hi = sm.prev(hi); + hi = sm.prev(hi); + REQUIRE(hi == hi_first); + } + + SECTION("next_around_target") { + // Check that we get to the same halfedge after applying next_around_target + // four times. + const Vertex_index target_vert = sm.target(hi_first); + for (int i=0; i<4;++i) { + hi = sm.next_around_target(hi); + REQUIRE((hi == hi_first) == (i == 3)); + REQUIRE(sm.is_same_vertex(sm.target(hi), target_vert)); + REQUIRE(! sm.is_border(hi)); + } + } + + SECTION("iterate around target and source") { + hi = sm.next_around_target(hi); + hi = sm.prev_around_target(hi); + hi = sm.prev_around_source(hi); + hi = sm.next_around_source(hi); + REQUIRE(hi == hi_first); + } + + SECTION("opposite") { + const Vertex_index target = sm.target(hi); + const Vertex_index source = sm.source(hi); + hi = sm.opposite(hi); + REQUIRE(sm.is_same_vertex(target, sm.source(hi))); + REQUIRE(sm.is_same_vertex(source, sm.target(hi))); + hi = sm.opposite(hi); + REQUIRE(hi == hi_first); + } + + SECTION("halfedges walk") { + for (int i=0; i<4; ++i) { + hi = sm.next(hi); + hi = sm.opposite(hi); + } + REQUIRE(hi == hi_first); + } + + SECTION("point accessor") { + Halfedge_index hi = sm.halfedge(Face_index(0)); + hi = sm.opposite(hi); + hi = sm.prev(hi); + hi = sm.opposite(hi); + REQUIRE(hi.face() == Face_index(6)); + REQUIRE(sm.point(sm.target(hi)).isApprox(cube.vertices[7])); + } +} + + + + +TEST_CASE("SurfaceMesh on a broken cube", "[SurfaceMesh]") { + indexed_triangle_set cube = its_make_cube_broken(1., 1., 1.); + SurfaceMesh sm(cube); + + SECTION("Check inverted face") { + Halfedge_index hi = sm.halfedge(Face_index(8)); + for (int i=0; i<3; ++i) { + REQUIRE(! hi.is_invalid()); + REQUIRE(sm.is_border(hi)); + } + REQUIRE(hi == sm.halfedge(Face_index(8))); + hi = sm.opposite(hi); + REQUIRE(hi.is_invalid()); + } + + SECTION("missing face") { + Halfedge_index hi = sm.halfedge(Face_index(0)); + for (int i=0; i<3; ++i) + hi = sm.next_around_source(hi); + hi = sm.next(hi); + REQUIRE(sm.is_border(hi)); + REQUIRE(! hi.is_invalid()); + hi = sm.opposite(hi); + REQUIRE(hi.is_invalid()); + } +} From 8833fb7ab4f6c60c65a12ceb48a16f4bf899deec Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 17 Jun 2022 12:19:47 +0200 Subject: [PATCH 106/250] SurfaceMesh testing (to be reverted later) Fixed conflicts while rebasing to master --- src/libslic3r/TriangleMesh.cpp | 11 +- src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | 252 ++++++++++++----------- src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp | 2 + 3 files changed, 147 insertions(+), 118 deletions(-) diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index df820fac92..ef96e2400f 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -885,13 +885,20 @@ Polygon its_convex_hull_2d_above(const indexed_triangle_set &its, const Transfor indexed_triangle_set its_make_cube(double xd, double yd, double zd) { auto x = float(xd), y = float(yd), z = float(zd); - return { + /*return { { {0, 1, 2}, {0, 2, 3}, {4, 5, 6}, {4, 6, 7}, {0, 4, 7}, {0, 7, 1}, {1, 7, 6}, {1, 6, 2}, {2, 6, 5}, {2, 5, 3}, {4, 0, 3}, {4, 3, 5} }, { {x, y, 0}, {x, 0, 0}, {0, 0, 0}, {0, y, 0}, {x, y, z}, {0, y, z}, {0, 0, z}, {x, 0, z} } - }; + };*/ + return { + { {0, 1, 2}, {0, 2, 3}, {4, 5, 6}, {4, 6, 7}, + {0, 4, 7}, {0, 7, 1}, {1, 7, 6}, {1, 6, 2}, + {2, 5, 6}, {2, 5, 3}, {4, 0, 3}, /*{4, 3, 5}*/ }, + { {x, y, 0}, {x, 0, 0}, {0, 0, 0}, {0, y, 0}, + {x, y, z}, {0, y, z}, {0, 0, z}, {x, 0, z} } + }; } indexed_triangle_set its_make_prism(float width, float length, float height) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index 3af58dd960..70bbc92107 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -10,6 +10,7 @@ #include "libslic3r/Geometry/ConvexHull.hpp" #include "libslic3r/Model.hpp" +#include "libslic3r/SurfaceMesh.hpp" #include @@ -21,9 +22,31 @@ namespace GUI { static const Slic3r::ColorRGBA DEFAULT_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.5f }; static const Slic3r::ColorRGBA DEFAULT_HOVER_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.75f }; + + + +// TESTING: +static Halfedge_index hi; +static bool hi_initialized = false; +static std::unique_ptr sm_ptr; +static Vertex_index src; +static Vertex_index tgt; + + + + + + GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) -{} +{ + indexed_triangle_set a = its_make_cone(0.05, .2); + its_rotate_x(a, M_PI); + its_translate(a, stl_vertex(0., 0., .8)); + indexed_triangle_set b = its_make_cylinder(.02, 0.8); + its_merge(a, b); + arrow.init_from(a); +} bool GLGizmoFlatten::on_mouse(const wxMouseEvent &mouse_event) { @@ -37,9 +60,7 @@ bool GLGizmoFlatten::on_mouse(const wxMouseEvent &mouse_event) m_mouse_left_down = true; Selection &selection = m_parent.get_selection(); if (selection.is_single_full_instance()) { - // Rotate the object so the normal points downward: - selection.flattening_rotate(m_planes[m_hover_id].normal); - m_parent.do_rotate(L("Gizmo-Place on Face")); + hi = sm_ptr->halfedge(Face_index(m_hover_id)); } return true; } @@ -101,6 +122,18 @@ void GLGizmoFlatten::on_render() const Selection& selection = m_parent.get_selection(); #if ENABLE_LEGACY_OPENGL_REMOVAL + + + + if (!hi_initialized) { + const indexed_triangle_set & its = m_c->selection_info()->model_object()->volumes.front()->mesh().its; + sm_ptr.reset(new SurfaceMesh(its)); + hi = sm_ptr->halfedge(Face_index(0)); + hi_initialized = true; + } + SurfaceMesh & sm = *sm_ptr; + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader == nullptr) return; @@ -136,8 +169,13 @@ void GLGizmoFlatten::on_render() m_planes[i].vbo.model.set_color(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); m_planes[i].vbo.model.render(); #else - m_planes[i].vbo.set_color(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); - m_planes[i].vbo.render(); + int cur_face = hi.is_invalid() ? 1000000 : sm.face(hi); + for (int i = 0; i < m_planes.size(); ++i) { + m_planes[i].vbo.set_color(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); + if (i == cur_face) + m_planes[i].vbo.set_color(i == m_hover_id ? ColorRGBA(.5f, 0.f, 0.f, 1.f) : ColorRGBA(1.f, 0.f, 0.f, 1.f)); + m_planes[i].vbo.render(); + } #endif // ENABLE_RAYCAST_PICKING #else glsafe(::glColor4fv(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR.data() : DEFAULT_PLANE_COLOR.data())); @@ -150,6 +188,90 @@ void GLGizmoFlatten::on_render() #endif // !ENABLE_LEGACY_OPENGL_REMOVAL } + + + + + ///////////////// + //////////////// + ////////////////// + + auto draw_arrow = [&](const Vec3d& from, const Vec3d& to) -> void { + Vec3d desired_pos = from; + Vec3d desired_dir = to - from; + double desired_len = desired_dir.norm(); + desired_dir.normalize(); + + Transform3d m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); + m.translate(desired_pos); + Eigen::Quaterniond q; + Transform3d rot = Transform3d::Identity(); + rot.matrix().block(0, 0, 3, 3) = q.setFromTwoVectors(Vec3d::UnitZ(), desired_dir).toRotationMatrix(); + Transform3d sc = Transform3d::Identity(); + sc.scale(desired_len); + m = m * sc * rot; + + const Camera & camera = wxGetApp().plater()->get_camera(); + Transform3d view_model_matrix = camera.get_view_matrix() * + Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m; + + shader->set_uniform("view_model_matrix", view_model_matrix); + arrow.render(); + }; + + m_imgui->begin(std::string("DEBUG")); + bool invalid = hi.is_invalid(); + if (invalid) { + if (m_imgui->button(std::string("HALFEDGE INVALID (Click to reset)"))) + hi = sm.halfedge(Face_index(0)); + } + else { + m_imgui->text(sm.is_border(hi) ? "BORDER HALFEDGE !" : "Halfedge is not border"); + m_imgui->text((std::string("Face: ") + std::to_string(int(hi.face()))).c_str()); + m_imgui->text(std::string("Target degree:" + std::to_string(sm.degree(sm.target(hi))))); + m_imgui->text(std::string("Face degree:" + std::to_string(sm.degree(sm.face(hi))))); + } + m_imgui->disabled_begin(invalid); + if (m_imgui->button(std::string("next"))) + hi = sm.next(hi); + if (m_imgui->button(std::string("prev"))) + hi = sm.prev(hi); + if (m_imgui->button(std::string("opposite"))) + hi = sm.opposite(hi); + if (m_imgui->button(std::string("next_around_target"))) + hi = sm.next_around_target(hi); + if (m_imgui->button(std::string("prev_around_target"))) + hi = sm.prev_around_target(hi); + if (m_imgui->button(std::string("next_around_source"))) + hi = sm.next_around_source(hi); + if (m_imgui->button(std::string("prev_around_source"))) + hi = sm.prev_around_source(hi); + if (m_imgui->button(std::string("remember one"))) + src = sm.target(hi); + if (m_imgui->button(std::string("switch to halfedge"))) { + tgt = sm.target(hi); + hi = sm.halfedge(src, tgt); + } + + if (invalid) + m_imgui->disabled_end(); + m_imgui->end(); + + if (!hi.is_invalid()) { + Vec3d a = sm.point(sm.source(hi)).cast(); + Vec3d b = sm.point(sm.target(hi)).cast(); + draw_arrow(a, b); + } + + + ///////////////// + //////////////// + ////////////////// + + + + + glsafe(::glEnable(GL_CULL_FACE)); glsafe(::glDisable(GL_BLEND)); @@ -253,11 +375,11 @@ void GLGizmoFlatten::update_planes() for (const ModelVolume* vol : mo->volumes) { if (vol->type() != ModelVolumeType::MODEL_PART) continue; - TriangleMesh vol_ch = vol->get_convex_hull(); + TriangleMesh vol_ch = vol->mesh(); //vol->get_convex_hull(); vol_ch.transform(vol->get_matrix()); ch.merge(vol_ch); } - ch = ch.convex_hull_3d(); + //ch = ch.convex_hull_3d(); m_planes.clear(); #if ENABLE_RAYCAST_PICKING on_unregister_raycasters_for_picking(); @@ -281,47 +403,17 @@ void GLGizmoFlatten::update_planes() std::vector facet_visited(num_of_facets, false); int facet_queue_cnt = 0; const stl_normal* normal_ptr = nullptr; - int facet_idx = 0; - while (1) { - // Find next unvisited triangle: - for (; facet_idx < num_of_facets; ++ facet_idx) - if (!facet_visited[facet_idx]) { - facet_queue[facet_queue_cnt ++] = facet_idx; - facet_visited[facet_idx] = true; - normal_ptr = &face_normals[facet_idx]; - m_planes.emplace_back(); - break; - } - if (facet_idx == num_of_facets) - break; // Everything was visited already - - while (facet_queue_cnt > 0) { - int facet_idx = facet_queue[-- facet_queue_cnt]; - const stl_normal& this_normal = face_normals[facet_idx]; - if (std::abs(this_normal(0) - (*normal_ptr)(0)) < 0.001 && std::abs(this_normal(1) - (*normal_ptr)(1)) < 0.001 && std::abs(this_normal(2) - (*normal_ptr)(2)) < 0.001) { - const Vec3i face = ch.its.indices[facet_idx]; - for (int j=0; j<3; ++j) - m_planes.back().vertices.emplace_back(ch.its.vertices[face[j]].cast()); - - facet_visited[facet_idx] = true; - for (int j = 0; j < 3; ++ j) - if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && ! facet_visited[neighbor_idx]) - facet_queue[facet_queue_cnt ++] = neighbor_idx; - } - } - m_planes.back().normal = normal_ptr->cast(); + for (size_t i = 0; i < ch.its.indices.size(); ++i) { + const Vec3i & face = ch.its.indices[i]; + m_planes.emplace_back(); + for (int j = 0; j < 3; ++j) + m_planes.back().vertices.emplace_back(ch.its.vertices[face[j]].cast()); + m_planes.back().normal = face_normals[i].cast(); Pointf3s& verts = m_planes.back().vertices; // Now we'll transform all the points into world coordinates, so that the areas, angles and distances // make real sense. verts = transform(verts, inst_matrix); - - // if this is a just a very small triangle, remove it to speed up further calculations (it would be rejected later anyway): - if (verts.size() == 3 && - ((verts[0] - verts[1]).norm() < minimal_side - || (verts[0] - verts[2]).norm() < minimal_side - || (verts[1] - verts[2]).norm() < minimal_side)) - m_planes.pop_back(); } // Let's prepare transformation of the normal vector from mesh to instance coordinates. @@ -353,84 +445,12 @@ void GLGizmoFlatten::update_planes() polygon = Slic3r::Geometry::convex_hull(polygon); polygon = transform(polygon, tr.inverse()); - // Calculate area of the polygons and discard ones that are too small - float& area = m_planes[polygon_id].area; - area = 0.f; - for (unsigned int i = 0; i < polygon.size(); i++) // Shoelace formula - area += polygon[i](0)*polygon[i + 1 < polygon.size() ? i + 1 : 0](1) - polygon[i + 1 < polygon.size() ? i + 1 : 0](0)*polygon[i](1); - area = 0.5f * std::abs(area); - - bool discard = false; - if (area < minimal_area) - discard = true; - else { - // We also check the inner angles and discard polygons with angles smaller than the following threshold - const double angle_threshold = ::cos(10.0 * (double)PI / 180.0); - - for (unsigned int i = 0; i < polygon.size(); ++i) { - const Vec3d& prec = polygon[(i == 0) ? polygon.size() - 1 : i - 1]; - const Vec3d& curr = polygon[i]; - const Vec3d& next = polygon[(i == polygon.size() - 1) ? 0 : i + 1]; - - if ((prec - curr).normalized().dot((next - curr).normalized()) > angle_threshold) { - discard = true; - break; - } - } - } - - if (discard) { - m_planes[polygon_id--] = std::move(m_planes.back()); - m_planes.pop_back(); - continue; - } - // We will shrink the polygon a little bit so it does not touch the object edges: Vec3d centroid = std::accumulate(polygon.begin(), polygon.end(), Vec3d(0.0, 0.0, 0.0)); centroid /= (double)polygon.size(); for (auto& vertex : polygon) vertex = 0.9f*vertex + 0.1f*centroid; - // Polygon is now simple and convex, we'll round the corners to make them look nicer. - // The algorithm takes a vertex, calculates middles of respective sides and moves the vertex - // towards their average (controlled by 'aggressivity'). This is repeated k times. - // In next iterations, the neighbours are not always taken at the middle (to increase the - // rounding effect at the corners, where we need it most). - const unsigned int k = 10; // number of iterations - const float aggressivity = 0.2f; // agressivity - const unsigned int N = polygon.size(); - std::vector> neighbours; - if (k != 0) { - Pointf3s points_out(2*k*N); // vector long enough to store the future vertices - for (unsigned int j=0; j vertices; // should be in fact local in update_planes() #if ENABLE_LEGACY_OPENGL_REMOVAL From bd63320a0028e0ec66d4b8148438adf15896688a Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 3 Jun 2022 15:37:11 +0200 Subject: [PATCH 107/250] Measuring: separated another gizmo --- resources/icons/measure.svg | 13 + src/libslic3r/SurfaceMesh.hpp | 1 + src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 388 ++++++++++++++++++++++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 75 +++++ src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 + src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 1 + 7 files changed, 482 insertions(+) create mode 100644 resources/icons/measure.svg create mode 100644 src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp create mode 100644 src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp diff --git a/resources/icons/measure.svg b/resources/icons/measure.svg new file mode 100644 index 0000000000..275c522251 --- /dev/null +++ b/resources/icons/measure.svg @@ -0,0 +1,13 @@ + + + Layer 1 + + + + + + + + + + \ No newline at end of file diff --git a/src/libslic3r/SurfaceMesh.hpp b/src/libslic3r/SurfaceMesh.hpp index 47d5ed0dcc..e8ada4cd80 100644 --- a/src/libslic3r/SurfaceMesh.hpp +++ b/src/libslic3r/SurfaceMesh.hpp @@ -138,6 +138,7 @@ public: bool is_border(Halfedge_index h) const { return m_face_neighbors[h.m_face][h.m_side] == -1; } bool is_same_vertex(const Vertex_index& a, const Vertex_index& b) const { return m_its.indices[a.m_face][a.m_vertex_idx] == m_its.indices[b.m_face][b.m_vertex_idx]; } + Vec3i get_face_neighbors(Face_index face_id) const { assert(int(face_id) < int(m_face_neighbors.size())); return m_face_neighbors[face_id]; } diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 5a5e2bb5af..cd1e4ba2b3 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -63,6 +63,8 @@ set(SLIC3R_GUI_SOURCES GUI/Gizmos/GLGizmoSimplify.hpp GUI/Gizmos/GLGizmoMmuSegmentation.cpp GUI/Gizmos/GLGizmoMmuSegmentation.hpp + GUI/Gizmos/GLGizmoMeasure.cpp + GUI/Gizmos/GLGizmoMeasure.hpp GUI/GLSelectionRectangle.cpp GUI/GLSelectionRectangle.hpp GUI/GLModel.hpp diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp new file mode 100644 index 0000000000..572ea75dbe --- /dev/null +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -0,0 +1,388 @@ +// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. +#include "GLGizmoMeasure.hpp" +#include "slic3r/GUI/GLCanvas3D.hpp" +#include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/Plater.hpp" + +#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" + +#include "libslic3r/Geometry/ConvexHull.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/SurfaceMesh.hpp" + +#include + +#include + +namespace Slic3r { +namespace GUI { + +static const Slic3r::ColorRGBA DEFAULT_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.5f }; +static const Slic3r::ColorRGBA DEFAULT_HOVER_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.75f }; + +GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) + : GLGizmoBase(parent, icon_filename, sprite_id) +{} + + + +bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) +{ + if (mouse_event.Moving()) { + // only for sure + m_mouse_left_down = false; + return false; + } + if (mouse_event.LeftDown()) { + if (m_hover_id != -1) { + m_mouse_left_down = true; + Selection &selection = m_parent.get_selection(); + if (selection.is_single_full_instance()) { + // Rotate the object so the normal points downward: + selection.flattening_rotate(m_planes[m_hover_id].normal); + m_parent.do_rotate(L("Gizmo-Place on Face")); + } + return true; + } + + // fix: prevent restart gizmo when reselect object + // take responsibility for left up + if (m_parent.get_first_hover_volume_idx() >= 0) m_mouse_left_down = true; + + } else if (mouse_event.LeftUp()) { + if (m_mouse_left_down) { + // responsible for mouse left up after selecting plane + m_mouse_left_down = false; + return true; + } + } else if (mouse_event.Leaving()) { + m_mouse_left_down = false; + } + return false; +} + + + +void GLGizmoMeasure::data_changed() +{ + const Selection & selection = m_parent.get_selection(); + const ModelObject *model_object = nullptr; + if (selection.is_single_full_instance() || + selection.is_from_single_object() ) { + model_object = selection.get_model()->objects[selection.get_object_idx()]; + } + set_flattening_data(model_object); +} + + + +bool GLGizmoMeasure::on_init() +{ + // FIXME m_shortcut_key = WXK_CONTROL_F; + return true; +} + + + +void GLGizmoMeasure::on_set_state() +{ +} + + + +CommonGizmosDataID GLGizmoMeasure::on_get_requirements() const +{ + return CommonGizmosDataID::SelectionInfo; +} + + + +std::string GLGizmoMeasure::on_get_name() const +{ + return _u8L("Measure"); +} + + + +bool GLGizmoMeasure::on_is_activable() const +{ + // This is assumed in GLCanvas3D::do_rotate, do not change this + // without updating that function too. + return m_parent.get_selection().is_single_full_instance(); +} + + + +void GLGizmoMeasure::on_render() +{ + const Selection& selection = m_parent.get_selection(); + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + + shader->start_using(); + + glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); + + glsafe(::glEnable(GL_DEPTH_TEST)); + glsafe(::glEnable(GL_BLEND)); + + if (selection.is_single_full_instance()) { + const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d view_model_matrix = camera.get_view_matrix() * + Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m; + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + if (this->is_plane_update_necessary()) + update_planes(); + for (int i = 0; i < (int)m_planes.size(); ++i) { + m_planes[i].vbo.set_color(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); + m_planes[i].vbo.render(); + } + } + + glsafe(::glEnable(GL_CULL_FACE)); + glsafe(::glDisable(GL_BLEND)); + + shader->stop_using(); +} + + + + + +#if ! ENABLE_LEGACY_OPENGL_REMOVAL + #error NOT IMPLEMENTED +#endif +#if ! ENABLE_GL_SHADERS_ATTRIBUTES + #error NOT IMPLEMENTED +#endif + + + + + +void GLGizmoMeasure::on_render_for_picking() +{ + const Selection& selection = m_parent.get_selection(); + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + + shader->start_using(); + + glsafe(::glDisable(GL_DEPTH_TEST)); + glsafe(::glDisable(GL_BLEND)); + + if (selection.is_single_full_instance() && !wxGetKeyState(WXK_CONTROL)) { + const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d view_model_matrix = camera.get_view_matrix() * + Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m; + + shader->set_uniform("view_model_matrix", view_model_matrix); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + if (this->is_plane_update_necessary()) + update_planes(); + for (int i = 0; i < (int)m_planes.size(); ++i) { + m_planes[i].vbo.set_color(picking_color_component(i)); + m_planes[i].vbo.render(); + } + } + + glsafe(::glEnable(GL_CULL_FACE)); + + shader->stop_using(); +} + + + +void GLGizmoMeasure::set_flattening_data(const ModelObject* model_object) +{ + if (model_object != m_old_model_object) { + m_planes.clear(); + m_planes_valid = false; + } +} + + + +void GLGizmoMeasure::update_planes() +{ + const ModelObject* mo = m_c->selection_info()->model_object(); + TriangleMesh ch; + for (const ModelVolume* vol : mo->volumes) { + if (vol->type() != ModelVolumeType::MODEL_PART) + continue; + TriangleMesh vol_ch = vol->mesh(); + vol_ch.transform(vol->get_matrix()); + ch.merge(vol_ch); + } + m_planes.clear(); + const Transform3d& inst_matrix = mo->instances.front()->get_matrix(); + + // Now we'll go through all the facets and append Points of facets sharing the same normal. + // This part is still performed in mesh coordinate system. + const int num_of_facets = ch.facets_count(); + std::vector face_to_plane(num_of_facets, 0); + const std::vector face_normals = its_face_normals(ch.its); + const std::vector face_neighbors = its_face_neighbors(ch.its); + std::vector facet_queue(num_of_facets, 0); + std::vector facet_visited(num_of_facets, false); + int facet_queue_cnt = 0; + const stl_normal* normal_ptr = nullptr; + int facet_idx = 0; + + auto is_same_normal = [](const stl_normal& a, const stl_normal& b) -> bool { + return (std::abs(a(0) - b(0)) < 0.001 && std::abs(a(1) - b(1)) < 0.001 && std::abs(a(2) - b(2)) < 0.001); + }; + + while (1) { + // Find next unvisited triangle: + for (; facet_idx < num_of_facets; ++ facet_idx) + if (!facet_visited[facet_idx]) { + facet_queue[facet_queue_cnt ++] = facet_idx; + facet_visited[facet_idx] = true; + normal_ptr = &face_normals[facet_idx]; + face_to_plane[facet_idx] = m_planes.size(); + m_planes.emplace_back(); + break; + } + if (facet_idx == num_of_facets) + break; // Everything was visited already + + while (facet_queue_cnt > 0) { + int facet_idx = facet_queue[-- facet_queue_cnt]; + const stl_normal& this_normal = face_normals[facet_idx]; + if (is_same_normal(this_normal, *normal_ptr)) { + const Vec3i& face = ch.its.indices[facet_idx]; + for (int j=0; j<3; ++j) + m_planes.back().vertices.emplace_back(ch.its.vertices[face[j]].cast()); + + facet_visited[facet_idx] = true; + face_to_plane[facet_idx] = m_planes.size() - 1; + for (int j = 0; j < 3; ++ j) + if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && ! facet_visited[neighbor_idx]) + facet_queue[facet_queue_cnt ++] = neighbor_idx; + } + } + m_planes.back().normal = normal_ptr->cast(); + + Pointf3s& verts = m_planes.back().vertices; + // Now we'll transform all the points into world coordinates, so that the areas, angles and distances + // make real sense. + verts = transform(verts, inst_matrix); + } + + // Let's prepare transformation of the normal vector from mesh to instance coordinates. + Geometry::Transformation t(inst_matrix); + Vec3d scaling = t.get_scaling_factor(); + t.set_scaling_factor(Vec3d(1./scaling(0), 1./scaling(1), 1./scaling(2))); + + // Now we'll go through all the polygons, transform the points into xy plane to process them: + for (unsigned int polygon_id=0; polygon_id < m_planes.size(); ++polygon_id) { + Pointf3s& polygon = m_planes[polygon_id].vertices; + const Vec3d& normal = m_planes[polygon_id].normal; + + // transform the normal according to the instance matrix: + Vec3d normal_transformed = t.get_matrix() * normal; + + // We are going to rotate about z and y to flatten the plane + Eigen::Quaterniond q; + Transform3d m = Transform3d::Identity(); + m.matrix().block(0, 0, 3, 3) = q.setFromTwoVectors(normal_transformed, Vec3d::UnitZ()).toRotationMatrix(); + polygon = transform(polygon, m); + + // Now to remove the inner points. We'll misuse Geometry::convex_hull for that, but since + // it works in fixed point representation, we will rescale the polygon to avoid overflows. + // And yes, it is a nasty thing to do. Whoever has time is free to refactor. + Vec3d bb_size = BoundingBoxf3(polygon).size(); + float sf = std::min(1./bb_size(0), 1./bb_size(1)); + Transform3d tr = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), Vec3d(sf, sf, 1.f)); + polygon = transform(polygon, tr); + polygon = Slic3r::Geometry::convex_hull(polygon); + polygon = transform(polygon, tr.inverse()); + + // We will shrink the polygon a little bit so it does not touch the object edges: + Vec3d centroid = std::accumulate(polygon.begin(), polygon.end(), Vec3d(0.0, 0.0, 0.0)); + centroid /= (double)polygon.size(); + for (auto& vertex : polygon) + vertex = 0.95f*vertex + 0.05f*centroid; + + // Raise a bit above the object surface to avoid flickering: + for (auto& b : polygon) + b(2) += 0.1f; + + // Transform back to 3D (and also back to mesh coordinates) + polygon = transform(polygon, inst_matrix.inverse() * m.inverse()); + } + + // We'll sort the planes by area and only keep the 254 largest ones (because of the picking pass limitations): + std::sort(m_planes.rbegin(), m_planes.rend(), [](const PlaneData& a, const PlaneData& b) { return a.area < b.area; }); + m_planes.resize(std::min((int)m_planes.size(), 254)); + + // Planes are finished - let's save what we calculated it from: + m_volumes_matrices.clear(); + m_volumes_types.clear(); + for (const ModelVolume* vol : mo->volumes) { + m_volumes_matrices.push_back(vol->get_matrix()); + m_volumes_types.push_back(vol->type()); + } + m_first_instance_scale = mo->instances.front()->get_scaling_factor(); + m_first_instance_mirror = mo->instances.front()->get_mirror(); + m_old_model_object = mo; + + // And finally create respective VBOs. The polygon is convex with + // the vertices in order, so triangulation is trivial. + for (auto& plane : m_planes) { + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::TriangleFan, GLModel::Geometry::EVertexLayout::P3N3 }; + init_data.reserve_vertices(plane.vertices.size()); + init_data.reserve_indices(plane.vertices.size()); + // vertices + indices + for (size_t i = 0; i < plane.vertices.size(); ++i) { + init_data.add_vertex((Vec3f)plane.vertices[i].cast(), (Vec3f)plane.normal.cast()); + init_data.add_index((unsigned int)i); + } + plane.vbo.init_from(std::move(init_data)); + + // FIXME: vertices should really be local, they need not + // persist now when we use VBOs + plane.vertices.clear(); + plane.vertices.shrink_to_fit(); + } + + m_planes_valid = true; +} + + + +bool GLGizmoMeasure::is_plane_update_necessary() const +{ + const ModelObject* mo = m_c->selection_info()->model_object(); + if (m_state != On || ! mo || mo->instances.empty()) + return false; + + if (! m_planes_valid || mo != m_old_model_object + || mo->volumes.size() != m_volumes_matrices.size()) + return true; + + // We want to recalculate when the scale changes - some planes could (dis)appear. + if (! mo->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale) + || ! mo->instances.front()->get_mirror().isApprox(m_first_instance_mirror)) + return true; + + for (unsigned int i=0; i < mo->volumes.size(); ++i) + if (! mo->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i]) + || mo->volumes[i]->type() != m_volumes_types[i]) + return true; + + return false; +} + +} // namespace GUI +} // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp new file mode 100644 index 0000000000..9bf87a29f6 --- /dev/null +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -0,0 +1,75 @@ +#ifndef slic3r_GLGizmoMeasure_hpp_ +#define slic3r_GLGizmoMeasure_hpp_ + +#include "GLGizmoBase.hpp" +#if ENABLE_LEGACY_OPENGL_REMOVAL +#include "slic3r/GUI/GLModel.hpp" +#else +#include "slic3r/GUI/3DScene.hpp" +#endif // ENABLE_LEGACY_OPENGL_REMOVAL + + +namespace Slic3r { + +enum class ModelVolumeType : int; + + +namespace GUI { + + +class GLGizmoMeasure : public GLGizmoBase +{ +// This gizmo does not use grabbers. The m_hover_id relates to polygon managed by the class itself. + +private: + + struct PlaneData { + std::vector vertices; // should be in fact local in update_planes() + std::vector borders_facets; + GLModel vbo; + Vec3d normal; + float area; + }; + + // This holds information to decide whether recalculation is necessary: + std::vector m_volumes_matrices; + std::vector m_volumes_types; + Vec3d m_first_instance_scale; + Vec3d m_first_instance_mirror; + + std::vector m_planes; + std::vector m_face_to_plane; + bool m_mouse_left_down = false; // for detection left_up of this gizmo + bool m_planes_valid = false; + const ModelObject* m_old_model_object = nullptr; + std::vector instances_matrices; + + void update_planes(); + bool is_plane_update_necessary() const; + void set_flattening_data(const ModelObject* model_object); + +public: + GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); + + /// + /// Apply rotation on select plane + /// + /// Keep information about mouse click + /// Return True when use the information otherwise False. + bool on_mouse(const wxMouseEvent &mouse_event) override; + + void data_changed() override; +protected: + bool on_init() override; + std::string on_get_name() const override; + bool on_is_activable() const override; + void on_render() override; + void on_render_for_picking() override; + void on_set_state() override; + CommonGizmosDataID on_get_requirements() const override; +}; + +} // namespace GUI +} // namespace Slic3r + +#endif // slic3r_GLGizmoMeasure_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 8759e880d7..6d25f84fbc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -21,6 +21,7 @@ #include "slic3r/GUI/Gizmos/GLGizmoSeam.hpp" #include "slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp" #include "slic3r/GUI/Gizmos/GLGizmoSimplify.hpp" +#include "slic3r/GUI/Gizmos/GLGizmoMeasure.hpp" #include "libslic3r/format.hpp" #include "libslic3r/Model.hpp" @@ -106,6 +107,7 @@ bool GLGizmosManager::init() m_gizmos.emplace_back(new GLGizmoSeam(m_parent, "seam.svg", 8)); m_gizmos.emplace_back(new GLGizmoMmuSegmentation(m_parent, "mmu_segmentation.svg", 9)); m_gizmos.emplace_back(new GLGizmoSimplify(m_parent, "cut.svg", 10)); + m_gizmos.emplace_back(new GLGizmoMeasure(m_parent, "measure.svg", 11)); m_common_gizmos_data.reset(new CommonGizmosDataPool(&m_parent)); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 8a708f62a6..a759d911a9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -80,6 +80,7 @@ public: Seam, MmuSegmentation, Simplify, + Measure, Undefined }; From 2df91985520bc0755b203cc5912130df419604c7 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 21 Jun 2022 12:47:47 +0200 Subject: [PATCH 108/250] Measuring: Initial plane detection --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 144 +++++++++++------------ src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 4 +- 2 files changed, 74 insertions(+), 74 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 572ea75dbe..129407764c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -127,6 +127,7 @@ void GLGizmoMeasure::on_render() glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_BLEND)); + glsafe(::glLineWidth(5.f)); if (selection.is_single_full_instance()) { const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); @@ -227,15 +228,14 @@ void GLGizmoMeasure::update_planes() // Now we'll go through all the facets and append Points of facets sharing the same normal. // This part is still performed in mesh coordinate system. - const int num_of_facets = ch.facets_count(); - std::vector face_to_plane(num_of_facets, 0); + const size_t num_of_facets = ch.facets_count(); + std::vector face_to_plane(num_of_facets, size_t(-1)); const std::vector face_normals = its_face_normals(ch.its); const std::vector face_neighbors = its_face_neighbors(ch.its); std::vector facet_queue(num_of_facets, 0); - std::vector facet_visited(num_of_facets, false); int facet_queue_cnt = 0; const stl_normal* normal_ptr = nullptr; - int facet_idx = 0; + size_t seed_facet_idx = 0; auto is_same_normal = [](const stl_normal& a, const stl_normal& b) -> bool { return (std::abs(a(0) - b(0)) < 0.001 && std::abs(a(1) - b(1)) < 0.001 && std::abs(a(2) - b(2)) < 0.001); @@ -243,16 +243,15 @@ void GLGizmoMeasure::update_planes() while (1) { // Find next unvisited triangle: - for (; facet_idx < num_of_facets; ++ facet_idx) - if (!facet_visited[facet_idx]) { - facet_queue[facet_queue_cnt ++] = facet_idx; - facet_visited[facet_idx] = true; - normal_ptr = &face_normals[facet_idx]; - face_to_plane[facet_idx] = m_planes.size(); + for (; seed_facet_idx < num_of_facets; ++ seed_facet_idx) + if (face_to_plane[seed_facet_idx] == size_t(-1)) { + facet_queue[facet_queue_cnt ++] = seed_facet_idx; + normal_ptr = &face_normals[seed_facet_idx]; + face_to_plane[seed_facet_idx] = m_planes.size(); m_planes.emplace_back(); break; } - if (facet_idx == num_of_facets) + if (seed_facet_idx == num_of_facets) break; // Everything was visited already while (facet_queue_cnt > 0) { @@ -260,70 +259,69 @@ void GLGizmoMeasure::update_planes() const stl_normal& this_normal = face_normals[facet_idx]; if (is_same_normal(this_normal, *normal_ptr)) { const Vec3i& face = ch.its.indices[facet_idx]; - for (int j=0; j<3; ++j) - m_planes.back().vertices.emplace_back(ch.its.vertices[face[j]].cast()); - facet_visited[facet_idx] = true; face_to_plane[facet_idx] = m_planes.size() - 1; + m_planes.back().facets.emplace_back(facet_idx); for (int j = 0; j < 3; ++ j) - if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && ! facet_visited[neighbor_idx]) + if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && face_to_plane[neighbor_idx] == size_t(-1)) facet_queue[facet_queue_cnt ++] = neighbor_idx; } } - m_planes.back().normal = normal_ptr->cast(); - Pointf3s& verts = m_planes.back().vertices; - // Now we'll transform all the points into world coordinates, so that the areas, angles and distances - // make real sense. - verts = transform(verts, inst_matrix); + m_planes.back().normal = normal_ptr->cast(); } + assert(std::none_of(face_to_plane.begin(), face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); + + SurfaceMesh sm(ch.its); + for (int plane_id=0; plane_id < m_planes.size(); ++plane_id) { + //int plane_id = 5; { + const auto& facets = m_planes[plane_id].facets; + std::vector pts; + for (int face_id=0; face_id{ sm.point(sm.source(he)).cast() }); + Vertex_index target = sm.target(he); + const Halfedge_index he_start = he; + + do { + const Halfedge_index he_orig = he; + he = sm.next_around_target(he); + while ( face_to_plane[sm.face(he)] == plane_id && he != he_orig) + he = sm.next_around_target(he); + he = sm.opposite(he); + m_planes[plane_id].borders.back().emplace_back(sm.point(sm.source(he)).cast()); + } while (he != he_start); + } + } + + + // DEBUGGING: + //m_planes.erase(std::remove_if(m_planes.begin(), m_planes.end(), [](const PlaneData& p) { return p.borders.empty(); }), m_planes.end()); + + + + + // Let's prepare transformation of the normal vector from mesh to instance coordinates. Geometry::Transformation t(inst_matrix); Vec3d scaling = t.get_scaling_factor(); t.set_scaling_factor(Vec3d(1./scaling(0), 1./scaling(1), 1./scaling(2))); - // Now we'll go through all the polygons, transform the points into xy plane to process them: - for (unsigned int polygon_id=0; polygon_id < m_planes.size(); ++polygon_id) { - Pointf3s& polygon = m_planes[polygon_id].vertices; - const Vec3d& normal = m_planes[polygon_id].normal; - - // transform the normal according to the instance matrix: - Vec3d normal_transformed = t.get_matrix() * normal; - - // We are going to rotate about z and y to flatten the plane - Eigen::Quaterniond q; - Transform3d m = Transform3d::Identity(); - m.matrix().block(0, 0, 3, 3) = q.setFromTwoVectors(normal_transformed, Vec3d::UnitZ()).toRotationMatrix(); - polygon = transform(polygon, m); - - // Now to remove the inner points. We'll misuse Geometry::convex_hull for that, but since - // it works in fixed point representation, we will rescale the polygon to avoid overflows. - // And yes, it is a nasty thing to do. Whoever has time is free to refactor. - Vec3d bb_size = BoundingBoxf3(polygon).size(); - float sf = std::min(1./bb_size(0), 1./bb_size(1)); - Transform3d tr = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), Vec3d(sf, sf, 1.f)); - polygon = transform(polygon, tr); - polygon = Slic3r::Geometry::convex_hull(polygon); - polygon = transform(polygon, tr.inverse()); - - // We will shrink the polygon a little bit so it does not touch the object edges: - Vec3d centroid = std::accumulate(polygon.begin(), polygon.end(), Vec3d(0.0, 0.0, 0.0)); - centroid /= (double)polygon.size(); - for (auto& vertex : polygon) - vertex = 0.95f*vertex + 0.05f*centroid; - - // Raise a bit above the object surface to avoid flickering: - for (auto& b : polygon) - b(2) += 0.1f; - - // Transform back to 3D (and also back to mesh coordinates) - polygon = transform(polygon, inst_matrix.inverse() * m.inverse()); - } - - // We'll sort the planes by area and only keep the 254 largest ones (because of the picking pass limitations): - std::sort(m_planes.rbegin(), m_planes.rend(), [](const PlaneData& a, const PlaneData& b) { return a.area < b.area; }); - m_planes.resize(std::min((int)m_planes.size(), 254)); + // Planes are finished - let's save what we calculated it from: m_volumes_matrices.clear(); @@ -339,21 +337,23 @@ void GLGizmoMeasure::update_planes() // And finally create respective VBOs. The polygon is convex with // the vertices in order, so triangulation is trivial. for (auto& plane : m_planes) { - GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::TriangleFan, GLModel::Geometry::EVertexLayout::P3N3 }; - init_data.reserve_vertices(plane.vertices.size()); - init_data.reserve_indices(plane.vertices.size()); - // vertices + indices - for (size_t i = 0; i < plane.vertices.size(); ++i) { - init_data.add_vertex((Vec3f)plane.vertices[i].cast(), (Vec3f)plane.normal.cast()); - init_data.add_index((unsigned int)i); + for (auto& vertices : plane.borders) { + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3N3 }; + init_data.reserve_vertices(vertices.size()); + init_data.reserve_indices(vertices.size()); + // vertices + indices + for (size_t i = 0; i < vertices.size(); ++i) { + init_data.add_vertex((Vec3f)vertices[i].cast(), (Vec3f)plane.normal.cast()); + init_data.add_index((unsigned int)i); + } + plane.vbo.init_from(std::move(init_data)); } - plane.vbo.init_from(std::move(init_data)); // FIXME: vertices should really be local, they need not // persist now when we use VBOs - plane.vertices.clear(); - plane.vertices.shrink_to_fit(); + plane.borders.clear(); + plane.borders.shrink_to_fit(); } m_planes_valid = true; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 9bf87a29f6..87ad73d8c6 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -24,8 +24,8 @@ class GLGizmoMeasure : public GLGizmoBase private: struct PlaneData { - std::vector vertices; // should be in fact local in update_planes() - std::vector borders_facets; + std::vector> borders; // should be in fact local in update_planes() + std::vector facets; GLModel vbo; Vec3d normal; float area; From 7ae40e281b531ad5e21bc8200c8274c227bfb849 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 22 Jun 2022 10:34:58 +0200 Subject: [PATCH 109/250] Measuring: Simple visualization --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 62 ++++++++++++++++++------ src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 4 +- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 129407764c..de3fc398b9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -17,15 +17,13 @@ namespace Slic3r { namespace GUI { -static const Slic3r::ColorRGBA DEFAULT_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.5f }; -static const Slic3r::ColorRGBA DEFAULT_HOVER_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.75f }; +static const Slic3r::ColorRGBA DEFAULT_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.9f }; +static const Slic3r::ColorRGBA DEFAULT_HOVER_PLANE_COLOR = { 0.9f, 0.2f, 0.2f, 1.f }; GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) {} - - bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) { if (mouse_event.Moving()) { @@ -139,9 +137,29 @@ void GLGizmoMeasure::on_render() shader->set_uniform("projection_matrix", camera.get_projection_matrix()); if (this->is_plane_update_necessary()) update_planes(); - for (int i = 0; i < (int)m_planes.size(); ++i) { - m_planes[i].vbo.set_color(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); - m_planes[i].vbo.render(); + + m_imgui->begin(std::string("DEBUG")); + if (m_imgui->button("<-")) + --m_currently_shown_plane; + ImGui::SameLine(); + if (m_imgui->button("->")) + ++m_currently_shown_plane; + m_currently_shown_plane = std::clamp(m_currently_shown_plane, 0, int(m_planes.size())-1); + m_imgui->text(std::to_string(m_currently_shown_plane)); + m_imgui->end(); + + + //for (int i = 0; i < (int)m_planes.size(); ++i) { + int i = m_currently_shown_plane; + std::cout << m_hover_id << "\t" << m_currently_shown_plane << "\t" << std::endl; + if (i < m_planes.size()) { + for (int j=0; j<(int)m_planes[i].vbos.size(); ++j) { + m_planes[i].vbos[j].set_color(j == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); + if (j == m_hover_id) + m_planes[i].vbos[j].render(); + std::cout << " * " << j; + } + std::cout <get_instance_transformation().get_matrix(); @@ -189,9 +208,13 @@ void GLGizmoMeasure::on_render_for_picking() shader->set_uniform("projection_matrix", camera.get_projection_matrix()); if (this->is_plane_update_necessary()) update_planes(); - for (int i = 0; i < (int)m_planes.size(); ++i) { - m_planes[i].vbo.set_color(picking_color_component(i)); - m_planes[i].vbo.render(); + //for (int i = 0; i < (int)m_planes.size(); ++i) { + int i = m_currently_shown_plane; + if (i < m_planes.size()) { + for (int j=0; j<(int)m_planes[i].vbos.size(); ++j) { + m_planes[i].vbos[j].set_color(picking_color_component(j)); + m_planes[i].vbos[j].render(); + } } } @@ -277,7 +300,7 @@ void GLGizmoMeasure::update_planes() for (int plane_id=0; plane_id < m_planes.size(); ++plane_id) { //int plane_id = 5; { const auto& facets = m_planes[plane_id].facets; - std::vector pts; + std::vector pts; for (int face_id=0; face_id{ sm.point(sm.source(he)).cast() }); + pts.emplace_back(sm.point(sm.source(he)).cast()); Vertex_index target = sm.target(he); const Halfedge_index he_start = he; @@ -303,14 +326,20 @@ void GLGizmoMeasure::update_planes() while ( face_to_plane[sm.face(he)] == plane_id && he != he_orig) he = sm.next_around_target(he); he = sm.opposite(he); - m_planes[plane_id].borders.back().emplace_back(sm.point(sm.source(he)).cast()); + pts.emplace_back(sm.point(sm.source(he)).cast()); } while (he != he_start); + + if (pts.size() != 1) { + m_planes[plane_id].borders.emplace_back(pts); + pts.clear(); + } + } } // DEBUGGING: - //m_planes.erase(std::remove_if(m_planes.begin(), m_planes.end(), [](const PlaneData& p) { return p.borders.empty(); }), m_planes.end()); + m_planes.erase(std::remove_if(m_planes.begin(), m_planes.end(), [](const PlaneData& p) { return p.borders.empty(); }), m_planes.end()); @@ -337,7 +366,7 @@ void GLGizmoMeasure::update_planes() // And finally create respective VBOs. The polygon is convex with // the vertices in order, so triangulation is trivial. for (auto& plane : m_planes) { - for (auto& vertices : plane.borders) { + for (const auto& vertices : plane.borders) { GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3N3 }; init_data.reserve_vertices(vertices.size()); @@ -347,7 +376,8 @@ void GLGizmoMeasure::update_planes() init_data.add_vertex((Vec3f)vertices[i].cast(), (Vec3f)plane.normal.cast()); init_data.add_index((unsigned int)i); } - plane.vbo.init_from(std::move(init_data)); + plane.vbos.emplace_back(); + plane.vbos.back().init_from(std::move(init_data)); } // FIXME: vertices should really be local, they need not diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 87ad73d8c6..32b43e6f84 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -23,10 +23,12 @@ class GLGizmoMeasure : public GLGizmoBase private: + int m_currently_shown_plane = 0; + struct PlaneData { std::vector> borders; // should be in fact local in update_planes() std::vector facets; - GLModel vbo; + std::vector vbos; Vec3d normal; float area; }; From 70ea995f4a13a64975ae98642da3653b0f183711 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 1 Jul 2022 15:51:51 +0200 Subject: [PATCH 110/250] Measuring: First steps on extracting features --- src/libslic3r/SurfaceMesh.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 204 ++++++++++++++++++----- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 20 ++- 3 files changed, 183 insertions(+), 42 deletions(-) diff --git a/src/libslic3r/SurfaceMesh.hpp b/src/libslic3r/SurfaceMesh.hpp index e8ada4cd80..a4b261ceb9 100644 --- a/src/libslic3r/SurfaceMesh.hpp +++ b/src/libslic3r/SurfaceMesh.hpp @@ -17,6 +17,7 @@ class Halfedge_index { public: Halfedge_index() : m_face(Face_index(-1)), m_side(0) {} Face_index face() const { return m_face; } + unsigned char side() const { return m_side; } bool is_invalid() const { return int(m_face) < 0; } bool operator!=(const Halfedge_index& rhs) const { return ! ((*this) == rhs); } bool operator==(const Halfedge_index& rhs) const { return m_face == rhs.m_face && m_side == rhs.m_side; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index de3fc398b9..6c95e70b7f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -22,7 +22,10 @@ static const Slic3r::ColorRGBA DEFAULT_HOVER_PLANE_COLOR = { 0.9f, 0.2f, 0.2f, 1 GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) -{} +{ + m_vbo_sphere.init_from(its_make_sphere(1., M_PI/32.)); + m_vbo_cylinder.init_from(its_make_cylinder(1., 1.)); +} bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) { @@ -125,7 +128,7 @@ void GLGizmoMeasure::on_render() glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_BLEND)); - glsafe(::glLineWidth(5.f)); + glsafe(::glLineWidth(2.f)); if (selection.is_single_full_instance()) { const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); @@ -144,22 +147,47 @@ void GLGizmoMeasure::on_render() ImGui::SameLine(); if (m_imgui->button("->")) ++m_currently_shown_plane; - m_currently_shown_plane = std::clamp(m_currently_shown_plane, 0, int(m_planes.size())-1); - m_imgui->text(std::to_string(m_currently_shown_plane)); + m_currently_shown_plane = std::clamp(m_currently_shown_plane, 0, std::max(0, int(m_planes.size())-1)); + m_imgui->text(std::to_string(m_currently_shown_plane)); + m_imgui->checkbox(wxString("Show all"), m_show_all); m_imgui->end(); - //for (int i = 0; i < (int)m_planes.size(); ++i) { - int i = m_currently_shown_plane; - std::cout << m_hover_id << "\t" << m_currently_shown_plane << "\t" << std::endl; - if (i < m_planes.size()) { + int i = m_show_all ? 0 : m_currently_shown_plane; + for (int i = 0; i < (int)m_planes.size(); ++i) { + // Render all the borders. for (int j=0; j<(int)m_planes[i].vbos.size(); ++j) { m_planes[i].vbos[j].set_color(j == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); - if (j == m_hover_id) m_planes[i].vbos[j].render(); - std::cout << " * " << j; } - std::cout <::FromTwoVectors(Vec3d::UnitZ(), feature.endpoint - feature.pos); + view_feature_matrix *= q; + view_feature_matrix.scale(Vec3d(0.3, 0.3, (feature.endpoint - feature.pos).norm())); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_cylinder.set_color(ColorRGBA(0.7f, 0.7f, 0.f, 1.f)); + m_vbo_cylinder.render(); + } + + view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.pos)); + view_feature_matrix.scale(0.5); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_sphere.set_color(feature.type == SurfaceFeature::Line + ? ColorRGBA(1.f, 0.f, 0.f, 1.f) + : ColorRGBA(0.f, 1.f, 0.f, 1.f)); + m_vbo_sphere.render(); + + + shader->set_uniform("view_model_matrix", view_model_matrix); + } + + if (! m_show_all) + break; } } @@ -196,7 +224,7 @@ void GLGizmoMeasure::on_render_for_picking() glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_BLEND)); - glsafe(::glLineWidth(5.f)); + glsafe(::glLineWidth(2.f)); if (selection.is_single_full_instance() && !wxGetKeyState(WXK_CONTROL)) { const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); @@ -235,6 +263,73 @@ void GLGizmoMeasure::set_flattening_data(const ModelObject* model_object) +void GLGizmoMeasure::extract_features(GLGizmoMeasure::PlaneData& plane) +{ + plane.surface_features.clear(); + const Vec3d& normal = plane.normal; + + const double edge_threshold = 10. * (M_PI/180.); + + + + for (const std::vector& border : plane.borders) { + assert(border.size() > 1); + assert(! border.front().isApprox(border.back())); + double last_angle = 0.; + size_t first_idx = 0; + + for (size_t i=0; i edge_threshold || i == border.size() - 1) { + // Current feature ended. Save it and remember current point as beginning of the next. + bool is_line = (i == first_idx + 1); + plane.surface_features.emplace_back(SurfaceFeature{ + is_line ? SurfaceFeature::Line : SurfaceFeature::Circle, + is_line ? border[first_idx] : border[first_idx], // FIXME + border[i], + 0. // FIXME + }); + first_idx = i; + } else if (Slic3r::is_approx(angle, last_angle)) { + // possibly a segment of a circle + } else { + first_idx = i; + + } + } + last_angle = angle; + } + + // FIXME: Possibly merge the first and last feature. + + + + std::cout << "==================== " << std::endl; + } + + + for (const SurfaceFeature& f : plane.surface_features) { + std::cout << "- detected " << (f.type == SurfaceFeature::Line ? "Line" : "Circle") << std::endl; + std::cout<< f.pos << std::endl << std::endl << f.endpoint << std::endl; + std::cout << "----------------" << std::endl; + } + + + +} + + + void GLGizmoMeasure::update_planes() { const ModelObject* mo = m_c->selection_info()->model_object(); @@ -292,6 +387,7 @@ void GLGizmoMeasure::update_planes() } m_planes.back().normal = normal_ptr->cast(); + std::sort(m_planes.back().facets.begin(), m_planes.back().facets.end()); } assert(std::none_of(face_to_plane.begin(), face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); @@ -300,40 +396,57 @@ void GLGizmoMeasure::update_planes() for (int plane_id=0; plane_id < m_planes.size(); ++plane_id) { //int plane_id = 5; { const auto& facets = m_planes[plane_id].facets; - std::vector pts; + m_planes[plane_id].borders.clear(); + std::vector> visited(facets.size(), {false, false, false}); + for (int face_id=0; face_id()); - Vertex_index target = sm.target(he); - const Halfedge_index he_start = he; - - do { + // he is the first halfedge on the border. Now walk around and append the points. const Halfedge_index he_orig = he; - he = sm.next_around_target(he); - while ( face_to_plane[sm.face(he)] == plane_id && he != he_orig) - he = sm.next_around_target(he); - he = sm.opposite(he); - pts.emplace_back(sm.point(sm.source(he)).cast()); - } while (he != he_start); + m_planes[plane_id].borders.emplace_back(); + m_planes[plane_id].borders.back().emplace_back(sm.point(sm.source(he)).cast()); + Vertex_index target = sm.target(he); + const Halfedge_index he_start = he; + + Face_index fi = he.face(); + auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi)); + assert(face_it != facets.end()); + assert(*face_it == int(fi)); + visited[face_it - facets.begin()][he.side()] = true; - if (pts.size() != 1) { - m_planes[plane_id].borders.emplace_back(pts); - pts.clear(); + do { + const Halfedge_index he_orig = he; + he = sm.next_around_target(he); + while ( face_to_plane[sm.face(he)] == plane_id && he != he_orig) + he = sm.next_around_target(he); + he = sm.opposite(he); + + Face_index fi = he.face(); + auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi)); + assert(face_it != facets.end()); + assert(*face_it == int(fi)); + if (visited[face_it - facets.begin()][he.side()] && he != he_start) { + m_planes[plane_id].borders.back().resize(1); + break; + } + visited[face_it - facets.begin()][he.side()] = true; + + m_planes[plane_id].borders.back().emplace_back(sm.point(sm.source(he)).cast()); + } while (he != he_start); + + if (m_planes[plane_id].borders.back().size() == 1) + m_planes[plane_id].borders.pop_back(); } - } } @@ -365,8 +478,8 @@ void GLGizmoMeasure::update_planes() // And finally create respective VBOs. The polygon is convex with // the vertices in order, so triangulation is trivial. - for (auto& plane : m_planes) { - for (const auto& vertices : plane.borders) { + for (PlaneData& plane : m_planes) { + for (std::vector& vertices : plane.borders) { GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3N3 }; init_data.reserve_vertices(vertices.size()); @@ -378,8 +491,17 @@ void GLGizmoMeasure::update_planes() } plane.vbos.emplace_back(); plane.vbos.back().init_from(std::move(init_data)); + vertices.pop_back(); // first and last are the same } + static int n=0; + std::cout << "==================== " << std::endl; + std::cout << "==================== " << std::endl; + std::cout << "==================== " << std::endl; + std::cout << "Plane num. " << n++ << std::endl; + extract_features(plane); + + // FIXME: vertices should really be local, they need not // persist now when we use VBOs plane.borders.clear(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 32b43e6f84..3099366736 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -24,15 +24,33 @@ class GLGizmoMeasure : public GLGizmoBase private: int m_currently_shown_plane = 0; + bool m_show_all = false; + + GLModel m_vbo_sphere; + GLModel m_vbo_cylinder; + + struct SurfaceFeature { + enum Type { + Circle, + Line + }; + Type type; + Vec3d pos; + Vec3d endpoint; // for type == Line + double radius; // for type == Circle; + }; struct PlaneData { - std::vector> borders; // should be in fact local in update_planes() std::vector facets; + std::vector> borders; // should be in fact local in update_planes() + std::vector surface_features; std::vector vbos; Vec3d normal; float area; }; + static void extract_features(PlaneData& plane); + // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; std::vector m_volumes_types; From 0e372b8eb2a52eb34db60bb7e1f3573b5b9feb02 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 7 Jul 2022 12:30:26 +0200 Subject: [PATCH 111/250] Measuring: Improved visualization --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 50 ++++++++++++++---------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 5 ++- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 6c95e70b7f..0cb1067c39 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -149,12 +149,15 @@ void GLGizmoMeasure::on_render() ++m_currently_shown_plane; m_currently_shown_plane = std::clamp(m_currently_shown_plane, 0, std::max(0, int(m_planes.size())-1)); m_imgui->text(std::to_string(m_currently_shown_plane)); - m_imgui->checkbox(wxString("Show all"), m_show_all); + m_imgui->checkbox(wxString("Show all"), m_show_all_planes); + m_imgui->checkbox(wxString("Show points"), m_show_points); + m_imgui->checkbox(wxString("Show edges"), m_show_edges); + m_imgui->checkbox(wxString("Show circles"), m_show_circles); m_imgui->end(); - int i = m_show_all ? 0 : m_currently_shown_plane; - for (int i = 0; i < (int)m_planes.size(); ++i) { + int i = m_show_all_planes ? 0 : m_currently_shown_plane; + for (; i < (int)m_planes.size(); ++i) { // Render all the borders. for (int j=0; j<(int)m_planes[i].vbos.size(); ++j) { m_planes[i].vbos[j].set_color(j == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); @@ -165,7 +168,7 @@ void GLGizmoMeasure::on_render() // Render features: for (const SurfaceFeature& feature : m_planes[i].surface_features) { Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.pos)); - if (feature.type == SurfaceFeature::Line) { + if (m_show_edges && feature.type == SurfaceFeature::Line) { auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), feature.endpoint - feature.pos); view_feature_matrix *= q; view_feature_matrix.scale(Vec3d(0.3, 0.3, (feature.endpoint - feature.pos).norm())); @@ -174,19 +177,21 @@ void GLGizmoMeasure::on_render() m_vbo_cylinder.render(); } - view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.pos)); - view_feature_matrix.scale(0.5); - shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_sphere.set_color(feature.type == SurfaceFeature::Line - ? ColorRGBA(1.f, 0.f, 0.f, 1.f) - : ColorRGBA(0.f, 1.f, 0.f, 1.f)); - m_vbo_sphere.render(); + if (m_show_points && feature.type == SurfaceFeature::Line || m_show_circles && feature.type == SurfaceFeature::Circle) { + view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.pos)); + view_feature_matrix.scale(0.5); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_sphere.set_color(feature.type == SurfaceFeature::Line + ? ColorRGBA(1.f, 0.f, 0.f, 1.f) + : ColorRGBA(0.f, 1.f, 0.f, 1.f)); + m_vbo_sphere.render(); + } shader->set_uniform("view_model_matrix", view_model_matrix); } - if (! m_show_all) + if (! m_show_all_planes) break; } } @@ -268,7 +273,7 @@ void GLGizmoMeasure::extract_features(GLGizmoMeasure::PlaneData& plane) plane.surface_features.clear(); const Vec3d& normal = plane.normal; - const double edge_threshold = 10. * (M_PI/180.); + const double edge_threshold = 25. * (M_PI/180.); @@ -276,9 +281,10 @@ void GLGizmoMeasure::extract_features(GLGizmoMeasure::PlaneData& plane) assert(border.size() > 1); assert(! border.front().isApprox(border.back())); double last_angle = 0.; - size_t first_idx = 0; + int first_idx = 0; + bool circle = false; - for (size_t i=0; i edge_threshold || i == border.size() - 1) { + bool same_as_last = Slic3r::is_approx(angle, last_angle); + + if (std::abs(angle) > edge_threshold || (! same_as_last && circle) || i == border.size() - 1) { // Current feature ended. Save it and remember current point as beginning of the next. bool is_line = (i == first_idx + 1); plane.surface_features.emplace_back(SurfaceFeature{ @@ -300,11 +308,13 @@ void GLGizmoMeasure::extract_features(GLGizmoMeasure::PlaneData& plane) 0. // FIXME }); first_idx = i; - } else if (Slic3r::is_approx(angle, last_angle)) { + circle = false; + } else if (same_as_last && ! circle) { // possibly a segment of a circle - } else { + first_idx = std::max(i-2, 0); + circle = true; + } else if (! circle) { first_idx = i; - } } last_angle = angle; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 3099366736..9534796a71 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -24,7 +24,10 @@ class GLGizmoMeasure : public GLGizmoBase private: int m_currently_shown_plane = 0; - bool m_show_all = false; + bool m_show_all_planes = false; + bool m_show_points = true; + bool m_show_edges = true; + bool m_show_circles = true; GLModel m_vbo_sphere; GLModel m_vbo_cylinder; From 4c5fa7a857aa711d4988982de0336c56f31be958 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 13 Jul 2022 16:37:16 +0200 Subject: [PATCH 112/250] Measuring: Improved feature detection, added circle center calculation --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 120 ++++++++++++++--------- 1 file changed, 75 insertions(+), 45 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 0cb1067c39..e00d587814 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -9,6 +9,7 @@ #include "libslic3r/Geometry/ConvexHull.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/SurfaceMesh.hpp" +#include "libslic3r/Geometry/Circle.hpp" #include @@ -177,7 +178,7 @@ void GLGizmoMeasure::on_render() m_vbo_cylinder.render(); } - if (m_show_points && feature.type == SurfaceFeature::Line || m_show_circles && feature.type == SurfaceFeature::Circle) { + if ((m_show_points && feature.type == SurfaceFeature::Line) || m_show_circles && feature.type == SurfaceFeature::Circle) { view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.pos)); view_feature_matrix.scale(0.5); shader->set_uniform("view_model_matrix", view_feature_matrix); @@ -185,6 +186,14 @@ void GLGizmoMeasure::on_render() ? ColorRGBA(1.f, 0.f, 0.f, 1.f) : ColorRGBA(0.f, 1.f, 0.f, 1.f)); m_vbo_sphere.render(); + + /*view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.endpoint)); + view_feature_matrix.scale(0.5); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_sphere.set_color(feature.type == SurfaceFeature::Line + ? ColorRGBA(1.f, 0.f, 0.f, 1.f) + : ColorRGBA(1.f, 1.f, 0.f, 1.f)); + m_vbo_sphere.render();*/ } @@ -243,7 +252,7 @@ void GLGizmoMeasure::on_render_for_picking() update_planes(); //for (int i = 0; i < (int)m_planes.size(); ++i) { int i = m_currently_shown_plane; - if (i < m_planes.size()) { + if (i < int(m_planes.size())) { for (int j=0; j<(int)m_planes[i].vbos.size(); ++j) { m_planes[i].vbos[j].set_color(picking_color_component(j)); m_planes[i].vbos[j].render(); @@ -268,60 +277,84 @@ void GLGizmoMeasure::set_flattening_data(const ModelObject* model_object) +static std::pair get_center_and_radius(const std::vector& border, int start_idx, int end_idx, const Transform3d& trafo) +{ + Vec2ds pts; + double z = 0.; + for (int i=start_idx; i<=end_idx; ++i) { + Vec3d pt_transformed = trafo * border[i]; + z = pt_transformed.z(); + pts.emplace_back(pt_transformed.x(), pt_transformed.y()); + } + + auto circle = Geometry::circle_ransac(pts, 20); // FIXME: iterations? + + return std::make_pair(trafo.inverse() * Vec3d(circle.center.x(), circle.center.y(), z), circle.radius); +} + + + void GLGizmoMeasure::extract_features(GLGizmoMeasure::PlaneData& plane) { plane.surface_features.clear(); const Vec3d& normal = plane.normal; const double edge_threshold = 25. * (M_PI/180.); + std::vector angles; + + Eigen::Quaterniond q; + q.setFromTwoVectors(plane.normal, Vec3d::UnitZ()); + Transform3d trafo = Transform3d::Identity(); + trafo.rotate(q); for (const std::vector& border : plane.borders) { assert(border.size() > 1); assert(! border.front().isApprox(border.back())); - double last_angle = 0.; - int first_idx = 0; - bool circle = false; + int start_idx = -1; + + // First calculate angles at all the vertices. + angles.clear(); for (int i=0; i edge_threshold || (! same_as_last && circle) || i == border.size() - 1) { - // Current feature ended. Save it and remember current point as beginning of the next. - bool is_line = (i == first_idx + 1); - plane.surface_features.emplace_back(SurfaceFeature{ - is_line ? SurfaceFeature::Line : SurfaceFeature::Circle, - is_line ? border[first_idx] : border[first_idx], // FIXME - border[i], - 0. // FIXME - }); - first_idx = i; - circle = false; - } else if (same_as_last && ! circle) { - // possibly a segment of a circle - first_idx = std::max(i-2, 0); + + bool circle = false; + std::vector> circles; + for (int i=1; i center_and_radius = get_center_and_radius(border, start_idx, end_idx, trafo); + plane.surface_features.emplace_back(SurfaceFeature{ + SurfaceFeature::Circle, + // border[start_idx], border[end_idx], + center_and_radius.first, center_and_radius.first, center_and_radius.second + }); + } std::cout << "==================== " << std::endl; @@ -352,7 +385,7 @@ void GLGizmoMeasure::update_planes() ch.merge(vol_ch); } m_planes.clear(); - const Transform3d& inst_matrix = mo->instances.front()->get_matrix(); + // Now we'll go through all the facets and append Points of facets sharing the same normal. // This part is still performed in mesh coordinate system. @@ -403,13 +436,13 @@ void GLGizmoMeasure::update_planes() assert(std::none_of(face_to_plane.begin(), face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); SurfaceMesh sm(ch.its); - for (int plane_id=0; plane_id < m_planes.size(); ++plane_id) { + for (int plane_id=0; plane_id < int(m_planes.size()); ++plane_id) { //int plane_id = 5; { const auto& facets = m_planes[plane_id].facets; m_planes[plane_id].borders.clear(); std::vector> visited(facets.size(), {false, false, false}); - for (int face_id=0; face_id()); - Vertex_index target = sm.target(he); + std::vector& last_border = m_planes[plane_id].borders.back(); + last_border.emplace_back(sm.point(sm.source(he)).cast()); + //Vertex_index target = sm.target(he); const Halfedge_index he_start = he; Face_index fi = he.face(); @@ -446,15 +480,15 @@ void GLGizmoMeasure::update_planes() assert(face_it != facets.end()); assert(*face_it == int(fi)); if (visited[face_it - facets.begin()][he.side()] && he != he_start) { - m_planes[plane_id].borders.back().resize(1); + last_border.resize(1); break; } visited[face_it - facets.begin()][he.side()] = true; - m_planes[plane_id].borders.back().emplace_back(sm.point(sm.source(he)).cast()); + last_border.emplace_back(sm.point(sm.source(he)).cast()); } while (he != he_start); - if (m_planes[plane_id].borders.back().size() == 1) + if (last_border.size() == 1) m_planes[plane_id].borders.pop_back(); } } @@ -468,11 +502,7 @@ void GLGizmoMeasure::update_planes() - // Let's prepare transformation of the normal vector from mesh to instance coordinates. - Geometry::Transformation t(inst_matrix); - Vec3d scaling = t.get_scaling_factor(); - t.set_scaling_factor(Vec3d(1./scaling(0), 1./scaling(1), 1./scaling(2))); - + // Planes are finished - let's save what we calculated it from: From 9d5e9e887078c3ca149ab5194948688390c8698e Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 26 Jul 2022 10:12:59 +0200 Subject: [PATCH 113/250] Measuring: Separating frontend and backend --- src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/Measure.cpp | 323 ++++++++++++++++ src/libslic3r/Measure.hpp | 98 +++++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 448 ++++------------------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 43 +-- 5 files changed, 499 insertions(+), 415 deletions(-) create mode 100644 src/libslic3r/Measure.cpp create mode 100644 src/libslic3r/Measure.hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index ac1abe5375..a52848b229 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -180,6 +180,8 @@ set(SLIC3R_SOURCES MultiMaterialSegmentation.hpp MeshNormals.hpp MeshNormals.cpp + Measure.hpp + Measure.cpp CustomGCode.cpp CustomGCode.hpp Arrange.hpp diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp new file mode 100644 index 0000000000..d5cb9c24b3 --- /dev/null +++ b/src/libslic3r/Measure.cpp @@ -0,0 +1,323 @@ +#include "Measure.hpp" + +#include "libslic3r/Geometry/Circle.hpp" +#include "libslic3r/SurfaceMesh.hpp" + + + +namespace Slic3r { +namespace Measure { + + + +static std::pair get_center_and_radius(const std::vector& border, int start_idx, int end_idx, const Transform3d& trafo) +{ + Vec2ds pts; + double z = 0.; + for (int i=start_idx; i<=end_idx; ++i) { + Vec3d pt_transformed = trafo * border[i]; + z = pt_transformed.z(); + pts.emplace_back(pt_transformed.x(), pt_transformed.y()); + } + + auto circle = Geometry::circle_ransac(pts, 20); // FIXME: iterations? + + return std::make_pair(trafo.inverse() * Vec3d(circle.center.x(), circle.center.y(), z), circle.radius); +} + + + + +class MeasuringImpl { +public: + explicit MeasuringImpl(const indexed_triangle_set& its); + struct PlaneData { + std::vector facets; + std::vector> borders; // FIXME: should be in fact local in update_planes() + std::vector> surface_features; + Vec3d normal; + float area; + }; + + const std::vector& get_features() const; + +private: + void update_planes(); + void extract_features(PlaneData& plane); + void save_features(); + + + std::vector m_planes; + std::vector m_features; + const indexed_triangle_set& m_its; +}; + + + + + + +MeasuringImpl::MeasuringImpl(const indexed_triangle_set& its) +: m_its{its} +{ + update_planes(); + + for (PlaneData& plane : m_planes) { + extract_features(plane); + + plane.borders.clear(); + plane.borders.shrink_to_fit(); + } + + save_features(); +} + + +void MeasuringImpl::update_planes() +{ + m_planes.clear(); + + // Now we'll go through all the facets and append Points of facets sharing the same normal. + // This part is still performed in mesh coordinate system. + const size_t num_of_facets = m_its.indices.size(); + std::vector face_to_plane(num_of_facets, size_t(-1)); + const std::vector face_normals = its_face_normals(m_its); + const std::vector face_neighbors = its_face_neighbors(m_its); + std::vector facet_queue(num_of_facets, 0); + int facet_queue_cnt = 0; + const stl_normal* normal_ptr = nullptr; + size_t seed_facet_idx = 0; + + auto is_same_normal = [](const stl_normal& a, const stl_normal& b) -> bool { + return (std::abs(a(0) - b(0)) < 0.001 && std::abs(a(1) - b(1)) < 0.001 && std::abs(a(2) - b(2)) < 0.001); + }; + + while (1) { + // Find next unvisited triangle: + for (; seed_facet_idx < num_of_facets; ++ seed_facet_idx) + if (face_to_plane[seed_facet_idx] == size_t(-1)) { + facet_queue[facet_queue_cnt ++] = seed_facet_idx; + normal_ptr = &face_normals[seed_facet_idx]; + face_to_plane[seed_facet_idx] = m_planes.size(); + m_planes.emplace_back(); + break; + } + if (seed_facet_idx == num_of_facets) + break; // Everything was visited already + + while (facet_queue_cnt > 0) { + int facet_idx = facet_queue[-- facet_queue_cnt]; + const stl_normal& this_normal = face_normals[facet_idx]; + if (is_same_normal(this_normal, *normal_ptr)) { + const Vec3i& face = m_its.indices[facet_idx]; + + face_to_plane[facet_idx] = m_planes.size() - 1; + m_planes.back().facets.emplace_back(facet_idx); + for (int j = 0; j < 3; ++ j) + if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && face_to_plane[neighbor_idx] == size_t(-1)) + facet_queue[facet_queue_cnt ++] = neighbor_idx; + } + } + + m_planes.back().normal = normal_ptr->cast(); + std::sort(m_planes.back().facets.begin(), m_planes.back().facets.end()); + } + + assert(std::none_of(face_to_plane.begin(), face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); + + SurfaceMesh sm(m_its); + for (int plane_id=0; plane_id < int(m_planes.size()); ++plane_id) { + //int plane_id = 5; { + const auto& facets = m_planes[plane_id].facets; + m_planes[plane_id].borders.clear(); + std::vector> visited(facets.size(), {false, false, false}); + + for (int face_id=0; face_id& last_border = m_planes[plane_id].borders.back(); + last_border.emplace_back(sm.point(sm.source(he)).cast()); + //Vertex_index target = sm.target(he); + const Halfedge_index he_start = he; + + Face_index fi = he.face(); + auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi)); + assert(face_it != facets.end()); + assert(*face_it == int(fi)); + visited[face_it - facets.begin()][he.side()] = true; + + do { + const Halfedge_index he_orig = he; + he = sm.next_around_target(he); + while ( face_to_plane[sm.face(he)] == plane_id && he != he_orig) + he = sm.next_around_target(he); + he = sm.opposite(he); + + Face_index fi = he.face(); + auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi)); + assert(face_it != facets.end()); + assert(*face_it == int(fi)); + if (visited[face_it - facets.begin()][he.side()] && he != he_start) { + last_border.resize(1); + break; + } + visited[face_it - facets.begin()][he.side()] = true; + + last_border.emplace_back(sm.point(sm.source(he)).cast()); + } while (he != he_start); + + if (last_border.size() == 1) + m_planes[plane_id].borders.pop_back(); + } + } + } + + m_planes.erase(std::remove_if(m_planes.begin(), m_planes.end(), + [](const PlaneData& p) { return p.borders.empty(); }), + m_planes.end()); +} + + + + + + +void MeasuringImpl::extract_features(PlaneData& plane) +{ + plane.surface_features.clear(); + const Vec3d& normal = plane.normal; + + const double edge_threshold = 25. * (M_PI/180.); + std::vector angles; + + Eigen::Quaterniond q; + q.setFromTwoVectors(plane.normal, Vec3d::UnitZ()); + Transform3d trafo = Transform3d::Identity(); + trafo.rotate(q); + + + + for (const std::vector& border : plane.borders) { + assert(border.size() > 1); + int start_idx = -1; + + + // First calculate angles at all the vertices. + angles.clear(); + for (int i=0; i> circles; + for (int i=1; i circles[cidx].first) + i = circles[cidx++].second; + else plane.surface_features.emplace_back(std::unique_ptr( + new Edge(border[i-1], border[i]))); + } + + // FIXME Throw away / do not create edges which are parts of circles. + + // FIXME Check and maybe merge first and last circle. + + for (const auto& [start_idx, end_idx] : circles) { + std::pair center_and_radius = get_center_and_radius(border, start_idx, end_idx, trafo); + plane.surface_features.emplace_back(std::unique_ptr( + new Circle(center_and_radius.first, center_and_radius.second) + )); + } + + } +} + + + +void MeasuringImpl::save_features() +{ + m_features.clear(); + for (PlaneData& plane : m_planes) + //PlaneData& plane = m_planes[0]; + { + for (std::unique_ptr& feature : plane.surface_features) { + m_features.emplace_back(feature.get()); + } + } +} + + + +const std::vector& MeasuringImpl::get_features() const +{ + return m_features; +} + + + + + + + + + + + + + +Measuring::Measuring(const indexed_triangle_set& its) +: priv{std::make_unique(its)} +{} + +Measuring::~Measuring() {} + + +const std::vector& Measuring::get_features() const +{ + return priv->get_features(); +} + + + + + + +} // namespace Measure +} // namespace Slic3r diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp new file mode 100644 index 0000000000..bbc7d9e1e9 --- /dev/null +++ b/src/libslic3r/Measure.hpp @@ -0,0 +1,98 @@ +#ifndef Slic3r_Measure_hpp_ +#define Slic3r_Measure_hpp_ + +#include + +#include "Point.hpp" + + +struct indexed_triangle_set; + + + +namespace Slic3r { +namespace Measure { + + +enum class SurfaceFeatureType { + Edge = 1 << 0, + Circle = 1 << 1, + Plane = 1 << 2 + }; + +class SurfaceFeature { +public: + virtual SurfaceFeatureType get_type() const = 0; +}; + +class Edge : public SurfaceFeature { +public: + Edge(const Vec3d& start, const Vec3d& end) : m_start{start}, m_end{end} {} + SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Edge; } + std::pair get_edge() const { return std::make_pair(m_start, m_end); } +private: + Vec3d m_start; + Vec3d m_end; +}; + +class Circle : public SurfaceFeature { +public: + Circle(const Vec3d& center, double radius) : m_center{center}, m_radius{radius} {} + SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Circle; } + Vec3d get_center() const { return m_center; } + double get_radius() const { return m_radius; } +private: + Vec3d m_center; + double m_radius; +}; + +class Plane : public SurfaceFeature { +public: + SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Plane; } + +}; + + +class MeasuringImpl; + + +class Measuring { +public: + // Construct the measurement object on a given its. The its must remain + // valid and unchanged during the whole lifetime of the object. + explicit Measuring(const indexed_triangle_set& its); + ~Measuring(); + + // Return a reference to a list of all features identified on the its. + const std::vector& get_features() const; + + // Given a face_idx where the mouse cursor points, return a feature that + // should be highlighted or nullptr. + const SurfaceFeature* get_feature(size_t face_idx, const Vec3d& point) const; + + // Returns distance between two SurfaceFeatures. + static double get_distance(const SurfaceFeature* a, const SurfaceFeature* b); + + // Returns true if an x/y/z distance between features makes sense. + // If so, result contains the distances. + static bool get_distances(const SurfaceFeature* a, const SurfaceFeature* b, std::array& result); + + // Returns true if an x/y/z distance between feature and a point makes sense. + // If so, result contains the distances. + static bool get_axis_aligned_distances(const SurfaceFeature* feature, const Vec3d* pt, std::array& result); + + // Returns true if measuring angles between features makes sense. + // If so, result contains the angle in radians. + static bool get_angle(const SurfaceFeature* a, const SurfaceFeature* b, double& result); + + +private: + + std::unique_ptr priv; +}; + + +} // namespace Measure +} // namespace Slic3r + +#endif // Slic3r_Measure_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index e00d587814..043adba976 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -6,10 +6,8 @@ #include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" -#include "libslic3r/Geometry/ConvexHull.hpp" #include "libslic3r/Model.hpp" -#include "libslic3r/SurfaceMesh.hpp" -#include "libslic3r/Geometry/Circle.hpp" +#include "libslic3r/Measure.hpp" #include @@ -30,6 +28,10 @@ GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filen bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) { + m_mouse_pos_x = mouse_event.GetX(); + m_mouse_pos_y = mouse_event.GetY(); + + if (mouse_event.Moving()) { // only for sure m_mouse_left_down = false; @@ -38,12 +40,7 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) if (mouse_event.LeftDown()) { if (m_hover_id != -1) { m_mouse_left_down = true; - Selection &selection = m_parent.get_selection(); - if (selection.is_single_full_instance()) { - // Rotate the object so the normal points downward: - selection.flattening_rotate(m_planes[m_hover_id].normal); - m_parent.do_rotate(L("Gizmo-Place on Face")); - } + return true; } @@ -94,7 +91,7 @@ void GLGizmoMeasure::on_set_state() CommonGizmosDataID GLGizmoMeasure::on_get_requirements() const { - return CommonGizmosDataID::SelectionInfo; + return CommonGizmosDataID(int(CommonGizmosDataID::SelectionInfo) | int(CommonGizmosDataID::Raycaster)); } @@ -139,70 +136,59 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - if (this->is_plane_update_necessary()) - update_planes(); + + + update_if_needed(); + m_imgui->begin(std::string("DEBUG")); - if (m_imgui->button("<-")) - --m_currently_shown_plane; - ImGui::SameLine(); - if (m_imgui->button("->")) - ++m_currently_shown_plane; - m_currently_shown_plane = std::clamp(m_currently_shown_plane, 0, std::max(0, int(m_planes.size())-1)); - m_imgui->text(std::to_string(m_currently_shown_plane)); - m_imgui->checkbox(wxString("Show all"), m_show_all_planes); - m_imgui->checkbox(wxString("Show points"), m_show_points); - m_imgui->checkbox(wxString("Show edges"), m_show_edges); - m_imgui->checkbox(wxString("Show circles"), m_show_circles); - m_imgui->end(); + + m_imgui->checkbox(wxString("Show all features"), m_show_all); + + Vec3f pos; + Vec3f normal; + size_t facet_idx; + m_c->raycaster()->raycasters().front()->unproject_on_mesh(Vec2d(m_mouse_pos_x, m_mouse_pos_y), m, camera, pos, normal, nullptr, &facet_idx); + ImGui::Separator(); + m_imgui->text(std::string("face_idx: ") + std::to_string(facet_idx)); + m_imgui->text(std::string("pos_x: ") + std::to_string(pos.x())); + m_imgui->text(std::string("pos_y: ") + std::to_string(pos.y())); + m_imgui->text(std::string("pos_z: ") + std::to_string(pos.z())); - int i = m_show_all_planes ? 0 : m_currently_shown_plane; - for (; i < (int)m_planes.size(); ++i) { - // Render all the borders. - for (int j=0; j<(int)m_planes[i].vbos.size(); ++j) { - m_planes[i].vbos[j].set_color(j == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); - m_planes[i].vbos[j].render(); - } + + if (m_show_all) { + const std::vector features = m_measuring->get_features(); + for (const Measure::SurfaceFeature* feature : features) { + + if (feature->get_type() == Measure::SurfaceFeatureType::Circle) { + const auto* circle = static_cast(feature); + Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(circle->get_center())); + view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(circle->get_center())); + view_feature_matrix.scale(0.5); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_sphere.set_color(ColorRGBA(0.f, 1.f, 0.f, 1.f)); + m_vbo_sphere.render(); + } - // Render features: - for (const SurfaceFeature& feature : m_planes[i].surface_features) { - Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.pos)); - if (m_show_edges && feature.type == SurfaceFeature::Line) { - auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), feature.endpoint - feature.pos); + else if (feature->get_type() == Measure::SurfaceFeatureType::Edge) { + const auto* edge = static_cast(feature); + auto& [start, end] = edge->get_edge(); + Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(start)); + auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); view_feature_matrix *= q; - view_feature_matrix.scale(Vec3d(0.3, 0.3, (feature.endpoint - feature.pos).norm())); + view_feature_matrix.scale(Vec3d(0.075, 0.075, (end - start).norm())); shader->set_uniform("view_model_matrix", view_feature_matrix); m_vbo_cylinder.set_color(ColorRGBA(0.7f, 0.7f, 0.f, 1.f)); m_vbo_cylinder.render(); } - if ((m_show_points && feature.type == SurfaceFeature::Line) || m_show_circles && feature.type == SurfaceFeature::Circle) { - view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.pos)); - view_feature_matrix.scale(0.5); - shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_sphere.set_color(feature.type == SurfaceFeature::Line - ? ColorRGBA(1.f, 0.f, 0.f, 1.f) - : ColorRGBA(0.f, 1.f, 0.f, 1.f)); - m_vbo_sphere.render(); - - /*view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.endpoint)); - view_feature_matrix.scale(0.5); - shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_sphere.set_color(feature.type == SurfaceFeature::Line - ? ColorRGBA(1.f, 0.f, 0.f, 1.f) - : ColorRGBA(1.f, 1.f, 0.f, 1.f)); - m_vbo_sphere.render();*/ - } - - shader->set_uniform("view_model_matrix", view_model_matrix); } - - if (! m_show_all_planes) - break; + shader->set_uniform("view_model_matrix", view_model_matrix); } + m_imgui->end(); } glsafe(::glEnable(GL_CULL_FACE)); @@ -222,290 +208,45 @@ void GLGizmoMeasure::on_render() #error NOT IMPLEMENTED #endif - - - - void GLGizmoMeasure::on_render_for_picking() { - const Selection& selection = m_parent.get_selection(); - - GLShaderProgram* shader = wxGetApp().get_shader("flat"); - if (shader == nullptr) - return; - - shader->start_using(); - - glsafe(::glDisable(GL_DEPTH_TEST)); - glsafe(::glDisable(GL_BLEND)); - glsafe(::glLineWidth(2.f)); - - if (selection.is_single_full_instance() && !wxGetKeyState(WXK_CONTROL)) { - const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); - const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d view_model_matrix = camera.get_view_matrix() * - Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m; - - shader->set_uniform("view_model_matrix", view_model_matrix); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - if (this->is_plane_update_necessary()) - update_planes(); - //for (int i = 0; i < (int)m_planes.size(); ++i) { - int i = m_currently_shown_plane; - if (i < int(m_planes.size())) { - for (int j=0; j<(int)m_planes[i].vbos.size(); ++j) { - m_planes[i].vbos[j].set_color(picking_color_component(j)); - m_planes[i].vbos[j].render(); - } - } - } - - glsafe(::glEnable(GL_CULL_FACE)); - - shader->stop_using(); } void GLGizmoMeasure::set_flattening_data(const ModelObject* model_object) { - if (model_object != m_old_model_object) { - m_planes.clear(); - m_planes_valid = false; - } + if (model_object != m_old_model_object) + update_if_needed(); } - -static std::pair get_center_and_radius(const std::vector& border, int start_idx, int end_idx, const Transform3d& trafo) -{ - Vec2ds pts; - double z = 0.; - for (int i=start_idx; i<=end_idx; ++i) { - Vec3d pt_transformed = trafo * border[i]; - z = pt_transformed.z(); - pts.emplace_back(pt_transformed.x(), pt_transformed.y()); - } - - auto circle = Geometry::circle_ransac(pts, 20); // FIXME: iterations? - - return std::make_pair(trafo.inverse() * Vec3d(circle.center.x(), circle.center.y(), z), circle.radius); -} - - - -void GLGizmoMeasure::extract_features(GLGizmoMeasure::PlaneData& plane) -{ - plane.surface_features.clear(); - const Vec3d& normal = plane.normal; - - const double edge_threshold = 25. * (M_PI/180.); - std::vector angles; - - Eigen::Quaterniond q; - q.setFromTwoVectors(plane.normal, Vec3d::UnitZ()); - Transform3d trafo = Transform3d::Identity(); - trafo.rotate(q); - - - - for (const std::vector& border : plane.borders) { - assert(border.size() > 1); - assert(! border.front().isApprox(border.back())); - int start_idx = -1; - - - // First calculate angles at all the vertices. - angles.clear(); - for (int i=0; i> circles; - for (int i=1; i center_and_radius = get_center_and_radius(border, start_idx, end_idx, trafo); - plane.surface_features.emplace_back(SurfaceFeature{ - SurfaceFeature::Circle, - // border[start_idx], border[end_idx], - center_and_radius.first, center_and_radius.first, center_and_radius.second - }); - } - - - std::cout << "==================== " << std::endl; - } - - - for (const SurfaceFeature& f : plane.surface_features) { - std::cout << "- detected " << (f.type == SurfaceFeature::Line ? "Line" : "Circle") << std::endl; - std::cout<< f.pos << std::endl << std::endl << f.endpoint << std::endl; - std::cout << "----------------" << std::endl; - } - - - -} - - - -void GLGizmoMeasure::update_planes() +void GLGizmoMeasure::update_if_needed() { const ModelObject* mo = m_c->selection_info()->model_object(); - TriangleMesh ch; - for (const ModelVolume* vol : mo->volumes) { - if (vol->type() != ModelVolumeType::MODEL_PART) - continue; - TriangleMesh vol_ch = vol->mesh(); - vol_ch.transform(vol->get_matrix()); - ch.merge(vol_ch); - } - m_planes.clear(); - + if (m_state != On || ! mo || mo->instances.empty()) + return; - // Now we'll go through all the facets and append Points of facets sharing the same normal. - // This part is still performed in mesh coordinate system. - const size_t num_of_facets = ch.facets_count(); - std::vector face_to_plane(num_of_facets, size_t(-1)); - const std::vector face_normals = its_face_normals(ch.its); - const std::vector face_neighbors = its_face_neighbors(ch.its); - std::vector facet_queue(num_of_facets, 0); - int facet_queue_cnt = 0; - const stl_normal* normal_ptr = nullptr; - size_t seed_facet_idx = 0; + if (! m_measuring || mo != m_old_model_object + || mo->volumes.size() != m_volumes_matrices.size()) + goto UPDATE; - auto is_same_normal = [](const stl_normal& a, const stl_normal& b) -> bool { - return (std::abs(a(0) - b(0)) < 0.001 && std::abs(a(1) - b(1)) < 0.001 && std::abs(a(2) - b(2)) < 0.001); - }; + // We want to recalculate when the scale changes - some planes could (dis)appear. + if (! mo->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale) + || ! mo->instances.front()->get_mirror().isApprox(m_first_instance_mirror)) + goto UPDATE; - while (1) { - // Find next unvisited triangle: - for (; seed_facet_idx < num_of_facets; ++ seed_facet_idx) - if (face_to_plane[seed_facet_idx] == size_t(-1)) { - facet_queue[facet_queue_cnt ++] = seed_facet_idx; - normal_ptr = &face_normals[seed_facet_idx]; - face_to_plane[seed_facet_idx] = m_planes.size(); - m_planes.emplace_back(); - break; - } - if (seed_facet_idx == num_of_facets) - break; // Everything was visited already + for (unsigned int i=0; i < mo->volumes.size(); ++i) + if (! mo->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i]) + || mo->volumes[i]->type() != m_volumes_types[i]) + goto UPDATE; - while (facet_queue_cnt > 0) { - int facet_idx = facet_queue[-- facet_queue_cnt]; - const stl_normal& this_normal = face_normals[facet_idx]; - if (is_same_normal(this_normal, *normal_ptr)) { - const Vec3i& face = ch.its.indices[facet_idx]; + return; - face_to_plane[facet_idx] = m_planes.size() - 1; - m_planes.back().facets.emplace_back(facet_idx); - for (int j = 0; j < 3; ++ j) - if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && face_to_plane[neighbor_idx] == size_t(-1)) - facet_queue[facet_queue_cnt ++] = neighbor_idx; - } - } +UPDATE: + m_measuring.reset(new Measure::Measuring(mo->volumes.front()->mesh().its)); - m_planes.back().normal = normal_ptr->cast(); - std::sort(m_planes.back().facets.begin(), m_planes.back().facets.end()); - } - - assert(std::none_of(face_to_plane.begin(), face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); - - SurfaceMesh sm(ch.its); - for (int plane_id=0; plane_id < int(m_planes.size()); ++plane_id) { - //int plane_id = 5; { - const auto& facets = m_planes[plane_id].facets; - m_planes[plane_id].borders.clear(); - std::vector> visited(facets.size(), {false, false, false}); - - for (int face_id=0; face_id& last_border = m_planes[plane_id].borders.back(); - last_border.emplace_back(sm.point(sm.source(he)).cast()); - //Vertex_index target = sm.target(he); - const Halfedge_index he_start = he; - - Face_index fi = he.face(); - auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi)); - assert(face_it != facets.end()); - assert(*face_it == int(fi)); - visited[face_it - facets.begin()][he.side()] = true; - - do { - const Halfedge_index he_orig = he; - he = sm.next_around_target(he); - while ( face_to_plane[sm.face(he)] == plane_id && he != he_orig) - he = sm.next_around_target(he); - he = sm.opposite(he); - - Face_index fi = he.face(); - auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi)); - assert(face_it != facets.end()); - assert(*face_it == int(fi)); - if (visited[face_it - facets.begin()][he.side()] && he != he_start) { - last_border.resize(1); - break; - } - visited[face_it - facets.begin()][he.side()] = true; - - last_border.emplace_back(sm.point(sm.source(he)).cast()); - } while (he != he_start); - - if (last_border.size() == 1) - m_planes[plane_id].borders.pop_back(); - } - } - } - - - // DEBUGGING: - m_planes.erase(std::remove_if(m_planes.begin(), m_planes.end(), [](const PlaneData& p) { return p.borders.empty(); }), m_planes.end()); - - - - - - - - - // Planes are finished - let's save what we calculated it from: + // Let's save what we calculated it from: m_volumes_matrices.clear(); m_volumes_types.clear(); for (const ModelVolume* vol : mo->volumes) { @@ -515,65 +256,6 @@ void GLGizmoMeasure::update_planes() m_first_instance_scale = mo->instances.front()->get_scaling_factor(); m_first_instance_mirror = mo->instances.front()->get_mirror(); m_old_model_object = mo; - - // And finally create respective VBOs. The polygon is convex with - // the vertices in order, so triangulation is trivial. - for (PlaneData& plane : m_planes) { - for (std::vector& vertices : plane.borders) { - GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3N3 }; - init_data.reserve_vertices(vertices.size()); - init_data.reserve_indices(vertices.size()); - // vertices + indices - for (size_t i = 0; i < vertices.size(); ++i) { - init_data.add_vertex((Vec3f)vertices[i].cast(), (Vec3f)plane.normal.cast()); - init_data.add_index((unsigned int)i); - } - plane.vbos.emplace_back(); - plane.vbos.back().init_from(std::move(init_data)); - vertices.pop_back(); // first and last are the same - } - - static int n=0; - std::cout << "==================== " << std::endl; - std::cout << "==================== " << std::endl; - std::cout << "==================== " << std::endl; - std::cout << "Plane num. " << n++ << std::endl; - extract_features(plane); - - - // FIXME: vertices should really be local, they need not - // persist now when we use VBOs - plane.borders.clear(); - plane.borders.shrink_to_fit(); - } - - m_planes_valid = true; -} - - - -bool GLGizmoMeasure::is_plane_update_necessary() const -{ - const ModelObject* mo = m_c->selection_info()->model_object(); - if (m_state != On || ! mo || mo->instances.empty()) - return false; - - if (! m_planes_valid || mo != m_old_model_object - || mo->volumes.size() != m_volumes_matrices.size()) - return true; - - // We want to recalculate when the scale changes - some planes could (dis)appear. - if (! mo->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale) - || ! mo->instances.front()->get_mirror().isApprox(m_first_instance_mirror)) - return true; - - for (unsigned int i=0; i < mo->volumes.size(); ++i) - if (! mo->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i]) - || mo->volumes[i]->type() != m_volumes_types[i]) - return true; - - return false; } } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 9534796a71..2781d2b353 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -9,10 +9,15 @@ #endif // ENABLE_LEGACY_OPENGL_REMOVAL +#include + + namespace Slic3r { enum class ModelVolumeType : int; +namespace Measure { class Measuring; } + namespace GUI { @@ -22,53 +27,27 @@ class GLGizmoMeasure : public GLGizmoBase // This gizmo does not use grabbers. The m_hover_id relates to polygon managed by the class itself. private: - - int m_currently_shown_plane = 0; - bool m_show_all_planes = false; - bool m_show_points = true; - bool m_show_edges = true; - bool m_show_circles = true; + std::unique_ptr m_measuring; GLModel m_vbo_sphere; GLModel m_vbo_cylinder; - struct SurfaceFeature { - enum Type { - Circle, - Line - }; - Type type; - Vec3d pos; - Vec3d endpoint; // for type == Line - double radius; // for type == Circle; - }; - - struct PlaneData { - std::vector facets; - std::vector> borders; // should be in fact local in update_planes() - std::vector surface_features; - std::vector vbos; - Vec3d normal; - float area; - }; - - static void extract_features(PlaneData& plane); - // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; std::vector m_volumes_types; Vec3d m_first_instance_scale; Vec3d m_first_instance_mirror; - std::vector m_planes; - std::vector m_face_to_plane; bool m_mouse_left_down = false; // for detection left_up of this gizmo bool m_planes_valid = false; const ModelObject* m_old_model_object = nullptr; std::vector instances_matrices; - void update_planes(); - bool is_plane_update_necessary() const; + int m_mouse_pos_x; + int m_mouse_pos_y; + bool m_show_all = true; + + void update_if_needed(); void set_flattening_data(const ModelObject* model_object); public: From 7d6d33f92c9becccc942d0bccd662164b9a1830f Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 27 Jul 2022 09:58:21 +0200 Subject: [PATCH 114/250] Measuring: further separating frontend and backend --- src/libslic3r/Measure.cpp | 236 +++++++++++++++-------- src/libslic3r/Measure.hpp | 24 ++- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 91 ++++++--- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 4 +- 4 files changed, 233 insertions(+), 122 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index d5cb9c24b3..a8ee3d3265 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -39,16 +39,19 @@ public: float area; }; - const std::vector& get_features() const; + const std::vector& get_features() const; + const SurfaceFeature* get_feature(size_t face_idx, const Vec3d& point) const; + const std::vector> get_planes_triangle_indices() const; private: void update_planes(); - void extract_features(PlaneData& plane); + void extract_features(); void save_features(); std::vector m_planes; - std::vector m_features; + std::vector m_face_to_plane; + std::vector m_features; const indexed_triangle_set& m_its; }; @@ -61,14 +64,7 @@ MeasuringImpl::MeasuringImpl(const indexed_triangle_set& its) : m_its{its} { update_planes(); - - for (PlaneData& plane : m_planes) { - extract_features(plane); - - plane.borders.clear(); - plane.borders.shrink_to_fit(); - } - + extract_features(); save_features(); } @@ -80,7 +76,7 @@ void MeasuringImpl::update_planes() // Now we'll go through all the facets and append Points of facets sharing the same normal. // This part is still performed in mesh coordinate system. const size_t num_of_facets = m_its.indices.size(); - std::vector face_to_plane(num_of_facets, size_t(-1)); + m_face_to_plane.resize(num_of_facets, size_t(-1)); const std::vector face_normals = its_face_normals(m_its); const std::vector face_neighbors = its_face_neighbors(m_its); std::vector facet_queue(num_of_facets, 0); @@ -95,10 +91,10 @@ void MeasuringImpl::update_planes() while (1) { // Find next unvisited triangle: for (; seed_facet_idx < num_of_facets; ++ seed_facet_idx) - if (face_to_plane[seed_facet_idx] == size_t(-1)) { + if (m_face_to_plane[seed_facet_idx] == size_t(-1)) { facet_queue[facet_queue_cnt ++] = seed_facet_idx; normal_ptr = &face_normals[seed_facet_idx]; - face_to_plane[seed_facet_idx] = m_planes.size(); + m_face_to_plane[seed_facet_idx] = m_planes.size(); m_planes.emplace_back(); break; } @@ -111,10 +107,10 @@ void MeasuringImpl::update_planes() if (is_same_normal(this_normal, *normal_ptr)) { const Vec3i& face = m_its.indices[facet_idx]; - face_to_plane[facet_idx] = m_planes.size() - 1; + m_face_to_plane[facet_idx] = m_planes.size() - 1; m_planes.back().facets.emplace_back(facet_idx); for (int j = 0; j < 3; ++ j) - if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && face_to_plane[neighbor_idx] == size_t(-1)) + if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && m_face_to_plane[neighbor_idx] == size_t(-1)) facet_queue[facet_queue_cnt ++] = neighbor_idx; } } @@ -123,7 +119,7 @@ void MeasuringImpl::update_planes() std::sort(m_planes.back().facets.begin(), m_planes.back().facets.end()); } - assert(std::none_of(face_to_plane.begin(), face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); + assert(std::none_of(m_face_to_plane.begin(), m_face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); SurfaceMesh sm(m_its); for (int plane_id=0; plane_id < int(m_planes.size()); ++plane_id) { @@ -133,9 +129,9 @@ void MeasuringImpl::update_planes() std::vector> visited(facets.size(), {false, false, false}); for (int face_id=0; face_id angles; - Eigen::Quaterniond q; - q.setFromTwoVectors(plane.normal, Vec3d::UnitZ()); - Transform3d trafo = Transform3d::Identity(); - trafo.rotate(q); - - - for (const std::vector& border : plane.borders) { - assert(border.size() > 1); - int start_idx = -1; + for (int i=0; i& border : plane.borders) { + assert(border.size() > 1); + int start_idx = -1; + + // First calculate angles at all the vertices. + angles.clear(); + for (int i=0; i> circles; - for (int i=1; i> circles; + for (int i=1; i circles[cidx].first) + i = circles[cidx++].second; + else plane.surface_features.emplace_back(std::unique_ptr( + new Edge(border[i-1], border[i]))); + } + + // FIXME Throw away / do not create edges which are parts of circles or + // which lead to circle points (unless they belong to the same plane.) + + // FIXME Check and merge first and last circle if needed. + + // Now create the circle-typed surface features. + for (const auto& [start_idx, end_idx] : circles) { + std::pair center_and_radius = get_center_and_radius(border, start_idx, end_idx, trafo); + plane.surface_features.emplace_back(std::unique_ptr( + new Circle(center_and_radius.first, center_and_radius.second))); + } + } - // We have the circles. Now go around again and pick edges. - int cidx = 0; // index of next circle in the way - for (int i=1; i circles[cidx].first) - i = circles[cidx++].second; - else plane.surface_features.emplace_back(std::unique_ptr( - new Edge(border[i-1], border[i]))); - } - - // FIXME Throw away / do not create edges which are parts of circles. - - // FIXME Check and maybe merge first and last circle. - - for (const auto& [start_idx, end_idx] : circles) { - std::pair center_and_radius = get_center_and_radius(border, start_idx, end_idx, trafo); - plane.surface_features.emplace_back(std::unique_ptr( - new Circle(center_and_radius.first, center_and_radius.second) - )); - } + // The last surface feature is the plane itself. + plane.surface_features.emplace_back(std::unique_ptr( + new Plane(i))); + plane.borders.clear(); + plane.borders.shrink_to_fit(); } } @@ -277,7 +284,7 @@ void MeasuringImpl::save_features() for (PlaneData& plane : m_planes) //PlaneData& plane = m_planes[0]; { - for (std::unique_ptr& feature : plane.surface_features) { + for (const std::unique_ptr& feature : plane.surface_features) { m_features.emplace_back(feature.get()); } } @@ -285,13 +292,51 @@ void MeasuringImpl::save_features() -const std::vector& MeasuringImpl::get_features() const +const SurfaceFeature* MeasuringImpl::get_feature(size_t face_idx, const Vec3d& point) const +{ + if (face_idx >= m_face_to_plane.size()) + return nullptr; + + const PlaneData& plane = m_planes[m_face_to_plane[face_idx]]; + + const SurfaceFeature* closest_feature = nullptr; + double min_dist = std::numeric_limits::max(); + + for (const std::unique_ptr& feature : plane.surface_features) { + double dist = Measuring::get_distance(feature.get(), &point); + if (dist < 0.5 && dist < min_dist) { + min_dist = std::min(dist, min_dist); + closest_feature = feature.get(); + } + } + + if (closest_feature) + return closest_feature; + + // Nothing detected, return the plane as a whole. + assert(plane.surface_features.back().get()->get_type() == SurfaceFeatureType::Plane); + return plane.surface_features.back().get(); +} + + + +const std::vector& MeasuringImpl::get_features() const { return m_features; } +const std::vector> MeasuringImpl::get_planes_triangle_indices() const +{ + std::vector> out; + for (const PlaneData& plane : m_planes) + out.emplace_back(plane.facets); + return out; +} + + + @@ -309,12 +354,39 @@ Measuring::Measuring(const indexed_triangle_set& its) Measuring::~Measuring() {} -const std::vector& Measuring::get_features() const +const std::vector& Measuring::get_features() const { return priv->get_features(); } +const SurfaceFeature* Measuring::get_feature(size_t face_idx, const Vec3d& point) const +{ + return priv->get_feature(face_idx, point); +} + + + +const std::vector> Measuring::get_planes_triangle_indices() const +{ + return priv->get_planes_triangle_indices(); +} + + + +double Measuring::get_distance(const SurfaceFeature* feature, const Vec3d* pt) +{ + if (feature->get_type() == SurfaceFeatureType::Edge) { + const Edge* edge = static_cast(feature); + const auto& [s,e] = edge->get_edge(); + Eigen::ParametrizedLine line(s, (e-s).normalized()); + return line.distance(*pt); + } + + return std::numeric_limits::max(); +} + + diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index bbc7d9e1e9..1360b47ff7 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -48,8 +48,12 @@ private: class Plane : public SurfaceFeature { public: + Plane(int idx) : m_idx(idx) {} SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Plane; } + int get_plane_idx() const { return m_idx; } // index into vector provided by Measuring::get_plane_triangle_indices +private: + int m_idx; }; @@ -64,30 +68,30 @@ public: ~Measuring(); // Return a reference to a list of all features identified on the its. - const std::vector& get_features() const; + [[deprecated]]const std::vector& get_features() const; // Given a face_idx where the mouse cursor points, return a feature that // should be highlighted or nullptr. const SurfaceFeature* get_feature(size_t face_idx, const Vec3d& point) const; + // Returns a list of triangle indices for each identified plane. Each + // Plane object contains an index into this vector. + const std::vector> get_planes_triangle_indices() const; + + + // Returns distance between two SurfaceFeatures. static double get_distance(const SurfaceFeature* a, const SurfaceFeature* b); - // Returns true if an x/y/z distance between features makes sense. - // If so, result contains the distances. - static bool get_distances(const SurfaceFeature* a, const SurfaceFeature* b, std::array& result); - - // Returns true if an x/y/z distance between feature and a point makes sense. - // If so, result contains the distances. - static bool get_axis_aligned_distances(const SurfaceFeature* feature, const Vec3d* pt, std::array& result); + // Returns distance between a SurfaceFeature and a point. + static double get_distance(const SurfaceFeature* a, const Vec3d* pt); // Returns true if measuring angles between features makes sense. // If so, result contains the angle in radians. static bool get_angle(const SurfaceFeature* a, const SurfaceFeature* b, double& result); -private: - +private: std::unique_ptr priv; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 043adba976..a8b257a937 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -144,6 +144,7 @@ void GLGizmoMeasure::on_render() m_imgui->begin(std::string("DEBUG")); m_imgui->checkbox(wxString("Show all features"), m_show_all); + m_imgui->checkbox(wxString("Show all planes"), m_show_planes); Vec3f pos; Vec3f normal; @@ -157,37 +158,51 @@ void GLGizmoMeasure::on_render() - if (m_show_all) { - const std::vector features = m_measuring->get_features(); - for (const Measure::SurfaceFeature* feature : features) { + std::vector features = {m_measuring->get_feature(facet_idx, pos.cast())}; + if (m_show_all) { + features = m_measuring->get_features(); + features.erase(std::remove_if(features.begin(), features.end(), + [](const Measure::SurfaceFeature* f) { + return f->get_type() == Measure::SurfaceFeatureType::Plane; + }), features.end()); + } + + + for (const Measure::SurfaceFeature* feature : features) { + if (! feature) + continue; - if (feature->get_type() == Measure::SurfaceFeatureType::Circle) { - const auto* circle = static_cast(feature); - Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(circle->get_center())); - view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(circle->get_center())); - view_feature_matrix.scale(0.5); - shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_sphere.set_color(ColorRGBA(0.f, 1.f, 0.f, 1.f)); - m_vbo_sphere.render(); - } - - - else if (feature->get_type() == Measure::SurfaceFeatureType::Edge) { - const auto* edge = static_cast(feature); - auto& [start, end] = edge->get_edge(); - Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(start)); - auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); - view_feature_matrix *= q; - view_feature_matrix.scale(Vec3d(0.075, 0.075, (end - start).norm())); - shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_cylinder.set_color(ColorRGBA(0.7f, 0.7f, 0.f, 1.f)); - m_vbo_cylinder.render(); - } - - + if (feature->get_type() == Measure::SurfaceFeatureType::Circle) { + const auto* circle = static_cast(feature); + Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(circle->get_center())); + view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(circle->get_center())); + view_feature_matrix.scale(0.5); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_sphere.set_color(ColorRGBA(0.f, 1.f, 0.f, 1.f)); + m_vbo_sphere.render(); } - shader->set_uniform("view_model_matrix", view_model_matrix); + else if (feature->get_type() == Measure::SurfaceFeatureType::Edge) { + const auto* edge = static_cast(feature); + auto& [start, end] = edge->get_edge(); + Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(start)); + auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); + view_feature_matrix *= q; + view_feature_matrix.scale(Vec3d(0.075, 0.075, (end - start).norm())); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_cylinder.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); + m_vbo_cylinder.render(); + } + else if (feature->get_type() == Measure::SurfaceFeatureType::Plane) { + const auto* plane = static_cast(feature); + assert(plane->get_plane_idx() < m_plane_models.size()); + m_plane_models[plane->get_plane_idx()]->render(); + } } + shader->set_uniform("view_model_matrix", view_model_matrix); + if (m_show_planes) + for (const auto& glmodel : m_plane_models) + glmodel->render(); + m_imgui->end(); } @@ -244,7 +259,25 @@ void GLGizmoMeasure::update_if_needed() return; UPDATE: - m_measuring.reset(new Measure::Measuring(mo->volumes.front()->mesh().its)); + const indexed_triangle_set& its = mo->volumes.front()->mesh().its; + m_measuring.reset(new Measure::Measuring(its)); + m_plane_models.clear(); + const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); + for (const std::vector& triangle_indices : planes_triangles) { + m_plane_models.emplace_back(std::unique_ptr(new GLModel())); + GUI::GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GUI::GLModel::Geometry::EVertexLayout::P3 }; + init_data.color = ColorRGBA(0.9f, 0.9f, 0.9f, 0.5f); + int i = 0; + for (int idx : triangle_indices) { + init_data.add_vertex(its.vertices[its.indices[idx][0]]); + init_data.add_vertex(its.vertices[its.indices[idx][1]]); + init_data.add_vertex(its.vertices[its.indices[idx][2]]); + init_data.add_triangle(i, i+1, i+2); + i+=3; + } + m_plane_models.back()->init_from(std::move(init_data)); + } // Let's save what we calculated it from: m_volumes_matrices.clear(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 2781d2b353..f74b82fa46 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -45,7 +45,9 @@ private: int m_mouse_pos_x; int m_mouse_pos_y; - bool m_show_all = true; + bool m_show_all = false; + bool m_show_planes = false; + std::vector> m_plane_models; void update_if_needed(); void set_flattening_data(const ModelObject* model_object); From 457afca5de3359703df88105acc7600a3da9e505 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 27 Jul 2022 11:45:42 +0200 Subject: [PATCH 115/250] Measuring: added getters for circle visualization --- src/libslic3r/Measure.cpp | 11 ++++++++++- src/libslic3r/Measure.hpp | 8 +++++++- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 22 +++++++++++++++++++--- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index a8ee3d3265..724f4ab806 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -262,7 +262,7 @@ void MeasuringImpl::extract_features() for (const auto& [start_idx, end_idx] : circles) { std::pair center_and_radius = get_center_and_radius(border, start_idx, end_idx, trafo); plane.surface_features.emplace_back(std::unique_ptr( - new Circle(center_and_radius.first, center_and_radius.second))); + new Circle(center_and_radius.first, center_and_radius.second, plane.normal))); } } @@ -382,6 +382,15 @@ double Measuring::get_distance(const SurfaceFeature* feature, const Vec3d* pt) Eigen::ParametrizedLine line(s, (e-s).normalized()); return line.distance(*pt); } + else if (feature->get_type() == SurfaceFeatureType::Circle) { + const Circle* circle = static_cast(feature); + // Find a plane containing normal, center and the point. + const Vec3d& c = circle->get_center(); + const Vec3d& n = circle->get_normal(); + Eigen::Hyperplane circle_plane(n, c); + Vec3d proj = circle_plane.projection(*pt); + return std::sqrt( std::pow((proj - c).norm() - circle->get_radius(), 2.) + (*pt - proj).squaredNorm()); + } return std::numeric_limits::max(); } diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 1360b47ff7..0455291bfc 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -28,22 +28,28 @@ public: class Edge : public SurfaceFeature { public: Edge(const Vec3d& start, const Vec3d& end) : m_start{start}, m_end{end} {} + Edge(const Vec3d& start, const Vec3d& end, const Vec3d& pin) : m_start{start}, m_end{end}, + m_pin{std::unique_ptr(new Vec3d(pin))} {} SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Edge; } std::pair get_edge() const { return std::make_pair(m_start, m_end); } private: Vec3d m_start; Vec3d m_end; + std::unique_ptr m_pin; }; class Circle : public SurfaceFeature { public: - Circle(const Vec3d& center, double radius) : m_center{center}, m_radius{radius} {} + Circle(const Vec3d& center, double radius, const Vec3d& normal) + : m_center{center}, m_radius{radius}, m_normal{normal} {} SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Circle; } Vec3d get_center() const { return m_center; } double get_radius() const { return m_radius; } + Vec3d get_normal() const { return m_normal; } private: Vec3d m_center; double m_radius; + Vec3d m_normal; }; class Plane : public SurfaceFeature { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index a8b257a937..44dd44cc55 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -174,12 +174,28 @@ void GLGizmoMeasure::on_render() if (feature->get_type() == Measure::SurfaceFeatureType::Circle) { const auto* circle = static_cast(feature); - Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(circle->get_center())); - view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(circle->get_center())); + const Vec3d& c = circle->get_center(); + const Vec3d& n = circle->get_normal(); + Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(c)); view_feature_matrix.scale(0.5); shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_sphere.set_color(ColorRGBA(0.f, 1.f, 0.f, 1.f)); + m_vbo_sphere.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); m_vbo_sphere.render(); + + // Now draw the circle itself - let's take a funny shortcut: + Vec3d rad = n.cross(Vec3d::UnitX()); + if (rad.squaredNorm() < 0.1) + rad = n.cross(Vec3d::UnitY()); + rad *= circle->get_radius() * rad.norm(); + const int N = 20; + for (int i=0; iset_uniform("view_model_matrix", view_feature_matrix); + m_vbo_sphere.render(); + } } else if (feature->get_type() == Measure::SurfaceFeatureType::Edge) { const auto* edge = static_cast(feature); From 387dfb2b793bf8399d354c240cc65f819ec0dc54 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 27 Jul 2022 15:36:21 +0200 Subject: [PATCH 116/250] Measuring: Add detection of polygons and their centers --- src/libslic3r/Measure.cpp | 72 ++++++++++++++++++------ src/libslic3r/Measure.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 8 +++ 3 files changed, 63 insertions(+), 18 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 724f4ab806..056178bc4e 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -192,10 +192,11 @@ void MeasuringImpl::update_planes() void MeasuringImpl::extract_features() { - - - const double edge_threshold = 25. * (M_PI/180.); + auto N_to_angle = [](double N) -> double { return 2.*M_PI / N; }; + constexpr double polygon_upper_threshold = N_to_angle(4.5); + constexpr double polygon_lower_threshold = N_to_angle(8.5); std::vector angles; + std::vector lengths; for (int i=0; i M_PI) + angle = 2*M_PI - angle; + angles.push_back(angle); + lengths.push_back(v2.squaredNorm()); } assert(border.size() == angles.size()); + assert(border.size() == lengths.size()); bool circle = false; - std::vector> circles; + std::vector> circles; + std::vector> circles_idxs; for (int i=1; i( + new Circle(center, radius, plane.normal))); circle = false; } } } + // Some of the "circles" may actually be polygons. We want them detected as + // edges, but also to remember the center and save it into those edges. + // We will add all such edges manually and delete the detected circles, + // leaving it in circles_idxs so they are not picked again: + assert(circles.size() == circles_idxs.size()); + for (int i=circles.size()-1; i>=0; --i) { + assert(circles_idxs[i].first + 1 < angles.size() - 1); // Check that this is internal point of the circle, not the first, not the last. + double angle = angles[circles_idxs[i].first + 1]; + if (angle > polygon_lower_threshold) { + if (angle < polygon_upper_threshold) { + const Vec3d center = static_cast(circles[i].get())->get_center(); + for (int j=circles_idxs[i].first + 1; j<=circles_idxs[i].second; ++j) + plane.surface_features.emplace_back(std::unique_ptr( + new Edge(border[j-1], border[j], center))); + } else { + // This will be handled just like a regular edge. + circles_idxs.erase(circles_idxs.begin() + i); + } + circles.erase(circles.begin() + i); + } + } + + + + + + // We have the circles. Now go around again and pick edges. int cidx = 0; // index of next circle in the way for (int i=1; i circles[cidx].first) - i = circles[cidx++].second; + if (cidx < circles_idxs.size() && i > circles_idxs[cidx].first) + i = circles_idxs[cidx++].second; else plane.surface_features.emplace_back(std::unique_ptr( new Edge(border[i-1], border[i]))); } @@ -258,13 +297,10 @@ void MeasuringImpl::extract_features() // FIXME Check and merge first and last circle if needed. - // Now create the circle-typed surface features. - for (const auto& [start_idx, end_idx] : circles) { - std::pair center_and_radius = get_center_and_radius(border, start_idx, end_idx, trafo); - plane.surface_features.emplace_back(std::unique_ptr( - new Circle(center_and_radius.first, center_and_radius.second, plane.normal))); - } - + // Now move the circles into the feature list. + assert(std::all_of(circles.begin(), circles.end(), [](const std::unique_ptr& f) { return f->get_type() == SurfaceFeatureType::Circle; })); + plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(circles.begin()), + std::make_move_iterator(circles.end())); } // The last surface feature is the plane itself. diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 0455291bfc..1db35d9fcd 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -32,6 +32,7 @@ public: m_pin{std::unique_ptr(new Vec3d(pin))} {} SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Edge; } std::pair get_edge() const { return std::make_pair(m_start, m_end); } + const Vec3d* get_point_of_interest() const { return m_pin.get(); } private: Vec3d m_start; Vec3d m_end; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 44dd44cc55..1869983015 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -207,6 +207,14 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_feature_matrix); m_vbo_cylinder.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); m_vbo_cylinder.render(); + if (edge->get_point_of_interest()) { + Vec3d pin = *edge->get_point_of_interest(); + view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(pin)); + view_feature_matrix.scale(0.5); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_sphere.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); + m_vbo_sphere.render(); + } } else if (feature->get_type() == Measure::SurfaceFeatureType::Plane) { const auto* plane = static_cast(feature); From b23e28e9e4d7faff8b3f920ab47aa79c2a2a4965 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 18 Aug 2022 13:42:26 +0200 Subject: [PATCH 117/250] Measuring: refactoring --- src/libslic3r/Measure.cpp | 166 ++++++++++++++--------- src/libslic3r/Measure.hpp | 114 ++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 45 +++--- 3 files changed, 180 insertions(+), 145 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 056178bc4e..e59e3c04d4 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -34,24 +34,21 @@ public: struct PlaneData { std::vector facets; std::vector> borders; // FIXME: should be in fact local in update_planes() - std::vector> surface_features; + std::vector surface_features; Vec3d normal; float area; }; - const std::vector& get_features() const; - const SurfaceFeature* get_feature(size_t face_idx, const Vec3d& point) const; - const std::vector> get_planes_triangle_indices() const; + std::vector get_all_features() const; + std::optional get_feature(size_t face_idx, const Vec3d& point) const; + std::vector> get_planes_triangle_indices() const; private: void update_planes(); void extract_features(); - void save_features(); - - + std::vector m_planes; std::vector m_face_to_plane; - std::vector m_features; const indexed_triangle_set& m_its; }; @@ -65,7 +62,6 @@ MeasuringImpl::MeasuringImpl(const indexed_triangle_set& its) { update_planes(); extract_features(); - save_features(); } @@ -233,7 +229,7 @@ void MeasuringImpl::extract_features() bool circle = false; - std::vector> circles; + std::vector circles; std::vector> circles_idxs; for (int i=1; i( - new Circle(center, radius, plane.normal))); + circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::optional(), radius)); circle = false; } } @@ -266,10 +261,10 @@ void MeasuringImpl::extract_features() double angle = angles[circles_idxs[i].first + 1]; if (angle > polygon_lower_threshold) { if (angle < polygon_upper_threshold) { - const Vec3d center = static_cast(circles[i].get())->get_center(); + const Vec3d center = std::get<0>(circles[i].get_circle()); for (int j=circles_idxs[i].first + 1; j<=circles_idxs[i].second; ++j) - plane.surface_features.emplace_back(std::unique_ptr( - new Edge(border[j-1], border[j], center))); + plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, + border[j-1], border[j], std::make_optional(center), 0.)); } else { // This will be handled just like a regular edge. circles_idxs.erase(circles_idxs.begin() + i); @@ -288,8 +283,8 @@ void MeasuringImpl::extract_features() for (int i=1; i circles_idxs[cidx].first) i = circles_idxs[cidx++].second; - else plane.surface_features.emplace_back(std::unique_ptr( - new Edge(border[i-1], border[i]))); + else plane.surface_features.emplace_back(SurfaceFeature( + SurfaceFeatureType::Edge, border[i-1], border[i], std::optional(), 0.)); } // FIXME Throw away / do not create edges which are parts of circles or @@ -298,14 +293,16 @@ void MeasuringImpl::extract_features() // FIXME Check and merge first and last circle if needed. // Now move the circles into the feature list. - assert(std::all_of(circles.begin(), circles.end(), [](const std::unique_ptr& f) { return f->get_type() == SurfaceFeatureType::Circle; })); + assert(std::all_of(circles.begin(), circles.end(), [](const SurfaceFeature& f) { + return f.get_type() == SurfaceFeatureType::Circle; + })); plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(circles.begin()), std::make_move_iterator(circles.end())); } // The last surface feature is the plane itself. - plane.surface_features.emplace_back(std::unique_ptr( - new Plane(i))); + plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Plane, + Vec3d::Zero(), Vec3d::Zero(), std::optional(), i + 0.0001)); plane.borders.clear(); plane.borders.shrink_to_fit(); @@ -314,56 +311,58 @@ void MeasuringImpl::extract_features() -void MeasuringImpl::save_features() +std::vector MeasuringImpl::get_all_features() const { - m_features.clear(); - for (PlaneData& plane : m_planes) + std::vector features; //PlaneData& plane = m_planes[0]; - { - for (const std::unique_ptr& feature : plane.surface_features) { - m_features.emplace_back(feature.get()); - } - } + for (const PlaneData& plane : m_planes) + for (const SurfaceFeature& feature : plane.surface_features) + features.emplace_back(feature); + return features; } -const SurfaceFeature* MeasuringImpl::get_feature(size_t face_idx, const Vec3d& point) const + + + +std::optional MeasuringImpl::get_feature(size_t face_idx, const Vec3d& point) const { if (face_idx >= m_face_to_plane.size()) - return nullptr; + return std::optional(); const PlaneData& plane = m_planes[m_face_to_plane[face_idx]]; const SurfaceFeature* closest_feature = nullptr; double min_dist = std::numeric_limits::max(); - for (const std::unique_ptr& feature : plane.surface_features) { - double dist = Measuring::get_distance(feature.get(), &point); - if (dist < 0.5 && dist < min_dist) { - min_dist = std::min(dist, min_dist); - closest_feature = feature.get(); + MeasurementResult res; + SurfaceFeature point_sf(point); + + for (const SurfaceFeature& feature : plane.surface_features) { + res = get_measurement(feature, point_sf); + if (res.distance_strict) { // TODO: this should become an assert after all combinations are implemented. + double dist = *res.distance_strict; + if (dist < 0.5 && dist < min_dist) { + min_dist = std::min(dist, min_dist); + closest_feature = &feature; + } } } if (closest_feature) - return closest_feature; + return std::make_optional(*closest_feature); // Nothing detected, return the plane as a whole. - assert(plane.surface_features.back().get()->get_type() == SurfaceFeatureType::Plane); - return plane.surface_features.back().get(); + assert(plane.surface_features.back().get_type() == SurfaceFeatureType::Plane); + return std::make_optional(plane.surface_features.back()); } -const std::vector& MeasuringImpl::get_features() const -{ - return m_features; -} - -const std::vector> MeasuringImpl::get_planes_triangle_indices() const +std::vector> MeasuringImpl::get_planes_triangle_indices() const { std::vector> out; for (const PlaneData& plane : m_planes) @@ -390,45 +389,81 @@ Measuring::Measuring(const indexed_triangle_set& its) Measuring::~Measuring() {} -const std::vector& Measuring::get_features() const +std::vector Measuring::get_all_features() const { - return priv->get_features(); + return priv->get_all_features(); } -const SurfaceFeature* Measuring::get_feature(size_t face_idx, const Vec3d& point) const +std::optional Measuring::get_feature(size_t face_idx, const Vec3d& point) const { return priv->get_feature(face_idx, point); } -const std::vector> Measuring::get_planes_triangle_indices() const +std::vector> Measuring::get_planes_triangle_indices() const { return priv->get_planes_triangle_indices(); } -double Measuring::get_distance(const SurfaceFeature* feature, const Vec3d* pt) + + + + + + + + + + + +MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b) { - if (feature->get_type() == SurfaceFeatureType::Edge) { - const Edge* edge = static_cast(feature); - const auto& [s,e] = edge->get_edge(); - Eigen::ParametrizedLine line(s, (e-s).normalized()); - return line.distance(*pt); - } - else if (feature->get_type() == SurfaceFeatureType::Circle) { - const Circle* circle = static_cast(feature); - // Find a plane containing normal, center and the point. - const Vec3d& c = circle->get_center(); - const Vec3d& n = circle->get_normal(); - Eigen::Hyperplane circle_plane(n, c); - Vec3d proj = circle_plane.projection(*pt); - return std::sqrt( std::pow((proj - c).norm() - circle->get_radius(), 2.) + (*pt - proj).squaredNorm()); + assert(a.get_type() != SurfaceFeatureType::Undef && b.get_type() != SurfaceFeatureType::Undef); + + const bool swap = int(a.get_type()) > int(b.get_type()); + const SurfaceFeature& f1 = swap ? b : a; + const SurfaceFeature& f2 = swap ? a : b; + + MeasurementResult result; + if (f1.get_type() == SurfaceFeatureType::Point) { + if (f2.get_type() == SurfaceFeatureType::Point) { + Vec3d diff = (f2.get_point() - f1.get_point()); + result.distance_strict = diff.norm(); + result.distance_xyz = diff; + } else if (f2.get_type() == SurfaceFeatureType::Edge) { + const auto& [s,e] = f2.get_edge(); + Eigen::ParametrizedLine line(s, (e-s).normalized()); + result.distance_strict = std::make_optional(line.distance(f1.get_point())); // TODO: this is really infinite dist + } else if (f2.get_type() == SurfaceFeatureType::Circle) { + // Find a plane containing normal, center and the point. + const auto& [c, radius, n] = f2.get_circle(); + Eigen::Hyperplane circle_plane(n, c); + Vec3d proj = circle_plane.projection(f1.get_point()); + result.distance_strict = std::make_optional(std::sqrt( + std::pow((proj - c).norm() - radius, 2.) + (f1.get_point() - proj).squaredNorm())); + } else if (f2.get_type() == SurfaceFeatureType::Plane) { + } + } else if (f1.get_type() == SurfaceFeatureType::Edge) { + if (f2.get_type() == SurfaceFeatureType::Edge) { + } else if (f2.get_type() == SurfaceFeatureType::Circle) { + } else if (f2.get_type() == SurfaceFeatureType::Plane) { + } + } else if (f1.get_type() == SurfaceFeatureType::Circle) { + if (f2.get_type() == SurfaceFeatureType::Circle) { + } else if (f2.get_type() == SurfaceFeatureType::Plane) { + } + } else if (f1.get_type() == SurfaceFeatureType::Plane) { + assert(f2.get_type() == SurfaceFeatureType::Plane); + } - return std::numeric_limits::max(); + + + return result; } @@ -436,5 +471,8 @@ double Measuring::get_distance(const SurfaceFeature* feature, const Vec3d* pt) + + + } // namespace Measure } // namespace Slic3r diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 1db35d9fcd..87bed1cf17 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -1,6 +1,7 @@ #ifndef Slic3r_Measure_hpp_ #define Slic3r_Measure_hpp_ +#include #include #include "Point.hpp" @@ -15,55 +16,50 @@ namespace Measure { enum class SurfaceFeatureType { - Edge = 1 << 0, - Circle = 1 << 1, - Plane = 1 << 2 - }; + Undef, + Point, + Edge, + Circle, + Plane +}; class SurfaceFeature { -public: - virtual SurfaceFeatureType get_type() const = 0; -}; - -class Edge : public SurfaceFeature { public: - Edge(const Vec3d& start, const Vec3d& end) : m_start{start}, m_end{end} {} - Edge(const Vec3d& start, const Vec3d& end, const Vec3d& pin) : m_start{start}, m_end{end}, - m_pin{std::unique_ptr(new Vec3d(pin))} {} - SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Edge; } - std::pair get_edge() const { return std::make_pair(m_start, m_end); } - const Vec3d* get_point_of_interest() const { return m_pin.get(); } -private: - Vec3d m_start; - Vec3d m_end; - std::unique_ptr m_pin; -}; + SurfaceFeature(SurfaceFeatureType type, const Vec3d& pt1, const Vec3d& pt2, std::optional pt3, double value) + : m_type{type}, m_pt1{pt1}, m_pt2{pt2}, m_pt3{pt3}, m_value{value} {} -class Circle : public SurfaceFeature { -public: - Circle(const Vec3d& center, double radius, const Vec3d& normal) - : m_center{center}, m_radius{radius}, m_normal{normal} {} - SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Circle; } - Vec3d get_center() const { return m_center; } - double get_radius() const { return m_radius; } - Vec3d get_normal() const { return m_normal; } -private: - Vec3d m_center; - double m_radius; - Vec3d m_normal; -}; + explicit SurfaceFeature(const Vec3d& pt) + : m_type{SurfaceFeatureType::Point}, m_pt1{pt} {} -class Plane : public SurfaceFeature { -public: - Plane(int idx) : m_idx(idx) {} - SurfaceFeatureType get_type() const override { return SurfaceFeatureType::Plane; } - int get_plane_idx() const { return m_idx; } // index into vector provided by Measuring::get_plane_triangle_indices + + // Get type of this feature. + SurfaceFeatureType get_type() const { return m_type; } + + // For points, return the point. + Vec3d get_point() const { assert(m_type == SurfaceFeatureType::Point); return m_pt1; } + + // For edges, return start and end. + std::pair get_edge() const { assert(m_type == SurfaceFeatureType::Edge); return std::make_pair(m_pt1, m_pt2); } + + // For circles, return center, radius and normal. + std::tuple get_circle() const { assert(m_type == SurfaceFeatureType::Circle); return std::make_tuple(m_pt1, m_value, m_pt2); } + + // For planes, return index into vector provided by Measuring::get_plane_triangle_indices. + int get_plane_idx() const { return int(m_value); } + + // For anything, return an extra point that should also be considered a part of this. + std::optional get_extra_point() const { assert(m_type != SurfaceFeatureType::Undef); return m_pt3; } private: - int m_idx; + SurfaceFeatureType m_type = SurfaceFeatureType::Undef; + Vec3d m_pt1; + Vec3d m_pt2; + std::optional m_pt3; + double m_value; }; + class MeasuringImpl; @@ -75,34 +71,36 @@ public: ~Measuring(); // Return a reference to a list of all features identified on the its. - [[deprecated]]const std::vector& get_features() const; + // Use only for debugging. Expensive, do not call often. + [[deprecated]] std::vector get_all_features() const; // Given a face_idx where the mouse cursor points, return a feature that - // should be highlighted or nullptr. - const SurfaceFeature* get_feature(size_t face_idx, const Vec3d& point) const; + // should be highlighted (if any). + std::optional get_feature(size_t face_idx, const Vec3d& point) const; // Returns a list of triangle indices for each identified plane. Each - // Plane object contains an index into this vector. - const std::vector> get_planes_triangle_indices() const; - - - - // Returns distance between two SurfaceFeatures. - static double get_distance(const SurfaceFeature* a, const SurfaceFeature* b); - - // Returns distance between a SurfaceFeature and a point. - static double get_distance(const SurfaceFeature* a, const Vec3d* pt); - - // Returns true if measuring angles between features makes sense. - // If so, result contains the angle in radians. - static bool get_angle(const SurfaceFeature* a, const SurfaceFeature* b, double& result); - - + // Plane object contains an index into this vector. Expensive, do not + // call too often. + std::vector> get_planes_triangle_indices() const; + private: std::unique_ptr priv; }; + + +struct MeasurementResult { + std::optional angle; + std::optional distance_infinite; + std::optional distance_strict; + std::optional distance_xyz; +}; + +// Returns distance/angle between two SurfaceFeatures. +static MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b); + + } // namespace Measure } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 1869983015..7eaf7b2e0b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -158,24 +158,25 @@ void GLGizmoMeasure::on_render() - std::vector features = {m_measuring->get_feature(facet_idx, pos.cast())}; + std::vector features; if (m_show_all) { - features = m_measuring->get_features(); + features = m_measuring->get_all_features(); // EXPENSIVE - debugging only. features.erase(std::remove_if(features.begin(), features.end(), - [](const Measure::SurfaceFeature* f) { - return f->get_type() == Measure::SurfaceFeatureType::Plane; + [](const Measure::SurfaceFeature& f) { + return f.get_type() == Measure::SurfaceFeatureType::Plane; }), features.end()); + } else { + std::optional feat = m_measuring->get_feature(facet_idx, pos.cast()); + if (feat) + features.emplace_back(*feat); } - - - for (const Measure::SurfaceFeature* feature : features) { - if (! feature) - continue; - if (feature->get_type() == Measure::SurfaceFeatureType::Circle) { - const auto* circle = static_cast(feature); - const Vec3d& c = circle->get_center(); - const Vec3d& n = circle->get_normal(); + + + for (const Measure::SurfaceFeature& feature : features) { + + if (feature.get_type() == Measure::SurfaceFeatureType::Circle) { + const auto& [c, radius, n] = feature.get_circle(); Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(c)); view_feature_matrix.scale(0.5); shader->set_uniform("view_model_matrix", view_feature_matrix); @@ -186,7 +187,7 @@ void GLGizmoMeasure::on_render() Vec3d rad = n.cross(Vec3d::UnitX()); if (rad.squaredNorm() < 0.1) rad = n.cross(Vec3d::UnitY()); - rad *= circle->get_radius() * rad.norm(); + rad *= radius * rad.norm(); const int N = 20; for (int i=0; iget_type() == Measure::SurfaceFeatureType::Edge) { - const auto* edge = static_cast(feature); - auto& [start, end] = edge->get_edge(); + else if (feature.get_type() == Measure::SurfaceFeatureType::Edge) { + const auto& [start, end] = feature.get_edge(); Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(start)); auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); view_feature_matrix *= q; @@ -207,8 +207,8 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_feature_matrix); m_vbo_cylinder.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); m_vbo_cylinder.render(); - if (edge->get_point_of_interest()) { - Vec3d pin = *edge->get_point_of_interest(); + if (feature.get_extra_point()) { + Vec3d pin = *feature.get_extra_point(); view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(pin)); view_feature_matrix.scale(0.5); shader->set_uniform("view_model_matrix", view_feature_matrix); @@ -216,10 +216,9 @@ void GLGizmoMeasure::on_render() m_vbo_sphere.render(); } } - else if (feature->get_type() == Measure::SurfaceFeatureType::Plane) { - const auto* plane = static_cast(feature); - assert(plane->get_plane_idx() < m_plane_models.size()); - m_plane_models[plane->get_plane_idx()]->render(); + else if (feature.get_type() == Measure::SurfaceFeatureType::Plane) { + assert(feature.get_plane_idx() < m_plane_models.size()); + m_plane_models[feature.get_plane_idx()]->render(); } } shader->set_uniform("view_model_matrix", view_model_matrix); From b646fcad95b1b0726f1c2fc8c5dd4c8cf5aa7f32 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 18 Aug 2022 18:50:49 +0200 Subject: [PATCH 118/250] Measuring: implemented edge endpoint detection --- src/libslic3r/Measure.cpp | 91 ++++++++++++++++++++---- src/libslic3r/Measure.hpp | 9 ++- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 14 +++- 3 files changed, 94 insertions(+), 20 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index e59e3c04d4..8c7254f85b 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -9,6 +9,10 @@ namespace Slic3r { namespace Measure { +constexpr double feature_hover_limit = 0.5; // how close to a feature the mouse must be to highlight it +constexpr double edge_endpoint_limit = 0.5; // how close to an edge endpoint the mouse ... + + static std::pair get_center_and_radius(const std::vector& border, int start_idx, int end_idx, const Transform3d& trafo) { @@ -302,7 +306,7 @@ void MeasuringImpl::extract_features() // The last surface feature is the plane itself. plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Plane, - Vec3d::Zero(), Vec3d::Zero(), std::optional(), i + 0.0001)); + plane.normal, plane.borders.front().front(), std::optional(), i + 0.0001)); plane.borders.clear(); plane.borders.shrink_to_fit(); @@ -333,25 +337,39 @@ std::optional MeasuringImpl::get_feature(size_t face_idx, const const PlaneData& plane = m_planes[m_face_to_plane[face_idx]]; - const SurfaceFeature* closest_feature = nullptr; + size_t closest_feature_idx = size_t(-1); double min_dist = std::numeric_limits::max(); MeasurementResult res; SurfaceFeature point_sf(point); - for (const SurfaceFeature& feature : plane.surface_features) { - res = get_measurement(feature, point_sf); + for (size_t i=0; i line(s, (e-s).normalized()); - result.distance_strict = std::make_optional(line.distance(f1.get_point())); // TODO: this is really infinite dist + double dist_inf = line.distance(f1.get_point()); + Vec3d proj = line.projection(f1.get_point()); + double len_sq = (e-s).squaredNorm(); + double dist_start_sq = (proj-s).squaredNorm(); + double dist_end_sq = (proj-e).squaredNorm(); + if (dist_start_sq < len_sq && dist_end_sq < len_sq) { + // projection falls on the line - the strict distance is the same as infinite + result.distance_strict = std::make_optional(dist_inf); + } else { // the result is the closer of the endpoints + result.distance_strict = std::make_optional(std::sqrt(std::min(dist_start_sq, dist_end_sq) + dist_inf)); + } + result.distance_infinite = std::make_optional(dist_inf); + /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Circle) { // Find a plane containing normal, center and the point. const auto& [c, radius, n] = f2.get_circle(); Eigen::Hyperplane circle_plane(n, c); Vec3d proj = circle_plane.projection(f1.get_point()); - result.distance_strict = std::make_optional(std::sqrt( - std::pow((proj - c).norm() - radius, 2.) + (f1.get_point() - proj).squaredNorm())); + double dist = std::sqrt(std::pow((proj - c).norm() - radius, 2.) + + (f1.get_point() - proj).squaredNorm()); + + result.distance_strict = std::make_optional(dist); + /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { + const auto& [idx, normal, pt] = f2.get_plane(); + Eigen::Hyperplane plane(normal, pt); + result.distance_infinite = plane.absDistance(f1.get_point()); + // TODO: result.distance_strict = } + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// } else if (f1.get_type() == SurfaceFeatureType::Edge) { if (f2.get_type() == SurfaceFeatureType::Edge) { + /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Circle) { + /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { } + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// } else if (f1.get_type() == SurfaceFeatureType::Circle) { if (f2.get_type() == SurfaceFeatureType::Circle) { + /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { } + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// } else if (f1.get_type() == SurfaceFeatureType::Plane) { assert(f2.get_type() == SurfaceFeatureType::Plane); - + + const auto& [idx1, normal1, pt1] = f1.get_plane(); + const auto& [idx2, normal2, pt2] = f2.get_plane(); + double angle = 0.; + + if (! normal1.isApprox(normal2)) { + // The planes are parallel, calculate distance. + Eigen::Hyperplane plane(normal1, pt1); + result.distance_infinite = plane.absDistance(pt2); + } else { + // Planes are not parallel, calculate angle. + angle = std::acos(std::abs(normal1.dot(normal2))); + } + result.angle = angle; } diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 87bed1cf17..fe0b1687a1 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -31,7 +31,6 @@ public: explicit SurfaceFeature(const Vec3d& pt) : m_type{SurfaceFeatureType::Point}, m_pt1{pt} {} - // Get type of this feature. SurfaceFeatureType get_type() const { return m_type; } @@ -44,8 +43,8 @@ public: // For circles, return center, radius and normal. std::tuple get_circle() const { assert(m_type == SurfaceFeatureType::Circle); return std::make_tuple(m_pt1, m_value, m_pt2); } - // For planes, return index into vector provided by Measuring::get_plane_triangle_indices. - int get_plane_idx() const { return int(m_value); } + // For planes, return index into vector provided by Measuring::get_plane_triangle_indices, normal and point. + std::tuple get_plane() const { return std::make_tuple(int(m_value), m_pt1, m_pt2); } // For anything, return an extra point that should also be considered a part of this. std::optional get_extra_point() const { assert(m_type != SurfaceFeatureType::Undef); return m_pt3; } @@ -84,7 +83,7 @@ public: std::vector> get_planes_triangle_indices() const; private: - std::unique_ptr priv; + std::unique_ptr priv; }; @@ -98,7 +97,7 @@ struct MeasurementResult { }; // Returns distance/angle between two SurfaceFeatures. -static MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b); +MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b); } // namespace Measure diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 7eaf7b2e0b..07c920120b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -175,7 +175,14 @@ void GLGizmoMeasure::on_render() for (const Measure::SurfaceFeature& feature : features) { - if (feature.get_type() == Measure::SurfaceFeatureType::Circle) { + if (feature.get_type() == Measure::SurfaceFeatureType::Point) { + Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.get_point())); + view_feature_matrix.scale(0.5); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_sphere.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); + m_vbo_sphere.render(); + } + else if (feature.get_type() == Measure::SurfaceFeatureType::Circle) { const auto& [c, radius, n] = feature.get_circle(); Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(c)); view_feature_matrix.scale(0.5); @@ -217,8 +224,9 @@ void GLGizmoMeasure::on_render() } } else if (feature.get_type() == Measure::SurfaceFeatureType::Plane) { - assert(feature.get_plane_idx() < m_plane_models.size()); - m_plane_models[feature.get_plane_idx()]->render(); + const auto& [idx, normal, pt] = feature.get_plane(); + assert(idx < m_plane_models.size()); + m_plane_models[idx]->render(); } } shader->set_uniform("view_model_matrix", view_model_matrix); From 1942932229d28a62fe4985736734a14d0498c4a1 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 19 Aug 2022 09:05:44 +0200 Subject: [PATCH 119/250] Partial revert of 1e494e30 --- src/libslic3r/TriangleMesh.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index ef96e2400f..df820fac92 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -885,20 +885,13 @@ Polygon its_convex_hull_2d_above(const indexed_triangle_set &its, const Transfor indexed_triangle_set its_make_cube(double xd, double yd, double zd) { auto x = float(xd), y = float(yd), z = float(zd); - /*return { + return { { {0, 1, 2}, {0, 2, 3}, {4, 5, 6}, {4, 6, 7}, {0, 4, 7}, {0, 7, 1}, {1, 7, 6}, {1, 6, 2}, {2, 6, 5}, {2, 5, 3}, {4, 0, 3}, {4, 3, 5} }, { {x, y, 0}, {x, 0, 0}, {0, 0, 0}, {0, y, 0}, {x, y, z}, {0, y, z}, {0, 0, z}, {x, 0, z} } - };*/ - return { - { {0, 1, 2}, {0, 2, 3}, {4, 5, 6}, {4, 6, 7}, - {0, 4, 7}, {0, 7, 1}, {1, 7, 6}, {1, 6, 2}, - {2, 5, 6}, {2, 5, 3}, {4, 0, 3}, /*{4, 3, 5}*/ }, - { {x, y, 0}, {x, 0, 0}, {0, 0, 0}, {0, y, 0}, - {x, y, z}, {0, y, z}, {0, 0, z}, {x, 0, z} } - }; + }; } indexed_triangle_set its_make_prism(float width, float length, float height) From 964fa581fa30fe8584dd234f943d5b7bdefc993c Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 19 Aug 2022 09:19:10 +0200 Subject: [PATCH 120/250] Use unified color for hovering in GLGizmoMeasure --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 07c920120b..c17a116cc5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -16,8 +16,7 @@ namespace Slic3r { namespace GUI { -static const Slic3r::ColorRGBA DEFAULT_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.9f }; -static const Slic3r::ColorRGBA DEFAULT_HOVER_PLANE_COLOR = { 0.9f, 0.2f, 0.2f, 1.f }; +static const Slic3r::ColorRGBA HOVER_COLOR = { 0.8f, 0.2f, 0.2f, 1.0f }; GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) @@ -126,7 +125,10 @@ void GLGizmoMeasure::on_render() glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_BLEND)); - glsafe(::glLineWidth(2.f)); +#if ENABLE_GL_CORE_PROFILE + if (!OpenGLManager::get_gl_info().is_core_profile()) +#endif // ENABLE_GL_CORE_PROFILE + glsafe(::glLineWidth(2.f)); if (selection.is_single_full_instance()) { const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); @@ -179,7 +181,7 @@ void GLGizmoMeasure::on_render() Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.get_point())); view_feature_matrix.scale(0.5); shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_sphere.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); + m_vbo_sphere.set_color(HOVER_COLOR); m_vbo_sphere.render(); } else if (feature.get_type() == Measure::SurfaceFeatureType::Circle) { @@ -187,7 +189,7 @@ void GLGizmoMeasure::on_render() Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(c)); view_feature_matrix.scale(0.5); shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_sphere.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); + m_vbo_sphere.set_color(HOVER_COLOR); m_vbo_sphere.render(); // Now draw the circle itself - let's take a funny shortcut: @@ -212,20 +214,21 @@ void GLGizmoMeasure::on_render() view_feature_matrix *= q; view_feature_matrix.scale(Vec3d(0.075, 0.075, (end - start).norm())); shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_cylinder.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); + m_vbo_cylinder.set_color(HOVER_COLOR); m_vbo_cylinder.render(); if (feature.get_extra_point()) { Vec3d pin = *feature.get_extra_point(); view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(pin)); view_feature_matrix.scale(0.5); shader->set_uniform("view_model_matrix", view_feature_matrix); - m_vbo_sphere.set_color(ColorRGBA(0.8f, 0.2f, 0.2f, 1.f)); + m_vbo_sphere.set_color(HOVER_COLOR); m_vbo_sphere.render(); } } else if (feature.get_type() == Measure::SurfaceFeatureType::Plane) { const auto& [idx, normal, pt] = feature.get_plane(); assert(idx < m_plane_models.size()); + m_plane_models[idx]->set_color(HOVER_COLOR); m_plane_models[idx]->render(); } } From b821f1a33eab088b0cd7a3a5efbd78dc82226d5b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 19 Aug 2022 10:36:28 +0200 Subject: [PATCH 121/250] New icon for Measure Gizmo --- resources/icons/measure.svg | 106 +++++++++++++++++++++++++++++++----- 1 file changed, 93 insertions(+), 13 deletions(-) diff --git a/resources/icons/measure.svg b/resources/icons/measure.svg index 275c522251..3ea137a1ed 100644 --- a/resources/icons/measure.svg +++ b/resources/icons/measure.svg @@ -1,13 +1,93 @@ - - - Layer 1 - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + From a74c070a5e407d547da98dc4b5cebbe314c7ed15 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 19 Aug 2022 10:48:32 +0200 Subject: [PATCH 122/250] Set Measure Gizmo to be activable for single volume selections only --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 11 ++--------- src/slic3r/GUI/Selection.hpp | 1 + 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index c17a116cc5..582c76a0da 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -100,17 +100,12 @@ std::string GLGizmoMeasure::on_get_name() const return _u8L("Measure"); } - - bool GLGizmoMeasure::on_is_activable() const { - // This is assumed in GLCanvas3D::do_rotate, do not change this - // without updating that function too. - return m_parent.get_selection().is_single_full_instance(); + const Selection& selection = m_parent.get_selection(); + return selection.is_single_volume() || selection.is_single_volume_instance(); } - - void GLGizmoMeasure::on_render() { const Selection& selection = m_parent.get_selection(); @@ -139,9 +134,7 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - update_if_needed(); - m_imgui->begin(std::string("DEBUG")); diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index cebea29e05..e118f6bca5 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -328,6 +328,7 @@ public: #if ENABLE_WORLD_COORDINATE bool is_single_volume_or_modifier() const { return is_single_volume() || is_single_modifier(); } #endif // ENABLE_WORLD_COORDINATE + bool is_single_volume_instance() const { return is_single_full_instance() && m_list.size() == 1; } bool contains_volume(unsigned int volume_idx) const { return m_list.find(volume_idx) != m_list.end(); } // returns true if the selection contains all the given indices From a99871a2ab46ce3828ba2ffcb43309dc4cde6482 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 19 Aug 2022 11:02:13 +0200 Subject: [PATCH 123/250] Removed method set_flattening_data() from GLGizmoMeasure --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 9 ++------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 582c76a0da..c9ec63acdc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -69,7 +69,8 @@ void GLGizmoMeasure::data_changed() selection.is_from_single_object() ) { model_object = selection.get_model()->objects[selection.get_object_idx()]; } - set_flattening_data(model_object); + if (model_object != m_old_model_object) + update_if_needed(); } @@ -256,12 +257,6 @@ void GLGizmoMeasure::on_render_for_picking() -void GLGizmoMeasure::set_flattening_data(const ModelObject* model_object) -{ - if (model_object != m_old_model_object) - update_if_needed(); -} - void GLGizmoMeasure::update_if_needed() { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index f74b82fa46..bc48adea1b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -50,7 +50,6 @@ private: std::vector> m_plane_models; void update_if_needed(); - void set_flattening_data(const ModelObject* model_object); public: GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); @@ -63,6 +62,7 @@ public: bool on_mouse(const wxMouseEvent &mouse_event) override; void data_changed() override; + protected: bool on_init() override; std::string on_get_name() const override; From 6a2e7930cf64cb1bd12e5bd0afcd2867fad18649 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 22 Aug 2022 08:52:02 +0200 Subject: [PATCH 124/250] Measuring: allow to select single parts of a multipart object while Gizmo Measure is active --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 136 +++++++++++++---------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 7 +- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 26 +++-- src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 6 +- 4 files changed, 105 insertions(+), 70 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index c9ec63acdc..3e37fad743 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -64,12 +64,14 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) void GLGizmoMeasure::data_changed() { const Selection & selection = m_parent.get_selection(); - const ModelObject *model_object = nullptr; + const ModelObject* model_object = nullptr; + const ModelVolume* model_volume = nullptr; if (selection.is_single_full_instance() || selection.is_from_single_object() ) { model_object = selection.get_model()->objects[selection.get_object_idx()]; - } - if (model_object != m_old_model_object) + model_volume = model_object->volumes[selection.get_first_volume()->volume_idx()]; + } + if (model_object != m_old_model_object || model_volume != m_old_model_volume) update_if_needed(); } @@ -109,6 +111,10 @@ bool GLGizmoMeasure::on_is_activable() const void GLGizmoMeasure::on_render() { + // do not render if the user is panning/rotating the 3d scene + if (m_parent.is_mouse_dragging()) + return; + const Selection& selection = m_parent.get_selection(); GLShaderProgram* shader = wxGetApp().get_shader("flat"); @@ -126,33 +132,34 @@ void GLGizmoMeasure::on_render() #endif // ENABLE_GL_CORE_PROFILE glsafe(::glLineWidth(2.f)); - if (selection.is_single_full_instance()) { - const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); + if (selection.is_single_volume() || selection.is_single_volume_instance()) { + const Transform3d& model_matrix = selection.get_first_volume()->world_matrix(); const Camera& camera = wxGetApp().plater()->get_camera(); const Transform3d view_model_matrix = camera.get_view_matrix() * - Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m; + Geometry::assemble_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * model_matrix; shader->set_uniform("view_model_matrix", view_model_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); update_if_needed(); - m_imgui->begin(std::string("DEBUG")); - - m_imgui->checkbox(wxString("Show all features"), m_show_all); - m_imgui->checkbox(wxString("Show all planes"), m_show_planes); - Vec3f pos; Vec3f normal; size_t facet_idx; - m_c->raycaster()->raycasters().front()->unproject_on_mesh(Vec2d(m_mouse_pos_x, m_mouse_pos_y), m, camera, pos, normal, nullptr, &facet_idx); + m_c->raycaster()->raycasters().front()->unproject_on_mesh(Vec2d(m_mouse_pos_x, m_mouse_pos_y), model_matrix, camera, pos, normal, nullptr, &facet_idx); + +#define ENABLE_DEBUG_DIALOG 0 +#if ENABLE_DEBUG_DIALOG + m_imgui->begin(std::string("DEBUG")); + m_imgui->checkbox(wxString("Show all features"), m_show_all); + m_imgui->checkbox(wxString("Show all planes"), m_show_planes); ImGui::Separator(); m_imgui->text(std::string("face_idx: ") + std::to_string(facet_idx)); m_imgui->text(std::string("pos_x: ") + std::to_string(pos.x())); m_imgui->text(std::string("pos_y: ") + std::to_string(pos.y())); m_imgui->text(std::string("pos_z: ") + std::to_string(pos.z())); - - + m_imgui->end(); +#endif // ENABLE_DEBUG_DIALOG std::vector features; if (m_show_all) { @@ -230,8 +237,6 @@ void GLGizmoMeasure::on_render() if (m_show_planes) for (const auto& glmodel : m_plane_models) glmodel->render(); - - m_imgui->end(); } glsafe(::glEnable(GL_CULL_FACE)); @@ -260,57 +265,70 @@ void GLGizmoMeasure::on_render_for_picking() void GLGizmoMeasure::update_if_needed() { + auto do_update = [this](const ModelObject* object, const ModelVolume* volume) { + const indexed_triangle_set& its = (volume != nullptr) ? volume->mesh().its : object->volumes.front()->mesh().its; + m_measuring.reset(new Measure::Measuring(its)); + m_plane_models.clear(); + const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); + for (const std::vector& triangle_indices : planes_triangles) { + m_plane_models.emplace_back(std::unique_ptr(new GLModel())); + GUI::GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GUI::GLModel::Geometry::EVertexLayout::P3 }; + init_data.color = ColorRGBA(0.9f, 0.9f, 0.9f, 0.5f); + int i = 0; + for (int idx : triangle_indices) { + init_data.add_vertex(its.vertices[its.indices[idx][0]]); + init_data.add_vertex(its.vertices[its.indices[idx][1]]); + init_data.add_vertex(its.vertices[its.indices[idx][2]]); + init_data.add_triangle(i, i + 1, i + 2); + i += 3; + } + m_plane_models.back()->init_from(std::move(init_data)); + } + + // Let's save what we calculated it from: + m_volumes_matrices.clear(); + m_volumes_types.clear(); + m_first_instance_scale = Vec3d::Ones(); + m_first_instance_mirror = Vec3d::Ones(); + if (object != nullptr) { + for (const ModelVolume* vol : object->volumes) { + m_volumes_matrices.push_back(vol->get_matrix()); + m_volumes_types.push_back(vol->type()); + } + m_first_instance_scale = object->instances.front()->get_scaling_factor(); + m_first_instance_mirror = object->instances.front()->get_mirror(); + } + m_old_model_object = object; + m_old_model_volume = volume; + }; + const ModelObject* mo = m_c->selection_info()->model_object(); - if (m_state != On || ! mo || mo->instances.empty()) + const ModelVolume* mv = m_c->selection_info()->model_volume(); + if (m_state != On || (mo == nullptr && mv == nullptr)) return; - if (! m_measuring || mo != m_old_model_object - || mo->volumes.size() != m_volumes_matrices.size()) - goto UPDATE; + if (mo == nullptr) + mo = mv->get_object(); + + if (mo->instances.empty()) + return; + + if (!m_measuring || mo != m_old_model_object || mv != m_old_model_volume || mo->volumes.size() != m_volumes_matrices.size()) + do_update(mo, mv); // We want to recalculate when the scale changes - some planes could (dis)appear. - if (! mo->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale) - || ! mo->instances.front()->get_mirror().isApprox(m_first_instance_mirror)) - goto UPDATE; + if (!mo->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale) || + !mo->instances.front()->get_mirror().isApprox(m_first_instance_mirror)) + do_update(mo, mv); - for (unsigned int i=0; i < mo->volumes.size(); ++i) - if (! mo->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i]) - || mo->volumes[i]->type() != m_volumes_types[i]) - goto UPDATE; - - return; - -UPDATE: - const indexed_triangle_set& its = mo->volumes.front()->mesh().its; - m_measuring.reset(new Measure::Measuring(its)); - m_plane_models.clear(); - const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); - for (const std::vector& triangle_indices : planes_triangles) { - m_plane_models.emplace_back(std::unique_ptr(new GLModel())); - GUI::GLModel::Geometry init_data; - init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GUI::GLModel::Geometry::EVertexLayout::P3 }; - init_data.color = ColorRGBA(0.9f, 0.9f, 0.9f, 0.5f); - int i = 0; - for (int idx : triangle_indices) { - init_data.add_vertex(its.vertices[its.indices[idx][0]]); - init_data.add_vertex(its.vertices[its.indices[idx][1]]); - init_data.add_vertex(its.vertices[its.indices[idx][2]]); - init_data.add_triangle(i, i+1, i+2); - i+=3; + for (unsigned int i = 0; i < mo->volumes.size(); ++i) { + if (!mo->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i]) || + mo->volumes[i]->type() != m_volumes_types[i]) { + do_update(mo, mv); + break; } - m_plane_models.back()->init_from(std::move(init_data)); } - - // Let's save what we calculated it from: - m_volumes_matrices.clear(); - m_volumes_types.clear(); - for (const ModelVolume* vol : mo->volumes) { - m_volumes_matrices.push_back(vol->get_matrix()); - m_volumes_types.push_back(vol->type()); - } - m_first_instance_scale = mo->instances.front()->get_scaling_factor(); - m_first_instance_mirror = mo->instances.front()->get_mirror(); - m_old_model_object = mo; } } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index bc48adea1b..68baffd4ce 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -14,6 +14,8 @@ namespace Slic3r { +class ModelVolume; + enum class ModelVolumeType : int; namespace Measure { class Measuring; } @@ -35,12 +37,13 @@ private: // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; std::vector m_volumes_types; - Vec3d m_first_instance_scale; - Vec3d m_first_instance_mirror; + Vec3d m_first_instance_scale{ Vec3d::Ones() }; + Vec3d m_first_instance_mirror{ Vec3d::Ones() }; bool m_mouse_left_down = false; // for detection left_up of this gizmo bool m_planes_valid = false; const ModelObject* m_old_model_object = nullptr; + const ModelVolume* m_old_model_volume = nullptr; std::vector instances_matrices; int m_mouse_pos_x; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index ce3ba1d4ab..1eef6aced5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -119,21 +119,25 @@ void SelectionInfo::on_update() const Selection& selection = get_pool()->get_canvas()->get_selection(); if (selection.is_single_full_instance()) { m_model_object = selection.get_model()->objects[selection.get_object_idx()]; + m_model_volume = nullptr; m_z_shift = selection.get_first_volume()->get_sla_shift_z(); } - else + else { m_model_object = nullptr; + if (selection.is_single_volume()) + m_model_volume = selection.get_model()->objects[selection.get_object_idx()]->volumes[selection.get_first_volume()->volume_idx()]; + } } void SelectionInfo::on_release() { m_model_object = nullptr; + m_model_volume = nullptr; } int SelectionInfo::get_active_instance() const { - const Selection& selection = get_pool()->get_canvas()->get_selection(); - return selection.get_instance_idx(); + return get_pool()->get_canvas()->get_selection().get_instance_idx(); } @@ -329,12 +333,18 @@ void Raycaster::on_update() { wxBusyCursor wait; const ModelObject* mo = get_pool()->selection_info()->model_object(); + const ModelVolume* mv = get_pool()->selection_info()->model_volume(); - if (! mo) + if (mo == nullptr && mv == nullptr) return; + std::vector mvs; + if (mv != nullptr) + mvs.push_back(const_cast(mv)); + else + mvs = mo->volumes; + std::vector meshes; - const std::vector& mvs = mo->volumes; if (mvs.size() == 1) { assert(mvs.front()->is_model_part()); const HollowedMesh* hollowed_mesh_tracker = get_pool()->hollowed_mesh(); @@ -342,9 +352,9 @@ void Raycaster::on_update() meshes.push_back(hollowed_mesh_tracker->get_hollowed_mesh()); } if (meshes.empty()) { - for (const ModelVolume* mv : mvs) { - if (mv->is_model_part()) - meshes.push_back(&mv->mesh()); + for (const ModelVolume* v : mvs) { + if (v->is_model_part()) + meshes.push_back(&v->mesh()); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index 7dd2c110ea..c8b29f761e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -10,7 +10,7 @@ namespace Slic3r { class ModelObject; - +class ModelVolume; namespace GUI { @@ -153,7 +153,10 @@ public: explicit SelectionInfo(CommonGizmosDataPool* cgdp) : CommonGizmosDataBase(cgdp) {} + // Returns a non-null pointer if the selection is a single full instance ModelObject* model_object() const { return m_model_object; } + // Returns a non-null pointer if the selection is a single volume + ModelVolume* model_volume() const { return m_model_volume; } int get_active_instance() const; float get_sla_shift() const { return m_z_shift; } @@ -163,6 +166,7 @@ protected: private: ModelObject* m_model_object = nullptr; + ModelVolume* m_model_volume = nullptr; // int m_active_inst = -1; float m_z_shift = 0.f; }; From adb3d0101deefbdd51a3c7185ed8f768f2852efc Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 23 Aug 2022 13:17:09 +0200 Subject: [PATCH 125/250] Measuring: reworked rendering of hovered features --- src/slic3r/GUI/GLModel.cpp | 104 +++++++++++++++ src/slic3r/GUI/GLModel.hpp | 7 ++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 154 ++++++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 3 + 4 files changed, 211 insertions(+), 57 deletions(-) diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 2d6a66d43c..4c98b05172 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -2253,6 +2253,110 @@ GLModel::Geometry smooth_sphere(unsigned int resolution, float radius) return data; } + +GLModel::Geometry smooth_cylinder(Axis axis, unsigned int resolution, float radius, float height) +{ + resolution = std::max(4, resolution); + + const unsigned int sectorCount = resolution; + const float sectorStep = 2.0f * float(M_PI) / float(sectorCount); + + GLModel::Geometry data; + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + data.reserve_vertices(sectorCount * 4 + 2); + data.reserve_indices(sectorCount * 4 * 3); + + auto generate_vertices_on_circle = [sectorCount, sectorStep](Axis axis, float radius) { + std::vector ret; + ret.reserve(sectorCount); + for (unsigned int i = 0; i < sectorCount; ++i) { + // from 0 to 2pi + const float sectorAngle = (i != sectorCount) ? sectorStep * i : 0.0f; + const float x1 = radius * std::cos(sectorAngle); + const float x2 = radius * std::sin(sectorAngle); + + Vec3f v; + switch (axis) + { + case X: { v = Vec3f(0.0f, x1, x2); break; } + case Y: { v = Vec3f(-x1, 0.0f, x2); break; } + case Z: { v = Vec3f(x1, x2, 0.0f); break; } + default: { assert(false); break; } + } + + ret.emplace_back(v); + } + return ret; + }; + + const std::vector base_vertices = generate_vertices_on_circle(axis, radius); + + Vec3f h; + switch (axis) + { + case X: { h = height * Vec3f::UnitX(); break; } + case Y: { h = height * Vec3f::UnitY(); break; } + case Z: { h = height * Vec3f::UnitZ(); break; } + default: { assert(false); break; } + } + + // stem vertices + for (unsigned int i = 0; i < sectorCount; ++i) { + const Vec3f& v = base_vertices[i]; + const Vec3f n = v.normalized(); + data.add_vertex(v, n); + data.add_vertex(v + h, n); + } + + // stem triangles + for (unsigned int i = 0; i < sectorCount; ++i) { + unsigned int v1 = i * 2; + unsigned int v2 = (i < sectorCount - 1) ? v1 + 2 : 0; + unsigned int v3 = v2 + 1; + unsigned int v4 = v1 + 1; + data.add_triangle(v1, v2, v3); + data.add_triangle(v1, v3, v4); + } + + // bottom cap vertices + Vec3f cap_center = Vec3f::Zero(); + unsigned int cap_center_id = data.vertices_count(); + Vec3f normal; + switch (axis) + { + case X: { normal = -Vec3f::UnitX(); break; } + case Y: { normal = -Vec3f::UnitY(); break; } + case Z: { normal = -Vec3f::UnitZ(); break; } + default: { assert(false); break; } + } + + data.add_vertex(cap_center, normal); + for (unsigned int i = 0; i < sectorCount; ++i) { + data.add_vertex(base_vertices[i], normal); + } + + // bottom cap triangles + for (unsigned int i = 0; i < sectorCount; ++i) { + data.add_triangle(cap_center_id, (i < sectorCount - 1) ? cap_center_id + i + 2 : cap_center_id + 1, cap_center_id + i + 1); + } + + // top cap vertices + cap_center += h; + cap_center_id = data.vertices_count(); + normal = -normal; + + data.add_vertex(cap_center, normal); + for (unsigned int i = 0; i < sectorCount; ++i) { + data.add_vertex(base_vertices[i] + h, normal); + } + + // top cap triangles + for (unsigned int i = 0; i < sectorCount; ++i) { + data.add_triangle(cap_center_id, cap_center_id + i + 1, (i < sectorCount - 1) ? cap_center_id + i + 2 : cap_center_id + 1); + } + + return data; +} #endif // ENABLE_LEGACY_OPENGL_REMOVAL } // namespace GUI diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index c2845c8850..393e545ab9 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -376,7 +376,14 @@ namespace GUI { #if ENABLE_LEGACY_OPENGL_REMOVAL // create a sphere with the given resolution and smooth normals // the origin of the sphere is in its center + // the radius of the sphere is the given value GLModel::Geometry smooth_sphere(unsigned int resolution, float radius); + // create a cylinder with the given resolution and smooth normals + // the axis of the cylinder is the given value + // the radius of the cylinder is the given value + // the height of the cylinder is the given value + // the origin of the cylinder is in the center of the cap face having axis == 0 + GLModel::Geometry smooth_cylinder(Axis axis, unsigned int resolution, float radius, float height); #endif // ENABLE_LEGACY_OPENGL_REMOVAL } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 3e37fad743..5b6baa0153 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -8,6 +8,7 @@ #include "libslic3r/Model.hpp" #include "libslic3r/Measure.hpp" +#include "libslic3r/PresetBundle.hpp" #include @@ -21,8 +22,8 @@ static const Slic3r::ColorRGBA HOVER_COLOR = { 0.8f, 0.2f, 0.2f, 1.0f }; GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) { - m_vbo_sphere.init_from(its_make_sphere(1., M_PI/32.)); - m_vbo_cylinder.init_from(its_make_cylinder(1., 1.)); + m_vbo_sphere.init_from(smooth_sphere(16, 7.5f)); + m_vbo_cylinder.init_from(smooth_cylinder(Z, 16, 5.0f, 1.0f)); } bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) @@ -106,7 +107,9 @@ std::string GLGizmoMeasure::on_get_name() const bool GLGizmoMeasure::on_is_activable() const { const Selection& selection = m_parent.get_selection(); - return selection.is_single_volume() || selection.is_single_volume_instance(); + return (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) ? + selection.is_single_full_instance() : + selection.is_single_volume() || selection.is_single_volume_instance(); } void GLGizmoMeasure::on_render() @@ -117,30 +120,27 @@ void GLGizmoMeasure::on_render() const Selection& selection = m_parent.get_selection(); - GLShaderProgram* shader = wxGetApp().get_shader("flat"); + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) return; shader->start_using(); + shader->set_uniform("emission_factor", 0.25f); glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_BLEND)); -#if ENABLE_GL_CORE_PROFILE - if (!OpenGLManager::get_gl_info().is_core_profile()) -#endif // ENABLE_GL_CORE_PROFILE - glsafe(::glLineWidth(2.f)); - if (selection.is_single_volume() || selection.is_single_volume_instance()) { + if ((wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA && selection.is_single_full_instance()) || + (selection.is_single_volume() || selection.is_single_volume_instance())) { const Transform3d& model_matrix = selection.get_first_volume()->world_matrix(); const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d view_model_matrix = camera.get_view_matrix() * - Geometry::assemble_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * model_matrix; + const Transform3d& view_matrix = camera.get_view_matrix(); + const float inv_zoom = camera.get_inv_zoom(); - shader->set_uniform("view_model_matrix", view_model_matrix); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - + update_if_needed(); Vec3f pos; @@ -148,7 +148,6 @@ void GLGizmoMeasure::on_render() size_t facet_idx; m_c->raycaster()->raycasters().front()->unproject_on_mesh(Vec2d(m_mouse_pos_x, m_mouse_pos_y), model_matrix, camera, pos, normal, nullptr, &facet_idx); -#define ENABLE_DEBUG_DIALOG 0 #if ENABLE_DEBUG_DIALOG m_imgui->begin(std::string("DEBUG")); m_imgui->checkbox(wxString("Show all features"), m_show_all); @@ -162,34 +161,46 @@ void GLGizmoMeasure::on_render() #endif // ENABLE_DEBUG_DIALOG std::vector features; - if (m_show_all) { +#if ENABLE_DEBUG_DIALOG + if (m_show_all) { features = m_measuring->get_all_features(); // EXPENSIVE - debugging only. features.erase(std::remove_if(features.begin(), features.end(), [](const Measure::SurfaceFeature& f) { return f.get_type() == Measure::SurfaceFeatureType::Plane; }), features.end()); - } else { + } + else { +#endif // ENABLE_DEBUG_DIALOG std::optional feat = m_measuring->get_feature(facet_idx, pos.cast()); - if (feat) + if (feat.has_value()) features.emplace_back(*feat); - } - - +#if ENABLE_DEBUG_DIALOG + } +#endif // ENABLE_DEBUG_DIALOG for (const Measure::SurfaceFeature& feature : features) { - - if (feature.get_type() == Measure::SurfaceFeatureType::Point) { - Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.get_point())); - view_feature_matrix.scale(0.5); - shader->set_uniform("view_model_matrix", view_feature_matrix); + switch (feature.get_type()) { + case Measure::SurfaceFeatureType::Point: + { + const Vec3d& position = feature.get_point(); + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); + const Transform3d view_model_matrix = view_matrix * feature_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_vbo_sphere.set_color(HOVER_COLOR); m_vbo_sphere.render(); + break; } - else if (feature.get_type() == Measure::SurfaceFeatureType::Circle) { - const auto& [c, radius, n] = feature.get_circle(); - Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(c)); - view_feature_matrix.scale(0.5); - shader->set_uniform("view_model_matrix", view_feature_matrix); + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, n] = feature.get_circle(); + // render center + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); + const Transform3d view_model_matrix = view_matrix * feature_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_vbo_sphere.set_color(HOVER_COLOR); m_vbo_sphere.render(); @@ -198,45 +209,69 @@ void GLGizmoMeasure::on_render() if (rad.squaredNorm() < 0.1) rad = n.cross(Vec3d::UnitY()); rad *= radius * rad.norm(); - const int N = 20; - for (int i=0; iset_uniform("view_model_matrix", view_feature_matrix); + const int N = 32; + m_vbo_sphere.set_color(HOVER_COLOR); + for (int i = 0; i < N; ++i) { + rad = Eigen::AngleAxisd(2.0 * M_PI / N, n) * rad; + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(center + rad) * Geometry::scale_transform(N / 100.0 * inv_zoom); + const Transform3d view_model_matrix = view_matrix * feature_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_vbo_sphere.render(); } + break; } - else if (feature.get_type() == Measure::SurfaceFeatureType::Edge) { + case Measure::SurfaceFeatureType::Edge: + { const auto& [start, end] = feature.get_edge(); - Transform3d view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(start)); - auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); - view_feature_matrix *= q; - view_feature_matrix.scale(Vec3d(0.075, 0.075, (end - start).norm())); - shader->set_uniform("view_model_matrix", view_feature_matrix); + auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * q * + Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); + const Transform3d view_model_matrix = view_matrix * feature_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_vbo_cylinder.set_color(HOVER_COLOR); m_vbo_cylinder.render(); - if (feature.get_extra_point()) { - Vec3d pin = *feature.get_extra_point(); - view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(pin)); - view_feature_matrix.scale(0.5); - shader->set_uniform("view_model_matrix", view_feature_matrix); + +/* + std::optional extra_point = feature.get_extra_point(); + if (extra_point.has_value()) { + const Vec3d pin = *extra_point; + const Transform3d feature_matrix = Geometry::translation_transform(pin + selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * + Geometry::scale_transform(inv_zoom) * model_matrix; + const Transform3d view_model_matrix = view_matrix * feature_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_vbo_sphere.set_color(HOVER_COLOR); m_vbo_sphere.render(); } +*/ + break; } - else if (feature.get_type() == Measure::SurfaceFeatureType::Plane) { + case Measure::SurfaceFeatureType::Plane: + { const auto& [idx, normal, pt] = feature.get_plane(); assert(idx < m_plane_models.size()); + const Transform3d view_model_matrix = view_matrix * model_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); m_plane_models[idx]->set_color(HOVER_COLOR); m_plane_models[idx]->render(); - } + break; + } + } } - shader->set_uniform("view_model_matrix", view_model_matrix); +#if ENABLE_DEBUG_DIALOG if (m_show_planes) - for (const auto& glmodel : m_plane_models) + for (const auto& glmodel : m_plane_models) { + glmodel->set_color(HOVER_COLOR); glmodel->render(); + } +#endif // ENABLE_DEBUG_DIALOG } glsafe(::glEnable(GL_CULL_FACE)); @@ -272,14 +307,19 @@ void GLGizmoMeasure::update_if_needed() const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); for (const std::vector& triangle_indices : planes_triangles) { m_plane_models.emplace_back(std::unique_ptr(new GLModel())); - GUI::GLModel::Geometry init_data; - init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GUI::GLModel::Geometry::EVertexLayout::P3 }; + GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; init_data.color = ColorRGBA(0.9f, 0.9f, 0.9f, 0.5f); int i = 0; for (int idx : triangle_indices) { - init_data.add_vertex(its.vertices[its.indices[idx][0]]); - init_data.add_vertex(its.vertices[its.indices[idx][1]]); - init_data.add_vertex(its.vertices[its.indices[idx][2]]); + const Vec3f& v0 = its.vertices[its.indices[idx][0]]; + const Vec3f& v1 = its.vertices[its.indices[idx][1]]; + const Vec3f& v2 = its.vertices[its.indices[idx][2]]; + + const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); + init_data.add_vertex(v0, n); + init_data.add_vertex(v1, n); + init_data.add_vertex(v2, n); init_data.add_triangle(i, i + 1, i + 2); i += 3; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 68baffd4ce..8231711710 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -11,6 +11,7 @@ #include +#define ENABLE_DEBUG_DIALOG 0 namespace Slic3r { @@ -48,8 +49,10 @@ private: int m_mouse_pos_x; int m_mouse_pos_y; +#if ENABLE_DEBUG_DIALOG bool m_show_all = false; bool m_show_planes = false; +#endif // ENABLE_DEBUG_DIALOG std::vector> m_plane_models; void update_if_needed(); From 74d32277039fa0070232b6d0bc5e4383f5d71fbb Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 23 Aug 2022 13:53:55 +0200 Subject: [PATCH 126/250] Follow-up of a7d1c9b5e99132e51d84fcd5155ede7da1ecadd0 - Simplified code to generate a smooth cylinder --- src/slic3r/GUI/GLModel.cpp | 39 ++++-------------------- src/slic3r/GUI/GLModel.hpp | 13 +++----- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- 3 files changed, 12 insertions(+), 42 deletions(-) diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 4c98b05172..bb8d0b338d 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -2254,7 +2254,7 @@ GLModel::Geometry smooth_sphere(unsigned int resolution, float radius) return data; } -GLModel::Geometry smooth_cylinder(Axis axis, unsigned int resolution, float radius, float height) +GLModel::Geometry smooth_cylinder(unsigned int resolution, float radius, float height) { resolution = std::max(4, resolution); @@ -2266,39 +2266,19 @@ GLModel::Geometry smooth_cylinder(Axis axis, unsigned int resolution, float radi data.reserve_vertices(sectorCount * 4 + 2); data.reserve_indices(sectorCount * 4 * 3); - auto generate_vertices_on_circle = [sectorCount, sectorStep](Axis axis, float radius) { + auto generate_vertices_on_circle = [sectorCount, sectorStep](float radius) { std::vector ret; ret.reserve(sectorCount); for (unsigned int i = 0; i < sectorCount; ++i) { // from 0 to 2pi const float sectorAngle = (i != sectorCount) ? sectorStep * i : 0.0f; - const float x1 = radius * std::cos(sectorAngle); - const float x2 = radius * std::sin(sectorAngle); - - Vec3f v; - switch (axis) - { - case X: { v = Vec3f(0.0f, x1, x2); break; } - case Y: { v = Vec3f(-x1, 0.0f, x2); break; } - case Z: { v = Vec3f(x1, x2, 0.0f); break; } - default: { assert(false); break; } - } - - ret.emplace_back(v); + ret.emplace_back(radius * std::cos(sectorAngle), radius * std::sin(sectorAngle), 0.0f); } return ret; }; - const std::vector base_vertices = generate_vertices_on_circle(axis, radius); - - Vec3f h; - switch (axis) - { - case X: { h = height * Vec3f::UnitX(); break; } - case Y: { h = height * Vec3f::UnitY(); break; } - case Z: { h = height * Vec3f::UnitZ(); break; } - default: { assert(false); break; } - } + const std::vector base_vertices = generate_vertices_on_circle(radius); + const Vec3f h = height * Vec3f::UnitZ(); // stem vertices for (unsigned int i = 0; i < sectorCount; ++i) { @@ -2321,14 +2301,7 @@ GLModel::Geometry smooth_cylinder(Axis axis, unsigned int resolution, float radi // bottom cap vertices Vec3f cap_center = Vec3f::Zero(); unsigned int cap_center_id = data.vertices_count(); - Vec3f normal; - switch (axis) - { - case X: { normal = -Vec3f::UnitX(); break; } - case Y: { normal = -Vec3f::UnitY(); break; } - case Z: { normal = -Vec3f::UnitZ(); break; } - default: { assert(false); break; } - } + Vec3f normal = -Vec3f::UnitZ(); data.add_vertex(cap_center, normal); for (unsigned int i = 0; i < sectorCount; ++i) { diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index 393e545ab9..8fe821a3da 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -374,16 +374,13 @@ namespace GUI { GLModel::Geometry diamond(unsigned int resolution); #if ENABLE_LEGACY_OPENGL_REMOVAL - // create a sphere with the given resolution and smooth normals + // create a sphere with smooth normals // the origin of the sphere is in its center - // the radius of the sphere is the given value GLModel::Geometry smooth_sphere(unsigned int resolution, float radius); - // create a cylinder with the given resolution and smooth normals - // the axis of the cylinder is the given value - // the radius of the cylinder is the given value - // the height of the cylinder is the given value - // the origin of the cylinder is in the center of the cap face having axis == 0 - GLModel::Geometry smooth_cylinder(Axis axis, unsigned int resolution, float radius, float height); + // create a cylinder with smooth normals + // the axis of the cylinder is the Z axis + // the origin of the cylinder is the center of its bottom cap face + GLModel::Geometry smooth_cylinder(unsigned int resolution, float radius, float height); #endif // ENABLE_LEGACY_OPENGL_REMOVAL } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 5b6baa0153..327a60a046 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -23,7 +23,7 @@ GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filen : GLGizmoBase(parent, icon_filename, sprite_id) { m_vbo_sphere.init_from(smooth_sphere(16, 7.5f)); - m_vbo_cylinder.init_from(smooth_cylinder(Z, 16, 5.0f, 1.0f)); + m_vbo_cylinder.init_from(smooth_cylinder(16, 5.0f, 1.0f)); } bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) From c30cc15f41e52dbe7ff1e03c58652d8e81052e96 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 24 Aug 2022 11:25:15 +0200 Subject: [PATCH 127/250] Measuring: circle feature rendered using a torus --- src/slic3r/GUI/GLModel.cpp | 47 ++++++++++++++++- src/slic3r/GUI/GLModel.hpp | 4 ++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 67 ++++++++---------------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 5 +- 4 files changed, 76 insertions(+), 47 deletions(-) diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index bb8d0b338d..03d2677bea 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -2271,7 +2271,7 @@ GLModel::Geometry smooth_cylinder(unsigned int resolution, float radius, float h ret.reserve(sectorCount); for (unsigned int i = 0; i < sectorCount; ++i) { // from 0 to 2pi - const float sectorAngle = (i != sectorCount) ? sectorStep * i : 0.0f; + const float sectorAngle = sectorStep * i; ret.emplace_back(radius * std::cos(sectorAngle), radius * std::sin(sectorAngle), 0.0f); } return ret; @@ -2330,6 +2330,51 @@ GLModel::Geometry smooth_cylinder(unsigned int resolution, float radius, float h return data; } + +GLModel::Geometry smooth_torus(unsigned int primary_resolution, unsigned int secondary_resolution, float radius, float thickness) +{ + primary_resolution = std::max(4, primary_resolution); + secondary_resolution = std::max(4, secondary_resolution); + const unsigned int torusSectorCount = primary_resolution; + const float torusSectorStep = 2.0f * float(M_PI) / float(torusSectorCount); + const unsigned int sectionSectorCount = secondary_resolution; + const float sectionSectorStep = 2.0f * float(M_PI) / float(sectionSectorCount); + + GLModel::Geometry data; + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + data.reserve_vertices(torusSectorCount * sectionSectorCount); + data.reserve_indices(torusSectorCount * sectionSectorCount * 2 * 3); + + // vertices + for (unsigned int i = 0; i < torusSectorCount; ++i) { + const float sectionAngle = torusSectorStep * i; + const Vec3f sectionCenter(radius * std::cos(sectionAngle), radius * std::sin(sectionAngle), 0.0f); + for (unsigned int j = 0; j < sectionSectorCount; ++j) { + const float circleAngle = sectionSectorStep * j; + const float thickness_xy = thickness * std::cos(circleAngle); + const float thickness_z = thickness * std::sin(circleAngle); + const Vec3f v(thickness_xy * std::cos(sectionAngle), thickness_xy * std::sin(sectionAngle), thickness_z); + data.add_vertex(sectionCenter + v, (Vec3f)v.normalized()); + } + } + + // triangles + for (unsigned int i = 0; i < torusSectorCount; ++i) { + const unsigned int ii = i * sectionSectorCount; + const unsigned int ii_next = ((i + 1) % torusSectorCount) * sectionSectorCount; + for (unsigned int j = 0; j < sectionSectorCount; ++j) { + const unsigned int j_next = (j + 1) % sectionSectorCount; + const unsigned int i0 = ii + j; + const unsigned int i1 = ii_next + j; + const unsigned int i2 = ii_next + j_next; + const unsigned int i3 = ii + j_next; + data.add_triangle(i0, i1, i2); + data.add_triangle(i0, i2, i3); + } + } + + return data; +} #endif // ENABLE_LEGACY_OPENGL_REMOVAL } // namespace GUI diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index 8fe821a3da..e631952a3e 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -381,6 +381,10 @@ namespace GUI { // the axis of the cylinder is the Z axis // the origin of the cylinder is the center of its bottom cap face GLModel::Geometry smooth_cylinder(unsigned int resolution, float radius, float height); + // create a torus with smooth normals + // the axis of the torus is the Z axis + // the origin of the torus is in its center + GLModel::Geometry smooth_torus(unsigned int primary_resolution, unsigned int secondary_resolution, float radius, float thickness); #endif // ENABLE_LEGACY_OPENGL_REMOVAL } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 327a60a046..4e7cd3db1a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -22,8 +22,8 @@ static const Slic3r::ColorRGBA HOVER_COLOR = { 0.8f, 0.2f, 0.2f, 1.0f }; GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) { - m_vbo_sphere.init_from(smooth_sphere(16, 7.5f)); - m_vbo_cylinder.init_from(smooth_cylinder(16, 5.0f, 1.0f)); + m_sphere.init_from(smooth_sphere(16, 7.5f)); + m_cylinder.init_from(smooth_cylinder(16, 5.0f, 1.0f)); } bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) @@ -188,38 +188,32 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_vbo_sphere.set_color(HOVER_COLOR); - m_vbo_sphere.render(); + m_sphere.set_color(HOVER_COLOR); + m_sphere.render(); break; } case Measure::SurfaceFeatureType::Circle: { const auto& [center, radius, n] = feature.get_circle(); // render center - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); - const Transform3d view_model_matrix = view_matrix * feature_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_vbo_sphere.set_color(HOVER_COLOR); - m_vbo_sphere.render(); + const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); + const Transform3d center_view_model_matrix = view_matrix * center_matrix; + shader->set_uniform("view_model_matrix", center_view_model_matrix); + const Matrix3d center_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * center_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", center_view_normal_matrix); + m_sphere.set_color(HOVER_COLOR); + m_sphere.render(); - // Now draw the circle itself - let's take a funny shortcut: - Vec3d rad = n.cross(Vec3d::UnitX()); - if (rad.squaredNorm() < 0.1) - rad = n.cross(Vec3d::UnitY()); - rad *= radius * rad.norm(); - const int N = 32; - m_vbo_sphere.set_color(HOVER_COLOR); - for (int i = 0; i < N; ++i) { - rad = Eigen::AngleAxisd(2.0 * M_PI / N, n) * rad; - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(center + rad) * Geometry::scale_transform(N / 100.0 * inv_zoom); - const Transform3d view_model_matrix = view_matrix * feature_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_vbo_sphere.render(); - } + m_circle.reset(); + m_circle.init_from(smooth_torus(64, 16, float(radius), 5.0f * inv_zoom)); + + const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center); + const Transform3d circle_view_model_matrix = view_matrix * circle_matrix; + shader->set_uniform("view_model_matrix", circle_view_model_matrix); + const Matrix3d circle_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * circle_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", circle_view_normal_matrix); + m_circle.set_color(HOVER_COLOR); + m_circle.render(); break; } case Measure::SurfaceFeatureType::Edge: @@ -232,23 +226,8 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_vbo_cylinder.set_color(HOVER_COLOR); - m_vbo_cylinder.render(); - -/* - std::optional extra_point = feature.get_extra_point(); - if (extra_point.has_value()) { - const Vec3d pin = *extra_point; - const Transform3d feature_matrix = Geometry::translation_transform(pin + selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * - Geometry::scale_transform(inv_zoom) * model_matrix; - const Transform3d view_model_matrix = view_matrix * feature_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_vbo_sphere.set_color(HOVER_COLOR); - m_vbo_sphere.render(); - } -*/ + m_cylinder.set_color(HOVER_COLOR); + m_cylinder.render(); break; } case Measure::SurfaceFeatureType::Plane: diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 8231711710..23abdb3149 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -32,8 +32,9 @@ class GLGizmoMeasure : public GLGizmoBase private: std::unique_ptr m_measuring; - GLModel m_vbo_sphere; - GLModel m_vbo_cylinder; + GLModel m_sphere; + GLModel m_cylinder; + GLModel m_circle; // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; From 62a28c7baf6807fc3b14c069957806e355432553 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 24 Aug 2022 12:00:04 +0200 Subject: [PATCH 128/250] Measuring: refactoring related to plane models cache --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 41 +++++++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 2 +- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 4e7cd3db1a..68fbd2aaa0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -233,23 +233,28 @@ void GLGizmoMeasure::on_render() case Measure::SurfaceFeatureType::Plane: { const auto& [idx, normal, pt] = feature.get_plane(); - assert(idx < m_plane_models.size()); + assert(idx < m_plane_models_cache.size()); const Transform3d view_model_matrix = view_matrix * model_matrix; shader->set_uniform("view_model_matrix", view_model_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_plane_models[idx]->set_color(HOVER_COLOR); - m_plane_models[idx]->render(); + m_plane_models_cache[idx].set_color(HOVER_COLOR); + m_plane_models_cache[idx].render(); break; } } } #if ENABLE_DEBUG_DIALOG - if (m_show_planes) - for (const auto& glmodel : m_plane_models) { - glmodel->set_color(HOVER_COLOR); - glmodel->render(); + if (m_show_planes) { + const Transform3d view_model_matrix = view_matrix * model_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); + for (GLModel& glmodel : m_plane_models_cache) { + glmodel.set_color(HOVER_COLOR); + glmodel.render(); } + } #endif // ENABLE_DEBUG_DIALOG } @@ -279,17 +284,14 @@ void GLGizmoMeasure::on_render_for_picking() void GLGizmoMeasure::update_if_needed() { - auto do_update = [this](const ModelObject* object, const ModelVolume* volume) { - const indexed_triangle_set& its = (volume != nullptr) ? volume->mesh().its : object->volumes.front()->mesh().its; - m_measuring.reset(new Measure::Measuring(its)); - m_plane_models.clear(); + auto update_plane_models_cache = [this](const indexed_triangle_set& its) { + m_plane_models_cache.clear(); const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); for (const std::vector& triangle_indices : planes_triangles) { - m_plane_models.emplace_back(std::unique_ptr(new GLModel())); + m_plane_models_cache.emplace_back(GLModel()); GLModel::Geometry init_data; init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; - init_data.color = ColorRGBA(0.9f, 0.9f, 0.9f, 0.5f); - int i = 0; + unsigned int i = 0; for (int idx : triangle_indices) { const Vec3f& v0 = its.vertices[its.indices[idx][0]]; const Vec3f& v1 = its.vertices[its.indices[idx][1]]; @@ -302,8 +304,15 @@ void GLGizmoMeasure::update_if_needed() init_data.add_triangle(i, i + 1, i + 2); i += 3; } - m_plane_models.back()->init_from(std::move(init_data)); + m_plane_models_cache.back().init_from(std::move(init_data)); } + }; + + auto do_update = [this, update_plane_models_cache](const ModelObject* object, const ModelVolume* volume) { + const indexed_triangle_set& its = (volume != nullptr) ? volume->mesh().its : object->volumes.front()->mesh().its; + m_measuring.reset(new Measure::Measuring(its)); + + update_plane_models_cache(its); // Let's save what we calculated it from: m_volumes_matrices.clear(); @@ -315,7 +324,7 @@ void GLGizmoMeasure::update_if_needed() m_volumes_matrices.push_back(vol->get_matrix()); m_volumes_types.push_back(vol->type()); } - m_first_instance_scale = object->instances.front()->get_scaling_factor(); + m_first_instance_scale = object->instances.front()->get_scaling_factor(); m_first_instance_mirror = object->instances.front()->get_mirror(); } m_old_model_object = object; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 23abdb3149..2cbdd15061 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -35,6 +35,7 @@ private: GLModel m_sphere; GLModel m_cylinder; GLModel m_circle; + std::vector m_plane_models_cache; // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; @@ -54,7 +55,6 @@ private: bool m_show_all = false; bool m_show_planes = false; #endif // ENABLE_DEBUG_DIALOG - std::vector> m_plane_models; void update_if_needed(); From 86b390e2377393a07a562a6f4b8515b55888b264 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 24 Aug 2022 14:15:20 +0200 Subject: [PATCH 129/250] Refactoring into GLGizmoMeasure::on_render() --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 67 +++++++++++++----------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 68fbd2aaa0..dd562a6490 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -114,34 +114,20 @@ bool GLGizmoMeasure::on_is_activable() const void GLGizmoMeasure::on_render() { +#if !ENABLE_DEBUG_DIALOG // do not render if the user is panning/rotating the 3d scene if (m_parent.is_mouse_dragging()) return; +#endif // !ENABLE_DEBUG_DIALOG const Selection& selection = m_parent.get_selection(); - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); - if (shader == nullptr) - return; - - shader->start_using(); - shader->set_uniform("emission_factor", 0.25f); - - glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); - - glsafe(::glEnable(GL_DEPTH_TEST)); - glsafe(::glEnable(GL_BLEND)); - if ((wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA && selection.is_single_full_instance()) || (selection.is_single_volume() || selection.is_single_volume_instance())) { + update_if_needed(); + const Transform3d& model_matrix = selection.get_first_volume()->world_matrix(); const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d& view_matrix = camera.get_view_matrix(); - const float inv_zoom = camera.get_inv_zoom(); - - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - - update_if_needed(); Vec3f pos; Vec3f normal; @@ -165,19 +151,42 @@ void GLGizmoMeasure::on_render() if (m_show_all) { features = m_measuring->get_all_features(); // EXPENSIVE - debugging only. features.erase(std::remove_if(features.begin(), features.end(), - [](const Measure::SurfaceFeature& f) { - return f.get_type() == Measure::SurfaceFeatureType::Plane; - }), features.end()); + [](const Measure::SurfaceFeature& f) { + return f.get_type() == Measure::SurfaceFeatureType::Plane; + }), features.end()); } else { + if (!m_parent.is_mouse_dragging()) { #endif // ENABLE_DEBUG_DIALOG - std::optional feat = m_measuring->get_feature(facet_idx, pos.cast()); - if (feat.has_value()) - features.emplace_back(*feat); + std::optional feat = m_measuring->get_feature(facet_idx, pos.cast()); + if (feat.has_value()) + features.emplace_back(*feat); #if ENABLE_DEBUG_DIALOG + } } #endif // ENABLE_DEBUG_DIALOG - + +#if ENABLE_DEBUG_DIALOG + if (features.empty() && !m_show_planes) +#else + if (features.empty()) +#endif // ENABLE_DEBUG_DIALOG + return; + + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); + if (shader == nullptr) + return; + + shader->start_using(); + shader->set_uniform("emission_factor", 0.25f); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + + glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); + glsafe(::glEnable(GL_DEPTH_TEST)); + + const Transform3d& view_matrix = camera.get_view_matrix(); + const float inv_zoom = camera.get_inv_zoom(); + for (const Measure::SurfaceFeature& feature : features) { switch (feature.get_type()) { case Measure::SurfaceFeatureType::Point: @@ -256,18 +265,12 @@ void GLGizmoMeasure::on_render() } } #endif // ENABLE_DEBUG_DIALOG + shader->stop_using(); } - - glsafe(::glEnable(GL_CULL_FACE)); - glsafe(::glDisable(GL_BLEND)); - - shader->stop_using(); } - - #if ! ENABLE_LEGACY_OPENGL_REMOVAL #error NOT IMPLEMENTED #endif From 7b437861247a0fea5569bb68eeb759aaf4699f25 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 24 Aug 2022 15:02:46 +0200 Subject: [PATCH 130/250] Added tech ENABLE_MEASURE_GIZMO_DEBUG to embed debug code related to GLGizmoMeasure --- src/libslic3r/Measure.cpp | 3 ++ src/libslic3r/Measure.hpp | 4 +- src/libslic3r/Technologies.hpp | 2 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 50 ++++++++++-------------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 6 +-- 5 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 8c7254f85b..9cb46edfc1 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -1,3 +1,4 @@ +#include "libslic3r/libslic3r.h" #include "Measure.hpp" #include "libslic3r/Geometry/Circle.hpp" @@ -407,10 +408,12 @@ Measuring::Measuring(const indexed_triangle_set& its) Measuring::~Measuring() {} +#if ENABLE_MEASURE_GIZMO_DEBUG std::vector Measuring::get_all_features() const { return priv->get_all_features(); } +#endif // ENABLE_MEASURE_GIZMO_DEBUG std::optional Measuring::get_feature(size_t face_idx, const Vec3d& point) const diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index fe0b1687a1..98517b991b 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -69,9 +69,11 @@ public: explicit Measuring(const indexed_triangle_set& its); ~Measuring(); +#if ENABLE_MEASURE_GIZMO_DEBUG // Return a reference to a list of all features identified on the its. // Use only for debugging. Expensive, do not call often. - [[deprecated]] std::vector get_all_features() const; + std::vector get_all_features() const; +#endif // ENABLE_MEASURE_GIZMO_DEBUG // Given a face_idx where the mouse cursor points, return a feature that // should be highlighted (if any). diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index ad23b4cbe1..d5d2542cc5 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -66,6 +66,8 @@ // Enable picking using raytracing #define ENABLE_RAYCAST_PICKING (1 && ENABLE_LEGACY_OPENGL_REMOVAL) #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) +// Enable debug code for Measure Gizmo +#define ENABLE_MEASURE_GIZMO_DEBUG (0 && ENABLE_2_5_0_ALPHA1) #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index dd562a6490..d7a8f53f46 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -114,11 +114,11 @@ bool GLGizmoMeasure::on_is_activable() const void GLGizmoMeasure::on_render() { -#if !ENABLE_DEBUG_DIALOG +#if !ENABLE_MEASURE_GIZMO_DEBUG // do not render if the user is panning/rotating the 3d scene if (m_parent.is_mouse_dragging()) return; -#endif // !ENABLE_DEBUG_DIALOG +#endif // !ENABLE_MEASURE_GIZMO_DEBUG const Selection& selection = m_parent.get_selection(); @@ -134,7 +134,7 @@ void GLGizmoMeasure::on_render() size_t facet_idx; m_c->raycaster()->raycasters().front()->unproject_on_mesh(Vec2d(m_mouse_pos_x, m_mouse_pos_y), model_matrix, camera, pos, normal, nullptr, &facet_idx); -#if ENABLE_DEBUG_DIALOG +#if ENABLE_MEASURE_GIZMO_DEBUG m_imgui->begin(std::string("DEBUG")); m_imgui->checkbox(wxString("Show all features"), m_show_all); m_imgui->checkbox(wxString("Show all planes"), m_show_planes); @@ -144,33 +144,35 @@ void GLGizmoMeasure::on_render() m_imgui->text(std::string("pos_y: ") + std::to_string(pos.y())); m_imgui->text(std::string("pos_z: ") + std::to_string(pos.z())); m_imgui->end(); -#endif // ENABLE_DEBUG_DIALOG +#endif // ENABLE_MEASURE_GIZMO_DEBUG std::vector features; -#if ENABLE_DEBUG_DIALOG - if (m_show_all) { - features = m_measuring->get_all_features(); // EXPENSIVE - debugging only. - features.erase(std::remove_if(features.begin(), features.end(), - [](const Measure::SurfaceFeature& f) { - return f.get_type() == Measure::SurfaceFeatureType::Plane; - }), features.end()); +#if ENABLE_MEASURE_GIZMO_DEBUG + if (m_show_all || m_show_planes) { + features = m_measuring->get_all_features(); + if (!m_show_planes) + features.erase(std::remove_if(features.begin(), features.end(), + [](const Measure::SurfaceFeature& f) { + return f.get_type() == Measure::SurfaceFeatureType::Plane; + }), features.end()); + if (!m_show_all) + features.erase(std::remove_if(features.begin(), features.end(), + [](const Measure::SurfaceFeature& f) { + return f.get_type() != Measure::SurfaceFeatureType::Plane; + }), features.end()); } else { if (!m_parent.is_mouse_dragging()) { -#endif // ENABLE_DEBUG_DIALOG +#endif // ENABLE_MEASURE_GIZMO_DEBUG std::optional feat = m_measuring->get_feature(facet_idx, pos.cast()); if (feat.has_value()) features.emplace_back(*feat); -#if ENABLE_DEBUG_DIALOG +#if ENABLE_MEASURE_GIZMO_DEBUG } } -#endif // ENABLE_DEBUG_DIALOG +#endif // ENABLE_MEASURE_GIZMO_DEBUG -#if ENABLE_DEBUG_DIALOG - if (features.empty() && !m_show_planes) -#else if (features.empty()) -#endif // ENABLE_DEBUG_DIALOG return; GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); @@ -253,18 +255,6 @@ void GLGizmoMeasure::on_render() } } } -#if ENABLE_DEBUG_DIALOG - if (m_show_planes) { - const Transform3d view_model_matrix = view_matrix * model_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - for (GLModel& glmodel : m_plane_models_cache) { - glmodel.set_color(HOVER_COLOR); - glmodel.render(); - } - } -#endif // ENABLE_DEBUG_DIALOG shader->stop_using(); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 2cbdd15061..129175f159 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -11,8 +11,6 @@ #include -#define ENABLE_DEBUG_DIALOG 0 - namespace Slic3r { class ModelVolume; @@ -51,10 +49,10 @@ private: int m_mouse_pos_x; int m_mouse_pos_y; -#if ENABLE_DEBUG_DIALOG +#if ENABLE_MEASURE_GIZMO_DEBUG bool m_show_all = false; bool m_show_planes = false; -#endif // ENABLE_DEBUG_DIALOG +#endif // ENABLE_MEASURE_GIZMO_DEBUG void update_if_needed(); From aeb8dec4638be669c5862e34cbcc5adbff4200f7 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 25 Aug 2022 13:01:26 +0200 Subject: [PATCH 131/250] Measuring: code for Measure gizmo embedded into new tech ENABLE_MEASURE_GIZMO Fixed conflicts while rebasing to master --- src/libslic3r/Technologies.hpp | 4 +++- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 18 ++++-------------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 11 ++++------- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 4 ++++ 4 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index d5d2542cc5..4b6db1da45 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -66,8 +66,10 @@ // Enable picking using raytracing #define ENABLE_RAYCAST_PICKING (1 && ENABLE_LEGACY_OPENGL_REMOVAL) #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) +// Enable Measure Gizmo +#define ENABLE_MEASURE_GIZMO (1 && ENABLE_LEGACY_OPENGL_REMOVAL) // Enable debug code for Measure Gizmo -#define ENABLE_MEASURE_GIZMO_DEBUG (0 && ENABLE_2_5_0_ALPHA1) +#define ENABLE_MEASURE_GIZMO_DEBUG (0 && ENABLE_MEASURE_GIZMO) #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index d7a8f53f46..73ee87840a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -14,6 +14,8 @@ #include +#if ENABLE_MEASURE_GIZMO + namespace Slic3r { namespace GUI { @@ -261,20 +263,6 @@ void GLGizmoMeasure::on_render() -#if ! ENABLE_LEGACY_OPENGL_REMOVAL - #error NOT IMPLEMENTED -#endif -#if ! ENABLE_GL_SHADERS_ATTRIBUTES - #error NOT IMPLEMENTED -#endif - -void GLGizmoMeasure::on_render_for_picking() -{ -} - - - - void GLGizmoMeasure::update_if_needed() { auto update_plane_models_cache = [this](const indexed_triangle_set& its) { @@ -354,3 +342,5 @@ void GLGizmoMeasure::update_if_needed() } // namespace GUI } // namespace Slic3r + +#endif // ENABLE_MEASURE_GIZMO diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 129175f159..218b5e8757 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -1,15 +1,10 @@ #ifndef slic3r_GLGizmoMeasure_hpp_ #define slic3r_GLGizmoMeasure_hpp_ +#if ENABLE_MEASURE_GIZMO + #include "GLGizmoBase.hpp" -#if ENABLE_LEGACY_OPENGL_REMOVAL #include "slic3r/GUI/GLModel.hpp" -#else -#include "slic3r/GUI/3DScene.hpp" -#endif // ENABLE_LEGACY_OPENGL_REMOVAL - - -#include namespace Slic3r { @@ -81,4 +76,6 @@ protected: } // namespace GUI } // namespace Slic3r +#endif // ENABLE_MEASURE_GIZMO + #endif // slic3r_GLGizmoMeasure_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 6d25f84fbc..ff24dd84a3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -21,7 +21,9 @@ #include "slic3r/GUI/Gizmos/GLGizmoSeam.hpp" #include "slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp" #include "slic3r/GUI/Gizmos/GLGizmoSimplify.hpp" +#if ENABLE_MEASURE_GIZMO #include "slic3r/GUI/Gizmos/GLGizmoMeasure.hpp" +#endif // ENABLE_MEASURE_GIZMO #include "libslic3r/format.hpp" #include "libslic3r/Model.hpp" @@ -107,7 +109,9 @@ bool GLGizmosManager::init() m_gizmos.emplace_back(new GLGizmoSeam(m_parent, "seam.svg", 8)); m_gizmos.emplace_back(new GLGizmoMmuSegmentation(m_parent, "mmu_segmentation.svg", 9)); m_gizmos.emplace_back(new GLGizmoSimplify(m_parent, "cut.svg", 10)); +#if ENABLE_MEASURE_GIZMO m_gizmos.emplace_back(new GLGizmoMeasure(m_parent, "measure.svg", 11)); +#endif // ENABLE_MEASURE_GIZMO m_common_gizmos_data.reset(new CommonGizmosDataPool(&m_parent)); From 6c0aff0d23cb450671c41d50901707e2b7326ee5 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 29 Aug 2022 12:55:34 +0200 Subject: [PATCH 132/250] Measuring: Measure gizmo features registered for raycasted picking --- src/libslic3r/Measure.hpp | 10 ++ src/libslic3r/Technologies.hpp | 2 +- src/slic3r/GUI/GLCanvas3D.cpp | 4 +- src/slic3r/GUI/GLCanvas3D.hpp | 2 +- src/slic3r/GUI/GLModel.cpp | 15 +++ src/slic3r/GUI/GLModel.hpp | 2 + src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 132 ++++++++++++++++--- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 16 ++- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 4 +- 10 files changed, 160 insertions(+), 29 deletions(-) diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 98517b991b..2f27a72598 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -49,6 +49,16 @@ public: // For anything, return an extra point that should also be considered a part of this. std::optional get_extra_point() const { assert(m_type != SurfaceFeatureType::Undef); return m_pt3; } + bool operator == (const SurfaceFeature& other) const { + if (this->m_type != other.m_type) return false; + if (!this->m_pt1.isApprox(other.m_pt1)) return false; + if (!this->m_pt2.isApprox(other.m_pt2)) return false; + if (this->m_pt3.has_value() && !other.m_pt3.has_value()) return false; + if (!this->m_pt3.has_value() && other.m_pt3.has_value()) return false; + if (this->m_pt3.has_value() && other.m_pt3.has_value() && !(*this->m_pt3).isApprox(*other.m_pt3)) return false; + return this->m_value == other.m_value; + } + private: SurfaceFeatureType m_type = SurfaceFeatureType::Undef; Vec3d m_pt1; diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 4b6db1da45..baadc31bfd 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -67,7 +67,7 @@ #define ENABLE_RAYCAST_PICKING (1 && ENABLE_LEGACY_OPENGL_REMOVAL) #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) // Enable Measure Gizmo -#define ENABLE_MEASURE_GIZMO (1 && ENABLE_LEGACY_OPENGL_REMOVAL) +#define ENABLE_MEASURE_GIZMO (1 && ENABLE_RAYCAST_PICKING) // Enable debug code for Measure Gizmo #define ENABLE_MEASURE_GIZMO_DEBUG (0 && ENABLE_MEASURE_GIZMO) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 04a6918711..c63b70f9ea 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2252,7 +2252,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re #if ENABLE_LEGACY_OPENGL_REMOVAL volume.model.init_from(mesh); #if ENABLE_RAYCAST_PICKING - volume.mesh_raycaster = std::make_unique(std::make_shared(mesh)); + volume.mesh_raycaster = std::make_unique(std::make_shared(mesh)); #endif // ENABLE_RAYCAST_PICKING #else volume.indexed_vertex_array.load_mesh(mesh); @@ -2272,7 +2272,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re #if ENABLE_RAYCAST_PICKING const TriangleMesh& new_mesh = m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(); volume.model.init_from(new_mesh); - volume.mesh_raycaster = std::make_unique(std::make_shared(new_mesh)); + volume.mesh_raycaster = std::make_unique(std::make_shared(new_mesh)); #else volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh()); #endif // ENABLE_RAYCAST_PICKING diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 0adf1cb26d..34c6ed4ee0 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -680,7 +680,7 @@ public: #if ENABLE_RAYCAST_PICKING std::shared_ptr add_raycaster_for_picking(SceneRaycaster::EType type, int id, const MeshRaycaster& raycaster, - const Transform3d& trafo, bool use_back_faces = false) { + const Transform3d& trafo = Transform3d::Identity(), bool use_back_faces = false) { return m_scene_raycaster.add_raycaster(type, id, raycaster, trafo, use_back_faces); } void remove_raycasters_for_picking(SceneRaycaster::EType type, int id) { diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 03d2677bea..70af07b7d7 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -257,6 +257,21 @@ void GLModel::Geometry::remove_vertex(size_t id) } } +indexed_triangle_set GLModel::Geometry::get_as_indexed_triangle_set() const +{ + indexed_triangle_set its; + its.vertices.reserve(vertices_count()); + for (size_t i = 0; i < vertices_count(); ++i) { + its.vertices.emplace_back(extract_position_3(i)); + } + its.indices.reserve(indices_count() / 3); + for (size_t i = 0; i < indices_count() / 3; ++i) { + const size_t tri_id = i * 3; + its.indices.emplace_back(extract_index(tri_id), extract_index(tri_id + 1), extract_index(tri_id + 2)); + } + return its; +} + size_t GLModel::Geometry::vertex_stride_floats(const Format& format) { switch (format.vertex_layout) diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index e631952a3e..2d1e352c48 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -140,6 +140,8 @@ namespace GUI { size_t vertices_size_bytes() const { return vertices_size_floats() * sizeof(float); } size_t indices_size_bytes() const { return indices.size() * index_stride_bytes(*this); } + indexed_triangle_set get_as_indexed_triangle_set() const; + static size_t vertex_stride_floats(const Format& format); static size_t vertex_stride_bytes(const Format& format) { return vertex_stride_floats(format) * sizeof(float); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index bbae3f2429..99769e0061 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -114,7 +114,7 @@ void GLGizmoHollow::on_register_raycasters_for_picking() if (info != nullptr && !info->model_object()->sla_drain_holes.empty()) { const sla::DrainHoles& drain_holes = info->model_object()->sla_drain_holes; for (int i = 0; i < (int)drain_holes.size(); ++i) { - m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_cylinder.mesh_raycaster, Transform3d::Identity())); + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_cylinder.mesh_raycaster)); } update_raycasters_for_picking_transform(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 73ee87840a..e132cf2ce1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -7,7 +7,6 @@ #include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include "libslic3r/Model.hpp" -#include "libslic3r/Measure.hpp" #include "libslic3r/PresetBundle.hpp" #include @@ -20,12 +19,22 @@ namespace Slic3r { namespace GUI { static const Slic3r::ColorRGBA HOVER_COLOR = { 0.8f, 0.2f, 0.2f, 1.0f }; +static const int POINT_ID = 100; +static const int EDGE_ID = 200; +static const int CIRCLE_ID = 300; +static const int CIRCLE_CENTER_ID = 301; +static const int PLANE_ID = 400; GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) { - m_sphere.init_from(smooth_sphere(16, 7.5f)); - m_cylinder.init_from(smooth_cylinder(16, 5.0f, 1.0f)); + GLModel::Geometry sphere_geometry = smooth_sphere(16, 7.5f); + m_sphere.mesh_raycaster = std::make_unique(std::make_shared(std::move(sphere_geometry.get_as_indexed_triangle_set()))); + m_sphere.model.init_from(std::move(sphere_geometry)); + + GLModel::Geometry cylinder_geometry = smooth_cylinder(16, 5.0f, 1.0f); + m_cylinder.mesh_raycaster = std::make_unique(std::make_shared(std::move(cylinder_geometry.get_as_indexed_triangle_set()))); + m_cylinder.model.init_from(std::move(cylinder_geometry)); } bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) @@ -130,6 +139,7 @@ void GLGizmoMeasure::on_render() const Transform3d& model_matrix = selection.get_first_volume()->world_matrix(); const Camera& camera = wxGetApp().plater()->get_camera(); + const float inv_zoom = (float)camera.get_inv_zoom(); Vec3f pos; Vec3f normal; @@ -174,8 +184,70 @@ void GLGizmoMeasure::on_render() } #endif // ENABLE_MEASURE_GIZMO_DEBUG - if (features.empty()) - return; + if (m_features != features) { + GLGizmoMeasure::on_unregister_raycasters_for_picking(); + m_features = features; + if (m_features.empty()) + return; + +#if !ENABLE_MEASURE_GIZMO_DEBUG + for (const Measure::SurfaceFeature& feature : m_features) { + switch (feature.get_type()) { + case Measure::SurfaceFeatureType::Point: + { + m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, n] = feature.get_circle(); + m_circle.reset(); + GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); + m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); + m_circle.model.init_from(std::move(circle_geometry)); + + m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); + m_raycasters.insert({ CIRCLE_CENTER_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_CENTER_ID, *m_sphere.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto& [idx, normal, pt] = feature.get_plane(); + const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); + const std::vector& triangle_indices = planes_triangles[idx]; + + const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; + GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + unsigned int i = 0; + for (int idx : triangle_indices) { + const Vec3f& v0 = its.vertices[its.indices[idx][0]]; + const Vec3f& v1 = its.vertices[its.indices[idx][1]]; + const Vec3f& v2 = its.vertices[its.indices[idx][2]]; + + const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); + init_data.add_vertex(v0, n); + init_data.add_vertex(v1, n); + init_data.add_vertex(v2, n); + init_data.add_triangle(i, i + 1, i + 2); + i += 3; + } + + m_plane.reset(); + m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(init_data.get_as_indexed_triangle_set()))); + m_plane.model.init_from(std::move(init_data)); + m_raycasters.insert({ PLANE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID, *m_plane.mesh_raycaster) }); + break; + } + } + } +#endif // !ENABLE_MEASURE_GIZMO_DEBUG + } GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) @@ -189,9 +261,8 @@ void GLGizmoMeasure::on_render() glsafe(::glEnable(GL_DEPTH_TEST)); const Transform3d& view_matrix = camera.get_view_matrix(); - const float inv_zoom = camera.get_inv_zoom(); - for (const Measure::SurfaceFeature& feature : features) { + for (const Measure::SurfaceFeature& feature : m_features) { switch (feature.get_type()) { case Measure::SurfaceFeatureType::Point: { @@ -201,8 +272,11 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_sphere.set_color(HOVER_COLOR); - m_sphere.render(); + m_sphere.model.set_color(HOVER_COLOR); + m_sphere.model.render(); + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); break; } case Measure::SurfaceFeatureType::Circle: @@ -214,19 +288,22 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", center_view_model_matrix); const Matrix3d center_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * center_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", center_view_normal_matrix); - m_sphere.set_color(HOVER_COLOR); - m_sphere.render(); - - m_circle.reset(); - m_circle.init_from(smooth_torus(64, 16, float(radius), 5.0f * inv_zoom)); + m_sphere.model.set_color(HOVER_COLOR); + m_sphere.model.render(); + auto it = m_raycasters.find(CIRCLE_CENTER_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(center_matrix); const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center); const Transform3d circle_view_model_matrix = view_matrix * circle_matrix; shader->set_uniform("view_model_matrix", circle_view_model_matrix); const Matrix3d circle_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * circle_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", circle_view_normal_matrix); - m_circle.set_color(HOVER_COLOR); - m_circle.render(); + m_circle.model.set_color(HOVER_COLOR); + m_circle.model.render(); + it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(circle_matrix); break; } case Measure::SurfaceFeatureType::Edge: @@ -239,8 +316,11 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_cylinder.set_color(HOVER_COLOR); - m_cylinder.render(); + m_cylinder.model.set_color(HOVER_COLOR); + m_cylinder.model.render(); + auto it = m_raycasters.find(EDGE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); break; } case Measure::SurfaceFeatureType::Plane: @@ -253,6 +333,9 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_normal_matrix", view_normal_matrix); m_plane_models_cache[idx].set_color(HOVER_COLOR); m_plane_models_cache[idx].render(); + auto it = m_raycasters.find(PLANE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(model_matrix); break; } } @@ -340,6 +423,19 @@ void GLGizmoMeasure::update_if_needed() } } +void GLGizmoMeasure::on_register_raycasters_for_picking() +{ + // the features are rendered on top of the scene, so the raytraced picker should take it into account + m_parent.set_raycaster_gizmos_on_top(true); +} + +void GLGizmoMeasure::on_unregister_raycasters_for_picking() +{ + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo); + m_parent.set_raycaster_gizmos_on_top(false); + m_raycasters.clear(); +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 218b5e8757..41dc9fffba 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -5,6 +5,7 @@ #include "GLGizmoBase.hpp" #include "slic3r/GUI/GLModel.hpp" +#include "libslic3r/Measure.hpp" namespace Slic3r { @@ -25,10 +26,14 @@ class GLGizmoMeasure : public GLGizmoBase private: std::unique_ptr m_measuring; - GLModel m_sphere; - GLModel m_cylinder; - GLModel m_circle; + PickingModel m_sphere; + PickingModel m_cylinder; + PickingModel m_circle; + PickingModel m_plane; + std::vector m_plane_models_cache; + std::map> m_raycasters; + std::vector m_features; // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; @@ -53,7 +58,7 @@ private: public: GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); - + /// /// Apply rotation on select plane /// @@ -71,6 +76,9 @@ protected: void on_render_for_picking() override; void on_set_state() override; CommonGizmosDataID on_get_requirements() const override; + + virtual void on_register_raycasters_for_picking() override; + virtual void on_unregister_raycasters_for_picking() override; }; } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index b562eb49a0..7be4301ad1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -148,8 +148,8 @@ void GLGizmoSlaSupports::on_register_raycasters_for_picking() if (m_editing_mode && !m_editing_cache.empty()) { for (size_t i = 0; i < m_editing_cache.size(); ++i) { - m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_sphere.mesh_raycaster, Transform3d::Identity()), - m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_cone.mesh_raycaster, Transform3d::Identity())); + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_sphere.mesh_raycaster), + m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_cone.mesh_raycaster)); } update_raycasters_for_picking_transform(); } From ed287215dbf6161e5d259265959b0fc234ae14cf Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 30 Aug 2022 14:30:38 +0200 Subject: [PATCH 133/250] Measuring: Added Measure gizmo imgui dialog + removed tech ENABLE_MEASURE_GIZMO_DEBUG + locking of features by pressing CTRL key --- src/libslic3r/Measure.cpp | 2 - src/libslic3r/Measure.hpp | 6 +- src/libslic3r/Technologies.hpp | 2 - src/slic3r/GUI/GLCanvas3D.hpp | 5 + src/slic3r/GUI/GUI_Utils.hpp | 12 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 365 ++++++++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 19 +- src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 4 + src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 58 ++-- 9 files changed, 311 insertions(+), 162 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 9cb46edfc1..cdde276dda 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -408,12 +408,10 @@ Measuring::Measuring(const indexed_triangle_set& its) Measuring::~Measuring() {} -#if ENABLE_MEASURE_GIZMO_DEBUG std::vector Measuring::get_all_features() const { return priv->get_all_features(); } -#endif // ENABLE_MEASURE_GIZMO_DEBUG std::optional Measuring::get_feature(size_t face_idx, const Vec3d& point) const diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 2f27a72598..95d8f34cba 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -59,6 +59,10 @@ public: return this->m_value == other.m_value; } + bool operator != (const SurfaceFeature& other) const { + return !operator == (other); + } + private: SurfaceFeatureType m_type = SurfaceFeatureType::Undef; Vec3d m_pt1; @@ -79,11 +83,9 @@ public: explicit Measuring(const indexed_triangle_set& its); ~Measuring(); -#if ENABLE_MEASURE_GIZMO_DEBUG // Return a reference to a list of all features identified on the its. // Use only for debugging. Expensive, do not call often. std::vector get_all_features() const; -#endif // ENABLE_MEASURE_GIZMO_DEBUG // Given a face_idx where the mouse cursor points, return a feature that // should be highlighted (if any). diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index baadc31bfd..a96a39066c 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -68,8 +68,6 @@ #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) // Enable Measure Gizmo #define ENABLE_MEASURE_GIZMO (1 && ENABLE_RAYCAST_PICKING) -// Enable debug code for Measure Gizmo -#define ENABLE_MEASURE_GIZMO_DEBUG (0 && ENABLE_MEASURE_GIZMO) #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 34c6ed4ee0..7ce488ae54 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -19,6 +19,9 @@ #if ENABLE_RAYCAST_PICKING #include "SceneRaycaster.hpp" #endif // ENABLE_RAYCAST_PICKING +#if ENABLE_MEASURE_GIZMO +#include "GUI_Utils.hpp" +#endif // ENABLE_MEASURE_GIZMO #include "libslic3r/Slicing.hpp" @@ -135,6 +138,7 @@ private: wxTimer* m_timer; }; +#if !ENABLE_MEASURE_GIZMO class KeyAutoRepeatFilter { size_t m_count{ 0 }; @@ -144,6 +148,7 @@ public: void reset_count() { m_count = 0; } bool is_first() const { return m_count == 0; } }; +#endif // !ENABLE_MEASURE_GIZMO wxDECLARE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index d7d3529fee..e2152edd6d 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -416,6 +416,18 @@ public: ~TaskTimer(); }; +#if ENABLE_MEASURE_GIZMO +class KeyAutoRepeatFilter +{ + size_t m_count{ 0 }; + +public: + void increase_count() { ++m_count; } + void reset_count() { m_count = 0; } + bool is_first() const { return m_count == 0; } +}; +#endif // ENABLE_MEASURE_GIZMO + }} #endif diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index e132cf2ce1..2a856fb830 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -15,10 +15,26 @@ #if ENABLE_MEASURE_GIZMO +std::string surface_feature_type_as_string(Slic3r::Measure::SurfaceFeatureType type) +{ + switch (type) + { + default: + case Slic3r::Measure::SurfaceFeatureType::Undef: { return L("Undefined"); } + case Slic3r::Measure::SurfaceFeatureType::Point: { return L("Point"); } + case Slic3r::Measure::SurfaceFeatureType::Edge: { return L("Edge"); } + case Slic3r::Measure::SurfaceFeatureType::Circle: { return L("Circle"); } + case Slic3r::Measure::SurfaceFeatureType::Plane: { return L("Plane"); } + } +} + namespace Slic3r { namespace GUI { -static const Slic3r::ColorRGBA HOVER_COLOR = { 0.8f, 0.2f, 0.2f, 1.0f }; +static const Slic3r::ColorRGBA BASIC_HOVER_COLOR = { 0.8f, 0.2f, 0.2f, 1.0f }; +static const Slic3r::ColorRGBA EXTENDED_HOVER_COLOR = { 0.2f, 0.8f, 0.2f, 1.0f }; +static const Slic3r::ColorRGBA LOCK_COLOR = { 0.5f, 0.5f, 0.5f, 1.0f }; + static const int POINT_ID = 100; static const int EDGE_ID = 200; static const int CIRCLE_ID = 300; @@ -42,40 +58,39 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) m_mouse_pos_x = mouse_event.GetX(); m_mouse_pos_y = mouse_event.GetY(); - if (mouse_event.Moving()) { // only for sure m_mouse_left_down = false; return false; } - if (mouse_event.LeftDown()) { + else if (mouse_event.LeftDown()) { if (m_hover_id != -1) { - m_mouse_left_down = true; - + m_mouse_left_down = true; return true; } // fix: prevent restart gizmo when reselect object // take responsibility for left up - if (m_parent.get_first_hover_volume_idx() >= 0) m_mouse_left_down = true; + if (m_parent.get_first_hover_volume_idx() >= 0) + m_mouse_left_down = true; - } else if (mouse_event.LeftUp()) { + } + else if (mouse_event.LeftUp()) { if (m_mouse_left_down) { // responsible for mouse left up after selecting plane m_mouse_left_down = false; return true; } - } else if (mouse_event.Leaving()) { - m_mouse_left_down = false; } + else if (mouse_event.Leaving()) + m_mouse_left_down = false; + return false; } - - void GLGizmoMeasure::data_changed() { - const Selection & selection = m_parent.get_selection(); + const Selection& selection = m_parent.get_selection(); const ModelObject* model_object = nullptr; const ModelVolume* model_volume = nullptr; if (selection.is_single_full_instance() || @@ -87,29 +102,43 @@ void GLGizmoMeasure::data_changed() update_if_needed(); } - - -bool GLGizmoMeasure::on_init() +bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) { - // FIXME m_shortcut_key = WXK_CONTROL_F; + if (action == SLAGizmoEventType::CtrlDown) { + if (m_ctrl_kar_filter.is_first()) { + if (!m_features.empty()) + m_mode = EMode::ExtendedSelection; + } + + m_ctrl_kar_filter.increase_count(); + } + else if (action == SLAGizmoEventType::CtrlUp) { + m_ctrl_kar_filter.reset_count(); + m_mode = EMode::BasicSelection; + } + return true; } - +bool GLGizmoMeasure::on_init() +{ + m_shortcut_key = WXK_CONTROL_U; + return true; +} void GLGizmoMeasure::on_set_state() { + if (m_state == Off) + m_ctrl_kar_filter.reset_count(); + else + m_mode = EMode::BasicSelection; } - - CommonGizmosDataID GLGizmoMeasure::on_get_requirements() const { return CommonGizmosDataID(int(CommonGizmosDataID::SelectionInfo) | int(CommonGizmosDataID::Raycaster)); } - - std::string GLGizmoMeasure::on_get_name() const { return _u8L("Measure"); @@ -125,11 +154,9 @@ bool GLGizmoMeasure::on_is_activable() const void GLGizmoMeasure::on_render() { -#if !ENABLE_MEASURE_GIZMO_DEBUG // do not render if the user is panning/rotating the 3d scene if (m_parent.is_mouse_dragging()) return; -#endif // !ENABLE_MEASURE_GIZMO_DEBUG const Selection& selection = m_parent.get_selection(); @@ -146,107 +173,76 @@ void GLGizmoMeasure::on_render() size_t facet_idx; m_c->raycaster()->raycasters().front()->unproject_on_mesh(Vec2d(m_mouse_pos_x, m_mouse_pos_y), model_matrix, camera, pos, normal, nullptr, &facet_idx); -#if ENABLE_MEASURE_GIZMO_DEBUG - m_imgui->begin(std::string("DEBUG")); - m_imgui->checkbox(wxString("Show all features"), m_show_all); - m_imgui->checkbox(wxString("Show all planes"), m_show_planes); - ImGui::Separator(); - m_imgui->text(std::string("face_idx: ") + std::to_string(facet_idx)); - m_imgui->text(std::string("pos_x: ") + std::to_string(pos.x())); - m_imgui->text(std::string("pos_y: ") + std::to_string(pos.y())); - m_imgui->text(std::string("pos_z: ") + std::to_string(pos.z())); - m_imgui->end(); -#endif // ENABLE_MEASURE_GIZMO_DEBUG - std::vector features; -#if ENABLE_MEASURE_GIZMO_DEBUG - if (m_show_all || m_show_planes) { - features = m_measuring->get_all_features(); - if (!m_show_planes) - features.erase(std::remove_if(features.begin(), features.end(), - [](const Measure::SurfaceFeature& f) { - return f.get_type() == Measure::SurfaceFeatureType::Plane; - }), features.end()); - if (!m_show_all) - features.erase(std::remove_if(features.begin(), features.end(), - [](const Measure::SurfaceFeature& f) { - return f.get_type() != Measure::SurfaceFeatureType::Plane; - }), features.end()); + if (m_mode == EMode::BasicSelection) { + std::optional feat = m_measuring->get_feature(facet_idx, pos.cast()); + if (feat.has_value()) + features.emplace_back(*feat); } - else { - if (!m_parent.is_mouse_dragging()) { -#endif // ENABLE_MEASURE_GIZMO_DEBUG - std::optional feat = m_measuring->get_feature(facet_idx, pos.cast()); - if (feat.has_value()) - features.emplace_back(*feat); -#if ENABLE_MEASURE_GIZMO_DEBUG - } - } -#endif // ENABLE_MEASURE_GIZMO_DEBUG - if (m_features != features) { - GLGizmoMeasure::on_unregister_raycasters_for_picking(); - m_features = features; - if (m_features.empty()) - return; + if (m_mode == EMode::BasicSelection) { + if (m_features != features) { + GLGizmoMeasure::on_unregister_raycasters_for_picking(); + m_features = features; + if (m_features.empty()) + return; -#if !ENABLE_MEASURE_GIZMO_DEBUG - for (const Measure::SurfaceFeature& feature : m_features) { - switch (feature.get_type()) { - case Measure::SurfaceFeatureType::Point: - { - m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); - break; - } - case Measure::SurfaceFeatureType::Edge: - { - m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); - break; - } - case Measure::SurfaceFeatureType::Circle: - { - const auto& [center, radius, n] = feature.get_circle(); - m_circle.reset(); - GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); - m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); - m_circle.model.init_from(std::move(circle_geometry)); - - m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); - m_raycasters.insert({ CIRCLE_CENTER_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_CENTER_ID, *m_sphere.mesh_raycaster) }); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - const auto& [idx, normal, pt] = feature.get_plane(); - const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); - const std::vector& triangle_indices = planes_triangles[idx]; - - const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; - GLModel::Geometry init_data; - init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; - unsigned int i = 0; - for (int idx : triangle_indices) { - const Vec3f& v0 = its.vertices[its.indices[idx][0]]; - const Vec3f& v1 = its.vertices[its.indices[idx][1]]; - const Vec3f& v2 = its.vertices[its.indices[idx][2]]; - - const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); - init_data.add_vertex(v0, n); - init_data.add_vertex(v1, n); - init_data.add_vertex(v2, n); - init_data.add_triangle(i, i + 1, i + 2); - i += 3; + for (const Measure::SurfaceFeature& feature : m_features) { + switch (feature.get_type()) { + case Measure::SurfaceFeatureType::Point: + { + m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); + break; } + case Measure::SurfaceFeatureType::Edge: + { + m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, n] = feature.get_circle(); + m_circle.reset(); + GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); + m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); + m_circle.model.init_from(std::move(circle_geometry)); - m_plane.reset(); - m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(init_data.get_as_indexed_triangle_set()))); - m_plane.model.init_from(std::move(init_data)); - m_raycasters.insert({ PLANE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID, *m_plane.mesh_raycaster) }); - break; - } + m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); + m_raycasters.insert({ CIRCLE_CENTER_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_CENTER_ID, *m_sphere.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto& [idx, normal, pt] = feature.get_plane(); + const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); + const std::vector& triangle_indices = planes_triangles[idx]; + + const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; + GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + unsigned int i = 0; + for (int idx : triangle_indices) { + const Vec3f& v0 = its.vertices[its.indices[idx][0]]; + const Vec3f& v1 = its.vertices[its.indices[idx][1]]; + const Vec3f& v2 = its.vertices[its.indices[idx][2]]; + + const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); + init_data.add_vertex(v0, n); + init_data.add_vertex(v1, n); + init_data.add_vertex(v2, n); + init_data.add_triangle(i, i + 1, i + 2); + i += 3; + } + + m_plane.reset(); + m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(init_data.get_as_indexed_triangle_set()))); + m_plane.model.init_from(std::move(init_data)); + m_raycasters.insert({ PLANE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID, *m_plane.mesh_raycaster) }); + break; + } + } } } -#endif // !ENABLE_MEASURE_GIZMO_DEBUG } GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); @@ -262,6 +258,13 @@ void GLGizmoMeasure::on_render() const Transform3d& view_matrix = camera.get_view_matrix(); + ColorRGBA color; + switch (m_mode) + { + case EMode::BasicSelection: { color = BASIC_HOVER_COLOR; break; } + case EMode::ExtendedSelection: { color = LOCK_COLOR; break; } + } + for (const Measure::SurfaceFeature& feature : m_features) { switch (feature.get_type()) { case Measure::SurfaceFeatureType::Point: @@ -272,7 +275,7 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_sphere.model.set_color(HOVER_COLOR); + m_sphere.model.set_color(color); m_sphere.model.render(); auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) @@ -288,7 +291,7 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", center_view_model_matrix); const Matrix3d center_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * center_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", center_view_normal_matrix); - m_sphere.model.set_color(HOVER_COLOR); + m_sphere.model.set_color(color); m_sphere.model.render(); auto it = m_raycasters.find(CIRCLE_CENTER_ID); if (it != m_raycasters.end() && it->second != nullptr) @@ -299,7 +302,7 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", circle_view_model_matrix); const Matrix3d circle_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * circle_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", circle_view_normal_matrix); - m_circle.model.set_color(HOVER_COLOR); + m_circle.model.set_color(color); m_circle.model.render(); it = m_raycasters.find(CIRCLE_ID); if (it != m_raycasters.end() && it->second != nullptr) @@ -316,7 +319,7 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_cylinder.model.set_color(HOVER_COLOR); + m_cylinder.model.set_color(color); m_cylinder.model.render(); auto it = m_raycasters.find(EDGE_ID); if (it != m_raycasters.end() && it->second != nullptr) @@ -331,7 +334,7 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_plane_models_cache[idx].set_color(HOVER_COLOR); + m_plane_models_cache[idx].set_color(color); m_plane_models_cache[idx].render(); auto it = m_raycasters.find(PLANE_ID); if (it != m_raycasters.end() && it->second != nullptr) @@ -344,8 +347,6 @@ void GLGizmoMeasure::on_render() } } - - void GLGizmoMeasure::update_if_needed() { auto update_plane_models_cache = [this](const indexed_triangle_set& its) { @@ -423,6 +424,124 @@ void GLGizmoMeasure::update_if_needed() } } +void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit) +{ + static Measure::SurfaceFeature last_feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Undef, Vec3d::Zero(), Vec3d::Zero(), std::nullopt, 0.0); + + static float last_y = 0.0f; + static float last_h = 0.0f; + + m_imgui->begin(_L("Measure tool"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + + // adjust window position to avoid overlap the view toolbar + const float win_h = ImGui::GetWindowHeight(); + y = std::min(y, bottom_limit - win_h); + ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always); + if (last_h != win_h || last_y != y) { + // ask canvas for another frame to render the window in the correct position + m_imgui->set_requires_extra_frame(); + if (last_h != win_h) + last_h = win_h; + if (last_y != y) + last_y = y; + } + + if (m_features.empty()) + m_imgui->text(_u8L("Select features to measure")); + + auto add_row_to_table = [this](const wxString& label, const std::string& value) { + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, label); + ImGui::TableSetColumnIndex(1); + m_imgui->text(value); + }; + + const Transform3d volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); + Measure::SurfaceFeature curr_feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Undef, Vec3d::Zero(), Vec3d::Zero(), std::nullopt, 0.0); + for (size_t i = 0; i < m_features.size(); ++i) { + curr_feature = m_features[i]; + const Measure::SurfaceFeatureType type = curr_feature.get_type(); + if (type != Measure::SurfaceFeatureType::Undef) { + const std::string header = surface_feature_type_as_string(type) + std::string("##") + std::to_string(i); + if (ImGui::CollapsingHeader(header.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { + if (ImGui::BeginTable("Data", 2)) { + switch (type) + { + case Measure::SurfaceFeatureType::Point: + { + const Vec3d position = volume_matrix * curr_feature.get_point(); + char buf[1024]; + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", position.x(), position.y(), position.z()); + add_row_to_table(_u8L("Position") + ":", std::string(buf)); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + auto [from, to] = curr_feature.get_edge(); + from = volume_matrix * from; + to = volume_matrix * to; + char buf[1024]; + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", from.x(), from.y(), from.z()); + add_row_to_table(_u8L("From") + ":", std::string(buf)); + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", to.x(), to.y(), to.z()); + add_row_to_table(_u8L("To") + ":", std::string(buf)); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + auto [center, radius, normal] = curr_feature.get_circle(); + center = volume_matrix * center; + normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + char buf[1024]; + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", center.x(), center.y(), center.z()); + add_row_to_table(_u8L("Center") + ":", std::string(buf)); + sprintf(buf, "%.3f", radius); + add_row_to_table(_u8L("Radius") + ":", std::string(buf)); + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", normal.x(), normal.y(), normal.z()); + add_row_to_table(_u8L("Normal") + ":", std::string(buf)); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + auto [idx, normal, origin] = curr_feature.get_plane(); + origin = volume_matrix * origin; + normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + char buf[1024]; + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", origin.x(), origin.y(), origin.z()); + add_row_to_table(_u8L("Origin") + ":", std::string(buf)); + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", normal.x(), normal.y(), normal.z()); + add_row_to_table(_u8L("Normal") + ":", std::string(buf)); + break; + } + } + ImGui::EndTable(); + } + } + } + } + + if (last_feature != curr_feature) { + // the dialog may have changed its size, ask for an extra frame to render it properly + last_feature = curr_feature; + m_imgui->set_requires_extra_frame(); + } + + if (!m_features.empty()) { + static const std::string ctrl = +#ifdef __APPLE__ + "⌘" +#else + "Ctrl" +#endif //__APPLE__ + ; + + ImGui::Separator(); + m_imgui->text(_u8L("Press") + " " + ctrl + " " + _u8L("to enable extended selection")); + } + m_imgui->end(); +} + void GLGizmoMeasure::on_register_raycasters_for_picking() { // the features are rendered on top of the scene, so the raytraced picker should take it into account diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 41dc9fffba..a3d027dccd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -5,6 +5,7 @@ #include "GLGizmoBase.hpp" #include "slic3r/GUI/GLModel.hpp" +#include "slic3r/GUI/GUI_Utils.hpp" #include "libslic3r/Measure.hpp" namespace Slic3r { @@ -18,12 +19,19 @@ namespace Measure { class Measuring; } namespace GUI { +enum class SLAGizmoEventType : unsigned char; class GLGizmoMeasure : public GLGizmoBase { // This gizmo does not use grabbers. The m_hover_id relates to polygon managed by the class itself. -private: + enum class EMode : unsigned char + { + BasicSelection, + ExtendedSelection + }; + + EMode m_mode{ EMode::BasicSelection }; std::unique_ptr m_measuring; PickingModel m_sphere; @@ -49,10 +57,8 @@ private: int m_mouse_pos_x; int m_mouse_pos_y; -#if ENABLE_MEASURE_GIZMO_DEBUG - bool m_show_all = false; - bool m_show_planes = false; -#endif // ENABLE_MEASURE_GIZMO_DEBUG + + KeyAutoRepeatFilter m_ctrl_kar_filter; void update_if_needed(); @@ -68,6 +74,8 @@ public: void data_changed() override; + bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); + protected: bool on_init() override; std::string on_get_name() const override; @@ -77,6 +85,7 @@ protected: void on_set_state() override; CommonGizmosDataID on_get_requirements() const override; + virtual void on_render_input_window(float x, float y, float bottom_limit) override; virtual void on_register_raycasters_for_picking() override; virtual void on_unregister_raycasters_for_picking() override; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index c8b29f761e..c3aa1691f1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -24,6 +24,10 @@ enum class SLAGizmoEventType : unsigned char { Dragging, Delete, SelectAll, +#if ENABLE_MEASURE_GIZMO + CtrlDown, + CtrlUp, +#endif // ENABLE_MEASURE_GIZMO ShiftUp, AltUp, ApplyChanges, diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index ff24dd84a3..fbf0afe13a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -294,6 +294,10 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p return dynamic_cast(m_gizmos[Seam].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); else if (m_current == MmuSegmentation) return dynamic_cast(m_gizmos[MmuSegmentation].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); +#if ENABLE_MEASURE_GIZMO + else if (m_current == Measure) + return dynamic_cast(m_gizmos[Measure].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); +#endif // ENABLE_MEASURE_GIZMO else return false; } @@ -499,8 +503,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) bool processed = false; - if ((evt.GetModifiers() & ctrlMask) != 0) - { + if ((evt.GetModifiers() & ctrlMask) != 0) { switch (keyCode) { #ifdef __APPLE__ @@ -518,15 +521,13 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) } } } - else if (!evt.HasModifiers()) - { + else if (!evt.HasModifiers()) { switch (keyCode) { // key ESC case WXK_ESCAPE: { - if (m_current != Undefined) - { + if (m_current != Undefined) { if ((m_current != SlaSupports) || !gizmo_event(SLAGizmoEventType::DiscardChanges)) reset_all_states(); @@ -563,8 +564,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) case 'A': case 'a': { - if (m_current == SlaSupports) - { + if (m_current == SlaSupports) { gizmo_event(SLAGizmoEventType::AutomaticGeneration); // set as processed no matter what's returned by gizmo_event() to avoid the calling canvas to process 'A' as arrange processed = true; @@ -582,8 +582,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) case 'F': case 'f': { - if (m_current == Scale) - { + if (m_current == Scale) { if (!is_dragging()) wxGetApp().plater()->scale_selection_to_fit_print_volume(); @@ -595,8 +594,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) } } - if (!processed && !evt.HasModifiers()) - { + if (!processed && !evt.HasModifiers()) { if (handle_shortcut(keyCode)) processed = true; } @@ -612,10 +610,8 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) const int keyCode = evt.GetKeyCode(); bool processed = false; - if (evt.GetEventType() == wxEVT_KEY_UP) - { - if (m_current == SlaSupports || m_current == Hollow) - { + if (evt.GetEventType() == wxEVT_KEY_UP) { + if (m_current == SlaSupports || m_current == Hollow) { bool is_editing = true; bool is_rectangle_dragging = false; @@ -629,33 +625,33 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) is_rectangle_dragging = gizmo->is_selection_rectangle_dragging(); } - if (keyCode == WXK_SHIFT) - { + if (keyCode == WXK_SHIFT) { // shift has been just released - SLA gizmo might want to close rectangular selection. if (gizmo_event(SLAGizmoEventType::ShiftUp) || (is_editing && is_rectangle_dragging)) processed = true; } - else if (keyCode == WXK_ALT) - { + else if (keyCode == WXK_ALT) { // alt has been just released - SLA gizmo might want to close rectangular selection. if (gizmo_event(SLAGizmoEventType::AltUp) || (is_editing && is_rectangle_dragging)) processed = true; } } +#if ENABLE_MEASURE_GIZMO + else if (m_current == Measure && keyCode == WXK_CONTROL) { + gizmo_event(SLAGizmoEventType::CtrlUp, Vec2d::Zero(), false); + } +#endif // ENABLE_MEASURE_GIZMO // if (processed) // m_parent.set_cursor(GLCanvas3D::Standard); } - else if (evt.GetEventType() == wxEVT_KEY_DOWN) - { - if ((m_current == SlaSupports) && ((keyCode == WXK_SHIFT) || (keyCode == WXK_ALT)) - && dynamic_cast(get_current())->is_in_editing_mode()) - { + else if (evt.GetEventType() == wxEVT_KEY_DOWN) { + if (m_current == SlaSupports && (keyCode == WXK_SHIFT || keyCode == WXK_ALT) + && dynamic_cast(get_current())->is_in_editing_mode()) { // m_parent.set_cursor(GLCanvas3D::Cross); processed = true; } - else if (m_current == Cut) - { + else if (m_current == Cut) { auto do_move = [this, &processed](double delta_z) { GLGizmoCut* cut = dynamic_cast(get_current()); cut->set_cut_z(delta_z + cut->get_cut_z()); @@ -668,11 +664,17 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) case WXK_NUMPAD_DOWN: case WXK_DOWN: { do_move(-1.0); break; } default: { break; } } - } else if (m_current == Simplify && keyCode == WXK_ESCAPE) { + } + else if (m_current == Simplify && keyCode == WXK_ESCAPE) { GLGizmoSimplify *simplify = dynamic_cast(get_current()); if (simplify != nullptr) processed = simplify->on_esc_key_down(); } +#if ENABLE_MEASURE_GIZMO + else if (m_current == Measure && keyCode == WXK_CONTROL) { + gizmo_event(SLAGizmoEventType::CtrlDown, Vec2d::Zero(), true); + } +#endif // ENABLE_MEASURE_GIZMO } if (processed) From 9f4f09fbbfb62aa63a5c5916815946a4ce0fed42 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 30 Aug 2022 15:38:29 +0200 Subject: [PATCH 134/250] Refactoring of GLGizmoMeasure to simplify code --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 329 ++++++++++++----------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 7 +- 2 files changed, 167 insertions(+), 169 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 2a856fb830..2c040c9c3b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -55,8 +55,7 @@ GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filen bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) { - m_mouse_pos_x = mouse_event.GetX(); - m_mouse_pos_y = mouse_event.GetY(); + m_mouse_pos = { double(mouse_event.GetX()), double(mouse_event.GetY()) }; if (mouse_event.Moving()) { // only for sure @@ -106,7 +105,7 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po { if (action == SLAGizmoEventType::CtrlDown) { if (m_ctrl_kar_filter.is_first()) { - if (!m_features.empty()) + if (m_curr_feature.has_value()) m_mode = EMode::ExtendedSelection; } @@ -171,80 +170,84 @@ void GLGizmoMeasure::on_render() Vec3f pos; Vec3f normal; size_t facet_idx; - m_c->raycaster()->raycasters().front()->unproject_on_mesh(Vec2d(m_mouse_pos_x, m_mouse_pos_y), model_matrix, camera, pos, normal, nullptr, &facet_idx); + m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, model_matrix, camera, pos, normal, nullptr, &facet_idx); - std::vector features; - if (m_mode == EMode::BasicSelection) { - std::optional feat = m_measuring->get_feature(facet_idx, pos.cast()); - if (feat.has_value()) - features.emplace_back(*feat); - } + std::optional curr_feature; + if (m_mode == EMode::BasicSelection) + curr_feature = m_measuring->get_feature(facet_idx, pos.cast()); if (m_mode == EMode::BasicSelection) { - if (m_features != features) { + if (m_curr_feature != curr_feature) { GLGizmoMeasure::on_unregister_raycasters_for_picking(); - m_features = features; - if (m_features.empty()) + m_curr_feature = curr_feature; + if (!m_curr_feature.has_value()) return; - for (const Measure::SurfaceFeature& feature : m_features) { - switch (feature.get_type()) { - case Measure::SurfaceFeatureType::Point: - { - m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); - break; - } - case Measure::SurfaceFeatureType::Edge: - { - m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); - break; - } - case Measure::SurfaceFeatureType::Circle: - { - const auto& [center, radius, n] = feature.get_circle(); - m_circle.reset(); - GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); - m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); - m_circle.model.init_from(std::move(circle_geometry)); + switch (m_curr_feature->get_type()) { + case Measure::SurfaceFeatureType::Point: + { + m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, n] = m_curr_feature->get_circle(); - m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); - m_raycasters.insert({ CIRCLE_CENTER_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_CENTER_ID, *m_sphere.mesh_raycaster) }); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - const auto& [idx, normal, pt] = feature.get_plane(); - const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); - const std::vector& triangle_indices = planes_triangles[idx]; + // TODO: check for changed inv_zoom - const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; - GLModel::Geometry init_data; - init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; - unsigned int i = 0; - for (int idx : triangle_indices) { - const Vec3f& v0 = its.vertices[its.indices[idx][0]]; - const Vec3f& v1 = its.vertices[its.indices[idx][1]]; - const Vec3f& v2 = its.vertices[its.indices[idx][2]]; + m_circle.reset(); + GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); + m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); + m_circle.model.init_from(std::move(circle_geometry)); - const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); - init_data.add_vertex(v0, n); - init_data.add_vertex(v1, n); - init_data.add_vertex(v2, n); - init_data.add_triangle(i, i + 1, i + 2); - i += 3; - } + m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); + m_raycasters.insert({ CIRCLE_CENTER_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_CENTER_ID, *m_sphere.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto& [idx, normal, pt] = m_curr_feature->get_plane(); - m_plane.reset(); - m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(init_data.get_as_indexed_triangle_set()))); - m_plane.model.init_from(std::move(init_data)); - m_raycasters.insert({ PLANE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID, *m_plane.mesh_raycaster) }); - break; - } + // TODO: check for changed idx + + const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); + const std::vector& triangle_indices = planes_triangles[idx]; + + const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; + GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + unsigned int i = 0; + for (int idx : triangle_indices) { + const Vec3f& v0 = its.vertices[its.indices[idx][0]]; + const Vec3f& v1 = its.vertices[its.indices[idx][1]]; + const Vec3f& v2 = its.vertices[its.indices[idx][2]]; + + const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); + init_data.add_vertex(v0, n); + init_data.add_vertex(v1, n); + init_data.add_vertex(v2, n); + init_data.add_triangle(i, i + 1, i + 2); + i += 3; } + + m_plane.reset(); + m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(init_data.get_as_indexed_triangle_set()))); + m_plane.model.init_from(std::move(init_data)); + m_raycasters.insert({ PLANE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID, *m_plane.mesh_raycaster) }); + break; + } } } } + if (!m_curr_feature.has_value()) + return; + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) return; @@ -265,84 +268,84 @@ void GLGizmoMeasure::on_render() case EMode::ExtendedSelection: { color = LOCK_COLOR; break; } } - for (const Measure::SurfaceFeature& feature : m_features) { - switch (feature.get_type()) { - case Measure::SurfaceFeatureType::Point: - { - const Vec3d& position = feature.get_point(); - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); - const Transform3d view_model_matrix = view_matrix * feature_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_sphere.model.set_color(color); - m_sphere.model.render(); - auto it = m_raycasters.find(POINT_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(feature_matrix); - break; - } - case Measure::SurfaceFeatureType::Circle: - { - const auto& [center, radius, n] = feature.get_circle(); - // render center - const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); - const Transform3d center_view_model_matrix = view_matrix * center_matrix; - shader->set_uniform("view_model_matrix", center_view_model_matrix); - const Matrix3d center_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * center_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", center_view_normal_matrix); - m_sphere.model.set_color(color); - m_sphere.model.render(); - auto it = m_raycasters.find(CIRCLE_CENTER_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(center_matrix); - - const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center); - const Transform3d circle_view_model_matrix = view_matrix * circle_matrix; - shader->set_uniform("view_model_matrix", circle_view_model_matrix); - const Matrix3d circle_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * circle_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", circle_view_normal_matrix); - m_circle.model.set_color(color); - m_circle.model.render(); - it = m_raycasters.find(CIRCLE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(circle_matrix); - break; - } - case Measure::SurfaceFeatureType::Edge: - { - const auto& [start, end] = feature.get_edge(); - auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * q * - Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); - const Transform3d view_model_matrix = view_matrix * feature_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_cylinder.model.set_color(color); - m_cylinder.model.render(); - auto it = m_raycasters.find(EDGE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(feature_matrix); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - const auto& [idx, normal, pt] = feature.get_plane(); - assert(idx < m_plane_models_cache.size()); - const Transform3d view_model_matrix = view_matrix * model_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_plane_models_cache[idx].set_color(color); - m_plane_models_cache[idx].render(); - auto it = m_raycasters.find(PLANE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(model_matrix); - break; - } - } + switch (m_curr_feature->get_type()) { + case Measure::SurfaceFeatureType::Point: + { + const Vec3d& position = m_curr_feature->get_point(); + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); + const Transform3d view_model_matrix = view_matrix * feature_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); + m_sphere.model.set_color(color); + m_sphere.model.render(); + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); + break; } + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, n] = m_curr_feature->get_circle(); + // render center + const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); + const Transform3d center_view_model_matrix = view_matrix * center_matrix; + shader->set_uniform("view_model_matrix", center_view_model_matrix); + const Matrix3d center_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * center_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", center_view_normal_matrix); + m_sphere.model.set_color(color); + m_sphere.model.render(); + auto it = m_raycasters.find(CIRCLE_CENTER_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(center_matrix); + + // render circle + const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center); + const Transform3d circle_view_model_matrix = view_matrix * circle_matrix; + shader->set_uniform("view_model_matrix", circle_view_model_matrix); + const Matrix3d circle_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * circle_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", circle_view_normal_matrix); + m_circle.model.set_color(color); + m_circle.model.render(); + it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(circle_matrix); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + const auto& [start, end] = m_curr_feature->get_edge(); + auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * q * + Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); + const Transform3d view_model_matrix = view_matrix * feature_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); + m_cylinder.model.set_color(color); + m_cylinder.model.render(); + auto it = m_raycasters.find(EDGE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto& [idx, normal, pt] = m_curr_feature->get_plane(); + assert(idx < m_plane_models_cache.size()); + const Transform3d view_model_matrix = view_matrix * model_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); + m_plane_models_cache[idx].set_color(color); + m_plane_models_cache[idx].render(); + auto it = m_raycasters.find(PLANE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(model_matrix); + break; + } + } + shader->stop_using(); } } @@ -426,7 +429,8 @@ void GLGizmoMeasure::update_if_needed() void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit) { - static Measure::SurfaceFeature last_feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Undef, Vec3d::Zero(), Vec3d::Zero(), std::nullopt, 0.0); + static std::optional last_feature; + static EMode last_mode = EMode::BasicSelection; static float last_y = 0.0f; static float last_h = 0.0f; @@ -446,31 +450,27 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit last_y = y; } - if (m_features.empty()) + if (!m_curr_feature.has_value()) m_imgui->text(_u8L("Select features to measure")); + else { + auto add_row_to_table = [this](const wxString& label, const std::string& value) { + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, label); + ImGui::TableSetColumnIndex(1); + m_imgui->text(value); + }; - auto add_row_to_table = [this](const wxString& label, const std::string& value) { - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, label); - ImGui::TableSetColumnIndex(1); - m_imgui->text(value); - }; - - const Transform3d volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); - Measure::SurfaceFeature curr_feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Undef, Vec3d::Zero(), Vec3d::Zero(), std::nullopt, 0.0); - for (size_t i = 0; i < m_features.size(); ++i) { - curr_feature = m_features[i]; - const Measure::SurfaceFeatureType type = curr_feature.get_type(); + const Transform3d volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); + const Measure::SurfaceFeatureType type = m_curr_feature->get_type(); if (type != Measure::SurfaceFeatureType::Undef) { - const std::string header = surface_feature_type_as_string(type) + std::string("##") + std::to_string(i); - if (ImGui::CollapsingHeader(header.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { + if (ImGui::CollapsingHeader(surface_feature_type_as_string(type).c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { if (ImGui::BeginTable("Data", 2)) { switch (type) { case Measure::SurfaceFeatureType::Point: { - const Vec3d position = volume_matrix * curr_feature.get_point(); + const Vec3d position = volume_matrix * m_curr_feature->get_point(); char buf[1024]; sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", position.x(), position.y(), position.z()); add_row_to_table(_u8L("Position") + ":", std::string(buf)); @@ -478,7 +478,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } case Measure::SurfaceFeatureType::Edge: { - auto [from, to] = curr_feature.get_edge(); + auto [from, to] = m_curr_feature->get_edge(); from = volume_matrix * from; to = volume_matrix * to; char buf[1024]; @@ -490,7 +490,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } case Measure::SurfaceFeatureType::Circle: { - auto [center, radius, normal] = curr_feature.get_circle(); + auto [center, radius, normal] = m_curr_feature->get_circle(); center = volume_matrix * center; normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; char buf[1024]; @@ -504,7 +504,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } case Measure::SurfaceFeatureType::Plane: { - auto [idx, normal, origin] = curr_feature.get_plane(); + auto [idx, normal, origin] = m_curr_feature->get_plane(); origin = volume_matrix * origin; normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; char buf[1024]; @@ -521,14 +521,15 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } } - if (last_feature != curr_feature) { + if (last_feature != m_curr_feature || last_mode != m_mode) { // the dialog may have changed its size, ask for an extra frame to render it properly - last_feature = curr_feature; + last_feature = m_curr_feature; + last_mode = m_mode; m_imgui->set_requires_extra_frame(); } - if (!m_features.empty()) { - static const std::string ctrl = + if (m_curr_feature.has_value() && m_mode == EMode::BasicSelection) { + static const std::string ctrl = #ifdef __APPLE__ "⌘" #else diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index a3d027dccd..34a536af96 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -41,7 +41,7 @@ class GLGizmoMeasure : public GLGizmoBase std::vector m_plane_models_cache; std::map> m_raycasters; - std::vector m_features; + std::optional m_curr_feature; // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; @@ -50,13 +50,10 @@ class GLGizmoMeasure : public GLGizmoBase Vec3d m_first_instance_mirror{ Vec3d::Ones() }; bool m_mouse_left_down = false; // for detection left_up of this gizmo - bool m_planes_valid = false; const ModelObject* m_old_model_object = nullptr; const ModelVolume* m_old_model_volume = nullptr; - std::vector instances_matrices; - int m_mouse_pos_x; - int m_mouse_pos_y; + Vec2d m_mouse_pos{ Vec2d::Zero() }; KeyAutoRepeatFilter m_ctrl_kar_filter; From 2bb16b1dc88d44090d8c17c2447b94034e954f33 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 30 Aug 2022 15:50:11 +0200 Subject: [PATCH 135/250] Refactoring of GLGizmoMeasure::on_render_input_window to simplify code --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 38 +++++++++++------------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 6 ++-- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 2c040c9c3b..3e803fa603 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -460,6 +460,16 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::TableSetColumnIndex(1); m_imgui->text(value); }; + auto format_double = [](double value) { + char buf[1024]; + sprintf(buf, "%.3f", value); + return std::string(buf); + }; + auto format_vec3 = [](const Vec3d& v) { + char buf[1024]; + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", v.x(), v.y(), v.z()); + return std::string(buf); + }; const Transform3d volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); const Measure::SurfaceFeatureType type = m_curr_feature->get_type(); @@ -471,9 +481,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit case Measure::SurfaceFeatureType::Point: { const Vec3d position = volume_matrix * m_curr_feature->get_point(); - char buf[1024]; - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", position.x(), position.y(), position.z()); - add_row_to_table(_u8L("Position") + ":", std::string(buf)); + add_row_to_table(_u8L("Position") + ":", format_vec3(position)); break; } case Measure::SurfaceFeatureType::Edge: @@ -481,11 +489,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit auto [from, to] = m_curr_feature->get_edge(); from = volume_matrix * from; to = volume_matrix * to; - char buf[1024]; - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", from.x(), from.y(), from.z()); - add_row_to_table(_u8L("From") + ":", std::string(buf)); - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", to.x(), to.y(), to.z()); - add_row_to_table(_u8L("To") + ":", std::string(buf)); + add_row_to_table(_u8L("From") + ":", format_vec3(from)); + add_row_to_table(_u8L("To") + ":", format_vec3(to)); break; } case Measure::SurfaceFeatureType::Circle: @@ -493,13 +498,9 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit auto [center, radius, normal] = m_curr_feature->get_circle(); center = volume_matrix * center; normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; - char buf[1024]; - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", center.x(), center.y(), center.z()); - add_row_to_table(_u8L("Center") + ":", std::string(buf)); - sprintf(buf, "%.3f", radius); - add_row_to_table(_u8L("Radius") + ":", std::string(buf)); - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", normal.x(), normal.y(), normal.z()); - add_row_to_table(_u8L("Normal") + ":", std::string(buf)); + add_row_to_table(_u8L("Center") + ":", format_vec3(center)); + add_row_to_table(_u8L("Radius") + ":", format_double(radius)); + add_row_to_table(_u8L("Normal") + ":", format_vec3(normal)); break; } case Measure::SurfaceFeatureType::Plane: @@ -507,11 +508,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit auto [idx, normal, origin] = m_curr_feature->get_plane(); origin = volume_matrix * origin; normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; - char buf[1024]; - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", origin.x(), origin.y(), origin.z()); - add_row_to_table(_u8L("Origin") + ":", std::string(buf)); - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", normal.x(), normal.y(), normal.z()); - add_row_to_table(_u8L("Normal") + ":", std::string(buf)); + add_row_to_table(_u8L("Origin") + ":", format_vec3(origin)); + add_row_to_table(_u8L("Normal") + ":", format_vec3(normal)); break; } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 34a536af96..12e0fbfe1d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -49,9 +49,9 @@ class GLGizmoMeasure : public GLGizmoBase Vec3d m_first_instance_scale{ Vec3d::Ones() }; Vec3d m_first_instance_mirror{ Vec3d::Ones() }; - bool m_mouse_left_down = false; // for detection left_up of this gizmo - const ModelObject* m_old_model_object = nullptr; - const ModelVolume* m_old_model_volume = nullptr; + bool m_mouse_left_down{ false }; // for detection left_up of this gizmo + const ModelObject* m_old_model_object{ nullptr }; + const ModelVolume* m_old_model_volume{ nullptr }; Vec2d m_mouse_pos{ Vec2d::Zero() }; From 60aaebc1fe5ece729f7aebb77a5c856cbab0e9a0 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 31 Aug 2022 12:42:55 +0200 Subject: [PATCH 136/250] Measuring: Measure gizmo - added visualization of point for extended selection and updates to imgui dialog --- src/slic3r/GUI/GLCanvas3D.cpp | 9 +- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 255 +++++++++++++---------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 + 3 files changed, 151 insertions(+), 114 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index c63b70f9ea..7d8ca616b4 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5465,8 +5465,13 @@ void GLCanvas3D::_picking_pass() // do not add the volume id if any gizmo is active and CTRL is pressed if (m_gizmos.get_current_type() == GLGizmosManager::EType::Undefined || !wxGetKeyState(WXK_CONTROL)) { m_hover_volume_idxs.emplace_back(hit.raycaster_id); +#if !ENABLE_MEASURE_GIZMO m_gizmos.set_hover_id(-1); +#endif // !ENABLE_MEASURE_GIZMO } +#if ENABLE_MEASURE_GIZMO + m_gizmos.set_hover_id(-1); +#endif // ENABLE_MEASURE_GIZMO } } else @@ -5477,8 +5482,8 @@ void GLCanvas3D::_picking_pass() case SceneRaycaster::EType::Gizmo: { const Size& cnv_size = get_canvas_size(); - bool inside = 0 <= m_mouse.position.x() && m_mouse.position.x() < cnv_size.get_width() && - 0 <= m_mouse.position.y() && m_mouse.position.y() < cnv_size.get_height(); + const bool inside = 0 <= m_mouse.position.x() && m_mouse.position.x() < cnv_size.get_width() && + 0 <= m_mouse.position.y() && m_mouse.position.y() < cnv_size.get_height(); m_gizmos.set_hover_id(inside ? hit.raycaster_id : -1); break; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 3e803fa603..932f9113f1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -21,7 +21,7 @@ std::string surface_feature_type_as_string(Slic3r::Measure::SurfaceFeatureType t { default: case Slic3r::Measure::SurfaceFeatureType::Undef: { return L("Undefined"); } - case Slic3r::Measure::SurfaceFeatureType::Point: { return L("Point"); } + case Slic3r::Measure::SurfaceFeatureType::Point: { return L("Vertex"); } case Slic3r::Measure::SurfaceFeatureType::Edge: { return L("Edge"); } case Slic3r::Measure::SurfaceFeatureType::Circle: { return L("Circle"); } case Slic3r::Measure::SurfaceFeatureType::Plane: { return L("Plane"); } @@ -32,15 +32,22 @@ namespace Slic3r { namespace GUI { static const Slic3r::ColorRGBA BASIC_HOVER_COLOR = { 0.8f, 0.2f, 0.2f, 1.0f }; -static const Slic3r::ColorRGBA EXTENDED_HOVER_COLOR = { 0.2f, 0.8f, 0.2f, 1.0f }; +static const Slic3r::ColorRGBA EXTENDED_HOVER_COLOR = { 0.8f, 0.8f, 0.2f, 1.0f }; static const Slic3r::ColorRGBA LOCK_COLOR = { 0.5f, 0.5f, 0.5f, 1.0f }; static const int POINT_ID = 100; static const int EDGE_ID = 200; static const int CIRCLE_ID = 300; -static const int CIRCLE_CENTER_ID = 301; static const int PLANE_ID = 400; +static const std::string CTRL_STR = +#ifdef __APPLE__ +"⌘" +#else +"Ctrl" +#endif //__APPLE__ +; + GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) { @@ -127,8 +134,11 @@ bool GLGizmoMeasure::on_init() void GLGizmoMeasure::on_set_state() { - if (m_state == Off) + if (m_state == Off) { m_ctrl_kar_filter.reset_count(); + m_curr_feature.reset(); + m_curr_ex_feature_position.reset(); + } else m_mode = EMode::BasicSelection; } @@ -167,16 +177,19 @@ void GLGizmoMeasure::on_render() const Camera& camera = wxGetApp().plater()->get_camera(); const float inv_zoom = (float)camera.get_inv_zoom(); - Vec3f pos; - Vec3f normal; + Vec3f position_on_model; + Vec3f normal_on_model; size_t facet_idx; - m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, model_matrix, camera, pos, normal, nullptr, &facet_idx); + m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, model_matrix, camera, position_on_model, normal_on_model, nullptr, &facet_idx); + + const bool is_hovering_on_extended_selection = m_mode == EMode::ExtendedSelection && m_hover_id != -1; std::optional curr_feature; if (m_mode == EMode::BasicSelection) - curr_feature = m_measuring->get_feature(facet_idx, pos.cast()); + curr_feature = m_measuring->get_feature(facet_idx, position_on_model.cast()); if (m_mode == EMode::BasicSelection) { + m_curr_ex_feature_position.reset(); if (m_curr_feature != curr_feature) { GLGizmoMeasure::on_unregister_raycasters_for_picking(); m_curr_feature = curr_feature; @@ -196,7 +209,7 @@ void GLGizmoMeasure::on_render() } case Measure::SurfaceFeatureType::Circle: { - const auto& [center, radius, n] = m_curr_feature->get_circle(); + const auto& [center, radius, normal] = m_curr_feature->get_circle(); // TODO: check for changed inv_zoom @@ -206,12 +219,12 @@ void GLGizmoMeasure::on_render() m_circle.model.init_from(std::move(circle_geometry)); m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); - m_raycasters.insert({ CIRCLE_CENTER_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_CENTER_ID, *m_sphere.mesh_raycaster) }); + m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); break; } case Measure::SurfaceFeatureType::Plane: { - const auto& [idx, normal, pt] = m_curr_feature->get_plane(); + const auto& [idx, normal, point] = m_curr_feature->get_plane(); // TODO: check for changed idx @@ -244,6 +257,8 @@ void GLGizmoMeasure::on_render() } } } + else if (m_mode == EMode::ExtendedSelection) + m_curr_ex_feature_position = position_on_model.cast(); if (!m_curr_feature.has_value()) return; @@ -261,23 +276,27 @@ void GLGizmoMeasure::on_render() const Transform3d& view_matrix = camera.get_view_matrix(); - ColorRGBA color; + ColorRGBA feature_color; switch (m_mode) { - case EMode::BasicSelection: { color = BASIC_HOVER_COLOR; break; } - case EMode::ExtendedSelection: { color = LOCK_COLOR; break; } + case EMode::BasicSelection: { feature_color = BASIC_HOVER_COLOR; break; } + case EMode::ExtendedSelection: { feature_color = LOCK_COLOR; break; } } + auto set_matrix_uniforms = [shader, &view_matrix](const Transform3d& model_matrix) { + const Transform3d view_model_matrix = view_matrix * model_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); + }; + switch (m_curr_feature->get_type()) { case Measure::SurfaceFeatureType::Point: { const Vec3d& position = m_curr_feature->get_point(); const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); - const Transform3d view_model_matrix = view_matrix * feature_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_sphere.model.set_color(color); + set_matrix_uniforms(feature_matrix); + m_sphere.model.set_color(is_hovering_on_extended_selection ? EXTENDED_HOVER_COLOR : feature_color); m_sphere.model.render(); auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) @@ -289,23 +308,17 @@ void GLGizmoMeasure::on_render() const auto& [center, radius, n] = m_curr_feature->get_circle(); // render center const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); - const Transform3d center_view_model_matrix = view_matrix * center_matrix; - shader->set_uniform("view_model_matrix", center_view_model_matrix); - const Matrix3d center_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * center_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", center_view_normal_matrix); - m_sphere.model.set_color(color); + set_matrix_uniforms(center_matrix); + m_sphere.model.set_color((is_hovering_on_extended_selection && m_hover_id == POINT_ID) ? EXTENDED_HOVER_COLOR : feature_color); m_sphere.model.render(); - auto it = m_raycasters.find(CIRCLE_CENTER_ID); + auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) it->second->set_transform(center_matrix); // render circle const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center); - const Transform3d circle_view_model_matrix = view_matrix * circle_matrix; - shader->set_uniform("view_model_matrix", circle_view_model_matrix); - const Matrix3d circle_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * circle_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", circle_view_normal_matrix); - m_circle.model.set_color(color); + set_matrix_uniforms(circle_matrix); + m_circle.model.set_color(feature_color); m_circle.model.render(); it = m_raycasters.find(CIRCLE_ID); if (it != m_raycasters.end() && it->second != nullptr) @@ -318,11 +331,8 @@ void GLGizmoMeasure::on_render() auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * q * Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); - const Transform3d view_model_matrix = view_matrix * feature_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_cylinder.model.set_color(color); + set_matrix_uniforms(feature_matrix); + m_cylinder.model.set_color(feature_color); m_cylinder.model.render(); auto it = m_raycasters.find(EDGE_ID); if (it != m_raycasters.end() && it->second != nullptr) @@ -333,11 +343,8 @@ void GLGizmoMeasure::on_render() { const auto& [idx, normal, pt] = m_curr_feature->get_plane(); assert(idx < m_plane_models_cache.size()); - const Transform3d view_model_matrix = view_matrix * model_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_plane_models_cache[idx].set_color(color); + set_matrix_uniforms(model_matrix); + m_plane_models_cache[idx].set_color(feature_color); m_plane_models_cache[idx].render(); auto it = m_raycasters.find(PLANE_ID); if (it != m_raycasters.end() && it->second != nullptr) @@ -346,6 +353,15 @@ void GLGizmoMeasure::on_render() } } + if (is_hovering_on_extended_selection && m_curr_ex_feature_position.has_value()) { + if (m_hover_id != POINT_ID) { + Transform3d matrix = model_matrix * Geometry::translation_transform(*m_curr_ex_feature_position) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(matrix); + m_sphere.model.set_color(EXTENDED_HOVER_COLOR); + m_sphere.model.render(); + } + } + shader->stop_using(); } } @@ -450,70 +466,97 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit last_y = y; } - if (!m_curr_feature.has_value()) - m_imgui->text(_u8L("Select features to measure")); - else { - auto add_row_to_table = [this](const wxString& label, const std::string& value) { - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, label); - ImGui::TableSetColumnIndex(1); - m_imgui->text(value); - }; - auto format_double = [](double value) { - char buf[1024]; - sprintf(buf, "%.3f", value); - return std::string(buf); - }; - auto format_vec3 = [](const Vec3d& v) { - char buf[1024]; - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", v.x(), v.y(), v.z()); - return std::string(buf); - }; + auto add_row_to_table = [this](const wxString& label, const std::string& value) { + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, label); + ImGui::TableSetColumnIndex(1); + m_imgui->text(value); + }; + auto format_double = [](double value) { + char buf[1024]; + sprintf(buf, "%.3f", value); + return std::string(buf); + }; + auto format_vec3 = [](const Vec3d& v) { + char buf[1024]; + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", v.x(), v.y(), v.z()); + return std::string(buf); + }; + if (ImGui::BeginTable("Commands", 2)) { + add_row_to_table(_u8L("Left mouse button"), (m_mode == EMode::BasicSelection) ? _u8L("Select feature") : _u8L("Select point")); + if (m_mode == EMode::BasicSelection && m_hover_id != -1) + add_row_to_table(CTRL_STR, _u8L("Enable point selection")); + ImGui::EndTable(); + } + + if (m_curr_feature.has_value()) { const Transform3d volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); - const Measure::SurfaceFeatureType type = m_curr_feature->get_type(); - if (type != Measure::SurfaceFeatureType::Undef) { - if (ImGui::CollapsingHeader(surface_feature_type_as_string(type).c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { - if (ImGui::BeginTable("Data", 2)) { - switch (type) - { - case Measure::SurfaceFeatureType::Point: - { - const Vec3d position = volume_matrix * m_curr_feature->get_point(); + const Measure::SurfaceFeatureType feature_type = m_curr_feature->get_type(); + if (m_mode == EMode::BasicSelection) { + if (feature_type != Measure::SurfaceFeatureType::Undef) { + if (ImGui::CollapsingHeader(surface_feature_type_as_string(feature_type).c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { + if (ImGui::BeginTable("Data", 2)) { + switch (feature_type) + { + case Measure::SurfaceFeatureType::Point: + { + const Vec3d position = volume_matrix * m_curr_feature->get_point(); + add_row_to_table(_u8L("Position") + ":", format_vec3(position)); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + auto [from, to] = m_curr_feature->get_edge(); + from = volume_matrix * from; + to = volume_matrix * to; + add_row_to_table(_u8L("From") + ":", format_vec3(from)); + add_row_to_table(_u8L("To") + ":", format_vec3(to)); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + auto [center, radius, normal] = m_curr_feature->get_circle(); + center = volume_matrix * center; + normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + add_row_to_table(_u8L("Center") + ":", format_vec3(center)); + add_row_to_table(_u8L("Radius") + ":", format_double(radius)); + add_row_to_table(_u8L("Normal") + ":", format_vec3(normal)); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + auto [idx, normal, origin] = m_curr_feature->get_plane(); + origin = volume_matrix * origin; + normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + add_row_to_table(_u8L("Origin") + ":", format_vec3(origin)); + add_row_to_table(_u8L("Normal") + ":", format_vec3(normal)); + break; + } + } + ImGui::EndTable(); + } + } + } + } + else if (m_mode == EMode::ExtendedSelection) { + if (m_hover_id != -1) { + std::string header; + switch (feature_type) { + case Measure::SurfaceFeatureType::Point: { header = _u8L("Vertex"); break; } + case Measure::SurfaceFeatureType::Edge: { header = _u8L("Point on edge"); break; } + case Measure::SurfaceFeatureType::Circle: { header = (m_hover_id == POINT_ID) ? _u8L("Center of circle") : _u8L("Point on circle"); break; } + case Measure::SurfaceFeatureType::Plane: { header = _u8L("Point on plane"); break; } + default: { assert(false); break; } + } + + if (ImGui::CollapsingHeader(header.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { + const Vec3d position = volume_matrix * *m_curr_ex_feature_position; + if (ImGui::BeginTable("Data", 2)) { add_row_to_table(_u8L("Position") + ":", format_vec3(position)); - break; + ImGui::EndTable(); } - case Measure::SurfaceFeatureType::Edge: - { - auto [from, to] = m_curr_feature->get_edge(); - from = volume_matrix * from; - to = volume_matrix * to; - add_row_to_table(_u8L("From") + ":", format_vec3(from)); - add_row_to_table(_u8L("To") + ":", format_vec3(to)); - break; - } - case Measure::SurfaceFeatureType::Circle: - { - auto [center, radius, normal] = m_curr_feature->get_circle(); - center = volume_matrix * center; - normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; - add_row_to_table(_u8L("Center") + ":", format_vec3(center)); - add_row_to_table(_u8L("Radius") + ":", format_double(radius)); - add_row_to_table(_u8L("Normal") + ":", format_vec3(normal)); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - auto [idx, normal, origin] = m_curr_feature->get_plane(); - origin = volume_matrix * origin; - normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; - add_row_to_table(_u8L("Origin") + ":", format_vec3(origin)); - add_row_to_table(_u8L("Normal") + ":", format_vec3(normal)); - break; - } - } - ImGui::EndTable(); } } } @@ -526,18 +569,6 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit m_imgui->set_requires_extra_frame(); } - if (m_curr_feature.has_value() && m_mode == EMode::BasicSelection) { - static const std::string ctrl = -#ifdef __APPLE__ - "⌘" -#else - "Ctrl" -#endif //__APPLE__ - ; - - ImGui::Separator(); - m_imgui->text(_u8L("Press") + " " + ctrl + " " + _u8L("to enable extended selection")); - } m_imgui->end(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 12e0fbfe1d..0c90d3d310 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -42,6 +42,7 @@ class GLGizmoMeasure : public GLGizmoBase std::vector m_plane_models_cache; std::map> m_raycasters; std::optional m_curr_feature; + std::optional m_curr_ex_feature_position; // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; From 16aac5f9193df572b2f5c2dba89dfd4e2e680c99 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 31 Aug 2022 14:56:00 +0200 Subject: [PATCH 137/250] Measuring: Measure gizmo - Improved visualization of points for extended selection --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 53 +++++++++++++++++++++--- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 932f9113f1..89ba8cd410 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -257,8 +257,50 @@ void GLGizmoMeasure::on_render() } } } - else if (m_mode == EMode::ExtendedSelection) - m_curr_ex_feature_position = position_on_model.cast(); + else if (is_hovering_on_extended_selection) { + switch (m_curr_feature->get_type()) + { + case Measure::SurfaceFeatureType::Point: + { + m_curr_ex_feature_position = model_matrix * m_curr_feature->get_point(); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + auto it = m_raycasters.find(EDGE_ID); + if (it != m_raycasters.end() && it->second != nullptr) { + Vec3f p; + Vec3f n; + const Transform3d& trafo = it->second->get_transform(); + it->second->get_raycaster()->unproject_on_mesh(m_mouse_pos, trafo, camera, p, n); + m_curr_ex_feature_position = trafo * p.cast(); + } + break; + } + case Measure::SurfaceFeatureType::Plane: + { + m_curr_ex_feature_position = model_matrix * position_on_model.cast(); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, normal] = m_curr_feature->get_circle(); + if (m_hover_id == POINT_ID) + m_curr_ex_feature_position = model_matrix * center; + else { + auto it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end() && it->second != nullptr) { + Vec3f p; + Vec3f n; + const Transform3d& trafo = it->second->get_transform(); + it->second->get_raycaster()->unproject_on_mesh(m_mouse_pos, trafo, camera, p, n); + m_curr_ex_feature_position = trafo * p.cast(); + } + } + break; + } + } + } if (!m_curr_feature.has_value()) return; @@ -355,7 +397,7 @@ void GLGizmoMeasure::on_render() if (is_hovering_on_extended_selection && m_curr_ex_feature_position.has_value()) { if (m_hover_id != POINT_ID) { - Transform3d matrix = model_matrix * Geometry::translation_transform(*m_curr_ex_feature_position) * Geometry::scale_transform(inv_zoom); + const Transform3d matrix = Geometry::translation_transform(*m_curr_ex_feature_position) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(matrix); m_sphere.model.set_color(EXTENDED_HOVER_COLOR); m_sphere.model.render(); @@ -541,7 +583,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } } else if (m_mode == EMode::ExtendedSelection) { - if (m_hover_id != -1) { + if (m_hover_id != -1 && m_curr_ex_feature_position.has_value()) { std::string header; switch (feature_type) { case Measure::SurfaceFeatureType::Point: { header = _u8L("Vertex"); break; } @@ -552,9 +594,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } if (ImGui::CollapsingHeader(header.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { - const Vec3d position = volume_matrix * *m_curr_ex_feature_position; if (ImGui::BeginTable("Data", 2)) { - add_row_to_table(_u8L("Position") + ":", format_vec3(position)); + add_row_to_table(_u8L("Position") + ":", format_vec3(*m_curr_ex_feature_position)); ImGui::EndTable(); } } From 8d923bb12ee61a02e0813f576860357602fd38ed Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 31 Aug 2022 15:31:39 +0200 Subject: [PATCH 138/250] Measuring: Measure gizmo - Further improvements in visualization of points for extended selection --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 89ba8cd410..a9c2e18257 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -273,6 +273,7 @@ void GLGizmoMeasure::on_render() Vec3f n; const Transform3d& trafo = it->second->get_transform(); it->second->get_raycaster()->unproject_on_mesh(m_mouse_pos, trafo, camera, p, n); + p = { 0.0f, 0.0f, p.z() }; m_curr_ex_feature_position = trafo * p.cast(); } break; @@ -294,6 +295,10 @@ void GLGizmoMeasure::on_render() Vec3f n; const Transform3d& trafo = it->second->get_transform(); it->second->get_raycaster()->unproject_on_mesh(m_mouse_pos, trafo, camera, p, n); + float angle = std::atan2(p.y(), p.x()); + if (angle < 0.0f) + angle += 2.0f * float(M_PI); + p = float(radius) * Vec3f(std::cos(angle), std::sin(angle), 0.0f); m_curr_ex_feature_position = trafo * p.cast(); } } From b64686835b9a72b53a26faaf3ca7908331a40ad0 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 1 Sep 2022 09:44:40 +0200 Subject: [PATCH 139/250] Measuring: Optimization into GLGizmoMeasure::on_render() --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 59 +++++++++++++----------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 4 +- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index a9c2e18257..13415e70ac 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -106,6 +106,9 @@ void GLGizmoMeasure::data_changed() } if (model_object != m_old_model_object || model_volume != m_old_model_volume) update_if_needed(); + + m_last_inv_zoom = 0.0f; + m_last_plane_idx = -1; } bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) @@ -211,12 +214,13 @@ void GLGizmoMeasure::on_render() { const auto& [center, radius, normal] = m_curr_feature->get_circle(); - // TODO: check for changed inv_zoom - - m_circle.reset(); - GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); - m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); - m_circle.model.init_from(std::move(circle_geometry)); + if (m_last_inv_zoom != inv_zoom) { + m_last_inv_zoom = inv_zoom; + m_circle.reset(); + GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); + m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); + m_circle.model.init_from(std::move(circle_geometry)); + } m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); @@ -225,32 +229,33 @@ void GLGizmoMeasure::on_render() case Measure::SurfaceFeatureType::Plane: { const auto& [idx, normal, point] = m_curr_feature->get_plane(); + if (m_last_plane_idx != idx) { + m_last_plane_idx = idx; + const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); + const std::vector& triangle_indices = planes_triangles[idx]; - // TODO: check for changed idx + const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; + GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + unsigned int i = 0; + for (int idx : triangle_indices) { + const Vec3f& v0 = its.vertices[its.indices[idx][0]]; + const Vec3f& v1 = its.vertices[its.indices[idx][1]]; + const Vec3f& v2 = its.vertices[its.indices[idx][2]]; - const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); - const std::vector& triangle_indices = planes_triangles[idx]; + const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); + init_data.add_vertex(v0, n); + init_data.add_vertex(v1, n); + init_data.add_vertex(v2, n); + init_data.add_triangle(i, i + 1, i + 2); + i += 3; + } - const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; - GLModel::Geometry init_data; - init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; - unsigned int i = 0; - for (int idx : triangle_indices) { - const Vec3f& v0 = its.vertices[its.indices[idx][0]]; - const Vec3f& v1 = its.vertices[its.indices[idx][1]]; - const Vec3f& v2 = its.vertices[its.indices[idx][2]]; - - const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); - init_data.add_vertex(v0, n); - init_data.add_vertex(v1, n); - init_data.add_vertex(v2, n); - init_data.add_triangle(i, i + 1, i + 2); - i += 3; + m_plane.reset(); + m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(init_data.get_as_indexed_triangle_set()))); + m_plane.model.init_from(std::move(init_data)); } - m_plane.reset(); - m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(init_data.get_as_indexed_triangle_set()))); - m_plane.model.init_from(std::move(init_data)); m_raycasters.insert({ PLANE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID, *m_plane.mesh_raycaster) }); break; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 0c90d3d310..a19b2d5486 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -44,11 +44,13 @@ class GLGizmoMeasure : public GLGizmoBase std::optional m_curr_feature; std::optional m_curr_ex_feature_position; - // This holds information to decide whether recalculation is necessary: + // These hold information to decide whether recalculation is necessary: std::vector m_volumes_matrices; std::vector m_volumes_types; Vec3d m_first_instance_scale{ Vec3d::Ones() }; Vec3d m_first_instance_mirror{ Vec3d::Ones() }; + float m_last_inv_zoom{ 0.0f }; + int m_last_plane_idx{ -1 }; bool m_mouse_left_down{ false }; // for detection left_up of this gizmo const ModelObject* m_old_model_object{ nullptr }; From 19df0dadeb49fb9f456609ae8fd52bbc779410bd Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 1 Sep 2022 09:54:16 +0200 Subject: [PATCH 140/250] Fixed warnings --- src/libslic3r/Measure.cpp | 18 +++++++++--------- src/libslic3r/Measure.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 7 ++++++- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index cdde276dda..1a79369a3e 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -106,7 +106,7 @@ void MeasuringImpl::update_planes() int facet_idx = facet_queue[-- facet_queue_cnt]; const stl_normal& this_normal = face_normals[facet_idx]; if (is_same_normal(this_normal, *normal_ptr)) { - const Vec3i& face = m_its.indices[facet_idx]; +// const Vec3i& face = m_its.indices[facet_idx]; m_face_to_plane[facet_idx] = m_planes.size() - 1; m_planes.back().facets.emplace_back(facet_idx); @@ -132,7 +132,7 @@ void MeasuringImpl::update_planes() for (int face_id=0; face_id lengths; - for (int i=0; i M_PI) @@ -236,10 +236,10 @@ void MeasuringImpl::extract_features() bool circle = false; std::vector circles; std::vector> circles_idxs; - for (int i=1; i polygon_lower_threshold) { if (angle < polygon_upper_threshold) { const Vec3d center = std::get<0>(circles[i].get_circle()); - for (int j=circles_idxs[i].first + 1; j<=circles_idxs[i].second; ++j) + for (int j=(int)circles_idxs[i].first + 1; j<=(int)circles_idxs[i].second; ++j) plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[j-1], border[j], std::make_optional(center), 0.)); } else { @@ -286,7 +286,7 @@ void MeasuringImpl::extract_features() // We have the circles. Now go around again and pick edges. int cidx = 0; // index of next circle in the way for (int i=1; i circles_idxs[cidx].first) + if (cidx < (int)circles_idxs.size() && i > (int)circles_idxs[cidx].first) i = circles_idxs[cidx++].second; else plane.surface_features.emplace_back(SurfaceFeature( SurfaceFeatureType::Edge, border[i-1], border[i], std::optional(), 0.)); diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 95d8f34cba..9e3629589b 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -68,7 +68,7 @@ private: Vec3d m_pt1; Vec3d m_pt2; std::optional m_pt3; - double m_value; + double m_value{ 0.0 }; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 13415e70ac..54c944590b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -200,6 +200,7 @@ void GLGizmoMeasure::on_render() return; switch (m_curr_feature->get_type()) { + default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); @@ -265,6 +266,7 @@ void GLGizmoMeasure::on_render() else if (is_hovering_on_extended_selection) { switch (m_curr_feature->get_type()) { + default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { m_curr_ex_feature_position = model_matrix * m_curr_feature->get_point(); @@ -342,7 +344,9 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_normal_matrix", view_normal_matrix); }; - switch (m_curr_feature->get_type()) { + switch (m_curr_feature->get_type()) + { + default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { const Vec3d& position = m_curr_feature->get_point(); @@ -552,6 +556,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (ImGui::BeginTable("Data", 2)) { switch (feature_type) { + default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { const Vec3d position = volume_matrix * m_curr_feature->get_point(); From 89ae6cf4ee792f3326db9967deba439ca6ecd9b3 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 1 Sep 2022 10:19:12 +0200 Subject: [PATCH 141/250] Refactoring into GLGizmoMeasure.cpp to remove duplicated code --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 63 +++++++++++------------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 54c944590b..3b257076a2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -48,6 +48,30 @@ static const std::string CTRL_STR = #endif //__APPLE__ ; +static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const std::vector>& planes_triangles, int idx) +{ + assert(0 <= idx && idx < (int)planes_triangles.size()); + const std::vector& triangle_indices = planes_triangles[idx]; + + GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + unsigned int i = 0; + for (int idx : triangle_indices) { + const Vec3f& v0 = its.vertices[its.indices[idx][0]]; + const Vec3f& v1 = its.vertices[its.indices[idx][1]]; + const Vec3f& v2 = its.vertices[its.indices[idx][2]]; + + const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); + init_data.add_vertex(v0, n); + init_data.add_vertex(v1, n); + init_data.add_vertex(v2, n); + init_data.add_triangle(i, i + 1, i + 2); + i += 3; + } + + return init_data; +} + GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) { @@ -232,26 +256,9 @@ void GLGizmoMeasure::on_render() const auto& [idx, normal, point] = m_curr_feature->get_plane(); if (m_last_plane_idx != idx) { m_last_plane_idx = idx; - const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); - const std::vector& triangle_indices = planes_triangles[idx]; - const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; - GLModel::Geometry init_data; - init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; - unsigned int i = 0; - for (int idx : triangle_indices) { - const Vec3f& v0 = its.vertices[its.indices[idx][0]]; - const Vec3f& v1 = its.vertices[its.indices[idx][1]]; - const Vec3f& v2 = its.vertices[its.indices[idx][2]]; - - const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); - init_data.add_vertex(v0, n); - init_data.add_vertex(v1, n); - init_data.add_vertex(v2, n); - init_data.add_triangle(i, i + 1, i + 2); - i += 3; - } - + const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); + GLModel::Geometry init_data = init_plane_data(its, planes_triangles, idx); m_plane.reset(); m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(init_data.get_as_indexed_triangle_set()))); m_plane.model.init_from(std::move(init_data)); @@ -427,23 +434,9 @@ void GLGizmoMeasure::update_if_needed() auto update_plane_models_cache = [this](const indexed_triangle_set& its) { m_plane_models_cache.clear(); const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); - for (const std::vector& triangle_indices : planes_triangles) { + for (int idx = 0; idx < (int)planes_triangles.size(); ++idx) { m_plane_models_cache.emplace_back(GLModel()); - GLModel::Geometry init_data; - init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; - unsigned int i = 0; - for (int idx : triangle_indices) { - const Vec3f& v0 = its.vertices[its.indices[idx][0]]; - const Vec3f& v1 = its.vertices[its.indices[idx][1]]; - const Vec3f& v2 = its.vertices[its.indices[idx][2]]; - - const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); - init_data.add_vertex(v0, n); - init_data.add_vertex(v1, n); - init_data.add_vertex(v2, n); - init_data.add_triangle(i, i + 1, i + 2); - i += 3; - } + GLModel::Geometry init_data = init_plane_data(its, planes_triangles, idx); m_plane_models_cache.back().init_from(std::move(init_data)); } }; From 928a642eb94ae8f04aee26e8242deb836cc1d3c3 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 2 Sep 2022 11:24:06 +0200 Subject: [PATCH 142/250] Measuring: Added features selection in GLGizmoMeasure --- src/libslic3r/Measure.hpp | 6 +- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 382 +++++++++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 39 ++- 3 files changed, 297 insertions(+), 130 deletions(-) diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 9e3629589b..3aefc0b54b 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -107,7 +107,11 @@ struct MeasurementResult { std::optional angle; std::optional distance_infinite; std::optional distance_strict; - std::optional distance_xyz; + std::optional distance_xyz; + + bool has_any_data() const { + return angle.has_value() || distance_infinite.has_value() || distance_strict.has_value() || distance_xyz.has_value(); + } }; // Returns distance/angle between two SurfaceFeatures. diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 3b257076a2..8c27678ce0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -31,9 +31,8 @@ std::string surface_feature_type_as_string(Slic3r::Measure::SurfaceFeatureType t namespace Slic3r { namespace GUI { -static const Slic3r::ColorRGBA BASIC_HOVER_COLOR = { 0.8f, 0.2f, 0.2f, 1.0f }; -static const Slic3r::ColorRGBA EXTENDED_HOVER_COLOR = { 0.8f, 0.8f, 0.2f, 1.0f }; -static const Slic3r::ColorRGBA LOCK_COLOR = { 0.5f, 0.5f, 0.5f, 1.0f }; +static const Slic3r::ColorRGBA SELECTED_1ST_COLOR = { 0.25f, 0.75f, 0.75f, 1.0f }; +static const Slic3r::ColorRGBA SELECTED_2ND_COLOR = { 0.75f, 0.25f, 0.75f, 1.0f }; static const int POINT_ID = 100; static const int EDGE_ID = 200; @@ -95,7 +94,23 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) } else if (mouse_event.LeftDown()) { if (m_hover_id != -1) { - m_mouse_left_down = true; + m_mouse_left_down = true; + + auto set_item_from_feature = [this]() { + const SelectedFeatures::Item item = { m_mode, (m_mode == EMode::ExtendedSelection) ? + Measure::SurfaceFeature(Measure::SurfaceFeatureType::Point, *m_curr_ex_feature_position, Vec3d::Zero(), std::nullopt, 0.0) : + m_curr_feature }; + return item; + }; + + if (m_selected_features.first.feature.has_value()) { + const SelectedFeatures::Item item = set_item_from_feature(); + if (m_selected_features.first != item) + m_selected_features.second = item; + } + else + m_selected_features.first = set_item_from_feature(); + return true; } @@ -103,7 +118,6 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) // take responsibility for left up if (m_parent.get_first_hover_volume_idx() >= 0) m_mouse_left_down = true; - } else if (mouse_event.LeftUp()) { if (m_mouse_left_down) { @@ -133,6 +147,7 @@ void GLGizmoMeasure::data_changed() m_last_inv_zoom = 0.0f; m_last_plane_idx = -1; + m_selected_features.reset(); } bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) @@ -321,13 +336,13 @@ void GLGizmoMeasure::on_render() } } - if (!m_curr_feature.has_value()) + if (!m_curr_feature.has_value() && !m_selected_features.first.feature.has_value()) return; GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) return; - + shader->start_using(); shader->set_uniform("emission_factor", 0.25f); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); @@ -337,13 +352,6 @@ void GLGizmoMeasure::on_render() const Transform3d& view_matrix = camera.get_view_matrix(); - ColorRGBA feature_color; - switch (m_mode) - { - case EMode::BasicSelection: { feature_color = BASIC_HOVER_COLOR; break; } - case EMode::ExtendedSelection: { feature_color = LOCK_COLOR; break; } - } - auto set_matrix_uniforms = [shader, &view_matrix](const Transform3d& model_matrix) { const Transform3d view_model_matrix = view_matrix * model_matrix; shader->set_uniform("view_model_matrix", view_model_matrix); @@ -351,76 +359,143 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_normal_matrix", view_normal_matrix); }; - switch (m_curr_feature->get_type()) - { - default: { assert(false); break; } - case Measure::SurfaceFeatureType::Point: - { - const Vec3d& position = m_curr_feature->get_point(); - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); - set_matrix_uniforms(feature_matrix); - m_sphere.model.set_color(is_hovering_on_extended_selection ? EXTENDED_HOVER_COLOR : feature_color); - m_sphere.model.render(); - auto it = m_raycasters.find(POINT_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(feature_matrix); - break; - } - case Measure::SurfaceFeatureType::Circle: - { - const auto& [center, radius, n] = m_curr_feature->get_circle(); - // render center - const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); - set_matrix_uniforms(center_matrix); - m_sphere.model.set_color((is_hovering_on_extended_selection && m_hover_id == POINT_ID) ? EXTENDED_HOVER_COLOR : feature_color); - m_sphere.model.render(); - auto it = m_raycasters.find(POINT_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(center_matrix); + auto render_feature = [this, set_matrix_uniforms](const Measure::SurfaceFeature& feature, const std::vector& colors, + const Transform3d& model_matrix, float inv_zoom, bool update_raycasters) { + switch (feature.get_type()) + { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + const Vec3d& position = feature.get_point(); + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(feature_matrix); + m_sphere.model.set_color(colors.front()); + m_sphere.model.render(); + if (update_raycasters) { + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); + } + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, n] = feature.get_circle(); + // render center + const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(center_matrix); + m_sphere.model.set_color(colors.front()); + m_sphere.model.render(); + if (update_raycasters) { + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(center_matrix); + } + // render circle + const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center); + set_matrix_uniforms(circle_matrix); + m_circle.model.set_color(colors.back()); + m_circle.model.render(); + if (update_raycasters) { + auto it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(circle_matrix); + } + break; + } + case Measure::SurfaceFeatureType::Edge: + { + const auto& [start, end] = feature.get_edge(); + auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * q * + Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); + set_matrix_uniforms(feature_matrix); + m_cylinder.model.set_color(colors.front()); + m_cylinder.model.render(); + if (update_raycasters) { + auto it = m_raycasters.find(EDGE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); + } + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto& [idx, normal, pt] = feature.get_plane(); + assert(idx < m_plane_models_cache.size()); + set_matrix_uniforms(model_matrix); + m_plane_models_cache[idx].set_color(colors.front()); + m_plane_models_cache[idx].render(); + if (update_raycasters) { + auto it = m_raycasters.find(PLANE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(model_matrix); + } + break; + } + } + }; - // render circle - const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center); - set_matrix_uniforms(circle_matrix); - m_circle.model.set_color(feature_color); - m_circle.model.render(); - it = m_raycasters.find(CIRCLE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(circle_matrix); - break; + auto hover_selection_color = [this]() { + return saturate(!m_selected_features.first.feature.has_value() ? SELECTED_1ST_COLOR : SELECTED_2ND_COLOR, 1.5f); + }; + + auto hovering_color = [this, hover_selection_color, &selection]() { + return (m_mode == EMode::ExtendedSelection) ? selection.get_first_volume()->render_color : hover_selection_color(); + }; + + if (m_curr_feature.has_value()) { + std::vector colors; + if (m_selected_features.first.feature.has_value() && *m_curr_feature == *m_selected_features.first.feature) + colors.emplace_back(SELECTED_1ST_COLOR); + else if (m_selected_features.second.feature.has_value() && *m_curr_feature == *m_selected_features.second.feature) + colors.emplace_back(SELECTED_2ND_COLOR); + else { + switch (m_curr_feature->get_type()) + { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + colors.emplace_back(hover_selection_color()); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + colors.emplace_back((m_hover_id == POINT_ID) ? hover_selection_color() : hovering_color()); + colors.emplace_back(hovering_color()); + break; + } + case Measure::SurfaceFeatureType::Edge: + case Measure::SurfaceFeatureType::Plane: + { + colors.emplace_back(hovering_color()); + break; + } + } + } + + render_feature(*m_curr_feature, colors, model_matrix, inv_zoom, true); } - case Measure::SurfaceFeatureType::Edge: - { - const auto& [start, end] = m_curr_feature->get_edge(); - auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * q * - Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); - set_matrix_uniforms(feature_matrix); - m_cylinder.model.set_color(feature_color); - m_cylinder.model.render(); - auto it = m_raycasters.find(EDGE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(feature_matrix); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - const auto& [idx, normal, pt] = m_curr_feature->get_plane(); - assert(idx < m_plane_models_cache.size()); - set_matrix_uniforms(model_matrix); - m_plane_models_cache[idx].set_color(feature_color); - m_plane_models_cache[idx].render(); - auto it = m_raycasters.find(PLANE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(model_matrix); - break; + + if (m_selected_features.first.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.first.feature)) { + std::vector colors; + colors.emplace_back(SELECTED_1ST_COLOR); + render_feature(*m_selected_features.first.feature, colors, + (m_selected_features.first.mode == EMode::BasicSelection) ? model_matrix : Transform3d::Identity(), inv_zoom, false); } + if (m_selected_features.second.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.second.feature)) { + std::vector colors; + colors.emplace_back(SELECTED_2ND_COLOR); + render_feature(*m_selected_features.second.feature, colors, + (m_selected_features.second.mode == EMode::BasicSelection) ? model_matrix : Transform3d::Identity(), inv_zoom, false); } if (is_hovering_on_extended_selection && m_curr_ex_feature_position.has_value()) { if (m_hover_id != POINT_ID) { const Transform3d matrix = Geometry::translation_transform(*m_curr_ex_feature_position) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(matrix); - m_sphere.model.set_color(EXTENDED_HOVER_COLOR); + m_sphere.model.set_color(hover_selection_color()); +// m_sphere.model.set_color(EXTENDED_HOVER_COLOR); m_sphere.model.render(); } } @@ -496,6 +571,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit { static std::optional last_feature; static EMode last_mode = EMode::BasicSelection; + static SelectedFeatures last_selected_features; static float last_y = 0.0f; static float last_h = 0.0f; @@ -515,18 +591,20 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit last_y = y; } - auto add_row_to_table = [this](const wxString& label, const std::string& value) { + auto add_row_to_table = [this](const std::string& label, const ImVec4& label_color, const std::string& value, const ImVec4& value_color) { ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, label); + m_imgui->text_colored(label_color, label); ImGui::TableSetColumnIndex(1); - m_imgui->text(value); + m_imgui->text_colored(value_color, value); }; + auto format_double = [](double value) { char buf[1024]; sprintf(buf, "%.3f", value); return std::string(buf); }; + auto format_vec3 = [](const Vec3d& v) { char buf[1024]; sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", v.x(), v.y(), v.z()); @@ -534,9 +612,10 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit }; if (ImGui::BeginTable("Commands", 2)) { - add_row_to_table(_u8L("Left mouse button"), (m_mode == EMode::BasicSelection) ? _u8L("Select feature") : _u8L("Select point")); + add_row_to_table(_u8L("Left mouse button"), ImGuiWrapper::COL_ORANGE_LIGHT, + (m_mode == EMode::BasicSelection) ? _u8L("Select feature") : _u8L("Select point"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); if (m_mode == EMode::BasicSelection && m_hover_id != -1) - add_row_to_table(CTRL_STR, _u8L("Enable point selection")); + add_row_to_table(CTRL_STR, ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable point selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); } @@ -545,48 +624,49 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit const Measure::SurfaceFeatureType feature_type = m_curr_feature->get_type(); if (m_mode == EMode::BasicSelection) { if (feature_type != Measure::SurfaceFeatureType::Undef) { - if (ImGui::CollapsingHeader(surface_feature_type_as_string(feature_type).c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { - if (ImGui::BeginTable("Data", 2)) { - switch (feature_type) - { - default: { assert(false); break; } - case Measure::SurfaceFeatureType::Point: - { - const Vec3d position = volume_matrix * m_curr_feature->get_point(); - add_row_to_table(_u8L("Position") + ":", format_vec3(position)); - break; - } - case Measure::SurfaceFeatureType::Edge: - { - auto [from, to] = m_curr_feature->get_edge(); - from = volume_matrix * from; - to = volume_matrix * to; - add_row_to_table(_u8L("From") + ":", format_vec3(from)); - add_row_to_table(_u8L("To") + ":", format_vec3(to)); - break; - } - case Measure::SurfaceFeatureType::Circle: - { - auto [center, radius, normal] = m_curr_feature->get_circle(); - center = volume_matrix * center; - normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; - add_row_to_table(_u8L("Center") + ":", format_vec3(center)); - add_row_to_table(_u8L("Radius") + ":", format_double(radius)); - add_row_to_table(_u8L("Normal") + ":", format_vec3(normal)); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - auto [idx, normal, origin] = m_curr_feature->get_plane(); - origin = volume_matrix * origin; - normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; - add_row_to_table(_u8L("Origin") + ":", format_vec3(origin)); - add_row_to_table(_u8L("Normal") + ":", format_vec3(normal)); - break; - } - } - ImGui::EndTable(); + ImGui::Separator(); + m_imgui->text(surface_feature_type_as_string(feature_type) + ":"); + if (ImGui::BeginTable("Data", 2)) { + switch (feature_type) + { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + const Vec3d position = volume_matrix * m_curr_feature->get_point(); + add_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; } + case Measure::SurfaceFeatureType::Edge: + { + auto [from, to] = m_curr_feature->get_edge(); + from = volume_matrix * from; + to = volume_matrix * to; + add_row_to_table(_u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_row_to_table(_u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_row_to_table(_u8L("Length") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + auto [center, radius, normal] = m_curr_feature->get_circle(); + center = volume_matrix * center; + normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + add_row_to_table(_u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_row_to_table(_u8L("Radius") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + auto [idx, normal, origin] = m_curr_feature->get_plane(); + origin = volume_matrix * origin; + normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + add_row_to_table(_u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; + } + } + ImGui::EndTable(); } } } @@ -601,20 +681,68 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit default: { assert(false); break; } } - if (ImGui::CollapsingHeader(header.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { - if (ImGui::BeginTable("Data", 2)) { - add_row_to_table(_u8L("Position") + ":", format_vec3(*m_curr_ex_feature_position)); - ImGui::EndTable(); - } + ImGui::Separator(); + m_imgui->text(header + ":"); + if (ImGui::BeginTable("Data", 2)) { + add_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(*m_curr_ex_feature_position), + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ImGui::EndTable(); } } } } - if (last_feature != m_curr_feature || last_mode != m_mode) { + ImGui::Separator(); + m_imgui->text(_u8L("Selection")); + if (ImGui::BeginTable("Selection", 2)) { + add_row_to_table("1", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), m_selected_features.first.feature.has_value() ? + surface_feature_type_as_string(m_selected_features.first.feature->get_type()) : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR)); + add_row_to_table("2", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), m_selected_features.second.feature.has_value() ? + surface_feature_type_as_string(m_selected_features.second.feature->get_type()) : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR)); + ImGui::EndTable(); + } + + if (m_selected_features.first.feature.has_value()) { + if (m_imgui->button(_u8L("Restart"))) { + m_selected_features.reset(); + m_imgui->set_requires_extra_frame(); + } + } + + if (m_selected_features.second.feature.has_value()) { + const Measure::MeasurementResult measure = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature); + ImGui::Separator(); + if (measure.has_any_data()) { + m_imgui->text(_u8L("Measure")); + if (ImGui::BeginTable("Measure", 2)) { + if (measure.angle.has_value()) { + add_row_to_table(_u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(*measure.angle)), + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + if (measure.distance_infinite.has_value()) { + add_row_to_table(_u8L("Distance Infinite") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(*measure.distance_infinite), + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + if (measure.distance_strict.has_value()) { + add_row_to_table(_u8L("Distance Strict") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(*measure.distance_strict), + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + if (measure.distance_xyz.has_value()) { + add_row_to_table(_u8L("Distance XYZ") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(*measure.distance_xyz), + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + ImGui::EndTable(); + } + } + else + m_imgui->text(_u8L("No measure available")); + } + + if (last_feature != m_curr_feature || last_mode != m_mode || last_selected_features != m_selected_features) { // the dialog may have changed its size, ask for an extra frame to render it properly last_feature = m_curr_feature; last_mode = m_mode; + last_selected_features = m_selected_features; m_imgui->set_requires_extra_frame(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index a19b2d5486..28e617e4cd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -23,14 +23,47 @@ enum class SLAGizmoEventType : unsigned char; class GLGizmoMeasure : public GLGizmoBase { -// This gizmo does not use grabbers. The m_hover_id relates to polygon managed by the class itself. - enum class EMode : unsigned char { BasicSelection, ExtendedSelection }; + struct SelectedFeatures + { + struct Item + { + EMode mode{ EMode::BasicSelection }; + std::optional feature; + + bool operator == (const Item& other) const { + if (this->mode != other.mode) return false; + return this->feature == other.feature; + } + + bool operator != (const Item& other) const { + return !operator == (other); + } + }; + + Item first; + Item second; + + void reset() { + first.feature.reset(); + second.feature.reset(); + } + + bool operator == (const SelectedFeatures& other) const { + if (this->first != other.first) return false; + return this->second == other.second; + } + + bool operator != (const SelectedFeatures& other) const { + return !operator == (other); + } + }; + EMode m_mode{ EMode::BasicSelection }; std::unique_ptr m_measuring; @@ -60,6 +93,8 @@ class GLGizmoMeasure : public GLGizmoBase KeyAutoRepeatFilter m_ctrl_kar_filter; + SelectedFeatures m_selected_features; + void update_if_needed(); public: From 1e5b01a31d3085c8edd06a6b6c4eb291b3c98edf Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 2 Sep 2022 12:26:56 +0200 Subject: [PATCH 143/250] Measuring: Changes in GLGizmoMeasure imgui dialog layout --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 97 ++++++++++++------------ src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 14 +++- 2 files changed, 61 insertions(+), 50 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 8c27678ce0..6fe6c36ef3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -15,19 +15,6 @@ #if ENABLE_MEASURE_GIZMO -std::string surface_feature_type_as_string(Slic3r::Measure::SurfaceFeatureType type) -{ - switch (type) - { - default: - case Slic3r::Measure::SurfaceFeatureType::Undef: { return L("Undefined"); } - case Slic3r::Measure::SurfaceFeatureType::Point: { return L("Vertex"); } - case Slic3r::Measure::SurfaceFeatureType::Edge: { return L("Edge"); } - case Slic3r::Measure::SurfaceFeatureType::Circle: { return L("Circle"); } - case Slic3r::Measure::SurfaceFeatureType::Plane: { return L("Plane"); } - } -} - namespace Slic3r { namespace GUI { @@ -47,6 +34,32 @@ static const std::string CTRL_STR = #endif //__APPLE__ ; +static std::string surface_feature_type_as_string(Measure::SurfaceFeatureType type) +{ + switch (type) + { + default: + case Measure::SurfaceFeatureType::Undef: { return L("Undefined"); } + case Measure::SurfaceFeatureType::Point: { return L("Vertex"); } + case Measure::SurfaceFeatureType::Edge: { return L("Edge"); } + case Measure::SurfaceFeatureType::Circle: { return L("Circle"); } + case Measure::SurfaceFeatureType::Plane: { return L("Plane"); } + } +} + +static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType type, int hover_id) +{ + std::string ret; + switch (type) { + case Measure::SurfaceFeatureType::Point: { ret = _u8L("Vertex"); break; } + case Measure::SurfaceFeatureType::Edge: { ret = _u8L("Point on edge"); break; } + case Measure::SurfaceFeatureType::Circle: { ret = (hover_id == POINT_ID) ? _u8L("Center of circle") : _u8L("Point on circle"); break; } + case Measure::SurfaceFeatureType::Plane: { ret = _u8L("Point on plane"); break; } + default: { assert(false); break; } + } + return ret; +} + static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const std::vector>& planes_triangles, int idx) { assert(0 <= idx && idx < (int)planes_triangles.size()); @@ -97,9 +110,9 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) m_mouse_left_down = true; auto set_item_from_feature = [this]() { - const SelectedFeatures::Item item = { m_mode, (m_mode == EMode::ExtendedSelection) ? - Measure::SurfaceFeature(Measure::SurfaceFeatureType::Point, *m_curr_ex_feature_position, Vec3d::Zero(), std::nullopt, 0.0) : - m_curr_feature }; + const SelectedFeatures::Item item = { m_mode, + (m_mode == EMode::ExtendedSelection) ? point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id) : surface_feature_type_as_string(m_curr_feature->get_type()), + (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(Measure::SurfaceFeatureType::Point, *m_curr_point_on_feature_position, Vec3d::Zero(), std::nullopt, 0.0) : m_curr_feature }; return item; }; @@ -179,7 +192,7 @@ void GLGizmoMeasure::on_set_state() if (m_state == Off) { m_ctrl_kar_filter.reset_count(); m_curr_feature.reset(); - m_curr_ex_feature_position.reset(); + m_curr_point_on_feature_position.reset(); } else m_mode = EMode::BasicSelection; @@ -231,7 +244,7 @@ void GLGizmoMeasure::on_render() curr_feature = m_measuring->get_feature(facet_idx, position_on_model.cast()); if (m_mode == EMode::BasicSelection) { - m_curr_ex_feature_position.reset(); + m_curr_point_on_feature_position.reset(); if (m_curr_feature != curr_feature) { GLGizmoMeasure::on_unregister_raycasters_for_picking(); m_curr_feature = curr_feature; @@ -291,7 +304,7 @@ void GLGizmoMeasure::on_render() default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { - m_curr_ex_feature_position = model_matrix * m_curr_feature->get_point(); + m_curr_point_on_feature_position = model_matrix * m_curr_feature->get_point(); break; } case Measure::SurfaceFeatureType::Edge: @@ -303,20 +316,20 @@ void GLGizmoMeasure::on_render() const Transform3d& trafo = it->second->get_transform(); it->second->get_raycaster()->unproject_on_mesh(m_mouse_pos, trafo, camera, p, n); p = { 0.0f, 0.0f, p.z() }; - m_curr_ex_feature_position = trafo * p.cast(); + m_curr_point_on_feature_position = trafo * p.cast(); } break; } case Measure::SurfaceFeatureType::Plane: { - m_curr_ex_feature_position = model_matrix * position_on_model.cast(); + m_curr_point_on_feature_position = model_matrix * position_on_model.cast(); break; } case Measure::SurfaceFeatureType::Circle: { const auto& [center, radius, normal] = m_curr_feature->get_circle(); if (m_hover_id == POINT_ID) - m_curr_ex_feature_position = model_matrix * center; + m_curr_point_on_feature_position = model_matrix * center; else { auto it = m_raycasters.find(CIRCLE_ID); if (it != m_raycasters.end() && it->second != nullptr) { @@ -328,7 +341,7 @@ void GLGizmoMeasure::on_render() if (angle < 0.0f) angle += 2.0f * float(M_PI); p = float(radius) * Vec3f(std::cos(angle), std::sin(angle), 0.0f); - m_curr_ex_feature_position = trafo * p.cast(); + m_curr_point_on_feature_position = trafo * p.cast(); } } break; @@ -490,12 +503,11 @@ void GLGizmoMeasure::on_render() (m_selected_features.second.mode == EMode::BasicSelection) ? model_matrix : Transform3d::Identity(), inv_zoom, false); } - if (is_hovering_on_extended_selection && m_curr_ex_feature_position.has_value()) { + if (is_hovering_on_extended_selection && m_curr_point_on_feature_position.has_value()) { if (m_hover_id != POINT_ID) { - const Transform3d matrix = Geometry::translation_transform(*m_curr_ex_feature_position) * Geometry::scale_transform(inv_zoom); + const Transform3d matrix = Geometry::translation_transform(*m_curr_point_on_feature_position) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(matrix); m_sphere.model.set_color(hover_selection_color()); -// m_sphere.model.set_color(EXTENDED_HOVER_COLOR); m_sphere.model.render(); } } @@ -591,12 +603,12 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit last_y = y; } - auto add_row_to_table = [this](const std::string& label, const ImVec4& label_color, const std::string& value, const ImVec4& value_color) { + auto add_row_to_table = [this](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) { ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); - m_imgui->text_colored(label_color, label); + m_imgui->text_colored(col_1_color, col_1); ImGui::TableSetColumnIndex(1); - m_imgui->text_colored(value_color, value); + m_imgui->text_colored(col_2_color, col_2); }; auto format_double = [](double value) { @@ -671,20 +683,11 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } } else if (m_mode == EMode::ExtendedSelection) { - if (m_hover_id != -1 && m_curr_ex_feature_position.has_value()) { - std::string header; - switch (feature_type) { - case Measure::SurfaceFeatureType::Point: { header = _u8L("Vertex"); break; } - case Measure::SurfaceFeatureType::Edge: { header = _u8L("Point on edge"); break; } - case Measure::SurfaceFeatureType::Circle: { header = (m_hover_id == POINT_ID) ? _u8L("Center of circle") : _u8L("Point on circle"); break; } - case Measure::SurfaceFeatureType::Plane: { header = _u8L("Point on plane"); break; } - default: { assert(false); break; } - } - + if (m_hover_id != -1 && m_curr_point_on_feature_position.has_value()) { ImGui::Separator(); - m_imgui->text(header + ":"); + m_imgui->text(point_on_feature_type_as_string(feature_type, m_hover_id) + ":"); if (ImGui::BeginTable("Data", 2)) { - add_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(*m_curr_ex_feature_position), + add_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(*m_curr_point_on_feature_position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); } @@ -693,12 +696,12 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } ImGui::Separator(); - m_imgui->text(_u8L("Selection")); - if (ImGui::BeginTable("Selection", 2)) { - add_row_to_table("1", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), m_selected_features.first.feature.has_value() ? - surface_feature_type_as_string(m_selected_features.first.feature->get_type()) : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR)); - add_row_to_table("2", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), m_selected_features.second.feature.has_value() ? - surface_feature_type_as_string(m_selected_features.second.feature->get_type()) : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR)); + const ImGuiTableFlags flags = /*ImGuiTableFlags_SizingStretchSame | */ImGuiTableFlags_BordersOuter | /*ImGuiTableFlags_BordersV | */ImGuiTableFlags_BordersH; + if (ImGui::BeginTable("Selection", 2, flags)) { + add_row_to_table(_u8L("Selection") + " 1:", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), m_selected_features.first.feature.has_value() ? + m_selected_features.first.source : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR)); + add_row_to_table(_u8L("Selection") + " 2:", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), m_selected_features.second.feature.has_value() ? + m_selected_features.second.source : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR)); ImGui::EndTable(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 28e617e4cd..4492080732 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -34,24 +34,32 @@ class GLGizmoMeasure : public GLGizmoBase struct Item { EMode mode{ EMode::BasicSelection }; + std::string source; std::optional feature; bool operator == (const Item& other) const { if (this->mode != other.mode) return false; + if (this->source != other.source) return false; return this->feature == other.feature; } bool operator != (const Item& other) const { return !operator == (other); } + + void reset() { + mode = EMode::BasicSelection; + source.clear(); + feature.reset(); + } }; Item first; Item second; void reset() { - first.feature.reset(); - second.feature.reset(); + first.reset(); + second.reset(); } bool operator == (const SelectedFeatures& other) const { @@ -75,7 +83,7 @@ class GLGizmoMeasure : public GLGizmoBase std::vector m_plane_models_cache; std::map> m_raycasters; std::optional m_curr_feature; - std::optional m_curr_ex_feature_position; + std::optional m_curr_point_on_feature_position; // These hold information to decide whether recalculation is necessary: std::vector m_volumes_matrices; From 9edc2545cec19b6ed52d95e427239e18840e5d13 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 5 Sep 2022 08:26:19 +0200 Subject: [PATCH 144/250] Measuring: Disable scene raycasters while GLGizmoMeasure is active --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 101 +++++++++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 5 ++ 2 files changed, 71 insertions(+), 35 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 6fe6c36ef3..8fddf11adf 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -167,8 +167,10 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po { if (action == SLAGizmoEventType::CtrlDown) { if (m_ctrl_kar_filter.is_first()) { - if (m_curr_feature.has_value()) + if (m_curr_feature.has_value()) { m_mode = EMode::ExtendedSelection; + disable_scene_raycasters(); + } } m_ctrl_kar_filter.increase_count(); @@ -176,6 +178,7 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po else if (action == SLAGizmoEventType::CtrlUp) { m_ctrl_kar_filter.reset_count(); m_mode = EMode::BasicSelection; + restore_scene_raycasters_state(); } return true; @@ -193,9 +196,19 @@ void GLGizmoMeasure::on_set_state() m_ctrl_kar_filter.reset_count(); m_curr_feature.reset(); m_curr_point_on_feature_position.reset(); + restore_scene_raycasters_state(); } - else + else { m_mode = EMode::BasicSelection; + // store current state of scene raycaster for later use + m_scene_raycaster_state.clear(); + m_scene_raycasters = m_parent.get_raycasters_for_picking(SceneRaycaster::EType::Volume); + if (m_scene_raycasters != nullptr) { + for (const auto r : *m_scene_raycasters) { + m_scene_raycaster_state.emplace_back(r->is_active()); + } + } + } } CommonGizmosDataID GLGizmoMeasure::on_get_requirements() const @@ -234,16 +247,13 @@ void GLGizmoMeasure::on_render() Vec3f position_on_model; Vec3f normal_on_model; - size_t facet_idx; - m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, model_matrix, camera, position_on_model, normal_on_model, nullptr, &facet_idx); + size_t model_facet_idx; + m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, model_matrix, camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); - const bool is_hovering_on_extended_selection = m_mode == EMode::ExtendedSelection && m_hover_id != -1; - - std::optional curr_feature; - if (m_mode == EMode::BasicSelection) - curr_feature = m_measuring->get_feature(facet_idx, position_on_model.cast()); + const bool is_hovering_on_locked_feature = m_mode == EMode::ExtendedSelection && m_hover_id != -1; if (m_mode == EMode::BasicSelection) { + std::optional curr_feature = m_measuring->get_feature(model_facet_idx, position_on_model.cast()); m_curr_point_on_feature_position.reset(); if (m_curr_feature != curr_feature) { GLGizmoMeasure::on_unregister_raycasters_for_picking(); @@ -265,8 +275,7 @@ void GLGizmoMeasure::on_render() } case Measure::SurfaceFeatureType::Circle: { - const auto& [center, radius, normal] = m_curr_feature->get_circle(); - + const auto [center, radius, normal] = m_curr_feature->get_circle(); if (m_last_inv_zoom != inv_zoom) { m_last_inv_zoom = inv_zoom; m_circle.reset(); @@ -281,7 +290,7 @@ void GLGizmoMeasure::on_render() } case Measure::SurfaceFeatureType::Plane: { - const auto& [idx, normal, point] = m_curr_feature->get_plane(); + const auto [idx, normal, point] = m_curr_feature->get_plane(); if (m_last_plane_idx != idx) { m_last_plane_idx = idx; const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; @@ -298,7 +307,23 @@ void GLGizmoMeasure::on_render() } } } - else if (is_hovering_on_extended_selection) { + else if (is_hovering_on_locked_feature) { + auto default_callback = [](const Vec3f& v) { return v; }; + auto position_on_feature = [this](int feature_type_id, const Camera& camera, std::function callback = nullptr) -> Vec3d { + auto it = m_raycasters.find(feature_type_id); + if (it != m_raycasters.end() && it->second != nullptr) { + Vec3f p; + Vec3f n; + const Transform3d& trafo = it->second->get_transform(); + bool res = it->second->get_raycaster()->closest_hit(m_mouse_pos, trafo, camera, p, n); + assert(res); + if (callback) + p = callback(p); + return trafo * p.cast(); + } + return Vec3d::Zero(); + }; + switch (m_curr_feature->get_type()) { default: { assert(false); break; } @@ -309,40 +334,27 @@ void GLGizmoMeasure::on_render() } case Measure::SurfaceFeatureType::Edge: { - auto it = m_raycasters.find(EDGE_ID); - if (it != m_raycasters.end() && it->second != nullptr) { - Vec3f p; - Vec3f n; - const Transform3d& trafo = it->second->get_transform(); - it->second->get_raycaster()->unproject_on_mesh(m_mouse_pos, trafo, camera, p, n); - p = { 0.0f, 0.0f, p.z() }; - m_curr_point_on_feature_position = trafo * p.cast(); - } + m_curr_point_on_feature_position = position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); break; } case Measure::SurfaceFeatureType::Plane: { - m_curr_point_on_feature_position = model_matrix * position_on_model.cast(); + m_curr_point_on_feature_position = position_on_feature(PLANE_ID, camera); break; } case Measure::SurfaceFeatureType::Circle: { - const auto& [center, radius, normal] = m_curr_feature->get_circle(); + const auto [center, radius, normal] = m_curr_feature->get_circle(); if (m_hover_id == POINT_ID) m_curr_point_on_feature_position = model_matrix * center; else { - auto it = m_raycasters.find(CIRCLE_ID); - if (it != m_raycasters.end() && it->second != nullptr) { - Vec3f p; - Vec3f n; - const Transform3d& trafo = it->second->get_transform(); - it->second->get_raycaster()->unproject_on_mesh(m_mouse_pos, trafo, camera, p, n); - float angle = std::atan2(p.y(), p.x()); + const float r = radius; // needed for the following lambda + m_curr_point_on_feature_position = position_on_feature(CIRCLE_ID, camera, [r](const Vec3f& v) { + float angle = std::atan2(v.y(), v.x()); if (angle < 0.0f) angle += 2.0f * float(M_PI); - p = float(radius) * Vec3f(std::cos(angle), std::sin(angle), 0.0f); - m_curr_point_on_feature_position = trafo * p.cast(); - } + return float(r) * Vec3f(std::cos(angle), std::sin(angle), 0.0f); + }); } break; } @@ -503,7 +515,7 @@ void GLGizmoMeasure::on_render() (m_selected_features.second.mode == EMode::BasicSelection) ? model_matrix : Transform3d::Identity(), inv_zoom, false); } - if (is_hovering_on_extended_selection && m_curr_point_on_feature_position.has_value()) { + if (is_hovering_on_locked_feature && m_curr_point_on_feature_position.has_value()) { if (m_hover_id != POINT_ID) { const Transform3d matrix = Geometry::translation_transform(*m_curr_point_on_feature_position) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(matrix); @@ -579,6 +591,25 @@ void GLGizmoMeasure::update_if_needed() } } +void GLGizmoMeasure::disable_scene_raycasters() +{ + if (m_scene_raycasters != nullptr) { + for (auto r : *m_scene_raycasters) { + r->set_active(false); + } + } +} + +void GLGizmoMeasure::restore_scene_raycasters_state() +{ + if (m_scene_raycasters != nullptr) { + assert(m_scene_raycasters->size() == m_scene_raycaster_state.size()); + for (size_t i = 0; i < m_scene_raycasters->size(); ++i) { + (*m_scene_raycasters)[i]->set_active(m_scene_raycaster_state[i]); + } + } +} + void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit) { static std::optional last_feature; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 4492080732..9dad613973 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -84,6 +84,8 @@ class GLGizmoMeasure : public GLGizmoBase std::map> m_raycasters; std::optional m_curr_feature; std::optional m_curr_point_on_feature_position; + std::vector>* m_scene_raycasters{ nullptr }; + std::vector m_scene_raycaster_state; // These hold information to decide whether recalculation is necessary: std::vector m_volumes_matrices; @@ -105,6 +107,9 @@ class GLGizmoMeasure : public GLGizmoBase void update_if_needed(); + void disable_scene_raycasters(); + void restore_scene_raycasters_state(); + public: GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); From 9a7fd520b145e0743e9185ecaf7fe445084a4c1b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 5 Sep 2022 08:57:49 +0200 Subject: [PATCH 145/250] Fixed warnings --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 8fddf11adf..74a5c93f7c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -308,7 +308,6 @@ void GLGizmoMeasure::on_render() } } else if (is_hovering_on_locked_feature) { - auto default_callback = [](const Vec3f& v) { return v; }; auto position_on_feature = [this](int feature_type_id, const Camera& camera, std::function callback = nullptr) -> Vec3d { auto it = m_raycasters.find(feature_type_id); if (it != m_raycasters.end() && it->second != nullptr) { @@ -317,9 +316,11 @@ void GLGizmoMeasure::on_render() const Transform3d& trafo = it->second->get_transform(); bool res = it->second->get_raycaster()->closest_hit(m_mouse_pos, trafo, camera, p, n); assert(res); - if (callback) - p = callback(p); - return trafo * p.cast(); + if (res) { + if (callback) + p = callback(p); + return trafo * p.cast(); + } } return Vec3d::Zero(); }; From ed7534b8ceb136c96f5680eb8a445f175fd0f58b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 5 Sep 2022 09:18:07 +0200 Subject: [PATCH 146/250] Measuring: GLGizmoMeasure - Fixed update of circle geometry --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 3 ++- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 74a5c93f7c..bf7fd04a7d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -276,8 +276,9 @@ void GLGizmoMeasure::on_render() case Measure::SurfaceFeatureType::Circle: { const auto [center, radius, normal] = m_curr_feature->get_circle(); - if (m_last_inv_zoom != inv_zoom) { + if (m_last_inv_zoom != inv_zoom || m_last_circle != m_curr_feature) { m_last_inv_zoom = inv_zoom; + m_last_circle = m_curr_feature; m_circle.reset(); GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 9dad613973..7c82f7b9f8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -93,6 +93,7 @@ class GLGizmoMeasure : public GLGizmoBase Vec3d m_first_instance_scale{ Vec3d::Ones() }; Vec3d m_first_instance_mirror{ Vec3d::Ones() }; float m_last_inv_zoom{ 0.0f }; + std::optional m_last_circle; int m_last_plane_idx{ -1 }; bool m_mouse_left_down{ false }; // for detection left_up of this gizmo From 7b8c07c2a4c59e80c88f7d04a298286b7ecbb793 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 5 Sep 2022 12:05:25 +0200 Subject: [PATCH 147/250] Measuring: GLGizmoMeasure - show data in inches into imgui dialog, when needed --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 42 ++++++++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index bf7fd04a7d..f8f84d7bc8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -3,6 +3,7 @@ #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/Plater.hpp" +#include "slic3r/GUI/GUI_ObjectManipulation.hpp" #include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" @@ -664,6 +665,9 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::EndTable(); } + const bool use_inches = wxGetApp().app_config->get("use_inches") == "1"; + const std::string units = use_inches ? _u8L(" (in)") : _u8L(" (mm)"); + if (m_curr_feature.has_value()) { const Transform3d volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); const Measure::SurfaceFeatureType feature_type = m_curr_feature->get_type(); @@ -677,7 +681,9 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { - const Vec3d position = volume_matrix * m_curr_feature->get_point(); + Vec3d position = volume_matrix * m_curr_feature->get_point(); + if (use_inches) + position = ObjectManipulation::mm_to_in * position; add_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } @@ -686,9 +692,13 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit auto [from, to] = m_curr_feature->get_edge(); from = volume_matrix * from; to = volume_matrix * to; + if (use_inches) { + from = ObjectManipulation::mm_to_in * from; + to = ObjectManipulation::mm_to_in * to; + } add_row_to_table(_u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_row_to_table(_u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_row_to_table(_u8L("Length") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_row_to_table(_u8L("Length") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } case Measure::SurfaceFeatureType::Circle: @@ -696,8 +706,12 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit auto [center, radius, normal] = m_curr_feature->get_circle(); center = volume_matrix * center; normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + if (use_inches) { + center = ObjectManipulation::mm_to_in * center; + radius = ObjectManipulation::mm_to_in * radius; + } add_row_to_table(_u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_row_to_table(_u8L("Radius") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_row_to_table(_u8L("Radius") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } @@ -706,6 +720,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit auto [idx, normal, origin] = m_curr_feature->get_plane(); origin = volume_matrix * origin; normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + if (use_inches) + origin = ObjectManipulation::mm_to_in * origin; add_row_to_table(_u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; @@ -720,7 +736,10 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::Separator(); m_imgui->text(point_on_feature_type_as_string(feature_type, m_hover_id) + ":"); if (ImGui::BeginTable("Data", 2)) { - add_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(*m_curr_point_on_feature_position), + Vec3d position = ObjectManipulation::mm_to_in * *m_curr_point_on_feature_position; + if (use_inches) + position = ObjectManipulation::mm_to_in * position; + add_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); } @@ -756,15 +775,24 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::GetStyleColorVec4(ImGuiCol_Text)); } if (measure.distance_infinite.has_value()) { - add_row_to_table(_u8L("Distance Infinite") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(*measure.distance_infinite), + double distance = ObjectManipulation::mm_to_in * *measure.distance_infinite; + if (use_inches) + distance = ObjectManipulation::mm_to_in * distance; + add_row_to_table(_u8L("Distance Infinite") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } if (measure.distance_strict.has_value()) { - add_row_to_table(_u8L("Distance Strict") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(*measure.distance_strict), + double distance = ObjectManipulation::mm_to_in * *measure.distance_strict; + if (use_inches) + distance = ObjectManipulation::mm_to_in * distance; + add_row_to_table(_u8L("Distance Strict") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } if (measure.distance_xyz.has_value()) { - add_row_to_table(_u8L("Distance XYZ") + _u8L(" (mm)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(*measure.distance_xyz), + Vec3d distance = ObjectManipulation::mm_to_in * *measure.distance_xyz; + if (use_inches) + distance = ObjectManipulation::mm_to_in * distance; + add_row_to_table(_u8L("Distance XYZ") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } ImGui::EndTable(); From 1971f0b2cb5ac45367bca457743c2ae956732f5c Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 5 Sep 2022 12:49:19 +0200 Subject: [PATCH 148/250] Measuring: GLGizmoMeasure - Fixed detection of current hovered feature --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index f8f84d7bc8..40ca6d3df3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -249,12 +249,11 @@ void GLGizmoMeasure::on_render() Vec3f position_on_model; Vec3f normal_on_model; size_t model_facet_idx; - m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, model_matrix, camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); - + const bool mouse_on_object = m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, model_matrix, camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); const bool is_hovering_on_locked_feature = m_mode == EMode::ExtendedSelection && m_hover_id != -1; if (m_mode == EMode::BasicSelection) { - std::optional curr_feature = m_measuring->get_feature(model_facet_idx, position_on_model.cast()); + std::optional curr_feature = mouse_on_object ? m_measuring->get_feature(model_facet_idx, position_on_model.cast()) : std::nullopt; m_curr_point_on_feature_position.reset(); if (m_curr_feature != curr_feature) { GLGizmoMeasure::on_unregister_raycasters_for_picking(); @@ -552,7 +551,7 @@ void GLGizmoMeasure::update_if_needed() // Let's save what we calculated it from: m_volumes_matrices.clear(); m_volumes_types.clear(); - m_first_instance_scale = Vec3d::Ones(); + m_first_instance_scale = Vec3d::Ones(); m_first_instance_mirror = Vec3d::Ones(); if (object != nullptr) { for (const ModelVolume* vol : object->volumes) { From f95014dce2c39acf602618dc1ba349861a0da5fd Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 5 Sep 2022 13:26:01 +0200 Subject: [PATCH 149/250] Fixed warnings on ARM64 --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 40ca6d3df3..c1e81ff21d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -89,11 +89,11 @@ GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filen : GLGizmoBase(parent, icon_filename, sprite_id) { GLModel::Geometry sphere_geometry = smooth_sphere(16, 7.5f); - m_sphere.mesh_raycaster = std::make_unique(std::make_shared(std::move(sphere_geometry.get_as_indexed_triangle_set()))); + m_sphere.mesh_raycaster = std::make_unique(std::make_shared(sphere_geometry.get_as_indexed_triangle_set())); m_sphere.model.init_from(std::move(sphere_geometry)); GLModel::Geometry cylinder_geometry = smooth_cylinder(16, 5.0f, 1.0f); - m_cylinder.mesh_raycaster = std::make_unique(std::make_shared(std::move(cylinder_geometry.get_as_indexed_triangle_set()))); + m_cylinder.mesh_raycaster = std::make_unique(std::make_shared(cylinder_geometry.get_as_indexed_triangle_set())); m_cylinder.model.init_from(std::move(cylinder_geometry)); } @@ -205,7 +205,7 @@ void GLGizmoMeasure::on_set_state() m_scene_raycaster_state.clear(); m_scene_raycasters = m_parent.get_raycasters_for_picking(SceneRaycaster::EType::Volume); if (m_scene_raycasters != nullptr) { - for (const auto r : *m_scene_raycasters) { + for (const auto& r : *m_scene_raycasters) { m_scene_raycaster_state.emplace_back(r->is_active()); } } @@ -281,7 +281,7 @@ void GLGizmoMeasure::on_render() m_last_circle = m_curr_feature; m_circle.reset(); GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); - m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); + m_circle.mesh_raycaster = std::make_unique(std::make_shared(circle_geometry.get_as_indexed_triangle_set())); m_circle.model.init_from(std::move(circle_geometry)); } @@ -298,7 +298,7 @@ void GLGizmoMeasure::on_render() const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); GLModel::Geometry init_data = init_plane_data(its, planes_triangles, idx); m_plane.reset(); - m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(init_data.get_as_indexed_triangle_set()))); + m_plane.mesh_raycaster = std::make_unique(std::make_shared(init_data.get_as_indexed_triangle_set())); m_plane.model.init_from(std::move(init_data)); } From e10bd47ba315cefaca7883830119e2ccc570c3dd Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 5 Sep 2022 15:16:31 +0200 Subject: [PATCH 150/250] Measuring: GLGizmoMeasure - Added colored icon into imgui dialog --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 68 +++++++++++++++--------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index c1e81ff21d..21e86532a1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -636,12 +636,20 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit last_y = y; } - auto add_row_to_table = [this](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) { + auto add_row_to_table = [this](std::function col_1 = nullptr, std::function col_2 = nullptr) { + assert(col_1 != nullptr && col_2 != nullptr); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); - m_imgui->text_colored(col_1_color, col_1); + col_1(); ImGui::TableSetColumnIndex(1); - m_imgui->text_colored(col_2_color, col_2); + col_2(); + }; + + auto add_strings_row_to_table = [this, add_row_to_table](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) { + add_row_to_table( + [this, &col_1, &col_1_color]() { m_imgui->text_colored(col_1_color, col_1); }, + [this, &col_2, &col_2_color]() { m_imgui->text_colored(col_2_color, col_2); } + ); }; auto format_double = [](double value) { @@ -657,10 +665,22 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit }; if (ImGui::BeginTable("Commands", 2)) { - add_row_to_table(_u8L("Left mouse button"), ImGuiWrapper::COL_ORANGE_LIGHT, - (m_mode == EMode::BasicSelection) ? _u8L("Select feature") : _u8L("Select point"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_row_to_table( + [this]() { + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Left mouse button")); + }, + [this]() { + m_imgui->text_colored(ImGui::GetStyleColorVec4(ImGuiCol_Text), (m_mode == EMode::BasicSelection) ? _u8L("Select feature") : _u8L("Select point")); + ImGui::SameLine(); + const ImVec2 pos = ImGui::GetCursorScreenPos(); + const float rect_size = ImGui::GetTextLineHeight(); + ImGui::GetWindowDrawList()->AddRectFilled({ pos.x + 1.0f, pos.y + 1.0f }, { pos.x + rect_size, pos.y + rect_size }, + ImGuiWrapper::to_ImU32(m_selected_features.first.feature.has_value() ? SELECTED_2ND_COLOR : SELECTED_1ST_COLOR)); + ImGui::Dummy(ImVec2(rect_size, rect_size)); + } + ); if (m_mode == EMode::BasicSelection && m_hover_id != -1) - add_row_to_table(CTRL_STR, ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable point selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(CTRL_STR, ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable point selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); } @@ -683,7 +703,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit Vec3d position = volume_matrix * m_curr_feature->get_point(); if (use_inches) position = ObjectManipulation::mm_to_in * position; - add_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } case Measure::SurfaceFeatureType::Edge: @@ -695,9 +715,9 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit from = ObjectManipulation::mm_to_in * from; to = ObjectManipulation::mm_to_in * to; } - add_row_to_table(_u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_row_to_table(_u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_row_to_table(_u8L("Length") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(_u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(_u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(_u8L("Length") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } case Measure::SurfaceFeatureType::Circle: @@ -709,9 +729,9 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit center = ObjectManipulation::mm_to_in * center; radius = ObjectManipulation::mm_to_in * radius; } - add_row_to_table(_u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_row_to_table(_u8L("Radius") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(_u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(_u8L("Radius") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } case Measure::SurfaceFeatureType::Plane: @@ -721,8 +741,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; if (use_inches) origin = ObjectManipulation::mm_to_in * origin; - add_row_to_table(_u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(_u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } } @@ -738,7 +758,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit Vec3d position = ObjectManipulation::mm_to_in * *m_curr_point_on_feature_position; if (use_inches) position = ObjectManipulation::mm_to_in * position; - add_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), + add_strings_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); } @@ -747,11 +767,11 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } ImGui::Separator(); - const ImGuiTableFlags flags = /*ImGuiTableFlags_SizingStretchSame | */ImGuiTableFlags_BordersOuter | /*ImGuiTableFlags_BordersV | */ImGuiTableFlags_BordersH; + const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; if (ImGui::BeginTable("Selection", 2, flags)) { - add_row_to_table(_u8L("Selection") + " 1:", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), m_selected_features.first.feature.has_value() ? + add_strings_row_to_table(_u8L("Selection") + " 1:", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), m_selected_features.first.feature.has_value() ? m_selected_features.first.source : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR)); - add_row_to_table(_u8L("Selection") + " 2:", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), m_selected_features.second.feature.has_value() ? + add_strings_row_to_table(_u8L("Selection") + " 2:", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), m_selected_features.second.feature.has_value() ? m_selected_features.second.source : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR)); ImGui::EndTable(); } @@ -767,31 +787,31 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit const Measure::MeasurementResult measure = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature); ImGui::Separator(); if (measure.has_any_data()) { - m_imgui->text(_u8L("Measure")); + m_imgui->text(_u8L("Measure") + ":"); if (ImGui::BeginTable("Measure", 2)) { if (measure.angle.has_value()) { - add_row_to_table(_u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(*measure.angle)), + add_strings_row_to_table(_u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(*measure.angle)), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } if (measure.distance_infinite.has_value()) { double distance = ObjectManipulation::mm_to_in * *measure.distance_infinite; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - add_row_to_table(_u8L("Distance Infinite") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), + add_strings_row_to_table(_u8L("Distance Infinite") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } if (measure.distance_strict.has_value()) { double distance = ObjectManipulation::mm_to_in * *measure.distance_strict; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - add_row_to_table(_u8L("Distance Strict") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), + add_strings_row_to_table(_u8L("Distance Strict") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } if (measure.distance_xyz.has_value()) { Vec3d distance = ObjectManipulation::mm_to_in * *measure.distance_xyz; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - add_row_to_table(_u8L("Distance XYZ") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), + add_strings_row_to_table(_u8L("Distance XYZ") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } ImGui::EndTable(); From 512073d4894f37f4739453284891ff7cdbfc5d96 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 6 Sep 2022 10:17:53 +0200 Subject: [PATCH 151/250] Measuring: Added missing default values to SurfaceFeature member variables --- src/libslic3r/Measure.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 3aefc0b54b..3b811db0c5 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -64,9 +64,9 @@ public: } private: - SurfaceFeatureType m_type = SurfaceFeatureType::Undef; - Vec3d m_pt1; - Vec3d m_pt2; + SurfaceFeatureType m_type{ SurfaceFeatureType::Undef }; + Vec3d m_pt1{ Vec3d::Zero() }; + Vec3d m_pt2{ Vec3d::Zero() }; std::optional m_pt3; double m_value{ 0.0 }; }; From d9cb8919511fbf12431fa5fa7e87e5969353a4da Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 6 Sep 2022 10:54:56 +0200 Subject: [PATCH 152/250] Measuring: Rewritten method SurfaceFeature::operator ==() --- src/libslic3r/Measure.hpp | 23 ++++++++++++++++------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 4 ++-- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 3b811db0c5..5d71983f0b 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -44,19 +44,28 @@ public: std::tuple get_circle() const { assert(m_type == SurfaceFeatureType::Circle); return std::make_tuple(m_pt1, m_value, m_pt2); } // For planes, return index into vector provided by Measuring::get_plane_triangle_indices, normal and point. - std::tuple get_plane() const { return std::make_tuple(int(m_value), m_pt1, m_pt2); } + std::tuple get_plane() const { assert(m_type == SurfaceFeatureType::Plane); return std::make_tuple(int(m_value), m_pt1, m_pt2); } // For anything, return an extra point that should also be considered a part of this. std::optional get_extra_point() const { assert(m_type != SurfaceFeatureType::Undef); return m_pt3; } bool operator == (const SurfaceFeature& other) const { if (this->m_type != other.m_type) return false; - if (!this->m_pt1.isApprox(other.m_pt1)) return false; - if (!this->m_pt2.isApprox(other.m_pt2)) return false; - if (this->m_pt3.has_value() && !other.m_pt3.has_value()) return false; - if (!this->m_pt3.has_value() && other.m_pt3.has_value()) return false; - if (this->m_pt3.has_value() && other.m_pt3.has_value() && !(*this->m_pt3).isApprox(*other.m_pt3)) return false; - return this->m_value == other.m_value; + switch (this->m_type) + { + case SurfaceFeatureType::Undef: { break; } + case SurfaceFeatureType::Point: { return (this->m_pt1.isApprox(other.m_pt1)); } + case SurfaceFeatureType::Edge: { + return (this->m_pt1.isApprox(other.m_pt1) && this->m_pt2.isApprox(other.m_pt2)) || + (this->m_pt1.isApprox(other.m_pt2) && this->m_pt2.isApprox(other.m_pt1)); + } + case SurfaceFeatureType::Plane: + case SurfaceFeatureType::Circle: { + return (this->m_pt1.isApprox(other.m_pt1) && this->m_pt2.isApprox(other.m_pt2) && std::abs(this->m_value - other.m_value) < EPSILON); + } + } + + return false; } bool operator != (const SurfaceFeature& other) const { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 21e86532a1..942a8c93eb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -113,7 +113,7 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) auto set_item_from_feature = [this]() { const SelectedFeatures::Item item = { m_mode, (m_mode == EMode::ExtendedSelection) ? point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id) : surface_feature_type_as_string(m_curr_feature->get_type()), - (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(Measure::SurfaceFeatureType::Point, *m_curr_point_on_feature_position, Vec3d::Zero(), std::nullopt, 0.0) : m_curr_feature }; + (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(*m_curr_point_on_feature_position) : m_curr_feature }; return item; }; @@ -331,7 +331,7 @@ void GLGizmoMeasure::on_render() default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { - m_curr_point_on_feature_position = model_matrix * m_curr_feature->get_point(); + m_curr_point_on_feature_position = position_on_feature(POINT_ID, camera); break; } case Measure::SurfaceFeatureType::Edge: From bedfffac39c459b158708f31ba2455c1b9e3878c Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 6 Sep 2022 12:02:44 +0200 Subject: [PATCH 153/250] Measuring: GLGizmoMeasure - Use mouse right click to restart selection --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 49 ++++++++++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 + 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 942a8c93eb..ebf3139868 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -110,20 +110,13 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) if (m_hover_id != -1) { m_mouse_left_down = true; - auto set_item_from_feature = [this]() { - const SelectedFeatures::Item item = { m_mode, - (m_mode == EMode::ExtendedSelection) ? point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id) : surface_feature_type_as_string(m_curr_feature->get_type()), - (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(*m_curr_point_on_feature_position) : m_curr_feature }; - return item; - }; - if (m_selected_features.first.feature.has_value()) { - const SelectedFeatures::Item item = set_item_from_feature(); + const SelectedFeatures::Item item = item_from_feature(); if (m_selected_features.first != item) m_selected_features.second = item; } else - m_selected_features.first = set_item_from_feature(); + m_selected_features.first = item_from_feature(); return true; } @@ -140,6 +133,16 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) return true; } } + else if (mouse_event.RightDown()) { + if (m_hover_id != -1) { + if (m_selected_features.first.feature.has_value()) { + if (m_selected_features.first == item_from_feature()) { + m_selected_features.reset(); + m_imgui->set_requires_extra_frame(); + } + } + } + } else if (mouse_event.Leaving()) m_mouse_left_down = false; @@ -612,6 +615,14 @@ void GLGizmoMeasure::restore_scene_raycasters_state() } } +GLGizmoMeasure::SelectedFeatures::Item GLGizmoMeasure::item_from_feature() const +{ + const SelectedFeatures::Item item = { m_mode, + (m_mode == EMode::ExtendedSelection) ? point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id) : surface_feature_type_as_string(m_curr_feature->get_type()), + (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(*m_curr_point_on_feature_position) : m_curr_feature }; + return item; +} + void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit) { static std::optional last_feature; @@ -679,6 +690,14 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::Dummy(ImVec2(rect_size, rect_size)); } ); + + if (m_hover_id != -1) { + if (m_selected_features.first.feature.has_value()) { + if (m_selected_features.first == item_from_feature()) + add_strings_row_to_table(_u8L("Right mouse button"), ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + } + if (m_mode == EMode::BasicSelection && m_hover_id != -1) add_strings_row_to_table(CTRL_STR, ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable point selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); @@ -776,12 +795,12 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::EndTable(); } - if (m_selected_features.first.feature.has_value()) { - if (m_imgui->button(_u8L("Restart"))) { - m_selected_features.reset(); - m_imgui->set_requires_extra_frame(); - } - } + //if (m_selected_features.first.feature.has_value()) { + // if (m_imgui->button(_u8L("Restart"))) { + // m_selected_features.reset(); + // m_imgui->set_requires_extra_frame(); + // } + //} if (m_selected_features.second.feature.has_value()) { const Measure::MeasurementResult measure = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 7c82f7b9f8..d415de2c9c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -110,6 +110,7 @@ class GLGizmoMeasure : public GLGizmoBase void disable_scene_raycasters(); void restore_scene_raycasters_state(); + SelectedFeatures::Item item_from_feature() const; public: GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); From 805a793f53c4245c90302bf168f59e578a0d4e0b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 6 Sep 2022 15:06:56 +0200 Subject: [PATCH 154/250] Follow-up of 2b7520dc9eee8063c7d376811603c2d09c4a75e4 - Use CTRL + mouse right click to restart selection --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 35 ++++++++---------------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 - 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index ebf3139868..f1a011e572 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -109,6 +109,13 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) else if (mouse_event.LeftDown()) { if (m_hover_id != -1) { m_mouse_left_down = true; + + auto item_from_feature = [this]() { + const SelectedFeatures::Item item = { m_mode, + (m_mode == EMode::ExtendedSelection) ? point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id) : surface_feature_type_as_string(m_curr_feature->get_type()), + (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(*m_curr_point_on_feature_position) : m_curr_feature }; + return item; + }; if (m_selected_features.first.feature.has_value()) { const SelectedFeatures::Item item = item_from_feature(); @@ -133,15 +140,9 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) return true; } } - else if (mouse_event.RightDown()) { - if (m_hover_id != -1) { - if (m_selected_features.first.feature.has_value()) { - if (m_selected_features.first == item_from_feature()) { - m_selected_features.reset(); - m_imgui->set_requires_extra_frame(); - } - } - } + else if (mouse_event.RightDown() && mouse_event.CmdDown()) { + m_selected_features.reset(); + m_imgui->set_requires_extra_frame(); } else if (mouse_event.Leaving()) m_mouse_left_down = false; @@ -615,14 +616,6 @@ void GLGizmoMeasure::restore_scene_raycasters_state() } } -GLGizmoMeasure::SelectedFeatures::Item GLGizmoMeasure::item_from_feature() const -{ - const SelectedFeatures::Item item = { m_mode, - (m_mode == EMode::ExtendedSelection) ? point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id) : surface_feature_type_as_string(m_curr_feature->get_type()), - (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(*m_curr_point_on_feature_position) : m_curr_feature }; - return item; -} - void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit) { static std::optional last_feature; @@ -691,12 +684,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } ); - if (m_hover_id != -1) { - if (m_selected_features.first.feature.has_value()) { - if (m_selected_features.first == item_from_feature()) - add_strings_row_to_table(_u8L("Right mouse button"), ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - } - } + if (m_selected_features.first.feature.has_value()) + add_strings_row_to_table(CTRL_STR + "+" + _u8L("Right mouse button"), ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); if (m_mode == EMode::BasicSelection && m_hover_id != -1) add_strings_row_to_table(CTRL_STR, ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable point selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index d415de2c9c..7c82f7b9f8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -110,7 +110,6 @@ class GLGizmoMeasure : public GLGizmoBase void disable_scene_raycasters(); void restore_scene_raycasters_state(); - SelectedFeatures::Item item_from_feature() const; public: GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); From 14224eb38e848438acc4e722c0cbf0da65a48a57 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 7 Sep 2022 13:07:15 +0200 Subject: [PATCH 155/250] Measuring: bunch of fixes into GLGizmoMeasure + new tech ENABLE_MEASURE_GIZMO_DEBUG to show a debug imgui dialog containing data related to Measure Gizmo --- src/libslic3r/Technologies.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 222 +++++++++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 12 +- 3 files changed, 152 insertions(+), 83 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index a96a39066c..04ecfae670 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -68,6 +68,7 @@ #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) // Enable Measure Gizmo #define ENABLE_MEASURE_GIZMO (1 && ENABLE_RAYCAST_PICKING) +#define ENABLE_MEASURE_GIZMO_DEBUG (0 && ENABLE_MEASURE_GIZMO) #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index f1a011e572..b434cea9a7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -111,7 +111,7 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) m_mouse_left_down = true; auto item_from_feature = [this]() { - const SelectedFeatures::Item item = { m_mode, + const SelectedFeatures::Item item = { (m_mode == EMode::ExtendedSelection) ? point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id) : surface_feature_type_as_string(m_curr_feature->get_type()), (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(*m_curr_point_on_feature_position) : m_curr_feature }; return item; @@ -236,6 +236,10 @@ bool GLGizmoMeasure::on_is_activable() const void GLGizmoMeasure::on_render() { +#if ENABLE_MEASURE_GIZMO_DEBUG + render_debug_dialog(); +#endif // ENABLE_MEASURE_GIZMO_DEBUG + // do not render if the user is panning/rotating the 3d scene if (m_parent.is_mouse_dragging()) return; @@ -246,14 +250,14 @@ void GLGizmoMeasure::on_render() (selection.is_single_volume() || selection.is_single_volume_instance())) { update_if_needed(); - const Transform3d& model_matrix = selection.get_first_volume()->world_matrix(); + m_volume_matrix = selection.get_first_volume()->world_matrix(); const Camera& camera = wxGetApp().plater()->get_camera(); const float inv_zoom = (float)camera.get_inv_zoom(); Vec3f position_on_model; Vec3f normal_on_model; size_t model_facet_idx; - const bool mouse_on_object = m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, model_matrix, camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); + const bool mouse_on_object = m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, m_volume_matrix, camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); const bool is_hovering_on_locked_feature = m_mode == EMode::ExtendedSelection && m_hover_id != -1; if (m_mode == EMode::BasicSelection) { @@ -335,31 +339,31 @@ void GLGizmoMeasure::on_render() default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { - m_curr_point_on_feature_position = position_on_feature(POINT_ID, camera); + m_curr_point_on_feature_position = m_curr_feature->get_point(); break; } case Measure::SurfaceFeatureType::Edge: { - m_curr_point_on_feature_position = position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); + m_curr_point_on_feature_position = m_volume_matrix.inverse() * position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); break; } case Measure::SurfaceFeatureType::Plane: { - m_curr_point_on_feature_position = position_on_feature(PLANE_ID, camera); + m_curr_point_on_feature_position = m_volume_matrix.inverse() * position_on_feature(PLANE_ID, camera); break; } case Measure::SurfaceFeatureType::Circle: { const auto [center, radius, normal] = m_curr_feature->get_circle(); if (m_hover_id == POINT_ID) - m_curr_point_on_feature_position = model_matrix * center; + m_curr_point_on_feature_position = center; else { const float r = radius; // needed for the following lambda - m_curr_point_on_feature_position = position_on_feature(CIRCLE_ID, camera, [r](const Vec3f& v) { + m_curr_point_on_feature_position = m_volume_matrix.inverse() * position_on_feature(CIRCLE_ID, camera, [r](const Vec3f& v) { float angle = std::atan2(v.y(), v.x()); if (angle < 0.0f) angle += 2.0f * float(M_PI); - return float(r) * Vec3f(std::cos(angle), std::sin(angle), 0.0f); + return Vec3f(float(r) * std::cos(angle), float(r) * std::sin(angle), 0.0f); }); } break; @@ -411,7 +415,7 @@ void GLGizmoMeasure::on_render() } case Measure::SurfaceFeatureType::Circle: { - const auto& [center, radius, n] = feature.get_circle(); + const auto& [center, radius, normal] = feature.get_circle(); // render center const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(center_matrix); @@ -423,7 +427,7 @@ void GLGizmoMeasure::on_render() it->second->set_transform(center_matrix); } // render circle - const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center); + const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); set_matrix_uniforms(circle_matrix); m_circle.model.set_color(colors.back()); m_circle.model.render(); @@ -437,8 +441,8 @@ void GLGizmoMeasure::on_render() case Measure::SurfaceFeatureType::Edge: { const auto& [start, end] = feature.get_edge(); - auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * q * + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start) * Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); set_matrix_uniforms(feature_matrix); m_cylinder.model.set_color(colors.front()); @@ -505,25 +509,23 @@ void GLGizmoMeasure::on_render() } } - render_feature(*m_curr_feature, colors, model_matrix, inv_zoom, true); + render_feature(*m_curr_feature, colors, m_volume_matrix, inv_zoom, true); } if (m_selected_features.first.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.first.feature)) { std::vector colors; colors.emplace_back(SELECTED_1ST_COLOR); - render_feature(*m_selected_features.first.feature, colors, - (m_selected_features.first.mode == EMode::BasicSelection) ? model_matrix : Transform3d::Identity(), inv_zoom, false); + render_feature(*m_selected_features.first.feature, colors, m_volume_matrix, inv_zoom, false); } if (m_selected_features.second.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.second.feature)) { std::vector colors; colors.emplace_back(SELECTED_2ND_COLOR); - render_feature(*m_selected_features.second.feature, colors, - (m_selected_features.second.mode == EMode::BasicSelection) ? model_matrix : Transform3d::Identity(), inv_zoom, false); + render_feature(*m_selected_features.second.feature, colors, m_volume_matrix, inv_zoom, false); } if (is_hovering_on_locked_feature && m_curr_point_on_feature_position.has_value()) { if (m_hover_id != POINT_ID) { - const Transform3d matrix = Geometry::translation_transform(*m_curr_point_on_feature_position) * Geometry::scale_transform(inv_zoom); + const Transform3d matrix = m_volume_matrix * Geometry::translation_transform(*m_curr_point_on_feature_position) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(matrix); m_sphere.model.set_color(hover_selection_color()); m_sphere.model.render(); @@ -616,6 +618,100 @@ void GLGizmoMeasure::restore_scene_raycasters_state() } } +static void add_row_to_table(std::function col_1 = nullptr, std::function col_2 = nullptr) +{ + assert(col_1 != nullptr && col_2 != nullptr); + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + col_1(); + ImGui::TableSetColumnIndex(1); + col_2(); +}; + +static void add_strings_row_to_table(ImGuiWrapper& imgui, const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) +{ + add_row_to_table([&]() { imgui.text_colored(col_1_color, col_1); }, [&]() { imgui.text_colored(col_2_color, col_2); }); +}; + +static std::string format_double(double value) +{ + char buf[1024]; + sprintf(buf, "%.3f", value); + return std::string(buf); +}; + +static std::string format_vec3(const Vec3d& v) +{ + char buf[1024]; + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", v.x(), v.y(), v.z()); + return std::string(buf); +}; + +#if ENABLE_MEASURE_GIZMO_DEBUG +void GLGizmoMeasure::render_debug_dialog() +{ + auto add_feature_data = [this](const SelectedFeatures::Item& item) { + add_strings_row_to_table(*m_imgui, "Type", ImGuiWrapper::COL_ORANGE_LIGHT, item.source, ImGui::GetStyleColorVec4(ImGuiCol_Text)); + switch (item.feature->get_type()) + { + case Measure::SurfaceFeatureType::Point: + { + add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(item.feature->get_point()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + auto [from, to] = item.feature->get_edge(); + add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + auto [idx, normal, origin] = item.feature->get_plane(); + add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_value", ImGuiWrapper::COL_ORANGE_LIGHT, format_double(idx), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + auto [center, radius, normal] = item.feature->get_circle(); + add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, "m_value", ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; + } + } + std::optional extra_point = item.feature->get_extra_point(); + if (extra_point.has_value()) + add_strings_row_to_table(*m_imgui, "m_pt3", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(*extra_point), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + }; + + m_imgui->begin(_L("Measure tool debug"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + if (!m_selected_features.first.feature.has_value() && !m_selected_features.second.feature.has_value()) + m_imgui->text("Empty selection"); + else { + const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; + if (m_selected_features.first.feature.has_value()) { + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Selection 1"); + if (ImGui::BeginTable("Selection 1", 2, flags)) { + add_feature_data(m_selected_features.first); + ImGui::EndTable(); + } + } + if (m_selected_features.second.feature.has_value()) { + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Selection 2"); + if (ImGui::BeginTable("Selection 2", 2, flags)) { + add_feature_data(m_selected_features.second); + ImGui::EndTable(); + } + } + } + m_imgui->end(); +} +#endif // ENABLE_MEASURE_GIZMO_DEBUG + void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit) { static std::optional last_feature; @@ -640,34 +736,6 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit last_y = y; } - auto add_row_to_table = [this](std::function col_1 = nullptr, std::function col_2 = nullptr) { - assert(col_1 != nullptr && col_2 != nullptr); - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - col_1(); - ImGui::TableSetColumnIndex(1); - col_2(); - }; - - auto add_strings_row_to_table = [this, add_row_to_table](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) { - add_row_to_table( - [this, &col_1, &col_1_color]() { m_imgui->text_colored(col_1_color, col_1); }, - [this, &col_2, &col_2_color]() { m_imgui->text_colored(col_2_color, col_2); } - ); - }; - - auto format_double = [](double value) { - char buf[1024]; - sprintf(buf, "%.3f", value); - return std::string(buf); - }; - - auto format_vec3 = [](const Vec3d& v) { - char buf[1024]; - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", v.x(), v.y(), v.z()); - return std::string(buf); - }; - if (ImGui::BeginTable("Commands", 2)) { add_row_to_table( [this]() { @@ -685,10 +753,10 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ); if (m_selected_features.first.feature.has_value()) - add_strings_row_to_table(CTRL_STR + "+" + _u8L("Right mouse button"), ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, CTRL_STR + "+" + _u8L("Right mouse button"), ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); if (m_mode == EMode::BasicSelection && m_hover_id != -1) - add_strings_row_to_table(CTRL_STR, ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable point selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, CTRL_STR, ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable point selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); } @@ -696,7 +764,6 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit const std::string units = use_inches ? _u8L(" (in)") : _u8L(" (mm)"); if (m_curr_feature.has_value()) { - const Transform3d volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); const Measure::SurfaceFeatureType feature_type = m_curr_feature->get_type(); if (m_mode == EMode::BasicSelection) { if (feature_type != Measure::SurfaceFeatureType::Undef) { @@ -708,49 +775,49 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { - Vec3d position = volume_matrix * m_curr_feature->get_point(); + Vec3d position = m_volume_matrix * m_curr_feature->get_point(); if (use_inches) position = ObjectManipulation::mm_to_in * position; - add_strings_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } case Measure::SurfaceFeatureType::Edge: { auto [from, to] = m_curr_feature->get_edge(); - from = volume_matrix * from; - to = volume_matrix * to; + from = m_volume_matrix * from; + to = m_volume_matrix * to; if (use_inches) { from = ObjectManipulation::mm_to_in * from; to = ObjectManipulation::mm_to_in * to; } - add_strings_row_to_table(_u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(_u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(_u8L("Length") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Length") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } case Measure::SurfaceFeatureType::Circle: { auto [center, radius, normal] = m_curr_feature->get_circle(); - center = volume_matrix * center; - normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + center = m_volume_matrix * center; + normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; if (use_inches) { center = ObjectManipulation::mm_to_in * center; radius = ObjectManipulation::mm_to_in * radius; } - add_strings_row_to_table(_u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(_u8L("Radius") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Radius") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } case Measure::SurfaceFeatureType::Plane: { auto [idx, normal, origin] = m_curr_feature->get_plane(); - origin = volume_matrix * origin; - normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + origin = m_volume_matrix * origin; + normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; if (use_inches) origin = ObjectManipulation::mm_to_in * origin; - add_strings_row_to_table(_u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(_u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } } @@ -763,11 +830,10 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::Separator(); m_imgui->text(point_on_feature_type_as_string(feature_type, m_hover_id) + ":"); if (ImGui::BeginTable("Data", 2)) { - Vec3d position = ObjectManipulation::mm_to_in * *m_curr_point_on_feature_position; + Vec3d position = m_volume_matrix * *m_curr_point_on_feature_position; if (use_inches) position = ObjectManipulation::mm_to_in * position; - add_strings_row_to_table(_u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), - ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); } } @@ -777,9 +843,9 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::Separator(); const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; if (ImGui::BeginTable("Selection", 2, flags)) { - add_strings_row_to_table(_u8L("Selection") + " 1:", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), m_selected_features.first.feature.has_value() ? + add_strings_row_to_table(*m_imgui, _u8L("Selection") + " 1:", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), m_selected_features.first.feature.has_value() ? m_selected_features.first.source : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR)); - add_strings_row_to_table(_u8L("Selection") + " 2:", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), m_selected_features.second.feature.has_value() ? + add_strings_row_to_table(*m_imgui, _u8L("Selection") + " 2:", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), m_selected_features.second.feature.has_value() ? m_selected_features.second.source : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR)); ImGui::EndTable(); } @@ -798,28 +864,28 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit m_imgui->text(_u8L("Measure") + ":"); if (ImGui::BeginTable("Measure", 2)) { if (measure.angle.has_value()) { - add_strings_row_to_table(_u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(*measure.angle)), + add_strings_row_to_table(*m_imgui, _u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(*measure.angle)), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } if (measure.distance_infinite.has_value()) { - double distance = ObjectManipulation::mm_to_in * *measure.distance_infinite; + double distance = *measure.distance_infinite; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - add_strings_row_to_table(_u8L("Distance Infinite") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), + add_strings_row_to_table(*m_imgui, _u8L("Distance Infinite") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } if (measure.distance_strict.has_value()) { - double distance = ObjectManipulation::mm_to_in * *measure.distance_strict; + double distance = *measure.distance_strict; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - add_strings_row_to_table(_u8L("Distance Strict") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), + add_strings_row_to_table(*m_imgui, _u8L("Distance Strict") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } if (measure.distance_xyz.has_value()) { - Vec3d distance = ObjectManipulation::mm_to_in * *measure.distance_xyz; + Vec3d distance = *measure.distance_xyz; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - add_strings_row_to_table(_u8L("Distance XYZ") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), + add_strings_row_to_table(*m_imgui, _u8L("Distance XYZ") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); } ImGui::EndTable(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 7c82f7b9f8..e0789c821f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -33,12 +33,10 @@ class GLGizmoMeasure : public GLGizmoBase { struct Item { - EMode mode{ EMode::BasicSelection }; std::string source; std::optional feature; bool operator == (const Item& other) const { - if (this->mode != other.mode) return false; if (this->source != other.source) return false; return this->feature == other.feature; } @@ -48,7 +46,6 @@ class GLGizmoMeasure : public GLGizmoBase } void reset() { - mode = EMode::BasicSelection; source.clear(); feature.reset(); } @@ -62,12 +59,12 @@ class GLGizmoMeasure : public GLGizmoBase second.reset(); } - bool operator == (const SelectedFeatures& other) const { + bool operator == (const SelectedFeatures & other) const { if (this->first != other.first) return false; return this->second == other.second; } - bool operator != (const SelectedFeatures& other) const { + bool operator != (const SelectedFeatures & other) const { return !operator == (other); } }; @@ -80,6 +77,7 @@ class GLGizmoMeasure : public GLGizmoBase PickingModel m_circle; PickingModel m_plane; + Transform3d m_volume_matrix{ Transform3d::Identity() }; std::vector m_plane_models_cache; std::map> m_raycasters; std::optional m_curr_feature; @@ -111,6 +109,10 @@ class GLGizmoMeasure : public GLGizmoBase void disable_scene_raycasters(); void restore_scene_raycasters_state(); +#if ENABLE_MEASURE_GIZMO_DEBUG + void render_debug_dialog(); +#endif // ENABLE_MEASURE_GIZMO_DEBUG + public: GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); From 950272aff1b28d5e952e795215be544845375efd Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 7 Sep 2022 14:04:18 +0200 Subject: [PATCH 156/250] Measuring: Gizmo measure disabled for sinking volumes --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index b434cea9a7..db9fc0dd34 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -229,9 +229,12 @@ std::string GLGizmoMeasure::on_get_name() const bool GLGizmoMeasure::on_is_activable() const { const Selection& selection = m_parent.get_selection(); - return (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) ? + bool res = (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) ? selection.is_single_full_instance() : selection.is_single_volume() || selection.is_single_volume_instance(); + if (res) + res &= !selection.get_first_volume()->is_sinking(); + return res; } void GLGizmoMeasure::on_render() From f9087d580082167a1732f66bfd44aa1d5d540020 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 15 Sep 2022 12:28:16 +0200 Subject: [PATCH 157/250] Measuring: Gizmo measure shows dimensioning for distance point-point --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 146 +++++++++++++++++++++++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 8 ++ 2 files changed, 154 insertions(+) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index db9fc0dd34..92046c299f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -27,6 +27,9 @@ static const int EDGE_ID = 200; static const int CIRCLE_ID = 300; static const int PLANE_ID = 400; +static const float TRIANGLE_BASE = 16.0f; +static const float TRIANGLE_HEIGHT = TRIANGLE_BASE * 1.618033f; + static const std::string CTRL_STR = #ifdef __APPLE__ "⌘" @@ -537,6 +540,8 @@ void GLGizmoMeasure::on_render() shader->stop_using(); } + + render_dimensioning(); } void GLGizmoMeasure::update_if_needed() @@ -621,6 +626,147 @@ void GLGizmoMeasure::restore_scene_raycasters_state() } } +void GLGizmoMeasure::render_dimensioning() +{ + if (!m_selected_features.first.feature.has_value() || !m_selected_features.second.feature.has_value()) + return; + + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + + auto point_point_2D = [this, shader](const Vec3d& v1, const Vec3d& v2) { + if (v1.isApprox(v2)) + return; + + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d& view_matrix = camera.get_view_matrix(); + const Transform3d& projection_matrix = camera.get_projection_matrix(); + const Matrix4d projection_view_matrix = projection_matrix.matrix() * view_matrix.matrix(); + const std::array& viewport = camera.get_viewport(); + const double inv_zoom = camera.get_inv_zoom(); + + auto model_to_world = [this](const Vec3d& model) { + return (Vec3d)(m_volume_matrix * model); + }; + + auto world_to_clip = [&projection_view_matrix](const Vec3d& world) { + return (Vec4d)(projection_view_matrix * Vec4d(world.x(), world.y(), world.z(), 1.0)); + }; + + auto clip_to_ndc = [](const Vec4d& clip) { + return Vec2d(clip.x(), clip.y()) / clip.w(); + }; + + const double half_w = 0.5 * double(viewport[2]); + const double half_h = 0.5 * double(viewport[3]); + + auto ndc_to_ss = [&viewport, half_w, half_h](const Vec2d& ndc) { + return Vec2d(half_w * ndc.x() + double(viewport[0]) + half_w, half_h * ndc.y() + double(viewport[1]) + half_h); + }; + + Matrix4d ndc_to_ss_matrix; + ndc_to_ss_matrix << half_w, 0.0, 0.0, double(viewport[0]) + half_w, + 0.0, half_h, 0.0, double(viewport[1]) + half_h, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0; + + const Transform3d ss_to_ndc_matrix = Transform3d(ndc_to_ss_matrix.inverse()); + + // ndc coordinates + const Vec2d v1ndc = clip_to_ndc(world_to_clip(model_to_world(v1))); + const Vec2d v2ndc = clip_to_ndc(world_to_clip(model_to_world(v2))); + const Vec2d v12ndc = v2ndc - v1ndc; + const double v12ndc_len = v12ndc.norm(); + + // screen coordinates + const Vec2d v1ss = ndc_to_ss(v1ndc); + const Vec2d v2ss = ndc_to_ss(v2ndc); + + if (v1ss.isApprox(v2ss)) + return; + + const Vec2d v12ss = v2ss - v1ss; + const double v12ss_len = v12ss.norm(); + + const bool overlap = v12ss_len - 2.0 * TRIANGLE_HEIGHT < 0.0; + + const auto q12ss = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Vec3d(v12ss.x(), v12ss.y(), 0.0)); + const auto q21ss = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Vec3d(-v12ss.x(), -v12ss.y(), 0.0)); + + shader->set_uniform("projection_matrix", Transform3d::Identity()); + + const Vec3d v1ss_3 = { v1ss.x(), v1ss.y(), 0.0 }; + const Vec3d v2ss_3 = { v2ss.x(), v2ss.y(), 0.0 }; + + // stem + shader->set_uniform("view_model_matrix", overlap ? + ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q12ss * Geometry::translation_transform(-2.0 * TRIANGLE_HEIGHT * Vec3d::UnitX()) * Geometry::scale_transform({ v12ss_len + 4.0 * TRIANGLE_HEIGHT, 1.0f, 1.0f }) : + ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q12ss * Geometry::scale_transform({ v12ss_len, 1.0f, 1.0f })); + m_dimensioning.line.render(); + + // arrow 1 + shader->set_uniform("view_model_matrix", overlap ? + ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q12ss : + ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q21ss); + m_dimensioning.triangle.render(); + + // arrow 2 + shader->set_uniform("view_model_matrix", overlap ? + ss_to_ndc_matrix * Geometry::translation_transform(v2ss_3) * q21ss : + ss_to_ndc_matrix * Geometry::translation_transform(v2ss_3) * q12ss); + m_dimensioning.triangle.render(); + }; + + shader->start_using(); + + if (!m_dimensioning.line.is_initialized()) { + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; + init_data.color = ColorRGBA::WHITE(); + init_data.reserve_vertices(2); + init_data.reserve_indices(2); + + // vertices + init_data.add_vertex(Vec3f(0.0f, 0.0f, 0.0f)); + init_data.add_vertex(Vec3f(1.0f, 0.0f, 0.0f)); + + // indices + init_data.add_line(0, 1); + + m_dimensioning.line.init_from(std::move(init_data)); + } + + if (!m_dimensioning.triangle.is_initialized()) { + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 }; + init_data.color = ColorRGBA::WHITE(); + init_data.reserve_vertices(3); + init_data.reserve_indices(3); + + // vertices + init_data.add_vertex(Vec3f(0.0f, 0.0f, 0.0f)); + init_data.add_vertex(Vec3f(-TRIANGLE_HEIGHT, 0.5f * TRIANGLE_BASE, 0.0f)); + init_data.add_vertex(Vec3f(-TRIANGLE_HEIGHT, -0.5f * TRIANGLE_BASE, 0.0f)); + + // indices + init_data.add_triangle(0, 1, 2); + + m_dimensioning.triangle.init_from(std::move(init_data)); + } + + glsafe(::glDisable(GL_DEPTH_TEST)); + + if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { + point_point_2D(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_point()); + } + + glsafe(::glEnable(GL_DEPTH_TEST)); + + shader->stop_using(); +} + static void add_row_to_table(std::function col_1 = nullptr, std::function col_2 = nullptr) { assert(col_1 != nullptr && col_2 != nullptr); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index e0789c821f..4417a0d608 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -76,6 +76,12 @@ class GLGizmoMeasure : public GLGizmoBase PickingModel m_cylinder; PickingModel m_circle; PickingModel m_plane; + struct Dimensioning + { + GLModel line; + GLModel triangle; + }; + Dimensioning m_dimensioning; Transform3d m_volume_matrix{ Transform3d::Identity() }; std::vector m_plane_models_cache; @@ -109,6 +115,8 @@ class GLGizmoMeasure : public GLGizmoBase void disable_scene_raycasters(); void restore_scene_raycasters_state(); + void render_dimensioning(); + #if ENABLE_MEASURE_GIZMO_DEBUG void render_debug_dialog(); #endif // ENABLE_MEASURE_GIZMO_DEBUG From 5825e850128f54dbc675f3f9b2bf12fe18dc60c3 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 15 Sep 2022 14:42:04 +0200 Subject: [PATCH 158/250] Measuring: Gizmo measure shows dimensioning for distance point-edge --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 166 +++++++++++++++++------ 1 file changed, 125 insertions(+), 41 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 92046c299f..4caae10f43 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -626,6 +626,79 @@ void GLGizmoMeasure::restore_scene_raycasters_state() } } +class DimensioningHelper +{ + struct Cache + { + std::array viewport; + Matrix4d ndc_to_ss_matrix; + Transform3d ndc_to_ss_matrix_inverse; + }; + + static Cache s_cache; + +public: + static Vec3d model_to_world(const Vec3d& model, const Transform3d& world_matrix) { + return world_matrix * model; + } + + static Vec4d world_to_clip(const Vec3d& world, const Matrix4d& projection_view_matrix) { + return projection_view_matrix * Vec4d(world.x(), world.y(), world.z(), 1.0); + } + + static Vec3d clip_to_ndc(const Vec4d& clip) { + return Vec3d(clip.x(), clip.y(), clip.z()) / clip.w(); + } + + static Vec2d ndc_to_ss(const Vec3d& ndc, const std::array& viewport) { + const double half_w = 0.5 * double(viewport[2]); + const double half_h = 0.5 * double(viewport[3]); + return { half_w * ndc.x() + double(viewport[0]) + half_w, half_h * ndc.y() + double(viewport[1]) + half_h }; + }; + + static Vec4d model_to_clip(const Vec3d& model, const Transform3d& world_matrix, const Matrix4d& projection_view_matrix) { + return world_to_clip(model_to_world(model, world_matrix), projection_view_matrix); + } + + static Vec3d model_to_ndc(const Vec3d& model, const Transform3d& world_matrix, const Matrix4d& projection_view_matrix) { + return clip_to_ndc(world_to_clip(model_to_world(model, world_matrix), projection_view_matrix)); + } + + static Vec2d model_to_ss(const Vec3d& model, const Transform3d& world_matrix, const Matrix4d& projection_view_matrix, const std::array& viewport) { + return ndc_to_ss(clip_to_ndc(world_to_clip(model_to_world(model, world_matrix), projection_view_matrix)), viewport); + } + + static const Matrix4d& ndc_to_ss_matrix(const std::array& viewport) { + update(viewport); + return s_cache.ndc_to_ss_matrix; + } + + static const Transform3d ndc_to_ss_matrix_inverse(const std::array& viewport) { + update(viewport); + return s_cache.ndc_to_ss_matrix_inverse; + } + +private: + static void update(const std::array& viewport) { + if (s_cache.viewport == viewport) + return; + + std::cout << "DimensioningHelper::update()\n"; + + const double half_w = 0.5 * double(viewport[2]); + const double half_h = 0.5 * double(viewport[3]); + s_cache.ndc_to_ss_matrix << half_w, 0.0, 0.0, double(viewport[0]) + half_w, + 0.0, half_h, 0.0, double(viewport[1]) + half_h, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0; + + s_cache.ndc_to_ss_matrix_inverse = s_cache.ndc_to_ss_matrix.inverse(); + s_cache.viewport = viewport; + } +}; + +DimensioningHelper::Cache DimensioningHelper::s_cache = { { 0, 0, 0, 0 }, Matrix4d::Identity(), Transform3d::Identity() }; + void GLGizmoMeasure::render_dimensioning() { if (!m_selected_features.first.feature.has_value() || !m_selected_features.second.feature.has_value()) @@ -635,53 +708,17 @@ void GLGizmoMeasure::render_dimensioning() if (shader == nullptr) return; - auto point_point_2D = [this, shader](const Vec3d& v1, const Vec3d& v2) { + auto point_point = [this, shader](const Vec3d& v1, const Vec3d& v2) { if (v1.isApprox(v2)) return; const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d& view_matrix = camera.get_view_matrix(); - const Transform3d& projection_matrix = camera.get_projection_matrix(); - const Matrix4d projection_view_matrix = projection_matrix.matrix() * view_matrix.matrix(); + const Matrix4d projection_view_matrix = camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix(); const std::array& viewport = camera.get_viewport(); - const double inv_zoom = camera.get_inv_zoom(); - - auto model_to_world = [this](const Vec3d& model) { - return (Vec3d)(m_volume_matrix * model); - }; - - auto world_to_clip = [&projection_view_matrix](const Vec3d& world) { - return (Vec4d)(projection_view_matrix * Vec4d(world.x(), world.y(), world.z(), 1.0)); - }; - - auto clip_to_ndc = [](const Vec4d& clip) { - return Vec2d(clip.x(), clip.y()) / clip.w(); - }; - - const double half_w = 0.5 * double(viewport[2]); - const double half_h = 0.5 * double(viewport[3]); - - auto ndc_to_ss = [&viewport, half_w, half_h](const Vec2d& ndc) { - return Vec2d(half_w * ndc.x() + double(viewport[0]) + half_w, half_h * ndc.y() + double(viewport[1]) + half_h); - }; - - Matrix4d ndc_to_ss_matrix; - ndc_to_ss_matrix << half_w, 0.0, 0.0, double(viewport[0]) + half_w, - 0.0, half_h, 0.0, double(viewport[1]) + half_h, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0; - - const Transform3d ss_to_ndc_matrix = Transform3d(ndc_to_ss_matrix.inverse()); - - // ndc coordinates - const Vec2d v1ndc = clip_to_ndc(world_to_clip(model_to_world(v1))); - const Vec2d v2ndc = clip_to_ndc(world_to_clip(model_to_world(v2))); - const Vec2d v12ndc = v2ndc - v1ndc; - const double v12ndc_len = v12ndc.norm(); // screen coordinates - const Vec2d v1ss = ndc_to_ss(v1ndc); - const Vec2d v2ss = ndc_to_ss(v2ndc); + const Vec2d v1ss = DimensioningHelper::model_to_ss(v1, m_volume_matrix, projection_view_matrix, viewport); + const Vec2d v2ss = DimensioningHelper::model_to_ss(v2, m_volume_matrix, projection_view_matrix, viewport); if (v1ss.isApprox(v2ss)) return; @@ -699,6 +736,8 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d v1ss_3 = { v1ss.x(), v1ss.y(), 0.0 }; const Vec3d v2ss_3 = { v2ss.x(), v2ss.y(), 0.0 }; + const Transform3d ss_to_ndc_matrix = DimensioningHelper::ndc_to_ss_matrix_inverse(viewport); + // stem shader->set_uniform("view_model_matrix", overlap ? ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q12ss * Geometry::translation_transform(-2.0 * TRIANGLE_HEIGHT * Vec3d::UnitX()) * Geometry::scale_transform({ v12ss_len + 4.0 * TRIANGLE_HEIGHT, 1.0f, 1.0f }) : @@ -718,6 +757,43 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.triangle.render(); }; + auto point_edge = [this, shader, point_point](const Vec3d& v, const std::pair& e) { + const Vec3d e1v = v - e.first; + const Vec3d e1e2 = e.second - e.first; + const Vec3d e1e2_unit = e1e2.normalized(); + const Vec3d v_proj_on_e1e2 = e.first + e1v.dot(e1e2_unit) * e1e2_unit; + point_point(v, v_proj_on_e1e2); + + const Vec3d v_proj_on_e1e2e1 = v_proj_on_e1e2 - e.first; + bool on_e1_side = v_proj_on_e1e2e1.dot(e1e2) < 0.0; + bool on_e2_side = v_proj_on_e1e2e1.norm() > e1e2.norm(); + if (on_e1_side || on_e2_side) { + 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 Transform3d ss_to_ndc_matrix = DimensioningHelper::ndc_to_ss_matrix_inverse(viewport); + + shader->set_uniform("projection_matrix", Transform3d::Identity()); + + const Vec2d v_proj_on_e1e2ss = DimensioningHelper::model_to_ss(v_proj_on_e1e2, m_volume_matrix, projection_view_matrix, viewport); + auto render_extension = [this, &v_proj_on_e1e2ss, &projection_view_matrix, &viewport, &ss_to_ndc_matrix, shader](const Vec3d& p) { + const Vec2d pss = DimensioningHelper::model_to_ss(p, m_volume_matrix, projection_view_matrix, viewport); + if (!pss.isApprox(v_proj_on_e1e2ss)) { + const Vec2d pv_proj_on_e1e2ss = v_proj_on_e1e2ss - pss; + const double pv_proj_on_e1e2ss_len = pv_proj_on_e1e2ss.norm(); + + const auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Vec3d(pv_proj_on_e1e2ss.x(), pv_proj_on_e1e2ss.y(), 0.0)); + + shader->set_uniform("view_model_matrix", ss_to_ndc_matrix * Geometry::translation_transform({ pss.x(), pss.y(), 0.0 }) * q * + Geometry::scale_transform({ pv_proj_on_e1e2ss_len, 1.0f, 1.0f })); + m_dimensioning.line.render(); + } + }; + + render_extension(on_e1_side ? e.first : e.second); + } + }; + shader->start_using(); if (!m_dimensioning.line.is_initialized()) { @@ -759,7 +835,15 @@ void GLGizmoMeasure::render_dimensioning() if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - point_point_2D(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_point()); + point_point(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_point()); + } + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { + point_edge(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_edge()); + } + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { + point_edge(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_edge()); } glsafe(::glEnable(GL_DEPTH_TEST)); From 55209dba4b4d50c0964ecd4f61dd84e149c02f01 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 15 Sep 2022 15:27:49 +0200 Subject: [PATCH 159/250] Measuring: Gizmo measure shows dimensioning for distance point-plane --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 45 ++++++++++++++++-------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 4caae10f43..c1e6a0c9ff 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -758,34 +758,32 @@ void GLGizmoMeasure::render_dimensioning() }; auto point_edge = [this, shader, point_point](const Vec3d& v, const std::pair& e) { - const Vec3d e1v = v - e.first; const Vec3d e1e2 = e.second - e.first; const Vec3d e1e2_unit = e1e2.normalized(); - const Vec3d v_proj_on_e1e2 = e.first + e1v.dot(e1e2_unit) * e1e2_unit; - point_point(v, v_proj_on_e1e2); + const Vec3d v_proj = e.first + e1e2_unit.dot(v - e.first) * e1e2_unit; + point_point(v, v_proj); - const Vec3d v_proj_on_e1e2e1 = v_proj_on_e1e2 - e.first; - bool on_e1_side = v_proj_on_e1e2e1.dot(e1e2) < 0.0; - bool on_e2_side = v_proj_on_e1e2e1.norm() > e1e2.norm(); + const Vec3d v_proje1 = v_proj - e.first; + bool on_e1_side = v_proje1.dot(e1e2) < 0.0; + bool on_e2_side = v_proje1.norm() > e1e2.norm(); if (on_e1_side || on_e2_side) { 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 Transform3d ss_to_ndc_matrix = DimensioningHelper::ndc_to_ss_matrix_inverse(viewport); - shader->set_uniform("projection_matrix", Transform3d::Identity()); - - const Vec2d v_proj_on_e1e2ss = DimensioningHelper::model_to_ss(v_proj_on_e1e2, m_volume_matrix, projection_view_matrix, viewport); - auto render_extension = [this, &v_proj_on_e1e2ss, &projection_view_matrix, &viewport, &ss_to_ndc_matrix, shader](const Vec3d& p) { + const Vec2d v_projss = DimensioningHelper::model_to_ss(v_proj, m_volume_matrix, projection_view_matrix, viewport); + auto render_extension = [this, &v_projss, &projection_view_matrix, &viewport, &ss_to_ndc_matrix, shader](const Vec3d& p) { const Vec2d pss = DimensioningHelper::model_to_ss(p, m_volume_matrix, projection_view_matrix, viewport); - if (!pss.isApprox(v_proj_on_e1e2ss)) { - const Vec2d pv_proj_on_e1e2ss = v_proj_on_e1e2ss - pss; - const double pv_proj_on_e1e2ss_len = pv_proj_on_e1e2ss.norm(); + if (!pss.isApprox(v_projss)) { + const Vec2d pv_projss = v_projss - pss; + const double pv_projss_len = pv_projss.norm(); - const auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Vec3d(pv_proj_on_e1e2ss.x(), pv_proj_on_e1e2ss.y(), 0.0)); + const auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Vec3d(pv_projss.x(), pv_projss.y(), 0.0)); + shader->set_uniform("projection_matrix", Transform3d::Identity()); shader->set_uniform("view_model_matrix", ss_to_ndc_matrix * Geometry::translation_transform({ pss.x(), pss.y(), 0.0 }) * q * - Geometry::scale_transform({ pv_proj_on_e1e2ss_len, 1.0f, 1.0f })); + Geometry::scale_transform({ pv_projss_len, 1.0f, 1.0f })); m_dimensioning.line.render(); } }; @@ -794,6 +792,15 @@ void GLGizmoMeasure::render_dimensioning() } }; + auto point_plane = [this, shader, point_point](const Vec3d& v, const std::tuple& p) { + const auto& [idx, normal, origin] = p; + const double distance = normal.dot(v - origin); + if (std::abs(distance) < EPSILON) + return; + + point_point(v, v - distance * normal); + }; + shader->start_using(); if (!m_dimensioning.line.is_initialized()) { @@ -845,6 +852,14 @@ void GLGizmoMeasure::render_dimensioning() m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { point_edge(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_edge()); } + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { + point_plane(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_plane()); + } + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { + point_plane(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_plane()); + } glsafe(::glEnable(GL_DEPTH_TEST)); From cf55ffbd5efb1dd5874b4ef9e23d71a24195d570 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 16 Sep 2022 08:30:19 +0200 Subject: [PATCH 160/250] Measuring: Gizmo measure shows dimensioning for distance edge-edge --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 39 +++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index c1e6a0c9ff..d166982144 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -792,7 +792,7 @@ void GLGizmoMeasure::render_dimensioning() } }; - auto point_plane = [this, shader, point_point](const Vec3d& v, const std::tuple& p) { + auto point_plane = [shader, point_point](const Vec3d& v, const std::tuple& p) { const auto& [idx, normal, origin] = p; const double distance = normal.dot(v - origin); if (std::abs(distance) < EPSILON) @@ -801,6 +801,39 @@ void GLGizmoMeasure::render_dimensioning() point_point(v, v - distance * normal); }; + auto edge_edge = [this, shader, point_point](const std::pair& e1, const std::pair& e2) { + auto min_distance_edge_edge = [](const std::pair& e1, const std::pair& e2) { + auto distance_point_edge = [](const Vec3d& v, const std::pair& e) { + const Vec3d e1v = v - e.first; + const Vec3d e1e2_unit = (e.second - e.first).normalized(); + const Vec3d v_proj = e.first + e1e2_unit.dot(v - e.first) * e1e2_unit; + return std::make_pair((e1v - v_proj).norm(), v_proj); + }; + + std::vector> distances; + distances.emplace_back(std::make_tuple((e2.first - e1.first).norm(), e1.first, e2.first)); + distances.emplace_back(std::make_tuple((e2.second - e1.first).norm(), e1.first, e2.second)); + distances.emplace_back(std::make_tuple((e2.first - e1.second).norm(), e1.second, e2.first)); + distances.emplace_back(std::make_tuple((e2.second - e1.second).norm(), e1.second, e2.second)); + const auto dist_e11e2 = distance_point_edge(e1.first, e2); + distances.emplace_back(std::make_tuple(dist_e11e2.first, e1.first, dist_e11e2.second)); + const auto dist_e12e2 = distance_point_edge(e1.second, e2); + distances.emplace_back(std::make_tuple(dist_e12e2.first, e1.second, dist_e12e2.second)); + const auto dist_e21e1 = distance_point_edge(e2.first, e1); + distances.emplace_back(std::make_tuple(dist_e21e1.first, e2.first, dist_e21e1.second)); + const auto dist_e22e1 = distance_point_edge(e2.second, e1); + distances.emplace_back(std::make_tuple(dist_e22e1.first, e2.second, dist_e22e1.second)); + std::sort(distances.begin(), distances.end(), + [](const std::tuple& item1, const std::tuple& item2) { + return std::get<0>(item1) < std::get<0>(item2); + }); + return distances.front(); + }; + + const auto [dist, v1, v2] = min_distance_edge_edge(e1, e2); + point_point(v1, v2); + }; + shader->start_using(); if (!m_dimensioning.line.is_initialized()) { @@ -860,6 +893,10 @@ void GLGizmoMeasure::render_dimensioning() m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { point_plane(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_plane()); } + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { + edge_edge(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_edge()); + } glsafe(::glEnable(GL_DEPTH_TEST)); From 124216da029c0b29062f87c7fd1636f1c2c249d9 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 16 Sep 2022 09:57:07 +0200 Subject: [PATCH 161/250] Measuring: Gizmo measure shows dimensioning for distance point-circle --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 122 ++++++++++++++--------- 1 file changed, 77 insertions(+), 45 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index d166982144..bc89051520 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -19,6 +19,10 @@ namespace Slic3r { namespace GUI { +using Edge = std::pair; +using Plane = std::tuple; +using Circle = std::tuple; + static const Slic3r::ColorRGBA SELECTED_1ST_COLOR = { 0.25f, 0.75f, 0.75f, 1.0f }; static const Slic3r::ColorRGBA SELECTED_2ND_COLOR = { 0.75f, 0.25f, 0.75f, 1.0f }; @@ -64,6 +68,46 @@ static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType t return ret; } +static std::tuple distance_point_plane(const Vec3d& v, const Plane& p) +{ + const double distance = std::get<1>(p).dot(v - std::get<2>(p)); + return std::make_tuple(std::abs(distance), v, v - distance * std::get<1>(p)); +} + +static std::tuple distance_point_edge(const Vec3d& v, const Edge& e) +{ + const Vec3d e1v = v - e.first; + const Vec3d e1e2_unit = (e.second - e.first).normalized(); + const Vec3d v_proj = e.first + e1e2_unit.dot(e1v) * e1e2_unit; + return std::make_tuple((e1v - v_proj).norm(), v, v_proj); +} + +static std::tuple distance_point_circle(const Vec3d& v, const Circle& c) +{ + const auto& [center, radius, normal] = c; + const auto [distance, v1, v2] = distance_point_plane(v, std::make_tuple(0, normal, center)); + const Vec3d p_on_circle = center + radius * (v2 - center).normalized(); + return std::make_tuple((v - p_on_circle).norm(), v, p_on_circle); +} + +static std::tuple min_distance_edge_edge(const Edge& e1, const Edge& e2) +{ + std::vector> distances; + distances.emplace_back(std::make_tuple((e2.first - e1.first).norm(), e1.first, e2.first)); + distances.emplace_back(std::make_tuple((e2.second - e1.first).norm(), e1.first, e2.second)); + distances.emplace_back(std::make_tuple((e2.first - e1.second).norm(), e1.second, e2.first)); + distances.emplace_back(std::make_tuple((e2.second - e1.second).norm(), e1.second, e2.second)); + distances.emplace_back(distance_point_edge(e1.first, e2)); + distances.emplace_back(distance_point_edge(e1.second, e2)); + distances.emplace_back(distance_point_edge(e2.first, e1)); + distances.emplace_back(distance_point_edge(e2.second, e1)); + std::sort(distances.begin(), distances.end(), + [](const std::tuple& item1, const std::tuple& item2) { + return std::get<0>(item1) < std::get<0>(item2); + }); + return distances.front(); +} + static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const std::vector>& planes_triangles, int idx) { assert(0 <= idx && idx < (int)planes_triangles.size()); @@ -757,12 +801,11 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.triangle.render(); }; - auto point_edge = [this, shader, point_point](const Vec3d& v, const std::pair& e) { - const Vec3d e1e2 = e.second - e.first; - const Vec3d e1e2_unit = e1e2.normalized(); - const Vec3d v_proj = e.first + e1e2_unit.dot(v - e.first) * e1e2_unit; - point_point(v, v_proj); + auto point_edge = [this, shader, point_point](const Vec3d& v, const Edge& e) { + const auto [distance, v1, v_proj] = distance_point_edge(v, e); + point_point(v1, v_proj); + const Vec3d e1e2 = e.second - e.first; const Vec3d v_proje1 = v_proj - e.first; bool on_e1_side = v_proje1.dot(e1e2) < 0.0; bool on_e2_side = v_proje1.norm() > e1e2.norm(); @@ -792,45 +835,18 @@ void GLGizmoMeasure::render_dimensioning() } }; - auto point_plane = [shader, point_point](const Vec3d& v, const std::tuple& p) { - const auto& [idx, normal, origin] = p; - const double distance = normal.dot(v - origin); - if (std::abs(distance) < EPSILON) - return; - - point_point(v, v - distance * normal); + auto point_plane = [point_point](const Vec3d& v, const Plane& p) { + const auto [distance, v1, v2] = distance_point_plane(v, p); + point_point(v1, v2); }; - auto edge_edge = [this, shader, point_point](const std::pair& e1, const std::pair& e2) { - auto min_distance_edge_edge = [](const std::pair& e1, const std::pair& e2) { - auto distance_point_edge = [](const Vec3d& v, const std::pair& e) { - const Vec3d e1v = v - e.first; - const Vec3d e1e2_unit = (e.second - e.first).normalized(); - const Vec3d v_proj = e.first + e1e2_unit.dot(v - e.first) * e1e2_unit; - return std::make_pair((e1v - v_proj).norm(), v_proj); - }; + auto point_circle = [point_point](const Vec3d& v, const Circle& c) { + const auto [distance, v1, v2] = distance_point_circle(v, c); + point_point(v1, v2); + }; - std::vector> distances; - distances.emplace_back(std::make_tuple((e2.first - e1.first).norm(), e1.first, e2.first)); - distances.emplace_back(std::make_tuple((e2.second - e1.first).norm(), e1.first, e2.second)); - distances.emplace_back(std::make_tuple((e2.first - e1.second).norm(), e1.second, e2.first)); - distances.emplace_back(std::make_tuple((e2.second - e1.second).norm(), e1.second, e2.second)); - const auto dist_e11e2 = distance_point_edge(e1.first, e2); - distances.emplace_back(std::make_tuple(dist_e11e2.first, e1.first, dist_e11e2.second)); - const auto dist_e12e2 = distance_point_edge(e1.second, e2); - distances.emplace_back(std::make_tuple(dist_e12e2.first, e1.second, dist_e12e2.second)); - const auto dist_e21e1 = distance_point_edge(e2.first, e1); - distances.emplace_back(std::make_tuple(dist_e21e1.first, e2.first, dist_e21e1.second)); - const auto dist_e22e1 = distance_point_edge(e2.second, e1); - distances.emplace_back(std::make_tuple(dist_e22e1.first, e2.second, dist_e22e1.second)); - std::sort(distances.begin(), distances.end(), - [](const std::tuple& item1, const std::tuple& item2) { - return std::get<0>(item1) < std::get<0>(item2); - }); - return distances.front(); - }; - - const auto [dist, v1, v2] = min_distance_edge_edge(e1, e2); + auto edge_edge = [point_point](const Edge& e1, const Edge& e2) { + const auto [distance, v1, v2] = min_distance_edge_edge(e1, e2); point_point(v1, v2); }; @@ -873,26 +889,42 @@ void GLGizmoMeasure::render_dimensioning() glsafe(::glDisable(GL_DEPTH_TEST)); + // point-point if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { point_point(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_point()); } + // point-edge else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { point_edge(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_edge()); } - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - point_edge(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_edge()); - } + // point-plane else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { point_plane(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_plane()); } + // point-circle + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Circle) { + point_circle(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_circle()); + } + // edge-point + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { + point_edge(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_edge()); + } + // plane-point else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { point_plane(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_plane()); } + // circle-point + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { + point_circle(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_circle()); + } + // edge-edge else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { edge_edge(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_edge()); From 0d70bbba8b94ada8d7efd6c9ba50e70afadcc485 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 16 Sep 2022 11:24:44 +0200 Subject: [PATCH 162/250] Measuring: Use eigen library in distance calculations for Gizmo measure --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index bc89051520..bfcef7365b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -70,23 +70,22 @@ static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType t static std::tuple distance_point_plane(const Vec3d& v, const Plane& p) { - const double distance = std::get<1>(p).dot(v - std::get<2>(p)); - return std::make_tuple(std::abs(distance), v, v - distance * std::get<1>(p)); + const auto& [idx, normal, origin] = p; + const Eigen::Hyperplane plane(normal, origin); + return std::make_tuple(plane.absDistance(v), v, plane.projection(v)); } static std::tuple distance_point_edge(const Vec3d& v, const Edge& e) { - const Vec3d e1v = v - e.first; - const Vec3d e1e2_unit = (e.second - e.first).normalized(); - const Vec3d v_proj = e.first + e1e2_unit.dot(e1v) * e1e2_unit; - return std::make_tuple((e1v - v_proj).norm(), v, v_proj); + const Eigen::ParametrizedLine line(e.first, (e.second - e.first).normalized()); + return std::make_tuple(line.distance(v), v, line.projection(v)); } static std::tuple distance_point_circle(const Vec3d& v, const Circle& c) { const auto& [center, radius, normal] = c; - const auto [distance, v1, v2] = distance_point_plane(v, std::make_tuple(0, normal, center)); - const Vec3d p_on_circle = center + radius * (v2 - center).normalized(); + const Eigen::Hyperplane plane(normal, center); + const Vec3d p_on_circle = center + radius * (plane.projection(v) - center).normalized(); return std::make_tuple((v - p_on_circle).norm(), v, p_on_circle); } From a911df78eea8382307db22b8036b6d61cb4e0d2a Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 16 Sep 2022 13:28:15 +0200 Subject: [PATCH 163/250] Measuring: Gizmo measure shows dimensioning for distance plane-plane --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index bfcef7365b..9e0d2f60f8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -89,6 +89,14 @@ static std::tuple distance_point_circle(const Vec3d& v, co return std::make_tuple((v - p_on_circle).norm(), v, p_on_circle); } +static std::tuple distance_plane_plane(const Plane& p1, const Plane& p2) +{ + const auto& [idx1, normal1, origin1] = p1; + const auto& [idx2, normal2, origin2] = p2; + return (std::abs(std::abs(normal1.dot(normal2)) - 1.0) < EPSILON) ? distance_point_plane(origin2, p1) : + std::make_tuple(0.0, Vec3d::Zero(), Vec3d::Zero()); +} + static std::tuple min_distance_edge_edge(const Edge& e1, const Edge& e2) { std::vector> distances; @@ -726,8 +734,6 @@ private: if (s_cache.viewport == viewport) return; - std::cout << "DimensioningHelper::update()\n"; - const double half_w = 0.5 * double(viewport[2]); const double half_h = 0.5 * double(viewport[3]); s_cache.ndc_to_ss_matrix << half_w, 0.0, 0.0, double(viewport[0]) + half_w, @@ -849,6 +855,11 @@ void GLGizmoMeasure::render_dimensioning() point_point(v1, v2); }; + auto plane_plane = [point_point](const Plane& p1, const Plane& p2) { + const auto [distance, v1, v2] = distance_plane_plane(p1, p2); + point_point(v1, v2); + }; + shader->start_using(); if (!m_dimensioning.line.is_initialized()) { @@ -928,6 +939,11 @@ void GLGizmoMeasure::render_dimensioning() m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { edge_edge(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_edge()); } + // plane-plane + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { + plane_plane(m_selected_features.first.feature->get_plane(), m_selected_features.second.feature->get_plane()); + } glsafe(::glEnable(GL_DEPTH_TEST)); From c01270ca995ae04b5cc9bf6026c4585792a4fbb8 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 19 Sep 2022 10:01:02 +0200 Subject: [PATCH 164/250] Measuring: Gizmo measure shows dimensioning for distance edge-circle --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 62 +++++++++++++++++++----- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 9e0d2f60f8..bdb0420a8c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -89,15 +89,7 @@ static std::tuple distance_point_circle(const Vec3d& v, co return std::make_tuple((v - p_on_circle).norm(), v, p_on_circle); } -static std::tuple distance_plane_plane(const Plane& p1, const Plane& p2) -{ - const auto& [idx1, normal1, origin1] = p1; - const auto& [idx2, normal2, origin2] = p2; - return (std::abs(std::abs(normal1.dot(normal2)) - 1.0) < EPSILON) ? distance_point_plane(origin2, p1) : - std::make_tuple(0.0, Vec3d::Zero(), Vec3d::Zero()); -} - -static std::tuple min_distance_edge_edge(const Edge& e1, const Edge& e2) +static std::tuple distance_edge_edge(const Edge& e1, const Edge& e2) { std::vector> distances; distances.emplace_back(std::make_tuple((e2.first - e1.first).norm(), e1.first, e2.first)); @@ -115,6 +107,37 @@ static std::tuple min_distance_edge_edge(const Edge& e1, c return distances.front(); } +static std::tuple distance_edge_circle(const Edge& e, const Circle& c) +{ + const auto& [center, radius, normal] = c; + const Vec3d e1e2_unit = (e.second - e.first).normalized(); + double dot = std::abs(e1e2_unit.dot(normal)); + + if (dot < EPSILON) { + // edge parallel to circle's plane + const Eigen::Hyperplane plane(e1e2_unit, center); + const Eigen::ParametrizedLine line(e.first, e1e2_unit); + const Vec3d inter = line.intersectionPoint(plane); + return distance_point_circle(inter, c); + } + else if (std::abs(dot - 1.0) < EPSILON) + // edge parallel to circle's normal + return distance_point_circle(e.first, c); + else { + const auto [distance1, v11, v12] = distance_point_circle(e.first, c); + const auto [distance2, v21, v22] = distance_point_circle(e.second, c); + return (distance1 <= distance2) ? std::make_tuple(distance1, v11, v12) : std::make_tuple(distance2, v21, v22); + } +} + +static std::tuple distance_plane_plane(const Plane& p1, const Plane& p2) +{ + const auto& [idx1, normal1, origin1] = p1; + const auto& [idx2, normal2, origin2] = p2; + return (std::abs(std::abs(normal1.dot(normal2)) - 1.0) < EPSILON) ? distance_point_plane(origin2, p1) : + std::make_tuple(0.0, Vec3d::Zero(), Vec3d::Zero()); +} + static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const std::vector>& planes_triangles, int idx) { assert(0 <= idx && idx < (int)planes_triangles.size()); @@ -812,8 +835,8 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d e1e2 = e.second - e.first; const Vec3d v_proje1 = v_proj - e.first; - bool on_e1_side = v_proje1.dot(e1e2) < 0.0; - bool on_e2_side = v_proje1.norm() > e1e2.norm(); + const bool on_e1_side = v_proje1.dot(e1e2) < 0.0; + const bool on_e2_side = v_proje1.norm() > e1e2.norm(); if (on_e1_side || on_e2_side) { const Camera& camera = wxGetApp().plater()->get_camera(); const Matrix4d projection_view_matrix = camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix(); @@ -851,7 +874,12 @@ void GLGizmoMeasure::render_dimensioning() }; auto edge_edge = [point_point](const Edge& e1, const Edge& e2) { - const auto [distance, v1, v2] = min_distance_edge_edge(e1, e2); + const auto [distance, v1, v2] = distance_edge_edge(e1, e2); + point_point(v1, v2); + }; + + auto edge_circle = [point_point](const Edge& e, const Circle& c) { + const auto [distance, v1, v2] = distance_edge_circle(e, c); point_point(v1, v2); }; @@ -939,11 +967,21 @@ void GLGizmoMeasure::render_dimensioning() m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { edge_edge(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_edge()); } + // edge-circle + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Circle) { + edge_circle(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_circle()); + } // plane-plane else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { plane_plane(m_selected_features.first.feature->get_plane(), m_selected_features.second.feature->get_plane()); } + // circle-edge + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { + edge_circle(m_selected_features.second.feature->get_edge(), m_selected_features.first.feature->get_circle()); + } glsafe(::glEnable(GL_DEPTH_TEST)); From c5fd4d8a7db44deb31ebc2a0a5b9fbf5426c2cac Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 19 Sep 2022 11:44:03 +0200 Subject: [PATCH 165/250] Follow-up of 81d28c545cc1bbb31ee618934ae3afc72f3fc668 - Distance edge-circle calculated as in Fusion 360 --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 35 ++++++++++++------------ 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index bdb0420a8c..89396071c7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -110,24 +110,25 @@ static std::tuple distance_edge_edge(const Edge& e1, const static std::tuple distance_edge_circle(const Edge& e, const Circle& c) { const auto& [center, radius, normal] = c; - const Vec3d e1e2_unit = (e.second - e.first).normalized(); - double dot = std::abs(e1e2_unit.dot(normal)); + const Vec3d e1e2 = (e.second - e.first); + const Vec3d e1e2_unit = e1e2.normalized(); - if (dot < EPSILON) { - // edge parallel to circle's plane - const Eigen::Hyperplane plane(e1e2_unit, center); - const Eigen::ParametrizedLine line(e.first, e1e2_unit); - const Vec3d inter = line.intersectionPoint(plane); - return distance_point_circle(inter, c); - } - else if (std::abs(dot - 1.0) < EPSILON) - // edge parallel to circle's normal - return distance_point_circle(e.first, c); - else { - const auto [distance1, v11, v12] = distance_point_circle(e.first, c); - const auto [distance2, v21, v22] = distance_point_circle(e.second, c); - return (distance1 <= distance2) ? std::make_tuple(distance1, v11, v12) : std::make_tuple(distance2, v21, v22); - } + std::vector> distances; + distances.emplace_back(distance_point_circle(e.first, c)); + distances.emplace_back(distance_point_circle(e.second, c)); + + const Eigen::Hyperplane plane(e1e2_unit, center); + const Eigen::ParametrizedLine line(e.first, e1e2_unit); + const Vec3d inter = line.intersectionPoint(plane); + const Vec3d e1inter = inter - e.first; + if (e1inter.dot(e1e2) >= 0.0 && e1inter.norm() < e1e2.norm()) + distances.emplace_back(distance_point_circle(inter, c)); + + std::sort(distances.begin(), distances.end(), + [](const std::tuple& item1, const std::tuple& item2) { + return std::get<0>(item1) < std::get<0>(item2); + }); + return distances.front(); } static std::tuple distance_plane_plane(const Plane& p1, const Plane& p2) From 3bc7418835227e64133fae16e9e0af5c4378ea79 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 19 Sep 2022 13:22:09 +0200 Subject: [PATCH 166/250] Follow-up of 8d98f0869dc6c6c6e3c67da4bb0670f17c7acf36 - Distance edge-edge calculated as in Fusion 360 --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 89396071c7..5a477034ea 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -92,14 +92,22 @@ static std::tuple distance_point_circle(const Vec3d& v, co static std::tuple distance_edge_edge(const Edge& e1, const Edge& e2) { std::vector> distances; + auto add_point_edge_distance = [&distances](const Vec3d& v, const Edge& e) { + const auto [distance, v1, v2] = distance_point_edge(v, e); + const Vec3d e1e2 = e.second - e.first; + const Vec3d e1v2 = v2 - e.first; + if (e1v2.dot(e1e2) >= 0.0 && e1v2.norm() < e1e2.norm()) + distances.emplace_back(std::make_tuple(distance, v, v2)); + }; + distances.emplace_back(std::make_tuple((e2.first - e1.first).norm(), e1.first, e2.first)); distances.emplace_back(std::make_tuple((e2.second - e1.first).norm(), e1.first, e2.second)); distances.emplace_back(std::make_tuple((e2.first - e1.second).norm(), e1.second, e2.first)); distances.emplace_back(std::make_tuple((e2.second - e1.second).norm(), e1.second, e2.second)); - distances.emplace_back(distance_point_edge(e1.first, e2)); - distances.emplace_back(distance_point_edge(e1.second, e2)); - distances.emplace_back(distance_point_edge(e2.first, e1)); - distances.emplace_back(distance_point_edge(e2.second, e1)); + add_point_edge_distance(e1.first, e2); + add_point_edge_distance(e1.second, e2); + add_point_edge_distance(e2.first, e1); + add_point_edge_distance(e2.second, e1); std::sort(distances.begin(), distances.end(), [](const std::tuple& item1, const std::tuple& item2) { return std::get<0>(item1) < std::get<0>(item2); From e8a9280843c0dba1415d7150c9f982f6979d1cdd Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 21 Sep 2022 09:16:49 +0200 Subject: [PATCH 167/250] Measuring: Gizmo measure shows dimensioning for angle edge-edge --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 135 ++++++++++++++++++++++- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 3 +- 2 files changed, 133 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 5a477034ea..f6a6a46ca5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -31,7 +31,7 @@ static const int EDGE_ID = 200; static const int CIRCLE_ID = 300; static const int PLANE_ID = 400; -static const float TRIANGLE_BASE = 16.0f; +static const float TRIANGLE_BASE = 10.0f; static const float TRIANGLE_HEIGHT = TRIANGLE_BASE * 1.618033f; static const std::string CTRL_STR = @@ -782,6 +782,8 @@ DimensioningHelper::Cache DimensioningHelper::s_cache = { { 0, 0, 0, 0 }, Matrix void GLGizmoMeasure::render_dimensioning() { + static SelectedFeatures last_selected_features; + if (!m_selected_features.first.feature.has_value() || !m_selected_features.second.feature.has_value()) return; @@ -844,8 +846,8 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d e1e2 = e.second - e.first; const Vec3d v_proje1 = v_proj - e.first; - const bool on_e1_side = v_proje1.dot(e1e2) < 0.0; - const bool on_e2_side = v_proje1.norm() > e1e2.norm(); + const bool on_e1_side = v_proje1.dot(e1e2) < -EPSILON; + const bool on_e2_side = !on_e1_side && v_proje1.norm() > e1e2.norm(); if (on_e1_side || on_e2_side) { const Camera& camera = wxGetApp().plater()->get_camera(); const Matrix4d projection_view_matrix = camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix(); @@ -882,9 +884,131 @@ void GLGizmoMeasure::render_dimensioning() point_point(v1, v2); }; - auto edge_edge = [point_point](const Edge& e1, const Edge& e2) { + auto arc_edge_edge = [this, shader](Edge e1, Edge e2) { + Vec3d e1_unit = (e1.second - e1.first).normalized(); + Vec3d e2_unit = (e2.second - e2.first).normalized(); + const double dot = e1_unit.dot(e2_unit); + if (std::abs(std::abs(dot) - 1.0) < EPSILON) + // edges are parallel, return + return; + + // project edges on the plane defined by them + Vec3d normal = e1_unit.cross(e2_unit).normalized(); + const Eigen::Hyperplane plane(normal, e1.first); + Vec3d e11_proj = plane.projection(e1.first); + Vec3d e12_proj = plane.projection(e1.second); + Vec3d e21_proj = plane.projection(e2.first); + Vec3d e22_proj = plane.projection(e2.second); + + const bool coplanar = (e2.first - e21_proj).norm() < EPSILON && (e2.second - e22_proj).norm() < EPSILON; + + // rotate the plane to become the XY plane + auto qp = Eigen::Quaternion::FromTwoVectors(normal, Vec3d::UnitZ()); + auto qp_inverse = qp.inverse(); + const Vec3d e11_rot = qp * e11_proj; + const Vec3d e12_rot = qp * e12_proj; + const Vec3d e21_rot = qp * e21_proj; + const Vec3d e22_rot = qp * e22_proj; + + // discard Z + const Vec2d e11_rot_2d = Vec2d(e11_rot.x(), e11_rot.y()); + const Vec2d e12_rot_2d = Vec2d(e12_rot.x(), e12_rot.y()); + const Vec2d e21_rot_2d = Vec2d(e21_rot.x(), e21_rot.y()); + const Vec2d e22_rot_2d = Vec2d(e22_rot.x(), e22_rot.y()); + + // find intersection of edges in XY plane + const Eigen::Hyperplane e1_rot_2d_line = Eigen::Hyperplane::Through(e11_rot_2d, e12_rot_2d); + const Eigen::Hyperplane e2_rot_2d_line = Eigen::Hyperplane::Through(e21_rot_2d, e22_rot_2d); + const Vec2d center_rot_2d = e1_rot_2d_line.intersection(e2_rot_2d_line); + + // center in world coordinate + const Vec3d center = qp.inverse() * Vec3d(center_rot_2d.x(), center_rot_2d.y(), e11_rot.z()); + + // revert edges, if needed (we want them to move away from the center) + unsigned int revert_count = 0; + if ((center_rot_2d - e11_rot_2d).squaredNorm() > (center_rot_2d - e12_rot_2d).squaredNorm()) { + std::swap(e1.first, e1.second); + std::swap(e11_proj, e12_proj); + e1_unit = -e1_unit; + ++revert_count; + } + if ((center_rot_2d - e21_rot_2d).squaredNorm() > (center_rot_2d - e22_rot_2d).squaredNorm()) { + std::swap(e2.first, e2.second); + std::swap(e21_proj, e22_proj); + e2_unit = -e2_unit; + ++revert_count; + } + + if (revert_count == 1) { + normal = -normal; + qp = Eigen::Quaternion::FromTwoVectors(normal, Vec3d::UnitZ()); + qp_inverse = qp.inverse(); + } + + // arc angle + const double angle = std::acos(std::clamp(e1_unit.dot(e2_unit), -1.0, 1.0)); + // arc radius + const Vec3d e1_proj_mid = 0.5 * (e11_proj + e12_proj); + const Vec3d e2_proj_mid = 0.5 * (e21_proj + e22_proj); + const double radius = std::min((center - e1_proj_mid).norm(), (center - e2_proj_mid).norm()); + + if (!m_dimensioning.arc.is_initialized()) { + const unsigned int resolution = std::max(2, 64 * angle / double(PI)); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3 }; + init_data.color = ColorRGBA::WHITE(); + init_data.reserve_vertices(resolution + 1); + init_data.reserve_indices(resolution + 1); + + // vertices + indices + const double step = angle / double(resolution); + for (unsigned int i = 0; i <= resolution; ++i) { + const double a = step * double(i); + const Vec3d v = radius * (Eigen::Quaternion(Eigen::AngleAxisd(a, normal)) * e1_unit); + init_data.add_vertex((Vec3f)v.cast()); + init_data.add_index(i); + } + + m_dimensioning.arc.init_from(std::move(init_data)); + } + + auto render_edge_entension = [this, shader, ¢er, radius](const Edge& e, bool coplanar) { + const Vec3d e1center = center - e.first; + const Vec3d e1e2 = e.second - e.first; + const bool on_e1_side = e1center.dot(e1e2) < -EPSILON; + const bool on_e2_side = !on_e1_side && e1center.norm() > e1e2.norm(); + if (!coplanar || on_e1_side || on_e2_side) { + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + auto render_extension = [this, shader, &camera, ¢er, radius, coplanar](const Vec3d& p) { + const Vec3d centerp = p - center; + const auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), centerp.normalized()); + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * q * + Geometry::scale_transform({ coplanar ? centerp.norm() : radius, 1.0f, 1.0f })); + m_dimensioning.line.render(); + }; + render_extension(on_e1_side ? e.first : e.second); + } + }; + + auto render_arc = [this, shader, ¢er]() { + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center)); + m_dimensioning.arc.render(); + }; + + render_edge_entension({ e11_proj , e12_proj }, true); + render_edge_entension({ e21_proj , e22_proj }, coplanar); + render_arc(); + }; + + auto edge_edge = [point_point, arc_edge_edge](const Edge& e1, const Edge& e2) { + // distance const auto [distance, v1, v2] = distance_edge_edge(e1, e2); point_point(v1, v2); + // arc + arc_edge_edge(e1, e2); }; auto edge_circle = [point_point](const Edge& e, const Circle& c) { @@ -934,6 +1058,9 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.triangle.init_from(std::move(init_data)); } + if (last_selected_features != m_selected_features) + m_dimensioning.arc.reset(); + glsafe(::glDisable(GL_DEPTH_TEST)); // point-point diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 4417a0d608..51094ae12c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -80,7 +80,8 @@ class GLGizmoMeasure : public GLGizmoBase { GLModel line; GLModel triangle; - }; + GLModel arc; + }; Dimensioning m_dimensioning; Transform3d m_volume_matrix{ Transform3d::Identity() }; From 706d05b31fef20a68eb6ea9cbb333d440d16389d Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 23 Sep 2022 12:44:06 +0200 Subject: [PATCH 168/250] Measuring: Gizmo measure shows dimensioning for angle edge-plane --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 284 +++++++++++++++-------- 1 file changed, 181 insertions(+), 103 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index f6a6a46ca5..fc49e9883f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -75,20 +75,33 @@ static std::tuple distance_point_plane(const Vec3d& v, con return std::make_tuple(plane.absDistance(v), v, plane.projection(v)); } +static Vec3d vector_direction(const Vec3d& from, const Vec3d& to) +{ + return (to - from).normalized(); +} + +static Vec3d edge_direction(const Edge& e) +{ + return vector_direction(e.first, e.second); +} + +// returns: distance, 1st vertex, 2nd vertex static std::tuple distance_point_edge(const Vec3d& v, const Edge& e) { - const Eigen::ParametrizedLine line(e.first, (e.second - e.first).normalized()); + const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); return std::make_tuple(line.distance(v), v, line.projection(v)); } +// returns: distance, 1st vertex, 2nd vertex static std::tuple distance_point_circle(const Vec3d& v, const Circle& c) { const auto& [center, radius, normal] = c; const Eigen::Hyperplane plane(normal, center); - const Vec3d p_on_circle = center + radius * (plane.projection(v) - center).normalized(); + const Vec3d p_on_circle = center + radius * vector_direction(center, plane.projection(v)); return std::make_tuple((v - p_on_circle).norm(), v, p_on_circle); } +// returns: distance, 1st vertex, 2nd vertex static std::tuple distance_edge_edge(const Edge& e1, const Edge& e2) { std::vector> distances; @@ -115,18 +128,19 @@ static std::tuple distance_edge_edge(const Edge& e1, const return distances.front(); } +// returns: distance, 1st vertex, 2nd vertex static std::tuple distance_edge_circle(const Edge& e, const Circle& c) { const auto& [center, radius, normal] = c; const Vec3d e1e2 = (e.second - e.first); - const Vec3d e1e2_unit = e1e2.normalized(); + const Vec3d e1e2_unit = vector_direction(e.first, e.second); std::vector> distances; distances.emplace_back(distance_point_circle(e.first, c)); distances.emplace_back(distance_point_circle(e.second, c)); const Eigen::Hyperplane plane(e1e2_unit, center); - const Eigen::ParametrizedLine line(e.first, e1e2_unit); + const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); const Vec3d inter = line.intersectionPoint(plane); const Vec3d e1inter = inter - e.first; if (e1inter.dot(e1e2) >= 0.0 && e1inter.norm() < e1e2.norm()) @@ -139,6 +153,7 @@ static std::tuple distance_edge_circle(const Edge& e, cons return distances.front(); } +// returns: distance, 1st vertex, 2nd vertex static std::tuple distance_plane_plane(const Plane& p1, const Plane& p2) { const auto& [idx1, normal1, origin1] = p1; @@ -147,6 +162,71 @@ static std::tuple distance_plane_plane(const Plane& p1, co std::make_tuple(0.0, Vec3d::Zero(), Vec3d::Zero()); } +// returns: angle in rad, center of arc, radius of arc, whether or not the edges are coplanar +// After return, the edges are oriented so that they point away from their intersection point +static std::tuple angle_edge_edge(Edge& e1, Edge& e2) +{ + Vec3d e1_unit = edge_direction(e1); + Vec3d e2_unit = edge_direction(e2); + const double dot = e1_unit.dot(e2_unit); + // are edges parallel ? + if (std::abs(std::abs(dot) - 1.0) < EPSILON) + return std::make_tuple(0.0, e1.first, 0.0, true); + + // project edges on the plane defined by them + Vec3d normal = e1_unit.cross(e2_unit).normalized(); + const Eigen::Hyperplane plane(normal, e1.first); + Vec3d e11_proj = plane.projection(e1.first); + Vec3d e12_proj = plane.projection(e1.second); + Vec3d e21_proj = plane.projection(e2.first); + Vec3d e22_proj = plane.projection(e2.second); + + const bool coplanar = (e2.first - e21_proj).norm() < EPSILON && (e2.second - e22_proj).norm() < EPSILON; + + // rotate the plane to become the XY plane + auto qp = Eigen::Quaternion::FromTwoVectors(normal, Vec3d::UnitZ()); + auto qp_inverse = qp.inverse(); + const Vec3d e11_rot = qp * e11_proj; + const Vec3d e12_rot = qp * e12_proj; + const Vec3d e21_rot = qp * e21_proj; + const Vec3d e22_rot = qp * e22_proj; + + // discard Z + const Vec2d e11_rot_2d = Vec2d(e11_rot.x(), e11_rot.y()); + const Vec2d e12_rot_2d = Vec2d(e12_rot.x(), e12_rot.y()); + const Vec2d e21_rot_2d = Vec2d(e21_rot.x(), e21_rot.y()); + const Vec2d e22_rot_2d = Vec2d(e22_rot.x(), e22_rot.y()); + + // find intersection (arc center) of edges in XY plane + const Eigen::Hyperplane e1_rot_2d_line = Eigen::Hyperplane::Through(e11_rot_2d, e12_rot_2d); + const Eigen::Hyperplane e2_rot_2d_line = Eigen::Hyperplane::Through(e21_rot_2d, e22_rot_2d); + const Vec2d center_rot_2d = e1_rot_2d_line.intersection(e2_rot_2d_line); + + // arc center in original coordinate + const Vec3d center = qp_inverse * Vec3d(center_rot_2d.x(), center_rot_2d.y(), e11_rot.z()); + + // ensure the edges are pointing away from the center + if ((center_rot_2d - e11_rot_2d).squaredNorm() > (center_rot_2d - e12_rot_2d).squaredNorm()) { + std::swap(e1.first, e1.second); + std::swap(e11_proj, e12_proj); + e1_unit = -e1_unit; + } + if ((center_rot_2d - e21_rot_2d).squaredNorm() > (center_rot_2d - e22_rot_2d).squaredNorm()) { + std::swap(e2.first, e2.second); + std::swap(e21_proj, e22_proj); + e2_unit = -e2_unit; + } + + // arc angle + const double angle = std::acos(std::clamp(e1_unit.dot(e2_unit), -1.0, 1.0)); + // arc radius + const Vec3d e1_proj_mid = 0.5 * (e11_proj + e12_proj); + const Vec3d e2_proj_mid = 0.5 * (e21_proj + e22_proj); + const double radius = std::min((center - e1_proj_mid).norm(), (center - e2_proj_mid).norm()); + + return std::make_tuple(angle, center, radius, coplanar); +} + static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const std::vector>& planes_triangles, int idx) { assert(0 <= idx && idx < (int)planes_triangles.size()); @@ -884,73 +964,21 @@ void GLGizmoMeasure::render_dimensioning() point_point(v1, v2); }; - auto arc_edge_edge = [this, shader](Edge e1, Edge e2) { - Vec3d e1_unit = (e1.second - e1.first).normalized(); - Vec3d e2_unit = (e2.second - e2.first).normalized(); - const double dot = e1_unit.dot(e2_unit); - if (std::abs(std::abs(dot) - 1.0) < EPSILON) - // edges are parallel, return + auto arc_edge_edge = [this, shader](const Edge& e1, const Edge& e2, const double* const force_radius = nullptr) { + Edge e1copy = e1; + Edge e2copy = e2; + const auto [angle, center, radius, coplanar] = angle_edge_edge(e1copy, e2copy); + + if (radius == 0.0) return; - // project edges on the plane defined by them - Vec3d normal = e1_unit.cross(e2_unit).normalized(); - const Eigen::Hyperplane plane(normal, e1.first); - Vec3d e11_proj = plane.projection(e1.first); - Vec3d e12_proj = plane.projection(e1.second); - Vec3d e21_proj = plane.projection(e2.first); - Vec3d e22_proj = plane.projection(e2.second); + assert(force_radius == nullptr || *force_radius > 0.0); - const bool coplanar = (e2.first - e21_proj).norm() < EPSILON && (e2.second - e22_proj).norm() < EPSILON; + const double draw_radius = (force_radius != nullptr) ? *force_radius : radius; - // rotate the plane to become the XY plane - auto qp = Eigen::Quaternion::FromTwoVectors(normal, Vec3d::UnitZ()); - auto qp_inverse = qp.inverse(); - const Vec3d e11_rot = qp * e11_proj; - const Vec3d e12_rot = qp * e12_proj; - const Vec3d e21_rot = qp * e21_proj; - const Vec3d e22_rot = qp * e22_proj; - - // discard Z - const Vec2d e11_rot_2d = Vec2d(e11_rot.x(), e11_rot.y()); - const Vec2d e12_rot_2d = Vec2d(e12_rot.x(), e12_rot.y()); - const Vec2d e21_rot_2d = Vec2d(e21_rot.x(), e21_rot.y()); - const Vec2d e22_rot_2d = Vec2d(e22_rot.x(), e22_rot.y()); - - // find intersection of edges in XY plane - const Eigen::Hyperplane e1_rot_2d_line = Eigen::Hyperplane::Through(e11_rot_2d, e12_rot_2d); - const Eigen::Hyperplane e2_rot_2d_line = Eigen::Hyperplane::Through(e21_rot_2d, e22_rot_2d); - const Vec2d center_rot_2d = e1_rot_2d_line.intersection(e2_rot_2d_line); - - // center in world coordinate - const Vec3d center = qp.inverse() * Vec3d(center_rot_2d.x(), center_rot_2d.y(), e11_rot.z()); - - // revert edges, if needed (we want them to move away from the center) - unsigned int revert_count = 0; - if ((center_rot_2d - e11_rot_2d).squaredNorm() > (center_rot_2d - e12_rot_2d).squaredNorm()) { - std::swap(e1.first, e1.second); - std::swap(e11_proj, e12_proj); - e1_unit = -e1_unit; - ++revert_count; - } - if ((center_rot_2d - e21_rot_2d).squaredNorm() > (center_rot_2d - e22_rot_2d).squaredNorm()) { - std::swap(e2.first, e2.second); - std::swap(e21_proj, e22_proj); - e2_unit = -e2_unit; - ++revert_count; - } - - if (revert_count == 1) { - normal = -normal; - qp = Eigen::Quaternion::FromTwoVectors(normal, Vec3d::UnitZ()); - qp_inverse = qp.inverse(); - } - - // arc angle - const double angle = std::acos(std::clamp(e1_unit.dot(e2_unit), -1.0, 1.0)); - // arc radius - const Vec3d e1_proj_mid = 0.5 * (e11_proj + e12_proj); - const Vec3d e2_proj_mid = 0.5 * (e21_proj + e22_proj); - const double radius = std::min((center - e1_proj_mid).norm(), (center - e2_proj_mid).norm()); + const Vec3d e1_unit = edge_direction(e1copy); + const Vec3d e2_unit = edge_direction(e2copy); + const Vec3d normal = e1_unit.cross(e2_unit).normalized(); if (!m_dimensioning.arc.is_initialized()) { const unsigned int resolution = std::max(2, 64 * angle / double(PI)); @@ -964,7 +992,7 @@ void GLGizmoMeasure::render_dimensioning() const double step = angle / double(resolution); for (unsigned int i = 0; i <= resolution; ++i) { const double a = step * double(i); - const Vec3d v = radius * (Eigen::Quaternion(Eigen::AngleAxisd(a, normal)) * e1_unit); + const Vec3d v = draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(a, normal)) * e1_unit); init_data.add_vertex((Vec3f)v.cast()); init_data.add_index(i); } @@ -972,35 +1000,70 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.arc.init_from(std::move(init_data)); } - auto render_edge_entension = [this, shader, ¢er, radius](const Edge& e, bool coplanar) { - const Vec3d e1center = center - e.first; - const Vec3d e1e2 = e.second - e.first; - const bool on_e1_side = e1center.dot(e1e2) < -EPSILON; - const bool on_e2_side = !on_e1_side && e1center.norm() > e1e2.norm(); - if (!coplanar || on_e1_side || on_e2_side) { - const Camera& camera = wxGetApp().plater()->get_camera(); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - auto render_extension = [this, shader, &camera, ¢er, radius, coplanar](const Vec3d& p) { - const Vec3d centerp = p - center; - const auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), centerp.normalized()); - shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * q * - Geometry::scale_transform({ coplanar ? centerp.norm() : radius, 1.0f, 1.0f })); - m_dimensioning.line.render(); - }; - render_extension(on_e1_side ? e.first : e.second); - } - }; + // render arc + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center)); + m_dimensioning.arc.render(); - auto render_arc = [this, shader, ¢er]() { + // render edge 1 extension + const Vec3d e11e12 = e1copy.second - e1copy.first; + const Vec3d e11center = center - e1copy.first; + const double e11center_len = e11center.norm(); + if (e11center_len > EPSILON && e11center.dot(e11e12) < 0.0) { const Camera& camera = wxGetApp().plater()->get_camera(); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center)); - m_dimensioning.arc.render(); - }; + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), edge_direction(e1copy)) * + Geometry::scale_transform({ e11center_len, 1.0f, 1.0f })); + m_dimensioning.line.render(); + } - render_edge_entension({ e11_proj , e12_proj }, true); - render_edge_entension({ e21_proj , e22_proj }, coplanar); - render_arc(); + // render edge 2 extension + const Vec3d e21center = center - e2copy.first; + const double e21center_len = e21center.norm(); + if (e21center_len > EPSILON) { + const Camera& camera = wxGetApp().plater()->get_camera(); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), edge_direction(e2copy)) * + Geometry::scale_transform({ (coplanar && (force_radius == nullptr)) ? e21center_len : draw_radius, 1.0f, 1.0f })); + m_dimensioning.line.render(); + } + }; + + auto arc_edge_plane = [this, arc_edge_edge](const Edge& e, const Plane& p) { + const auto& [idx, normal, origin] = p; + const Vec3d e1e2 = e.second - e.first; + const double abs_dot = std::abs(normal.dot(edge_direction(e))); + if (abs_dot < EPSILON || std::abs(abs_dot - 1.0) < EPSILON) + return; + + const Eigen::Hyperplane plane(normal, origin); + const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); + const Vec3d inters = line.intersectionPoint(plane); + + // ensure the edge is pointing away from the intersection + Edge ecopy = e; + Vec3d e1e2copy = e1e2; + if ((ecopy.first - inters).squaredNorm() > (ecopy.second - inters).squaredNorm()) { + std::swap(ecopy.first, ecopy.second); + e1e2copy = -e1e2copy; + } + + // calculate 2nd edge (on the plane) + const Vec3d temp = normal.cross(e1e2copy); + const Vec3d edge_on_plane_unit = normal.cross(temp).normalized(); + Edge edge_on_plane = { origin, origin + e1e2copy.norm() * edge_on_plane_unit }; + + // ensure the 2nd edge is pointing in the correct direction + const Vec3d test_edge = (edge_on_plane.second - edge_on_plane.first).cross(e1e2copy); + if (test_edge.dot(temp) < 0.0) + edge_on_plane = { origin, origin - e1e2copy.norm() * edge_on_plane_unit }; + + const Vec3d e1e2copy_mid = 0.5 * (ecopy.second + ecopy.first); + const double radius = (inters - e1e2copy_mid).norm(); + arc_edge_edge(ecopy, edge_on_plane, &radius); }; auto edge_edge = [point_point, arc_edge_edge](const Edge& e1, const Edge& e2) { @@ -1011,6 +1074,11 @@ void GLGizmoMeasure::render_dimensioning() arc_edge_edge(e1, e2); }; + auto edge_plane = [point_point, arc_edge_plane](const Edge& e, const Plane& p) { + // arc + arc_edge_plane(e, p); + }; + auto edge_circle = [point_point](const Edge& e, const Circle& c) { const auto [distance, v1, v2] = distance_edge_circle(e, c); point_point(v1, v2); @@ -1088,31 +1156,41 @@ void GLGizmoMeasure::render_dimensioning() m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { point_edge(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_edge()); } - // plane-point - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - point_plane(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_plane()); - } - // circle-point - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - point_circle(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_circle()); - } // edge-edge else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { edge_edge(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_edge()); } + // edge-plane + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { + edge_plane(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_plane()); + } // edge-circle else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Circle) { edge_circle(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_circle()); } + // plane-point + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { + point_plane(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_plane()); + } + // plane-edge + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { + edge_plane(m_selected_features.second.feature->get_edge(), m_selected_features.first.feature->get_plane()); + } // plane-plane else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { plane_plane(m_selected_features.first.feature->get_plane(), m_selected_features.second.feature->get_plane()); } + // circle-point + else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle && + m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { + point_circle(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_circle()); + } // circle-edge else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { From 10459706b8d1149f39b38c43b1a2d625b03ed10d Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 26 Sep 2022 13:17:41 +0200 Subject: [PATCH 169/250] Fixed bug in get_measurement() function --- src/libslic3r/Measure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 1a79369a3e..c2b7edd5e2 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -518,7 +518,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& const auto& [idx2, normal2, pt2] = f2.get_plane(); double angle = 0.; - if (! normal1.isApprox(normal2)) { + if (normal1.isApprox(normal2)) { // The planes are parallel, calculate distance. Eigen::Hyperplane plane(normal1, pt1); result.distance_infinite = plane.absDistance(pt2); From aee76f0c11f8965574425b3e58f66024ee0bba9d Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 27 Sep 2022 10:21:57 +0200 Subject: [PATCH 170/250] Measuring - Refactoring in GLGizmoMeasure related to scene raycasters state cache Fixed conflicts while rebasing to master --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 25 +++++++++++------------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 9 +++++++-- src/slic3r/GUI/SceneRaycaster.cpp | 25 ++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index fc49e9883f..c511f7e501 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -372,11 +372,13 @@ void GLGizmoMeasure::on_set_state() else { m_mode = EMode::BasicSelection; // store current state of scene raycaster for later use - m_scene_raycaster_state.clear(); - m_scene_raycasters = m_parent.get_raycasters_for_picking(SceneRaycaster::EType::Volume); - if (m_scene_raycasters != nullptr) { - for (const auto& r : *m_scene_raycasters) { - m_scene_raycaster_state.emplace_back(r->is_active()); + m_scene_raycasters.clear(); + auto scene_raycasters = m_parent.get_raycasters_for_picking(SceneRaycaster::EType::Volume); + if (scene_raycasters != nullptr) { + m_scene_raycasters.reserve(scene_raycasters->size()); + for (auto r : *scene_raycasters) { + SceneRaycasterState state = { r, r->is_active() }; + m_scene_raycasters.emplace_back(state); } } } @@ -772,20 +774,15 @@ void GLGizmoMeasure::update_if_needed() void GLGizmoMeasure::disable_scene_raycasters() { - if (m_scene_raycasters != nullptr) { - for (auto r : *m_scene_raycasters) { - r->set_active(false); - } + for (auto r : m_scene_raycasters) { + r.raycaster->set_active(false); } } void GLGizmoMeasure::restore_scene_raycasters_state() { - if (m_scene_raycasters != nullptr) { - assert(m_scene_raycasters->size() == m_scene_raycaster_state.size()); - for (size_t i = 0; i < m_scene_raycasters->size(); ++i) { - (*m_scene_raycasters)[i]->set_active(m_scene_raycaster_state[i]); - } + for (auto r : m_scene_raycasters) { + r.raycaster->set_active(r.state); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 51094ae12c..08a9042b2c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -89,8 +89,13 @@ class GLGizmoMeasure : public GLGizmoBase std::map> m_raycasters; std::optional m_curr_feature; std::optional m_curr_point_on_feature_position; - std::vector>* m_scene_raycasters{ nullptr }; - std::vector m_scene_raycaster_state; + struct SceneRaycasterState + { + std::shared_ptr raycaster{ nullptr }; + bool state{true}; + + }; + std::vector m_scene_raycasters; // These hold information to decide whether recalculation is necessary: std::vector m_volumes_matrices; diff --git a/src/slic3r/GUI/SceneRaycaster.cpp b/src/slic3r/GUI/SceneRaycaster.cpp index 6d255ccdb4..a3e95293b9 100644 --- a/src/slic3r/GUI/SceneRaycaster.cpp +++ b/src/slic3r/GUI/SceneRaycaster.cpp @@ -173,6 +173,31 @@ void SceneRaycaster::render_hit(const Camera& camera) shader->stop_using(); } + +size_t SceneRaycaster::active_beds_count() const { + size_t count = 0; + for (const auto& b : m_bed) { + if (b->is_active()) + ++count; + } + return count; +} +size_t SceneRaycaster::active_volumes_count() const { + size_t count = 0; + for (const auto& v : m_volumes) { + if (v->is_active()) + ++count; + } + return count; +} +size_t SceneRaycaster::active_gizmos_count() const { + size_t count = 0; + for (const auto& g : m_gizmos) { + if (g->is_active()) + ++count; + } + return count; +} #endif // ENABLE_RAYCAST_PICKING_DEBUG std::vector>* SceneRaycaster::get_raycasters(EType type) From e0bfb17e64bc69957318d96c7f209d56c855fdbc Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 29 Sep 2022 08:43:03 +0200 Subject: [PATCH 171/250] Measuring - GLGizmoMeasure - Allow to deselect second feature by clicking on it Fixed conflicts while rebasing to master --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 83 +++++++++++++++++++----- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 + src/slic3r/GUI/SceneRaycaster.cpp | 6 +- src/slic3r/GUI/SceneRaycaster.hpp | 3 +- 4 files changed, 72 insertions(+), 21 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index c511f7e501..5dee42ad1e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -30,6 +30,8 @@ static const int POINT_ID = 100; static const int EDGE_ID = 200; static const int CIRCLE_ID = 300; static const int PLANE_ID = 400; +static const int SELECTION_1_ID = 501; +static const int SELECTION_2_ID = 502; static const float TRIANGLE_BASE = 10.0f; static const float TRIANGLE_HEIGHT = TRIANGLE_BASE * 1.618033f; @@ -47,11 +49,11 @@ static std::string surface_feature_type_as_string(Measure::SurfaceFeatureType ty switch (type) { default: - case Measure::SurfaceFeatureType::Undef: { return L("Undefined"); } - case Measure::SurfaceFeatureType::Point: { return L("Vertex"); } - case Measure::SurfaceFeatureType::Edge: { return L("Edge"); } - case Measure::SurfaceFeatureType::Circle: { return L("Circle"); } - case Measure::SurfaceFeatureType::Plane: { return L("Plane"); } + case Measure::SurfaceFeatureType::Undef: { return _u8L("Undefined"); } + case Measure::SurfaceFeatureType::Point: { return _u8L("Vertex"); } + case Measure::SurfaceFeatureType::Edge: { return _u8L("Edge"); } + case Measure::SurfaceFeatureType::Circle: { return _u8L("Circle"); } + case Measure::SurfaceFeatureType::Plane: { return _u8L("Plane"); } } } @@ -277,20 +279,44 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) m_mouse_left_down = true; auto item_from_feature = [this]() { - const SelectedFeatures::Item item = { - (m_mode == EMode::ExtendedSelection) ? point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id) : surface_feature_type_as_string(m_curr_feature->get_type()), - (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(*m_curr_point_on_feature_position) : m_curr_feature }; + SelectedFeatures::Item item; + if (m_hover_id == SELECTION_1_ID && m_selected_features.first.feature.has_value()) + item = m_selected_features.first; + else if (m_hover_id == SELECTION_2_ID && m_selected_features.second.feature.has_value()) + item = m_selected_features.second; + else { + item = { + (m_mode == EMode::ExtendedSelection) ? point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id) : surface_feature_type_as_string(m_curr_feature->get_type()), + (m_mode == EMode::ExtendedSelection) ? Measure::SurfaceFeature(*m_curr_point_on_feature_position) : m_curr_feature + }; + } return item; }; if (m_selected_features.first.feature.has_value()) { - const SelectedFeatures::Item item = item_from_feature(); - if (m_selected_features.first != item) - m_selected_features.second = item; - } - else - m_selected_features.first = item_from_feature(); + auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), + [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_2_ID; }); + if (it != m_selection_raycasters.end()) + m_selection_raycasters.erase(it); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, SELECTION_2_ID); + const SelectedFeatures::Item item = item_from_feature(); + if (m_selected_features.first != item) { + if (m_selected_features.second == item) + m_selected_features.second.reset(); + else { + m_selected_features.second = item; + if (m_mode == EMode::ExtendedSelection) + m_selection_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SELECTION_2_ID, *m_sphere.mesh_raycaster)); + } + } + } + else { + const SelectedFeatures::Item item = item_from_feature(); + m_selected_features.first = item; + if (m_mode == EMode::ExtendedSelection) + m_selection_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SELECTION_1_ID, *m_sphere.mesh_raycaster)); + } return true; } @@ -308,6 +334,7 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) } else if (mouse_event.RightDown() && mouse_event.CmdDown()) { m_selected_features.reset(); + m_selection_raycasters.clear(); m_imgui->set_requires_extra_frame(); } else if (mouse_event.Leaving()) @@ -332,6 +359,7 @@ void GLGizmoMeasure::data_changed() m_last_inv_zoom = 0.0f; m_last_plane_idx = -1; m_selected_features.reset(); + m_selection_raycasters.clear(); } bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) @@ -435,7 +463,11 @@ void GLGizmoMeasure::on_render() std::optional curr_feature = mouse_on_object ? m_measuring->get_feature(model_facet_idx, position_on_model.cast()) : std::nullopt; m_curr_point_on_feature_position.reset(); if (m_curr_feature != curr_feature) { - GLGizmoMeasure::on_unregister_raycasters_for_picking(); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); + m_raycasters.clear(); m_curr_feature = curr_feature; if (!m_curr_feature.has_value()) return; @@ -687,11 +719,23 @@ void GLGizmoMeasure::on_render() std::vector colors; colors.emplace_back(SELECTED_1ST_COLOR); render_feature(*m_selected_features.first.feature, colors, m_volume_matrix, inv_zoom, false); + if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point) { + auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), + [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_1_ID; }); + if (it != m_selection_raycasters.end()) + (*it)->set_transform(m_volume_matrix * Geometry::translation_transform(m_selected_features.first.feature->get_point()) * Geometry::scale_transform(inv_zoom)); + } } if (m_selected_features.second.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.second.feature)) { std::vector colors; colors.emplace_back(SELECTED_2ND_COLOR); render_feature(*m_selected_features.second.feature, colors, m_volume_matrix, inv_zoom, false); + if (m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { + auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), + [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_2_ID; }); + if (it != m_selection_raycasters.end()) + (*it)->set_transform(m_volume_matrix * Geometry::translation_transform(m_selected_features.second.feature->get_point()) * Geometry::scale_transform(inv_zoom)); + } } if (is_hovering_on_locked_feature && m_curr_point_on_feature_position.has_value()) { @@ -1269,7 +1313,7 @@ void GLGizmoMeasure::render_debug_dialog() add_strings_row_to_table(*m_imgui, "m_pt3", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(*extra_point), ImGui::GetStyleColorVec4(ImGuiCol_Text)); }; - m_imgui->begin(_L("Measure tool debug"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + m_imgui->begin(_L("Measure tool debug"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); if (!m_selected_features.first.feature.has_value() && !m_selected_features.second.feature.has_value()) m_imgui->text("Empty selection"); else { @@ -1323,7 +1367,10 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Left mouse button")); }, [this]() { - m_imgui->text_colored(ImGui::GetStyleColorVec4(ImGuiCol_Text), (m_mode == EMode::BasicSelection) ? _u8L("Select feature") : _u8L("Select point")); + m_imgui->text_colored(ImGui::GetStyleColorVec4(ImGuiCol_Text), + m_selected_features.second.feature.has_value() ? + ((m_mode == EMode::BasicSelection) ? _u8L("Select/Unselect feature") : _u8L("Select/Unselect point")) : + ((m_mode == EMode::BasicSelection) ? _u8L("Select feature") : _u8L("Select point"))); ImGui::SameLine(); const ImVec2 pos = ImGui::GetCursorScreenPos(); const float rect_size = ImGui::GetTextLineHeight(); @@ -1434,6 +1481,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit //if (m_selected_features.first.feature.has_value()) { // if (m_imgui->button(_u8L("Restart"))) { // m_selected_features.reset(); + // m_selection_raycasters.clear(); // m_imgui->set_requires_extra_frame(); // } //} @@ -1498,6 +1546,7 @@ void GLGizmoMeasure::on_unregister_raycasters_for_picking() m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo); m_parent.set_raycaster_gizmos_on_top(false); m_raycasters.clear(); + m_selection_raycasters.clear(); } } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 08a9042b2c..add13eb4c3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -87,6 +87,7 @@ class GLGizmoMeasure : public GLGizmoBase Transform3d m_volume_matrix{ Transform3d::Identity() }; std::vector m_plane_models_cache; std::map> m_raycasters; + std::vector> m_selection_raycasters; std::optional m_curr_feature; std::optional m_curr_point_on_feature_position; struct SceneRaycasterState diff --git a/src/slic3r/GUI/SceneRaycaster.cpp b/src/slic3r/GUI/SceneRaycaster.cpp index a3e95293b9..96ae536ca7 100644 --- a/src/slic3r/GUI/SceneRaycaster.cpp +++ b/src/slic3r/GUI/SceneRaycaster.cpp @@ -37,10 +37,10 @@ std::shared_ptr SceneRaycaster::add_raycaster(EType type, in const Transform3d& trafo, bool use_back_faces) { switch (type) { - case EType::Bed: { return m_bed.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo, use_back_faces)); } + case EType::Bed: { return m_bed.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo, use_back_faces)); } case EType::Volume: { return m_volumes.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo, use_back_faces)); } - case EType::Gizmo: { return m_gizmos.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo, use_back_faces)); } - default: { assert(false); return nullptr; } + case EType::Gizmo: { return m_gizmos.emplace_back(std::make_shared(encode_id(type, id), raycaster, trafo, use_back_faces)); } + default: { assert(false); return nullptr; } }; } diff --git a/src/slic3r/GUI/SceneRaycaster.hpp b/src/slic3r/GUI/SceneRaycaster.hpp index 7541badbb4..2254a2022d 100644 --- a/src/slic3r/GUI/SceneRaycaster.hpp +++ b/src/slic3r/GUI/SceneRaycaster.hpp @@ -105,9 +105,10 @@ public: size_t active_gizmos_count() const; #endif // ENABLE_RAYCAST_PICKING_DEBUG + static int decode_id(EType type, int id); + private: static int encode_id(EType type, int id); - static int decode_id(EType type, int id); static int base_id(EType type); }; From 1f9d42b14ff7d8a320971c45ffec2b6fc3ab36ba Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 29 Sep 2022 10:19:40 +0200 Subject: [PATCH 172/250] Measuring - GLGizmoMeasure - Added option to copy to clipboard the result of measurement Fixed conflicts while rebasing to master --- src/imgui/imconfig.h | 16 +++++++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 57 ++++++++++++++++++++---- src/slic3r/GUI/ImGuiWrapper.cpp | 3 ++ 3 files changed, 68 insertions(+), 8 deletions(-) diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h index f2c3ef0837..7c79058c4c 100644 --- a/src/imgui/imconfig.h +++ b/src/imgui/imconfig.h @@ -156,6 +156,21 @@ namespace ImGui const wchar_t InfoMarker = 0x2603; const wchar_t SliderFloatEditBtnIcon = 0x2604; const wchar_t SliderFloatEditBtnPressedIcon = 0x2605; +#if ENABLE_MEASURE_GIZMO + const wchar_t ClipboardBtnIcon = 0x2606; + const wchar_t LegendTravel = 0x2701; + const wchar_t LegendWipe = 0x2702; + const wchar_t LegendRetract = 0x2703; + const wchar_t LegendDeretract = 0x2704; + const wchar_t LegendSeams = 0x2705; + const wchar_t LegendToolChanges = 0x2706; + const wchar_t LegendColorChanges = 0x2707; + const wchar_t LegendPausePrints = 0x2708; + const wchar_t LegendCustomGCodes = 0x2709; + const wchar_t LegendCOG = 0x2710; + const wchar_t LegendShells = 0x2711; + const wchar_t LegendToolMarker = 0x2712; +#else const wchar_t LegendTravel = 0x2606; const wchar_t LegendWipe = 0x2607; const wchar_t LegendRetract = 0x2608; @@ -168,6 +183,7 @@ namespace ImGui const wchar_t LegendCOG = 0x2615; const wchar_t LegendShells = 0x2616; const wchar_t LegendToolMarker = 0x2617; +#endif // ENABLE_MEASURE_GIZMO // void MyFunction(const char* name, const MyMatrix44& v); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 5dee42ad1e..c232405019 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -10,6 +10,8 @@ #include "libslic3r/Model.hpp" #include "libslic3r/PresetBundle.hpp" +#include + #include #include @@ -1251,7 +1253,7 @@ static void add_row_to_table(std::function col_1 = nullptr, std::fun col_1(); ImGui::TableSetColumnIndex(1); col_2(); -}; +} static void add_strings_row_to_table(ImGuiWrapper& imgui, const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) { @@ -1263,14 +1265,14 @@ static std::string format_double(double value) char buf[1024]; sprintf(buf, "%.3f", value); return std::string(buf); -}; +} static std::string format_vec3(const Vec3d& v) { char buf[1024]; sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", v.x(), v.y(), v.z()); return std::string(buf); -}; +} #if ENABLE_MEASURE_GIZMO_DEBUG void GLGizmoMeasure::render_debug_dialog() @@ -1486,36 +1488,75 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit // } //} + auto add_measure_row_to_table = [this](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) { + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + m_imgui->text_colored(col_1_color, col_1); + ImGui::TableSetColumnIndex(1); + m_imgui->text_colored(col_2_color, col_2); + ImGui::TableSetColumnIndex(2); + ImGuiIO& io = ImGui::GetIO(); + const ImTextureID tex_id = io.Fonts->TexID; + assert(io.Fonts->TexWidth > 0 && io.Fonts->TexHeight > 0); + float inv_tex_w = 1.0f / float(io.Fonts->TexWidth); + float inv_tex_h = 1.0f / float(io.Fonts->TexHeight); + const ImFontAtlasCustomRect* const rect = m_imgui->GetTextureCustomRect(ImGui::ClipboardBtnIcon); + const ImVec2 size = { float(rect->Width), float(rect->Height) }; + const ImVec2 uv0 = ImVec2(float(rect->X) * inv_tex_w, float(rect->Y) * inv_tex_h); + const ImVec2 uv1 = ImVec2(float(rect->X + rect->Width) * inv_tex_w, float(rect->Y + rect->Height) * inv_tex_h); + ImGui::PushStyleColor(ImGuiCol_Button, { 0.25f, 0.25f, 0.25f, 0.0f }); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 0.4f, 0.4f, 0.4f, 1.0f }); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0.25f, 0.25f, 0.25f, 1.0f }); + if (m_imgui->image_button(tex_id, size, uv0, uv1)) { + wxTheClipboard->Open(); + wxTheClipboard->SetData(new wxTextDataObject(col_1 + ": " + col_2)); + wxTheClipboard->Close(); + } + ImGui::PopStyleColor(3); + if (ImGui::IsItemHovered()) { + const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; + m_imgui->tooltip(into_u8(_L("Copy to clipboard")).c_str(), max_tooltip_width); + } + }; + if (m_selected_features.second.feature.has_value()) { const Measure::MeasurementResult measure = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature); ImGui::Separator(); if (measure.has_any_data()) { m_imgui->text(_u8L("Measure") + ":"); - if (ImGui::BeginTable("Measure", 2)) { + if (ImGui::BeginTable("Measure", 3)) { if (measure.angle.has_value()) { - add_strings_row_to_table(*m_imgui, _u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(*measure.angle)), + ImGui::PushID((void*)(intptr_t)1); + add_measure_row_to_table(_u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(*measure.angle)), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ImGui::PopID(); } if (measure.distance_infinite.has_value()) { double distance = *measure.distance_infinite; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - add_strings_row_to_table(*m_imgui, _u8L("Distance Infinite") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), + ImGui::PushID((void*)(intptr_t)2); + add_measure_row_to_table(_u8L("Distance Infinite") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ImGui::PopID(); } if (measure.distance_strict.has_value()) { double distance = *measure.distance_strict; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - add_strings_row_to_table(*m_imgui, _u8L("Distance Strict") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), + ImGui::PushID((void*)(intptr_t)3); + add_measure_row_to_table(_u8L("Distance Strict") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ImGui::PopID(); } if (measure.distance_xyz.has_value()) { Vec3d distance = *measure.distance_xyz; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - add_strings_row_to_table(*m_imgui, _u8L("Distance XYZ") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), + ImGui::PushID((void*)(intptr_t)4); + add_measure_row_to_table(_u8L("Distance XYZ") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ImGui::PopID(); } ImGui::EndTable(); } diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index fe3f69a58b..b8c6c463f5 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -56,6 +56,9 @@ static const std::map font_icons = { {ImGui::PreferencesHoverButton, "notification_preferences_hover"}, {ImGui::SliderFloatEditBtnIcon, "edit_button" }, {ImGui::SliderFloatEditBtnPressedIcon, "edit_button_pressed" }, +#if ENABLE_MEASURE_GIZMO + {ImGui::ClipboardBtnIcon , "copy_menu" }, +#endif // ENABLE_MEASURE_GIZMO }; static const std::map font_icons_large = { From 9658c8c6774ec2d75dd097d9ebcfad44c96820cb Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 29 Sep 2022 11:22:23 +0200 Subject: [PATCH 173/250] Measurement: moving arrow-drawing functions from frontend to the backend (1/4) --- src/libslic3r/Measure.cpp | 24 +++-- src/libslic3r/Measure.hpp | 10 +- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 126 ++++++++++++----------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 4 +- 4 files changed, 92 insertions(+), 72 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index c2b7edd5e2..a627fe62cc 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -349,7 +349,7 @@ std::optional MeasuringImpl::get_feature(size_t face_idx, const // which is needless and relatively expensive. res = get_measurement(plane.surface_features[i], point_sf); if (res.distance_strict) { // TODO: this should become an assert after all combinations are implemented. - double dist = *res.distance_strict; + double dist = res.distance_strict->dist; if (dist < feature_hover_limit && dist < min_dist) { min_dist = std::min(dist, min_dist); closest_feature_idx = i; @@ -455,8 +455,9 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& if (f1.get_type() == SurfaceFeatureType::Point) { if (f2.get_type() == SurfaceFeatureType::Point) { Vec3d diff = (f2.get_point() - f1.get_point()); - result.distance_strict = diff.norm(); + result.distance_strict = std::make_optional(DistAndPoints{diff.norm(), f1.get_point(), f2.get_point()}); result.distance_xyz = diff; + /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Edge) { const auto& [s,e] = f2.get_edge(); @@ -468,11 +469,12 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& double dist_end_sq = (proj-e).squaredNorm(); if (dist_start_sq < len_sq && dist_end_sq < len_sq) { // projection falls on the line - the strict distance is the same as infinite - result.distance_strict = std::make_optional(dist_inf); + result.distance_strict = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); // TODO } else { // the result is the closer of the endpoints - result.distance_strict = std::make_optional(std::sqrt(std::min(dist_start_sq, dist_end_sq) + dist_inf)); + bool s_is_closer = dist_start_sq < dist_end_sq; + result.distance_strict = std::make_optional(DistAndPoints{std::sqrt(std::min(dist_start_sq, dist_end_sq) + dist_inf), f1.get_point(), s_is_closer ? s : e}); } - result.distance_infinite = std::make_optional(dist_inf); + result.distance_infinite = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); // TODO /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Circle) { // Find a plane containing normal, center and the point. @@ -482,12 +484,13 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& double dist = std::sqrt(std::pow((proj - c).norm() - radius, 2.) + (f1.get_point() - proj).squaredNorm()); - result.distance_strict = std::make_optional(dist); + const Vec3d p_on_circle = c + radius * (circle_plane.projection(f1.get_point()) - c).normalized(); + result.distance_strict = std::make_optional(DistAndPoints{dist, f1.get_point(), p_on_circle}); // TODO /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { const auto& [idx, normal, pt] = f2.get_plane(); Eigen::Hyperplane plane(normal, pt); - result.distance_infinite = plane.absDistance(f1.get_point()); + result.distance_infinite = std::make_optional(DistAndPoints{plane.absDistance(f1.get_point()), f1.get_point(), plane.projection(f1.get_point())}); // TODO // TODO: result.distance_strict = } /////////////////////////////////////////////////////////////////////////// @@ -495,18 +498,23 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& /////////////////////////////////////////////////////////////////////////// } else if (f1.get_type() == SurfaceFeatureType::Edge) { if (f2.get_type() == SurfaceFeatureType::Edge) { + result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Circle) { + result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { + result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// } else if (f1.get_type() == SurfaceFeatureType::Circle) { if (f2.get_type() == SurfaceFeatureType::Circle) { + result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { + result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// @@ -521,7 +529,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& if (normal1.isApprox(normal2)) { // The planes are parallel, calculate distance. Eigen::Hyperplane plane(normal1, pt1); - result.distance_infinite = plane.absDistance(pt2); + result.distance_infinite = std::make_optional(DistAndPoints{plane.absDistance(pt2), Vec3d::Zero(), Vec3d::Zero()}); } else { // Planes are not parallel, calculate angle. angle = std::acos(std::abs(normal1.dot(normal2))); diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 5d71983f0b..6b7940f2bf 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -110,12 +110,16 @@ private: }; - +struct DistAndPoints { + double dist; + Vec3d from; + Vec3d to; +}; struct MeasurementResult { std::optional angle; - std::optional distance_infinite; - std::optional distance_strict; + std::optional distance_infinite; + std::optional distance_strict; std::optional distance_xyz; bool has_any_data() const { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index c232405019..11cd651e5c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -72,13 +72,6 @@ static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType t return ret; } -static std::tuple distance_point_plane(const Vec3d& v, const Plane& p) -{ - const auto& [idx, normal, origin] = p; - const Eigen::Hyperplane plane(normal, origin); - return std::make_tuple(plane.absDistance(v), v, plane.projection(v)); -} - static Vec3d vector_direction(const Vec3d& from, const Vec3d& to) { return (to - from).normalized(); @@ -89,21 +82,13 @@ static Vec3d edge_direction(const Edge& e) return vector_direction(e.first, e.second); } -// returns: distance, 1st vertex, 2nd vertex -static std::tuple distance_point_edge(const Vec3d& v, const Edge& e) -{ - const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); - return std::make_tuple(line.distance(v), v, line.projection(v)); -} -// returns: distance, 1st vertex, 2nd vertex -static std::tuple distance_point_circle(const Vec3d& v, const Circle& c) -{ - const auto& [center, radius, normal] = c; - const Eigen::Hyperplane plane(normal, center); - const Vec3d p_on_circle = center + radius * vector_direction(center, plane.projection(v)); - return std::make_tuple((v - p_on_circle).norm(), v, p_on_circle); -} + + + + +/* + // returns: distance, 1st vertex, 2nd vertex static std::tuple distance_edge_edge(const Edge& e1, const Edge& e2) @@ -165,6 +150,34 @@ static std::tuple distance_plane_plane(const Plane& p1, co return (std::abs(std::abs(normal1.dot(normal2)) - 1.0) < EPSILON) ? distance_point_plane(origin2, p1) : std::make_tuple(0.0, Vec3d::Zero(), Vec3d::Zero()); } +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + // returns: angle in rad, center of arc, radius of arc, whether or not the edges are coplanar // After return, the edges are oriented so that they point away from their intersection point @@ -278,6 +291,9 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) } else if (mouse_event.LeftDown()) { if (m_hover_id != -1) { + SelectedFeatures selected_features_old = m_selected_features; + + m_mouse_left_down = true; auto item_from_feature = [this]() { @@ -319,6 +335,10 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) if (m_mode == EMode::ExtendedSelection) m_selection_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SELECTION_1_ID, *m_sphere.mesh_raycaster)); } + + if (m_selected_features != selected_features_old && m_selected_features.second.feature.has_value()) + m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature); + return true; } @@ -963,8 +983,11 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.triangle.render(); }; + auto point_edge = [this, shader, point_point](const Vec3d& v, const Edge& e) { - const auto [distance, v1, v_proj] = distance_point_edge(v, e); + const double distance = m_measurement_result.distance_infinite->dist; + const Vec3d v1 = m_measurement_result.distance_infinite->from; + const Vec3d v_proj = m_measurement_result.distance_infinite->to; point_point(v1, v_proj); const Vec3d e1e2 = e.second - e.first; @@ -997,16 +1020,7 @@ void GLGizmoMeasure::render_dimensioning() } }; - auto point_plane = [point_point](const Vec3d& v, const Plane& p) { - const auto [distance, v1, v2] = distance_point_plane(v, p); - point_point(v1, v2); - }; - - auto point_circle = [point_point](const Vec3d& v, const Circle& c) { - const auto [distance, v1, v2] = distance_point_circle(v, c); - point_point(v1, v2); - }; - +/* auto arc_edge_edge = [this, shader](const Edge& e1, const Edge& e2, const double* const force_radius = nullptr) { Edge e1copy = e1; Edge e2copy = e2; @@ -1130,7 +1144,7 @@ void GLGizmoMeasure::render_dimensioning() auto plane_plane = [point_point](const Plane& p1, const Plane& p2) { const auto [distance, v1, v2] = distance_plane_plane(p1, p2); point_point(v1, v2); - }; + };*/ shader->start_using(); @@ -1174,26 +1188,26 @@ void GLGizmoMeasure::render_dimensioning() glsafe(::glDisable(GL_DEPTH_TEST)); - // point-point - if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - point_point(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_point()); + // Render the arrow between the points that the backend passed: + if (m_selected_features.second.feature.has_value()) { + const Measure::DistAndPoints& dap = m_measurement_result.distance_infinite.has_value() + ? *m_measurement_result.distance_infinite + : *m_measurement_result.distance_strict; + point_point(dap.from, dap.to); } + + // Now if one of the features is an edge, draw also the extension of the edge to where the dist is measured: + // TODO... + + // point-edge else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { point_edge(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_edge()); } - // point-plane - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { - point_plane(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_plane()); - } - // point-circle - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Circle) { - point_circle(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_circle()); - } + + + /* // edge-point else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { @@ -1214,11 +1228,6 @@ void GLGizmoMeasure::render_dimensioning() m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Circle) { edge_circle(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_circle()); } - // plane-point - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - point_plane(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_plane()); - } // plane-edge else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { @@ -1229,16 +1238,12 @@ void GLGizmoMeasure::render_dimensioning() m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { plane_plane(m_selected_features.first.feature->get_plane(), m_selected_features.second.feature->get_plane()); } - // circle-point - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - point_circle(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_circle()); - } // circle-edge else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle && m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { edge_circle(m_selected_features.second.feature->get_edge(), m_selected_features.first.feature->get_circle()); } +*/ glsafe(::glEnable(GL_DEPTH_TEST)); @@ -1520,7 +1525,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit }; if (m_selected_features.second.feature.has_value()) { - const Measure::MeasurementResult measure = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature); + const Measure::MeasurementResult& measure = m_measurement_result; + ImGui::Separator(); if (measure.has_any_data()) { m_imgui->text(_u8L("Measure") + ":"); @@ -1532,7 +1538,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::PopID(); } if (measure.distance_infinite.has_value()) { - double distance = *measure.distance_infinite; + double distance = measure.distance_infinite->dist; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; ImGui::PushID((void*)(intptr_t)2); @@ -1541,7 +1547,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::PopID(); } if (measure.distance_strict.has_value()) { - double distance = *measure.distance_strict; + double distance = measure.distance_strict->dist; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; ImGui::PushID((void*)(intptr_t)3); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index add13eb4c3..7e65b8c89c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -70,7 +70,9 @@ class GLGizmoMeasure : public GLGizmoBase }; EMode m_mode{ EMode::BasicSelection }; - std::unique_ptr m_measuring; + Measure::MeasurementResult m_measurement_result; + + std::unique_ptr m_measuring; // PIMPL PickingModel m_sphere; PickingModel m_cylinder; From 8af3e5823a33872a60aa36c0aa3faeb1cc377453 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 29 Sep 2022 12:33:20 +0200 Subject: [PATCH 174/250] Measurement: moving arrow-drawing functions from frontend to the backend (2/4) --- src/libslic3r/Measure.cpp | 35 +++++++++++++++++++++++- src/libslic3r/Measure.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index a627fe62cc..01f48579d2 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -498,7 +498,40 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& /////////////////////////////////////////////////////////////////////////// } else if (f1.get_type() == SurfaceFeatureType::Edge) { if (f2.get_type() == SurfaceFeatureType::Edge) { - result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO + + std::vector distances; + + auto add_point_edge_distance = [&distances](const Vec3d& v, const std::pair& e) { + //const auto [distance, v1, v2] = distance_point_edge(v, SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second)); + + const MeasurementResult res = get_measurement(SurfaceFeature(v), SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second, std::optional(), 0.)); + double distance = res.distance_strict->dist; + Vec3d v1 = res.distance_strict->from; + Vec3d v2 = res.distance_strict->to; + + + const Vec3d e1e2 = e.second - e.first; + const Vec3d e1v2 = v2 - e.first; + if (e1v2.dot(e1e2) >= 0.0 && e1v2.norm() < e1e2.norm()) + distances.emplace_back(distance, v, v2); + }; + + std::pair e1 = f1.get_edge(); + std::pair e2 = f2.get_edge(); + + distances.emplace_back((e2.first - e1.first).norm(), e1.first, e2.first); + distances.emplace_back((e2.second - e1.first).norm(), e1.first, e2.second); + distances.emplace_back((e2.first - e1.second).norm(), e1.second, e2.first); + distances.emplace_back((e2.second - e1.second).norm(), e1.second, e2.second); + add_point_edge_distance(e1.first, e2); + add_point_edge_distance(e1.second, e2); + add_point_edge_distance(e2.first, e1); + add_point_edge_distance(e2.second, e1); + auto it = std::min_element(distances.begin(), distances.end(), + [](const DistAndPoints& item1, const DistAndPoints& item2) { + return item1.dist < item2.dist; + }); + result.distance_infinite = std::make_optional(*it); // TODO /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Circle) { result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 6b7940f2bf..fb36b50095 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -111,6 +111,7 @@ private: struct DistAndPoints { + DistAndPoints(double dist_, Vec3d from_, Vec3d to_) : dist(dist_), from(from_), to(to_) {} double dist; Vec3d from; Vec3d to; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 11cd651e5c..222d8087a0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -90,7 +90,7 @@ static Vec3d edge_direction(const Edge& e) /* -// returns: distance, 1st vertex, 2nd vertex +// returns: distance, 1st vertex, 2nd vertexs static std::tuple distance_edge_edge(const Edge& e1, const Edge& e2) { std::vector> distances; From 79ab1ab1b50ab3dd1bbbcc5854cb010688f4027a Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 29 Sep 2022 14:50:29 +0200 Subject: [PATCH 175/250] Measurement: moving arrow-drawing functions from frontend to the backend (3/4) --- src/libslic3r/Measure.cpp | 98 ++++++- src/libslic3r/Measure.hpp | 25 +- src/libslic3r/SurfaceMesh.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 310 ++++------------------- 4 files changed, 156 insertions(+), 278 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 01f48579d2..fbf248c0f7 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -431,6 +431,67 @@ std::vector> Measuring::get_planes_triangle_indices() const +static AngleAndPoints angle_edge_edge(const std::pair& e1, const std::pair& e2) +{ + Vec3d e1_unit = (e1.second - e1.first).normalized(); + Vec3d e2_unit = (e2.second - e2.first).normalized(); + const double dot = e1_unit.dot(e2_unit); + // are edges parallel ? + if (std::abs(std::abs(dot) - 1.0) < EPSILON) + return AngleAndPoints(0.0, e1.first, Vec3d::UnitX(), Vec3d::UnitX(), 0., true); + + // project edges on the plane defined by them + Vec3d normal = e1_unit.cross(e2_unit).normalized(); + const Eigen::Hyperplane plane(normal, e1.first); + Vec3d e11_proj = plane.projection(e1.first); + Vec3d e12_proj = plane.projection(e1.second); + Vec3d e21_proj = plane.projection(e2.first); + Vec3d e22_proj = plane.projection(e2.second); + + const bool coplanar = (e2.first - e21_proj).norm() < EPSILON && (e2.second - e22_proj).norm() < EPSILON; + + // rotate the plane to become the XY plane + auto qp = Eigen::Quaternion::FromTwoVectors(normal, Vec3d::UnitZ()); + auto qp_inverse = qp.inverse(); + const Vec3d e11_rot = qp * e11_proj; + const Vec3d e12_rot = qp * e12_proj; + const Vec3d e21_rot = qp * e21_proj; + const Vec3d e22_rot = qp * e22_proj; + + // discard Z + const Vec2d e11_rot_2d = Vec2d(e11_rot.x(), e11_rot.y()); + const Vec2d e12_rot_2d = Vec2d(e12_rot.x(), e12_rot.y()); + const Vec2d e21_rot_2d = Vec2d(e21_rot.x(), e21_rot.y()); + const Vec2d e22_rot_2d = Vec2d(e22_rot.x(), e22_rot.y()); + + // find intersection (arc center) of edges in XY plane + const Eigen::Hyperplane e1_rot_2d_line = Eigen::Hyperplane::Through(e11_rot_2d, e12_rot_2d); + const Eigen::Hyperplane e2_rot_2d_line = Eigen::Hyperplane::Through(e21_rot_2d, e22_rot_2d); + const Vec2d center_rot_2d = e1_rot_2d_line.intersection(e2_rot_2d_line); + + // arc center in original coordinate + const Vec3d center = qp_inverse * Vec3d(center_rot_2d.x(), center_rot_2d.y(), e11_rot.z()); + + // ensure the edges are pointing away from the center + if ((center_rot_2d - e11_rot_2d).squaredNorm() > (center_rot_2d - e12_rot_2d).squaredNorm()) { + std::swap(e11_proj, e12_proj); + e1_unit = -e1_unit; + } + if ((center_rot_2d - e21_rot_2d).squaredNorm() > (center_rot_2d - e22_rot_2d).squaredNorm()) { + std::swap(e21_proj, e22_proj); + e2_unit = -e2_unit; + } + + // arc angle + const double angle = std::acos(std::clamp(e1_unit.dot(e2_unit), -1.0, 1.0)); + // arc radius + const Vec3d e1_proj_mid = 0.5 * (e11_proj + e12_proj); + const Vec3d e2_proj_mid = 0.5 * (e21_proj + e22_proj); + const double radius = std::min((center - e1_proj_mid).norm(), (center - e2_proj_mid).norm()); + + return AngleAndPoints(angle, center, e1_unit, e2_unit, radius, coplanar); +} + @@ -469,12 +530,12 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& double dist_end_sq = (proj-e).squaredNorm(); if (dist_start_sq < len_sq && dist_end_sq < len_sq) { // projection falls on the line - the strict distance is the same as infinite - result.distance_strict = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); // TODO + result.distance_strict = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); } else { // the result is the closer of the endpoints bool s_is_closer = dist_start_sq < dist_end_sq; result.distance_strict = std::make_optional(DistAndPoints{std::sqrt(std::min(dist_start_sq, dist_end_sq) + dist_inf), f1.get_point(), s_is_closer ? s : e}); } - result.distance_infinite = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); // TODO + result.distance_infinite = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Circle) { // Find a plane containing normal, center and the point. @@ -498,18 +559,13 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& /////////////////////////////////////////////////////////////////////////// } else if (f1.get_type() == SurfaceFeatureType::Edge) { if (f2.get_type() == SurfaceFeatureType::Edge) { - std::vector distances; auto add_point_edge_distance = [&distances](const Vec3d& v, const std::pair& e) { - //const auto [distance, v1, v2] = distance_point_edge(v, SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second)); - const MeasurementResult res = get_measurement(SurfaceFeature(v), SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second, std::optional(), 0.)); double distance = res.distance_strict->dist; - Vec3d v1 = res.distance_strict->from; Vec3d v2 = res.distance_strict->to; - const Vec3d e1e2 = e.second - e.first; const Vec3d e1v2 = v2 - e.first; if (e1v2.dot(e1e2) >= 0.0 && e1v2.norm() < e1e2.norm()) @@ -531,10 +587,32 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& [](const DistAndPoints& item1, const DistAndPoints& item2) { return item1.dist < item2.dist; }); - result.distance_infinite = std::make_optional(*it); // TODO + result.distance_infinite = std::make_optional(*it); + + result.angle = angle_edge_edge(f1.get_edge(), f2.get_edge()); /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Circle) { - result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO + const std::pair e = f1.get_edge(); + const auto& [center, radius, normal] = f2.get_circle(); + const Vec3d e1e2 = (e.second - e.first); + const Vec3d e1e2_unit = (e.second - e.first).normalized(); + + std::vector distances; + distances.emplace_back(*get_measurement(SurfaceFeature(e.first), f2).distance_strict); + distances.emplace_back(*get_measurement(SurfaceFeature(e.second), f2).distance_strict); + + const Eigen::Hyperplane plane(e1e2_unit, center); + const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); + const Vec3d inter = line.intersectionPoint(plane); + const Vec3d e1inter = inter - e.first; + if (e1inter.dot(e1e2) >= 0.0 && e1inter.norm() < e1e2.norm()) + distances.emplace_back(*get_measurement(SurfaceFeature(inter), f2).distance_strict); + + auto it = std::min_element(distances.begin(), distances.end(), + [](const DistAndPoints& item1, const DistAndPoints& item2) { + return item1.dist < item2.dist; + }); + result.distance_infinite = std::make_optional(DistAndPoints{it->dist, it->from, it->to}); /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO @@ -567,7 +645,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& // Planes are not parallel, calculate angle. angle = std::acos(std::abs(normal1.dot(normal2))); } - result.angle = angle; + result.angle = std::make_optional(AngleAndPoints(angle, Vec3d::Zero(), Vec3d::UnitX(), Vec3d::UnitX(), 0., false)); // TODO } diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index fb36b50095..b88411a9f6 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -15,12 +15,12 @@ namespace Slic3r { namespace Measure { -enum class SurfaceFeatureType { - Undef, - Point, - Edge, - Circle, - Plane +enum class SurfaceFeatureType : int { + Undef = 0, + Point = 1 << 0, + Edge = 1 << 1, + Circle = 1 << 2, + Plane = 1 << 3 }; class SurfaceFeature { @@ -117,8 +117,19 @@ struct DistAndPoints { Vec3d to; }; +struct AngleAndPoints { + AngleAndPoints(double angle_, Vec3d center_, Vec3d e1_, Vec3d e2_, double radius_, bool coplanar_) + : angle(angle_), center(center_), e1(e1_), e2(e2_), radius(radius_), coplanar(coplanar_) {} + double angle; + Vec3d center; + Vec3d e1; + Vec3d e2; + double radius; + bool coplanar; +}; + struct MeasurementResult { - std::optional angle; + std::optional angle; std::optional distance_infinite; std::optional distance_strict; std::optional distance_xyz; diff --git a/src/libslic3r/SurfaceMesh.hpp b/src/libslic3r/SurfaceMesh.hpp index a4b261ceb9..9e547eec49 100644 --- a/src/libslic3r/SurfaceMesh.hpp +++ b/src/libslic3r/SurfaceMesh.hpp @@ -2,6 +2,7 @@ #define slic3r_SurfaceMesh_hpp_ #include +#include namespace Slic3r { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 222d8087a0..e9fbd7f8c0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -16,15 +16,13 @@ #include +#include + #if ENABLE_MEASURE_GIZMO namespace Slic3r { namespace GUI { -using Edge = std::pair; -using Plane = std::tuple; -using Circle = std::tuple; - static const Slic3r::ColorRGBA SELECTED_1ST_COLOR = { 0.25f, 0.75f, 0.75f, 1.0f }; static const Slic3r::ColorRGBA SELECTED_2ND_COLOR = { 0.75f, 0.25f, 0.75f, 1.0f }; @@ -72,176 +70,9 @@ static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType t return ret; } -static Vec3d vector_direction(const Vec3d& from, const Vec3d& to) +static Vec3d edge_direction(const std::pair& e) { - return (to - from).normalized(); -} - -static Vec3d edge_direction(const Edge& e) -{ - return vector_direction(e.first, e.second); -} - - - - - - -/* - - -// returns: distance, 1st vertex, 2nd vertexs -static std::tuple distance_edge_edge(const Edge& e1, const Edge& e2) -{ - std::vector> distances; - auto add_point_edge_distance = [&distances](const Vec3d& v, const Edge& e) { - const auto [distance, v1, v2] = distance_point_edge(v, e); - const Vec3d e1e2 = e.second - e.first; - const Vec3d e1v2 = v2 - e.first; - if (e1v2.dot(e1e2) >= 0.0 && e1v2.norm() < e1e2.norm()) - distances.emplace_back(std::make_tuple(distance, v, v2)); - }; - - distances.emplace_back(std::make_tuple((e2.first - e1.first).norm(), e1.first, e2.first)); - distances.emplace_back(std::make_tuple((e2.second - e1.first).norm(), e1.first, e2.second)); - distances.emplace_back(std::make_tuple((e2.first - e1.second).norm(), e1.second, e2.first)); - distances.emplace_back(std::make_tuple((e2.second - e1.second).norm(), e1.second, e2.second)); - add_point_edge_distance(e1.first, e2); - add_point_edge_distance(e1.second, e2); - add_point_edge_distance(e2.first, e1); - add_point_edge_distance(e2.second, e1); - std::sort(distances.begin(), distances.end(), - [](const std::tuple& item1, const std::tuple& item2) { - return std::get<0>(item1) < std::get<0>(item2); - }); - return distances.front(); -} - -// returns: distance, 1st vertex, 2nd vertex -static std::tuple distance_edge_circle(const Edge& e, const Circle& c) -{ - const auto& [center, radius, normal] = c; - const Vec3d e1e2 = (e.second - e.first); - const Vec3d e1e2_unit = vector_direction(e.first, e.second); - - std::vector> distances; - distances.emplace_back(distance_point_circle(e.first, c)); - distances.emplace_back(distance_point_circle(e.second, c)); - - const Eigen::Hyperplane plane(e1e2_unit, center); - const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); - const Vec3d inter = line.intersectionPoint(plane); - const Vec3d e1inter = inter - e.first; - if (e1inter.dot(e1e2) >= 0.0 && e1inter.norm() < e1e2.norm()) - distances.emplace_back(distance_point_circle(inter, c)); - - std::sort(distances.begin(), distances.end(), - [](const std::tuple& item1, const std::tuple& item2) { - return std::get<0>(item1) < std::get<0>(item2); - }); - return distances.front(); -} - -// returns: distance, 1st vertex, 2nd vertex -static std::tuple distance_plane_plane(const Plane& p1, const Plane& p2) -{ - const auto& [idx1, normal1, origin1] = p1; - const auto& [idx2, normal2, origin2] = p2; - return (std::abs(std::abs(normal1.dot(normal2)) - 1.0) < EPSILON) ? distance_point_plane(origin2, p1) : - std::make_tuple(0.0, Vec3d::Zero(), Vec3d::Zero()); -} -*/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// returns: angle in rad, center of arc, radius of arc, whether or not the edges are coplanar -// After return, the edges are oriented so that they point away from their intersection point -static std::tuple angle_edge_edge(Edge& e1, Edge& e2) -{ - Vec3d e1_unit = edge_direction(e1); - Vec3d e2_unit = edge_direction(e2); - const double dot = e1_unit.dot(e2_unit); - // are edges parallel ? - if (std::abs(std::abs(dot) - 1.0) < EPSILON) - return std::make_tuple(0.0, e1.first, 0.0, true); - - // project edges on the plane defined by them - Vec3d normal = e1_unit.cross(e2_unit).normalized(); - const Eigen::Hyperplane plane(normal, e1.first); - Vec3d e11_proj = plane.projection(e1.first); - Vec3d e12_proj = plane.projection(e1.second); - Vec3d e21_proj = plane.projection(e2.first); - Vec3d e22_proj = plane.projection(e2.second); - - const bool coplanar = (e2.first - e21_proj).norm() < EPSILON && (e2.second - e22_proj).norm() < EPSILON; - - // rotate the plane to become the XY plane - auto qp = Eigen::Quaternion::FromTwoVectors(normal, Vec3d::UnitZ()); - auto qp_inverse = qp.inverse(); - const Vec3d e11_rot = qp * e11_proj; - const Vec3d e12_rot = qp * e12_proj; - const Vec3d e21_rot = qp * e21_proj; - const Vec3d e22_rot = qp * e22_proj; - - // discard Z - const Vec2d e11_rot_2d = Vec2d(e11_rot.x(), e11_rot.y()); - const Vec2d e12_rot_2d = Vec2d(e12_rot.x(), e12_rot.y()); - const Vec2d e21_rot_2d = Vec2d(e21_rot.x(), e21_rot.y()); - const Vec2d e22_rot_2d = Vec2d(e22_rot.x(), e22_rot.y()); - - // find intersection (arc center) of edges in XY plane - const Eigen::Hyperplane e1_rot_2d_line = Eigen::Hyperplane::Through(e11_rot_2d, e12_rot_2d); - const Eigen::Hyperplane e2_rot_2d_line = Eigen::Hyperplane::Through(e21_rot_2d, e22_rot_2d); - const Vec2d center_rot_2d = e1_rot_2d_line.intersection(e2_rot_2d_line); - - // arc center in original coordinate - const Vec3d center = qp_inverse * Vec3d(center_rot_2d.x(), center_rot_2d.y(), e11_rot.z()); - - // ensure the edges are pointing away from the center - if ((center_rot_2d - e11_rot_2d).squaredNorm() > (center_rot_2d - e12_rot_2d).squaredNorm()) { - std::swap(e1.first, e1.second); - std::swap(e11_proj, e12_proj); - e1_unit = -e1_unit; - } - if ((center_rot_2d - e21_rot_2d).squaredNorm() > (center_rot_2d - e22_rot_2d).squaredNorm()) { - std::swap(e2.first, e2.second); - std::swap(e21_proj, e22_proj); - e2_unit = -e2_unit; - } - - // arc angle - const double angle = std::acos(std::clamp(e1_unit.dot(e2_unit), -1.0, 1.0)); - // arc radius - const Vec3d e1_proj_mid = 0.5 * (e11_proj + e12_proj); - const Vec3d e2_proj_mid = 0.5 * (e21_proj + e22_proj); - const double radius = std::min((center - e1_proj_mid).norm(), (center - e2_proj_mid).norm()); - - return std::make_tuple(angle, center, radius, coplanar); + return (e.second - e.first).normalized(); } static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const std::vector>& planes_triangles, int idx) @@ -984,11 +815,9 @@ void GLGizmoMeasure::render_dimensioning() }; - auto point_edge = [this, shader, point_point](const Vec3d& v, const Edge& e) { - const double distance = m_measurement_result.distance_infinite->dist; - const Vec3d v1 = m_measurement_result.distance_infinite->from; + auto point_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { + std::pair e = f1.get_type() == Measure::SurfaceFeatureType::Edge ? f1.get_edge() : f2.get_edge(); const Vec3d v_proj = m_measurement_result.distance_infinite->to; - point_point(v1, v_proj); const Vec3d e1e2 = e.second - e.first; const Vec3d v_proje1 = v_proj - e.first; @@ -1020,21 +849,30 @@ void GLGizmoMeasure::render_dimensioning() } }; -/* - auto arc_edge_edge = [this, shader](const Edge& e1, const Edge& e2, const double* const force_radius = nullptr) { - Edge e1copy = e1; - Edge e2copy = e2; - const auto [angle, center, radius, coplanar] = angle_edge_edge(e1copy, e2copy); + auto arc_edge_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2, double* const force_radius = nullptr) { + Measure::MeasurementResult res = Measure::get_measurement(f1, f2); + const double angle = res.angle->angle; + const Vec3d center = res.angle->center; + const Vec3d e1_unit = res.angle->e1; + const Vec3d e2_unit = res.angle->e2; + const double radius = res.angle->radius; + const bool coplanar = res.angle->coplanar; - if (radius == 0.0) + std::pair e1 = m_selected_features.first.feature->get_edge(); + std::pair e2 = m_selected_features.second.feature->get_edge(); + + if ((e1.second - e1.first).dot(e1_unit) < 0.) + std::swap(e1.first, e1.second); + if ((e2.second - e2.first).dot(e2_unit) < 0.) + std::swap(e2.first, e2.second); + + if (radius == 0.) return; assert(force_radius == nullptr || *force_radius > 0.0); - const double draw_radius = (force_radius != nullptr) ? *force_radius : radius; + double draw_radius = force_radius ? *force_radius : radius; - const Vec3d e1_unit = edge_direction(e1copy); - const Vec3d e2_unit = edge_direction(e2copy); const Vec3d normal = e1_unit.cross(e2_unit).normalized(); if (!m_dimensioning.arc.is_initialized()) { @@ -1064,31 +902,33 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.arc.render(); // render edge 1 extension - const Vec3d e11e12 = e1copy.second - e1copy.first; - const Vec3d e11center = center - e1copy.first; + const Vec3d e11e12 = e1.second - e1.first; + const Vec3d e11center = center - e1.first; const double e11center_len = e11center.norm(); if (e11center_len > EPSILON && e11center.dot(e11e12) < 0.0) { const Camera& camera = wxGetApp().plater()->get_camera(); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), edge_direction(e1copy)) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), edge_direction(e1)) * Geometry::scale_transform({ e11center_len, 1.0f, 1.0f })); m_dimensioning.line.render(); } // render edge 2 extension - const Vec3d e21center = center - e2copy.first; + const Vec3d e21center = center - e2.first; const double e21center_len = e21center.norm(); if (e21center_len > EPSILON) { const Camera& camera = wxGetApp().plater()->get_camera(); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), edge_direction(e2copy)) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), edge_direction(e2)) * Geometry::scale_transform({ (coplanar && (force_radius == nullptr)) ? e21center_len : draw_radius, 1.0f, 1.0f })); m_dimensioning.line.render(); } }; + +/* auto arc_edge_plane = [this, arc_edge_edge](const Edge& e, const Plane& p) { const auto& [idx, normal, origin] = p; const Vec3d e1e2 = e.second - e.first; @@ -1122,29 +962,7 @@ void GLGizmoMeasure::render_dimensioning() const double radius = (inters - e1e2copy_mid).norm(); arc_edge_edge(ecopy, edge_on_plane, &radius); }; - - auto edge_edge = [point_point, arc_edge_edge](const Edge& e1, const Edge& e2) { - // distance - const auto [distance, v1, v2] = distance_edge_edge(e1, e2); - point_point(v1, v2); - // arc - arc_edge_edge(e1, e2); - }; - - auto edge_plane = [point_point, arc_edge_plane](const Edge& e, const Plane& p) { - // arc - arc_edge_plane(e, p); - }; - - auto edge_circle = [point_point](const Edge& e, const Circle& c) { - const auto [distance, v1, v2] = distance_edge_circle(e, c); - point_point(v1, v2); - }; - - auto plane_plane = [point_point](const Plane& p1, const Plane& p2) { - const auto [distance, v1, v2] = distance_plane_plane(p1, p2); - point_point(v1, v2); - };*/ +*/ shader->start_using(); @@ -1188,63 +1006,33 @@ void GLGizmoMeasure::render_dimensioning() glsafe(::glDisable(GL_DEPTH_TEST)); - // Render the arrow between the points that the backend passed: if (m_selected_features.second.feature.has_value()) { + // Render the arrow between the points that the backend passed: const Measure::DistAndPoints& dap = m_measurement_result.distance_infinite.has_value() ? *m_measurement_result.distance_infinite : *m_measurement_result.distance_strict; point_point(dap.from, dap.to); - } - // Now if one of the features is an edge, draw also the extension of the edge to where the dist is measured: - // TODO... + const Measure::SurfaceFeature& f1 = *m_selected_features.first.feature; + const Measure::SurfaceFeature& f2 = *m_selected_features.second.feature; + Measure::SurfaceFeatureType ft1 = f1.get_type(); + Measure::SurfaceFeatureType ft2 = f2.get_type(); - // point-edge - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { - point_edge(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_edge()); + // Where needed, draw also the extension of the edge to where the dist is measured: + if ((int(ft1) | int(ft2)) == + (int(Measure::SurfaceFeatureType::Point) | int(Measure::SurfaceFeatureType::Edge))) + point_edge(f1, f2); + + + // Now if there is an angle to show, draw the arc: + if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Edge) + arc_edge_edge(f1, f2); + //if (int(ft1) | int(ft2) == (int(Measure::SurfaceFeatureType::Edge) | int(Measure::SurfaceFeatureType::Plane))) + // arc_edge_plane(); } - /* - // edge-point - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - point_edge(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_edge()); - } - // edge-edge - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { - edge_edge(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_edge()); - } - // edge-plane - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { - edge_plane(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_plane()); - } - // edge-circle - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Circle) { - edge_circle(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_circle()); - } - // plane-edge - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { - edge_plane(m_selected_features.second.feature->get_edge(), m_selected_features.first.feature->get_plane()); - } - // plane-plane - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { - plane_plane(m_selected_features.first.feature->get_plane(), m_selected_features.second.feature->get_plane()); - } - // circle-edge - else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle && - m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { - edge_circle(m_selected_features.second.feature->get_edge(), m_selected_features.first.feature->get_circle()); - } -*/ - glsafe(::glEnable(GL_DEPTH_TEST)); shader->stop_using(); @@ -1533,7 +1321,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (ImGui::BeginTable("Measure", 3)) { if (measure.angle.has_value()) { ImGui::PushID((void*)(intptr_t)1); - add_measure_row_to_table(_u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(*measure.angle)), + add_measure_row_to_table(_u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(measure.angle->angle)), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } From 7ceead76c880929b958dab3947bf997c94abf8ee Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 29 Sep 2022 16:39:39 +0200 Subject: [PATCH 176/250] Measurement: moving arrow-drawing functions from frontend to the backend (4/4) --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index e9fbd7f8c0..568d5db3a2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -849,7 +849,7 @@ void GLGizmoMeasure::render_dimensioning() } }; - auto arc_edge_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2, double* const force_radius = nullptr) { + auto arc_edge_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2, const double* force_radius = nullptr) { Measure::MeasurementResult res = Measure::get_measurement(f1, f2); const double angle = res.angle->angle; const Vec3d center = res.angle->center; @@ -928,8 +928,12 @@ void GLGizmoMeasure::render_dimensioning() }; -/* - auto arc_edge_plane = [this, arc_edge_edge](const Edge& e, const Plane& p) { + + auto arc_edge_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { + + std::pair e = f1.get_type() == Measure::SurfaceFeatureType::Edge ? f1.get_edge() : f2.get_edge(); + std::tuple p = f1.get_type() == Measure::SurfaceFeatureType::Plane ? f1.get_plane() : f2.get_plane(); + const auto& [idx, normal, origin] = p; const Vec3d e1e2 = e.second - e.first; const double abs_dot = std::abs(normal.dot(edge_direction(e))); @@ -941,7 +945,7 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d inters = line.intersectionPoint(plane); // ensure the edge is pointing away from the intersection - Edge ecopy = e; + std::pair ecopy = e; Vec3d e1e2copy = e1e2; if ((ecopy.first - inters).squaredNorm() > (ecopy.second - inters).squaredNorm()) { std::swap(ecopy.first, ecopy.second); @@ -951,7 +955,7 @@ void GLGizmoMeasure::render_dimensioning() // calculate 2nd edge (on the plane) const Vec3d temp = normal.cross(e1e2copy); const Vec3d edge_on_plane_unit = normal.cross(temp).normalized(); - Edge edge_on_plane = { origin, origin + e1e2copy.norm() * edge_on_plane_unit }; + std::pair edge_on_plane = { origin, origin + e1e2copy.norm() * edge_on_plane_unit }; // ensure the 2nd edge is pointing in the correct direction const Vec3d test_edge = (edge_on_plane.second - edge_on_plane.first).cross(e1e2copy); @@ -960,9 +964,11 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d e1e2copy_mid = 0.5 * (ecopy.second + ecopy.first); const double radius = (inters - e1e2copy_mid).norm(); - arc_edge_edge(ecopy, edge_on_plane, &radius); + arc_edge_edge(Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, ecopy.second, ecopy.first, std::optional(), 0.), + Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, edge_on_plane.second, edge_on_plane.first, std::optional(), 0.), + &radius); }; -*/ + shader->start_using(); @@ -1028,8 +1034,8 @@ void GLGizmoMeasure::render_dimensioning() // Now if there is an angle to show, draw the arc: if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Edge) arc_edge_edge(f1, f2); - //if (int(ft1) | int(ft2) == (int(Measure::SurfaceFeatureType::Edge) | int(Measure::SurfaceFeatureType::Plane))) - // arc_edge_plane(); + if (int(ft1) | int(ft2) == (int(Measure::SurfaceFeatureType::Edge) | int(Measure::SurfaceFeatureType::Plane))) + arc_edge_plane(f1, f2); } From 3449ad0f73f7708dc32f67c2cecfa1dff8380c77 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 30 Sep 2022 08:52:38 +0200 Subject: [PATCH 177/250] Fixed crashing asserts due to a bug in the just merged branch --- src/libslic3r/Measure.cpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 26 +++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index fbf248c0f7..78d3d524e7 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -646,6 +646,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& angle = std::acos(std::abs(normal1.dot(normal2))); } result.angle = std::make_optional(AngleAndPoints(angle, Vec3d::Zero(), Vec3d::UnitX(), Vec3d::UnitX(), 0., false)); // TODO + result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 568d5db3a2..6aebd0fa37 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -858,8 +858,8 @@ void GLGizmoMeasure::render_dimensioning() const double radius = res.angle->radius; const bool coplanar = res.angle->coplanar; - std::pair e1 = m_selected_features.first.feature->get_edge(); - std::pair e2 = m_selected_features.second.feature->get_edge(); + std::pair e1 = f1.get_edge(); + std::pair e2 = f2.get_edge(); if ((e1.second - e1.first).dot(e1_unit) < 0.) std::swap(e1.first, e1.second); @@ -1019,23 +1019,25 @@ void GLGizmoMeasure::render_dimensioning() : *m_measurement_result.distance_strict; point_point(dap.from, dap.to); - const Measure::SurfaceFeature& f1 = *m_selected_features.first.feature; - const Measure::SurfaceFeature& f2 = *m_selected_features.second.feature; - Measure::SurfaceFeatureType ft1 = f1.get_type(); - Measure::SurfaceFeatureType ft2 = f2.get_type(); + const Measure::SurfaceFeature* f1 = &(*m_selected_features.first.feature); + const Measure::SurfaceFeature* f2 = &(*m_selected_features.second.feature); + Measure::SurfaceFeatureType ft1 = f1->get_type(); + Measure::SurfaceFeatureType ft2 = f2->get_type(); + // Order features by type so following conditions are simple. + if (ft2 > ft2) + std::swap(ft1, ft2); // Where needed, draw also the extension of the edge to where the dist is measured: - if ((int(ft1) | int(ft2)) == - (int(Measure::SurfaceFeatureType::Point) | int(Measure::SurfaceFeatureType::Edge))) - point_edge(f1, f2); + if (ft1 == Measure::SurfaceFeatureType::Point && ft2 == Measure::SurfaceFeatureType::Edge) + point_edge(*f1, *f2); // Now if there is an angle to show, draw the arc: if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Edge) - arc_edge_edge(f1, f2); - if (int(ft1) | int(ft2) == (int(Measure::SurfaceFeatureType::Edge) | int(Measure::SurfaceFeatureType::Plane))) - arc_edge_plane(f1, f2); + arc_edge_edge(*f1, *f2); + if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Plane) + arc_edge_plane(*f1, *f2); } From 6990c3faace6258f5b2062ec8927992b2dc7954f Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 30 Sep 2022 09:44:22 +0200 Subject: [PATCH 178/250] Measuring - GLGizmoMeasure - Visualization and selection of extra point for edges --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 28 ++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 6aebd0fa37..76d2dacd64 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -62,7 +62,7 @@ static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType t std::string ret; switch (type) { case Measure::SurfaceFeatureType::Point: { ret = _u8L("Vertex"); break; } - case Measure::SurfaceFeatureType::Edge: { ret = _u8L("Point on edge"); break; } + case Measure::SurfaceFeatureType::Edge: { ret = (hover_id == POINT_ID) ? _u8L("Center of edge") : _u8L("Point on edge"); break; } case Measure::SurfaceFeatureType::Circle: { ret = (hover_id == POINT_ID) ? _u8L("Center of circle") : _u8L("Point on circle"); break; } case Measure::SurfaceFeatureType::Plane: { ret = _u8L("Point on plane"); break; } default: { assert(false); break; } @@ -335,6 +335,8 @@ void GLGizmoMeasure::on_render() case Measure::SurfaceFeatureType::Edge: { m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); + if (m_curr_feature->get_extra_point().has_value()) + m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); break; } case Measure::SurfaceFeatureType::Circle: @@ -400,7 +402,11 @@ void GLGizmoMeasure::on_render() } case Measure::SurfaceFeatureType::Edge: { - m_curr_point_on_feature_position = m_volume_matrix.inverse() * position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); + const std::optional extra = m_curr_feature->get_extra_point(); + if (extra.has_value() && m_hover_id == POINT_ID) + m_curr_point_on_feature_position = *extra; + else + m_curr_point_on_feature_position = m_volume_matrix.inverse() * position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); break; } case Measure::SurfaceFeatureType::Plane: @@ -497,11 +503,25 @@ void GLGizmoMeasure::on_render() case Measure::SurfaceFeatureType::Edge: { const auto& [start, end] = feature.get_edge(); + // render extra point + const std::optional extra = m_curr_feature->get_extra_point(); + if (extra.has_value()) { + const Transform3d point_matrix = model_matrix * Geometry::translation_transform(*extra) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(point_matrix); + m_sphere.model.set_color(colors.front()); + m_sphere.model.render(); + if (update_raycasters) { + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(point_matrix); + } + } + // render edge const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start) * Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); set_matrix_uniforms(feature_matrix); - m_cylinder.model.set_color(colors.front()); + m_cylinder.model.set_color(colors.back()); m_cylinder.model.render(); if (update_raycasters) { auto it = m_raycasters.find(EDGE_ID); @@ -550,13 +570,13 @@ void GLGizmoMeasure::on_render() colors.emplace_back(hover_selection_color()); break; } + case Measure::SurfaceFeatureType::Edge: case Measure::SurfaceFeatureType::Circle: { colors.emplace_back((m_hover_id == POINT_ID) ? hover_selection_color() : hovering_color()); colors.emplace_back(hovering_color()); break; } - case Measure::SurfaceFeatureType::Edge: case Measure::SurfaceFeatureType::Plane: { colors.emplace_back(hovering_color()); From bca8597712b162df93fccd8a0eeb59b5a744a72f Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 30 Sep 2022 12:06:07 +0200 Subject: [PATCH 179/250] Follow-up of 9b915bdd0985fd3deb7b99f4d3598b63fa5b3b99 - Fixed crash --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 76d2dacd64..5cc4ce24e3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -504,7 +504,7 @@ void GLGizmoMeasure::on_render() { const auto& [start, end] = feature.get_edge(); // render extra point - const std::optional extra = m_curr_feature->get_extra_point(); + const std::optional extra = feature.get_extra_point(); if (extra.has_value()) { const Transform3d point_matrix = model_matrix * Geometry::translation_transform(*extra) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(point_matrix); From f051847ac6f9cbe47f21c6b4cf2b2b29553fe34f Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 30 Sep 2022 12:54:00 +0200 Subject: [PATCH 180/250] Measuring - Added a bunch of utility functions in Measure.hpp --- src/libslic3r/Measure.cpp | 6 ++--- src/libslic3r/Measure.hpp | 32 ++++++++++++++++++++++++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 21 ++++------------ 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 78d3d524e7..b27425ea91 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -633,11 +633,11 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& } else if (f1.get_type() == SurfaceFeatureType::Plane) { assert(f2.get_type() == SurfaceFeatureType::Plane); - const auto& [idx1, normal1, pt1] = f1.get_plane(); - const auto& [idx2, normal2, pt2] = f2.get_plane(); + const auto [idx1, normal1, pt1] = f1.get_plane(); + const auto [idx2, normal2, pt2] = f2.get_plane(); double angle = 0.; - if (normal1.isApprox(normal2)) { + if (are_parallel(normal1, normal2)) { // The planes are parallel, calculate distance. Eigen::Hyperplane plane(normal1, pt1); result.distance_infinite = std::make_optional(DistAndPoints{plane.absDistance(pt2), Vec3d::Zero(), Vec3d::Zero()}); diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index b88411a9f6..4ac56a87f3 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -142,6 +142,38 @@ struct MeasurementResult { // Returns distance/angle between two SurfaceFeatures. MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b); +inline Vec3d edge_direction(const Vec3d& from, const Vec3d& to) { return (to - from).normalized(); } +inline Vec3d edge_direction(const SurfaceFeature& edge) { + assert(edge.get_type() == SurfaceFeatureType::Edge); + const auto [from, to] = edge.get_edge(); + return edge_direction(from, to); +} + +inline Vec3d plane_normal(const SurfaceFeature& plane) { + assert(plane.get_type() == SurfaceFeatureType::Plane); + return std::get<1>(plane.get_plane()); +} + +inline bool are_parallel(const Vec3d& v1, const Vec3d& v2) { return std::abs(std::abs(v1.dot(v2)) - 1.0) < EPSILON; } +inline bool are_perpendicular(const Vec3d& v1, const Vec3d& v2) { return std::abs(v1.dot(v2)) < EPSILON; } + +inline bool are_parallel(const SurfaceFeature& f1, const SurfaceFeature& f2) { + if (f1.get_type() == SurfaceFeatureType::Edge && f2.get_type() == SurfaceFeatureType::Edge) + return are_parallel(edge_direction(f1), edge_direction(f2)); + else if (f1.get_type() == SurfaceFeatureType::Edge && f2.get_type() == SurfaceFeatureType::Plane) + return are_perpendicular(edge_direction(f1), plane_normal(f2)); + else + return false; +} + +inline bool are_perpendicular(const SurfaceFeature& f1, const SurfaceFeature& f2) { + if (f1.get_type() == SurfaceFeatureType::Edge && f2.get_type() == SurfaceFeatureType::Edge) + return are_perpendicular(edge_direction(f1), edge_direction(f2)); + else if (f1.get_type() == SurfaceFeatureType::Edge && f2.get_type() == SurfaceFeatureType::Plane) + return are_parallel(edge_direction(f1), plane_normal(f2)); + else + return false; +} } // namespace Measure } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 5cc4ce24e3..421dfbedd5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -70,11 +70,6 @@ static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType t return ret; } -static Vec3d edge_direction(const std::pair& e) -{ - return (e.second - e.first).normalized(); -} - static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const std::vector>& planes_triangles, int idx) { assert(0 <= idx && idx < (int)planes_triangles.size()); @@ -123,8 +118,6 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) else if (mouse_event.LeftDown()) { if (m_hover_id != -1) { SelectedFeatures selected_features_old = m_selected_features; - - m_mouse_left_down = true; auto item_from_feature = [this]() { @@ -834,7 +827,6 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.triangle.render(); }; - auto point_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { std::pair e = f1.get_type() == Measure::SurfaceFeatureType::Edge ? f1.get_edge() : f2.get_edge(); const Vec3d v_proj = m_measurement_result.distance_infinite->to; @@ -929,7 +921,7 @@ void GLGizmoMeasure::render_dimensioning() const Camera& camera = wxGetApp().plater()->get_camera(); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), edge_direction(e1)) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e1.first, e1.second)) * Geometry::scale_transform({ e11center_len, 1.0f, 1.0f })); m_dimensioning.line.render(); } @@ -941,14 +933,12 @@ void GLGizmoMeasure::render_dimensioning() const Camera& camera = wxGetApp().plater()->get_camera(); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), edge_direction(e2)) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e2.first, e2.second)) * Geometry::scale_transform({ (coplanar && (force_radius == nullptr)) ? e21center_len : draw_radius, 1.0f, 1.0f })); m_dimensioning.line.render(); } }; - - auto arc_edge_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { std::pair e = f1.get_type() == Measure::SurfaceFeatureType::Edge ? f1.get_edge() : f2.get_edge(); @@ -956,8 +946,8 @@ void GLGizmoMeasure::render_dimensioning() const auto& [idx, normal, origin] = p; const Vec3d e1e2 = e.second - e.first; - const double abs_dot = std::abs(normal.dot(edge_direction(e))); - if (abs_dot < EPSILON || std::abs(abs_dot - 1.0) < EPSILON) + const double abs_dot = std::abs(normal.dot(Measure::edge_direction(f1))); + if (Measure::are_parallel(f1, f2) || Measure::are_perpendicular(f1, f2)) return; const Eigen::Hyperplane plane(normal, origin); @@ -1052,11 +1042,10 @@ void GLGizmoMeasure::render_dimensioning() if (ft1 == Measure::SurfaceFeatureType::Point && ft2 == Measure::SurfaceFeatureType::Edge) point_edge(*f1, *f2); - // Now if there is an angle to show, draw the arc: if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Edge) arc_edge_edge(*f1, *f2); - if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Plane) + else if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Plane) arc_edge_plane(*f1, *f2); } From cbd228731a180c50fa25d31f7db5483df7638d8e Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 30 Sep 2022 13:18:17 +0200 Subject: [PATCH 181/250] Measuring - Refactoring and bug fixing in GLGizmoMeasure::render_dimensioning() --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 36 +++++++++++------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 421dfbedd5..9a62a8c39f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -828,7 +828,8 @@ void GLGizmoMeasure::render_dimensioning() }; auto point_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { - std::pair e = f1.get_type() == Measure::SurfaceFeatureType::Edge ? f1.get_edge() : f2.get_edge(); + assert(f1.get_type() == Measure::SurfaceFeatureType::Point && f2.get_type() == Measure::SurfaceFeatureType::Edge); + const std::pair e = f2.get_edge(); const Vec3d v_proj = m_measurement_result.distance_infinite->to; const Vec3d e1e2 = e.second - e.first; @@ -862,7 +863,8 @@ void GLGizmoMeasure::render_dimensioning() }; auto arc_edge_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2, const double* force_radius = nullptr) { - Measure::MeasurementResult res = Measure::get_measurement(f1, f2); + assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Edge); + const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); const double angle = res.angle->angle; const Vec3d center = res.angle->center; const Vec3d e1_unit = res.angle->e1; @@ -940,13 +942,9 @@ void GLGizmoMeasure::render_dimensioning() }; auto arc_edge_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { - - std::pair e = f1.get_type() == Measure::SurfaceFeatureType::Edge ? f1.get_edge() : f2.get_edge(); - std::tuple p = f1.get_type() == Measure::SurfaceFeatureType::Plane ? f1.get_plane() : f2.get_plane(); - - const auto& [idx, normal, origin] = p; - const Vec3d e1e2 = e.second - e.first; - const double abs_dot = std::abs(normal.dot(Measure::edge_direction(f1))); + assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Plane); + std::pair e = f1.get_edge(); + const auto [idx, normal, origin] = f2.get_plane(); if (Measure::are_parallel(f1, f2) || Measure::are_perpendicular(f1, f2)) return; @@ -956,21 +954,20 @@ void GLGizmoMeasure::render_dimensioning() // ensure the edge is pointing away from the intersection std::pair ecopy = e; - Vec3d e1e2copy = e1e2; - if ((ecopy.first - inters).squaredNorm() > (ecopy.second - inters).squaredNorm()) { + if ((ecopy.first - inters).squaredNorm() > (ecopy.second - inters).squaredNorm()) std::swap(ecopy.first, ecopy.second); - e1e2copy = -e1e2copy; - } // calculate 2nd edge (on the plane) - const Vec3d temp = normal.cross(e1e2copy); + const Vec3d e1e2 = ecopy.second - ecopy.first; + const double e1e2_len = e1e2.norm(); + const Vec3d temp = normal.cross(e1e2); const Vec3d edge_on_plane_unit = normal.cross(temp).normalized(); - std::pair edge_on_plane = { origin, origin + e1e2copy.norm() * edge_on_plane_unit }; + std::pair edge_on_plane = { origin, origin + e1e2_len * edge_on_plane_unit }; // ensure the 2nd edge is pointing in the correct direction - const Vec3d test_edge = (edge_on_plane.second - edge_on_plane.first).cross(e1e2copy); + const Vec3d test_edge = (edge_on_plane.second - edge_on_plane.first).cross(e1e2); if (test_edge.dot(temp) < 0.0) - edge_on_plane = { origin, origin - e1e2copy.norm() * edge_on_plane_unit }; + edge_on_plane = { origin, origin - e1e2_len * edge_on_plane_unit }; const Vec3d e1e2copy_mid = 0.5 * (ecopy.second + ecopy.first); const double radius = (inters - e1e2copy_mid).norm(); @@ -1035,8 +1032,10 @@ void GLGizmoMeasure::render_dimensioning() Measure::SurfaceFeatureType ft2 = f2->get_type(); // Order features by type so following conditions are simple. - if (ft2 > ft2) + if (ft1 > ft2) { std::swap(ft1, ft2); + std::swap(f1, f2); + } // Where needed, draw also the extension of the edge to where the dist is measured: if (ft1 == Measure::SurfaceFeatureType::Point && ft2 == Measure::SurfaceFeatureType::Edge) @@ -1048,7 +1047,6 @@ void GLGizmoMeasure::render_dimensioning() else if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Plane) arc_edge_plane(*f1, *f2); } - glsafe(::glEnable(GL_DEPTH_TEST)); From 1c084c4f62b9919f56be3a23b76fb795aab54df4 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 30 Sep 2022 14:13:17 +0200 Subject: [PATCH 182/250] Measuring - Some refactoring --- src/libslic3r/Measure.cpp | 21 ++++++++++----------- src/libslic3r/Measure.hpp | 7 +++++-- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 18 ++++++++++-------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index b27425ea91..ff07aa0810 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -250,7 +250,7 @@ void MeasuringImpl::extract_features() // Add the circle and remember indices into borders. const auto& [center, radius] = get_center_and_radius(border, start_idx, i, trafo); circles_idxs.emplace_back(start_idx, i); - circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::optional(), radius)); + circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius)); circle = false; } } @@ -269,7 +269,7 @@ void MeasuringImpl::extract_features() const Vec3d center = std::get<0>(circles[i].get_circle()); for (int j=(int)circles_idxs[i].first + 1; j<=(int)circles_idxs[i].second; ++j) plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, - border[j-1], border[j], std::make_optional(center), 0.)); + border[j - 1], border[j], std::make_optional(center))); } else { // This will be handled just like a regular edge. circles_idxs.erase(circles_idxs.begin() + i); @@ -288,8 +288,8 @@ void MeasuringImpl::extract_features() for (int i=1; i (int)circles_idxs[cidx].first) i = circles_idxs[cidx++].second; - else plane.surface_features.emplace_back(SurfaceFeature( - SurfaceFeatureType::Edge, border[i-1], border[i], std::optional(), 0.)); + else + plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[i - 1], border[i])); } // FIXME Throw away / do not create edges which are parts of circles or @@ -307,7 +307,7 @@ void MeasuringImpl::extract_features() // The last surface feature is the plane itself. plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Plane, - plane.normal, plane.borders.front().front(), std::optional(), i + 0.0001)); + plane.normal, plane.borders.front().front(), std::nullopt, i + 0.0001)); plane.borders.clear(); plane.borders.shrink_to_fit(); @@ -433,13 +433,12 @@ std::vector> Measuring::get_planes_triangle_indices() const static AngleAndPoints angle_edge_edge(const std::pair& e1, const std::pair& e2) { - Vec3d e1_unit = (e1.second - e1.first).normalized(); - Vec3d e2_unit = (e2.second - e2.first).normalized(); - const double dot = e1_unit.dot(e2_unit); - // are edges parallel ? - if (std::abs(std::abs(dot) - 1.0) < EPSILON) + if (are_parallel(e1, e2)) return AngleAndPoints(0.0, e1.first, Vec3d::UnitX(), Vec3d::UnitX(), 0., true); + Vec3d e1_unit = edge_direction(e1.first, e1.second); + Vec3d e2_unit = edge_direction(e2.first, e2.second); + // project edges on the plane defined by them Vec3d normal = e1_unit.cross(e2_unit).normalized(); const Eigen::Hyperplane plane(normal, e1.first); @@ -562,7 +561,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& std::vector distances; auto add_point_edge_distance = [&distances](const Vec3d& v, const std::pair& e) { - const MeasurementResult res = get_measurement(SurfaceFeature(v), SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second, std::optional(), 0.)); + const MeasurementResult res = get_measurement(SurfaceFeature(v), SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second)); double distance = res.distance_strict->dist; Vec3d v2 = res.distance_strict->to; diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 4ac56a87f3..1c51289e8d 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -25,8 +25,8 @@ enum class SurfaceFeatureType : int { class SurfaceFeature { public: - SurfaceFeature(SurfaceFeatureType type, const Vec3d& pt1, const Vec3d& pt2, std::optional pt3, double value) - : m_type{type}, m_pt1{pt1}, m_pt2{pt2}, m_pt3{pt3}, m_value{value} {} + SurfaceFeature(SurfaceFeatureType type, const Vec3d& pt1, const Vec3d& pt2, std::optional pt3 = std::nullopt, double value = 0.0) + : m_type{ type }, m_pt1{ pt1 }, m_pt2{ pt2 }, m_pt3{ pt3 }, m_value{ value } {} explicit SurfaceFeature(const Vec3d& pt) : m_type{SurfaceFeatureType::Point}, m_pt1{pt} {} @@ -157,6 +157,9 @@ inline Vec3d plane_normal(const SurfaceFeature& plane) { inline bool are_parallel(const Vec3d& v1, const Vec3d& v2) { return std::abs(std::abs(v1.dot(v2)) - 1.0) < EPSILON; } inline bool are_perpendicular(const Vec3d& v1, const Vec3d& v2) { return std::abs(v1.dot(v2)) < EPSILON; } +inline bool are_parallel(const std::pair& e1, const std::pair& e2) { + return are_parallel(e1.second - e1.first, e2.second - e2.first); +} inline bool are_parallel(const SurfaceFeature& f1, const SurfaceFeature& f2) { if (f1.get_type() == SurfaceFeatureType::Edge && f2.get_type() == SurfaceFeatureType::Edge) return are_parallel(edge_direction(f1), edge_direction(f2)); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 9a62a8c39f..d6488b83a9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -887,8 +887,6 @@ void GLGizmoMeasure::render_dimensioning() double draw_radius = force_radius ? *force_radius : radius; - const Vec3d normal = e1_unit.cross(e2_unit).normalized(); - if (!m_dimensioning.arc.is_initialized()) { const unsigned int resolution = std::max(2, 64 * angle / double(PI)); GLModel::Geometry init_data; @@ -898,6 +896,7 @@ void GLGizmoMeasure::render_dimensioning() init_data.reserve_indices(resolution + 1); // vertices + indices + const Vec3d normal = e1_unit.cross(e2_unit).normalized(); const double step = angle / double(resolution); for (unsigned int i = 0; i <= resolution; ++i) { const double a = step * double(i); @@ -943,16 +942,19 @@ void GLGizmoMeasure::render_dimensioning() auto arc_edge_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Plane); - std::pair e = f1.get_edge(); - const auto [idx, normal, origin] = f2.get_plane(); if (Measure::are_parallel(f1, f2) || Measure::are_perpendicular(f1, f2)) return; + const std::pair e = f1.get_edge(); + const auto [idx, normal, origin] = f2.get_plane(); + + // ensure the edge is pointing away from the intersection + // 1st calculate instersection between edge and plane const Eigen::Hyperplane plane(normal, origin); const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); const Vec3d inters = line.intersectionPoint(plane); - // ensure the edge is pointing away from the intersection + // then verify edge direction and revert it, if needed std::pair ecopy = e; if ((ecopy.first - inters).squaredNorm() > (ecopy.second - inters).squaredNorm()) std::swap(ecopy.first, ecopy.second); @@ -971,9 +973,9 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d e1e2copy_mid = 0.5 * (ecopy.second + ecopy.first); const double radius = (inters - e1e2copy_mid).norm(); - arc_edge_edge(Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, ecopy.second, ecopy.first, std::optional(), 0.), - Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, edge_on_plane.second, edge_on_plane.first, std::optional(), 0.), - &radius); + arc_edge_edge(Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, ecopy.first, ecopy.second), + Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, edge_on_plane.first, edge_on_plane.second), + &radius); }; From 0a8f500819d8f6d06c2e11a5bd041d12cc3ac181 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 30 Sep 2022 14:35:39 +0200 Subject: [PATCH 183/250] Measuring - struct AngleAndPoints reworked as struct AngleAndEdges --- src/libslic3r/Measure.cpp | 14 +++++++------- src/libslic3r/Measure.hpp | 20 +++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 15 +++++---------- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index ff07aa0810..b9fb0f3448 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -427,14 +427,12 @@ std::vector> Measuring::get_planes_triangle_indices() const } +const AngleAndEdges AngleAndEdges::Dummy = { 0.0, Vec3d::Zero(), { Vec3d::Zero(), Vec3d::Zero() }, { Vec3d::Zero(), Vec3d::Zero() }, 0.0, true }; - - - -static AngleAndPoints angle_edge_edge(const std::pair& e1, const std::pair& e2) +static AngleAndEdges angle_edge_edge(std::pair e1, std::pair e2) { if (are_parallel(e1, e2)) - return AngleAndPoints(0.0, e1.first, Vec3d::UnitX(), Vec3d::UnitX(), 0., true); + return AngleAndEdges::Dummy; Vec3d e1_unit = edge_direction(e1.first, e1.second); Vec3d e2_unit = edge_direction(e2.first, e2.second); @@ -474,10 +472,12 @@ static AngleAndPoints angle_edge_edge(const std::pair& e1, const s // ensure the edges are pointing away from the center if ((center_rot_2d - e11_rot_2d).squaredNorm() > (center_rot_2d - e12_rot_2d).squaredNorm()) { std::swap(e11_proj, e12_proj); + std::swap(e1.first, e1.second); e1_unit = -e1_unit; } if ((center_rot_2d - e21_rot_2d).squaredNorm() > (center_rot_2d - e22_rot_2d).squaredNorm()) { std::swap(e21_proj, e22_proj); + std::swap(e2.first, e2.second); e2_unit = -e2_unit; } @@ -488,7 +488,7 @@ static AngleAndPoints angle_edge_edge(const std::pair& e1, const s const Vec3d e2_proj_mid = 0.5 * (e21_proj + e22_proj); const double radius = std::min((center - e1_proj_mid).norm(), (center - e2_proj_mid).norm()); - return AngleAndPoints(angle, center, e1_unit, e2_unit, radius, coplanar); + return { angle, center, e1, e2, radius, coplanar }; } @@ -644,7 +644,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& // Planes are not parallel, calculate angle. angle = std::acos(std::abs(normal1.dot(normal2))); } - result.angle = std::make_optional(AngleAndPoints(angle, Vec3d::Zero(), Vec3d::UnitX(), Vec3d::UnitX(), 0., false)); // TODO + result.angle = std::make_optional(AngleAndEdges(angle, Vec3d::Zero(), { Vec3d::Zero(), Vec3d::Zero() }, { Vec3d::Zero(), Vec3d::Zero() }, 0., false)); // TODO result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO } diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 1c51289e8d..c59c9bbbc7 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -26,7 +26,7 @@ enum class SurfaceFeatureType : int { class SurfaceFeature { public: SurfaceFeature(SurfaceFeatureType type, const Vec3d& pt1, const Vec3d& pt2, std::optional pt3 = std::nullopt, double value = 0.0) - : m_type{ type }, m_pt1{ pt1 }, m_pt2{ pt2 }, m_pt3{ pt3 }, m_value{ value } {} + : m_type(type), m_pt1(pt1), m_pt2(pt2), m_pt3(pt3), m_value(value) {} explicit SurfaceFeature(const Vec3d& pt) : m_type{SurfaceFeatureType::Point}, m_pt1{pt} {} @@ -117,19 +117,21 @@ struct DistAndPoints { Vec3d to; }; -struct AngleAndPoints { - AngleAndPoints(double angle_, Vec3d center_, Vec3d e1_, Vec3d e2_, double radius_, bool coplanar_) - : angle(angle_), center(center_), e1(e1_), e2(e2_), radius(radius_), coplanar(coplanar_) {} +struct AngleAndEdges { + AngleAndEdges(double angle_, const Vec3d& center_, const std::pair& e1_, const std::pair& e2_, double radius_, bool coplanar_) + : angle(angle_), center(center_), e1(e1_), e2(e2_), radius(radius_), coplanar(coplanar_) {} double angle; Vec3d center; - Vec3d e1; - Vec3d e2; + std::pair e1; + std::pair e2; double radius; bool coplanar; + + static const AngleAndEdges Dummy; }; struct MeasurementResult { - std::optional angle; + std::optional angle; std::optional distance_infinite; std::optional distance_strict; std::optional distance_xyz; @@ -143,10 +145,10 @@ struct MeasurementResult { MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b); inline Vec3d edge_direction(const Vec3d& from, const Vec3d& to) { return (to - from).normalized(); } +inline Vec3d edge_direction(const std::pair& e) { return edge_direction(e.first, e.second); } inline Vec3d edge_direction(const SurfaceFeature& edge) { assert(edge.get_type() == SurfaceFeatureType::Edge); - const auto [from, to] = edge.get_edge(); - return edge_direction(from, to); + return edge_direction(edge.get_edge()); } inline Vec3d plane_normal(const SurfaceFeature& plane) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index d6488b83a9..138e8c54a3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -867,19 +867,11 @@ void GLGizmoMeasure::render_dimensioning() const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); const double angle = res.angle->angle; const Vec3d center = res.angle->center; - const Vec3d e1_unit = res.angle->e1; - const Vec3d e2_unit = res.angle->e2; + const std::pair e1 = res.angle->e1; + const std::pair e2 = res.angle->e2; const double radius = res.angle->radius; const bool coplanar = res.angle->coplanar; - std::pair e1 = f1.get_edge(); - std::pair e2 = f2.get_edge(); - - if ((e1.second - e1.first).dot(e1_unit) < 0.) - std::swap(e1.first, e1.second); - if ((e2.second - e2.first).dot(e2_unit) < 0.) - std::swap(e2.first, e2.second); - if (radius == 0.) return; @@ -887,6 +879,9 @@ void GLGizmoMeasure::render_dimensioning() double draw_radius = force_radius ? *force_radius : radius; + const Vec3d e1_unit = Measure::edge_direction(e1); + const Vec3d e2_unit = Measure::edge_direction(e2); + if (!m_dimensioning.arc.is_initialized()) { const unsigned int resolution = std::max(2, 64 * angle / double(PI)); GLModel::Geometry init_data; From 3f8820bf203bab125864ef3d0159a4f3883d36ca Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 30 Sep 2022 15:50:31 +0200 Subject: [PATCH 184/250] Measuring - Calculation of angle between edge and plane moved to backend --- src/libslic3r/Measure.cpp | 48 ++++++++++++++++++++-- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 52 ++++++------------------ 2 files changed, 56 insertions(+), 44 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index b9fb0f3448..f2cbb9f640 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -429,7 +429,7 @@ std::vector> Measuring::get_planes_triangle_indices() const const AngleAndEdges AngleAndEdges::Dummy = { 0.0, Vec3d::Zero(), { Vec3d::Zero(), Vec3d::Zero() }, { Vec3d::Zero(), Vec3d::Zero() }, 0.0, true }; -static AngleAndEdges angle_edge_edge(std::pair e1, std::pair e2) +static AngleAndEdges angle_edge_edge(const std::pair& e1, const std::pair& e2) { if (are_parallel(e1, e2)) return AngleAndEdges::Dummy; @@ -470,14 +470,16 @@ static AngleAndEdges angle_edge_edge(std::pair e1, std::pair out_e1 = e1; + std::pair out_e2 = e2; if ((center_rot_2d - e11_rot_2d).squaredNorm() > (center_rot_2d - e12_rot_2d).squaredNorm()) { std::swap(e11_proj, e12_proj); - std::swap(e1.first, e1.second); + std::swap(out_e1.first, out_e1.second); e1_unit = -e1_unit; } if ((center_rot_2d - e21_rot_2d).squaredNorm() > (center_rot_2d - e22_rot_2d).squaredNorm()) { std::swap(e21_proj, e22_proj); - std::swap(e2.first, e2.second); + std::swap(out_e2.first, out_e2.second); e2_unit = -e2_unit; } @@ -488,9 +490,46 @@ static AngleAndEdges angle_edge_edge(std::pair e1, std::pair& e, const std::tuple& p) +{ + const auto& [idx, normal, origin] = p; + const Vec3d e1e2_unit = edge_direction(e); + if (are_parallel(e1e2_unit, normal) || are_perpendicular(e1e2_unit, normal)) + return AngleAndEdges::Dummy; + + // ensure the edge is pointing away from the intersection + // 1st calculate instersection between edge and plane + const Eigen::Hyperplane plane(normal, origin); + const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); + const Vec3d inters = line.intersectionPoint(plane); + + // then verify edge direction and revert it, if needed + Vec3d e1 = e.first; + Vec3d e2 = e.second; + if ((e1 - inters).squaredNorm() > (e2 - inters).squaredNorm()) + std::swap(e1, e2); + + const Vec3d e1e2 = e2 - e1; + const double e1e2_len = e1e2.norm(); + + // calculate 2nd edge (on the plane) + const Vec3d temp = normal.cross(e1e2); + const Vec3d edge_on_plane_unit = normal.cross(temp).normalized(); + std::pair edge_on_plane = { origin, origin + e1e2_len * edge_on_plane_unit }; + + // ensure the 2nd edge is pointing in the correct direction + const Vec3d test_edge = (edge_on_plane.second - edge_on_plane.first).cross(e1e2); + if (test_edge.dot(temp) < 0.0) + edge_on_plane = { origin, origin - e1e2_len * edge_on_plane_unit }; + + AngleAndEdges ret = angle_edge_edge({ e1, e2 }, edge_on_plane); + const Vec3d e1e2copy_mid = 0.5 * (e1 + e2); + ret.radius = (inters - e1e2copy_mid).norm(); + return ret; +} @@ -615,6 +654,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO + result.angle = angle_edge_plane(f1.get_edge(), f2.get_plane()); } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 138e8c54a3..db015bf1c2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -862,22 +862,20 @@ void GLGizmoMeasure::render_dimensioning() } }; - auto arc_edge_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2, const double* force_radius = nullptr) { + auto arc_edge_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2, double radius = 0.0) { assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Edge); const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); const double angle = res.angle->angle; const Vec3d center = res.angle->center; const std::pair e1 = res.angle->e1; const std::pair e2 = res.angle->e2; - const double radius = res.angle->radius; + const double calc_radius = res.angle->radius; const bool coplanar = res.angle->coplanar; - if (radius == 0.) + if (calc_radius == 0.0) return; - assert(force_radius == nullptr || *force_radius > 0.0); - - double draw_radius = force_radius ? *force_radius : radius; + const double draw_radius = (radius > 0.0) ? radius : calc_radius; const Vec3d e1_unit = Measure::edge_direction(e1); const Vec3d e2_unit = Measure::edge_direction(e2); @@ -930,50 +928,24 @@ void GLGizmoMeasure::render_dimensioning() shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e2.first, e2.second)) * - Geometry::scale_transform({ (coplanar && (force_radius == nullptr)) ? e21center_len : draw_radius, 1.0f, 1.0f })); + Geometry::scale_transform({ (coplanar && radius > 0.0) ? e21center_len : draw_radius, 1.0f, 1.0f })); m_dimensioning.line.render(); } }; auto arc_edge_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Plane); - if (Measure::are_parallel(f1, f2) || Measure::are_perpendicular(f1, f2)) + const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); + const std::pair e1 = res.angle->e1; + const std::pair e2 = res.angle->e2; + const double calc_radius = res.angle->radius; + if (calc_radius == 0.0) return; - const std::pair e = f1.get_edge(); - const auto [idx, normal, origin] = f2.get_plane(); - - // ensure the edge is pointing away from the intersection - // 1st calculate instersection between edge and plane - const Eigen::Hyperplane plane(normal, origin); - const Eigen::ParametrizedLine line = Eigen::ParametrizedLine::Through(e.first, e.second); - const Vec3d inters = line.intersectionPoint(plane); - - // then verify edge direction and revert it, if needed - std::pair ecopy = e; - if ((ecopy.first - inters).squaredNorm() > (ecopy.second - inters).squaredNorm()) - std::swap(ecopy.first, ecopy.second); - - // calculate 2nd edge (on the plane) - const Vec3d e1e2 = ecopy.second - ecopy.first; - const double e1e2_len = e1e2.norm(); - const Vec3d temp = normal.cross(e1e2); - const Vec3d edge_on_plane_unit = normal.cross(temp).normalized(); - std::pair edge_on_plane = { origin, origin + e1e2_len * edge_on_plane_unit }; - - // ensure the 2nd edge is pointing in the correct direction - const Vec3d test_edge = (edge_on_plane.second - edge_on_plane.first).cross(e1e2); - if (test_edge.dot(temp) < 0.0) - edge_on_plane = { origin, origin - e1e2_len * edge_on_plane_unit }; - - const Vec3d e1e2copy_mid = 0.5 * (ecopy.second + ecopy.first); - const double radius = (inters - e1e2copy_mid).norm(); - arc_edge_edge(Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, ecopy.first, ecopy.second), - Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, edge_on_plane.first, edge_on_plane.second), - &radius); + arc_edge_edge(Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, e1.first, e1.second), + Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, e2.first, e2.second), calc_radius); }; - shader->start_using(); if (!m_dimensioning.line.is_initialized()) { From 00fb180c70d2089df6ab0f1dbff375a92c7b7663 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 3 Oct 2022 09:14:47 +0200 Subject: [PATCH 185/250] Measuring - Gizmo measure shows dimensioning for angle plane-plane --- src/libslic3r/Measure.cpp | 54 ++++++++++++++++++++++-- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 15 +++++++ 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index f2cbb9f640..4d37ea712c 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -306,8 +306,17 @@ void MeasuringImpl::extract_features() } // The last surface feature is the plane itself. + Vec3d cog = Vec3d::Zero(); + size_t counter = 0; + for (const std::vector& b : plane.borders) { + for (size_t i = 1; i < b.size(); ++i) { + cog += b[i]; + ++counter; + } + } + cog /= double(counter); plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Plane, - plane.normal, plane.borders.front().front(), std::nullopt, i + 0.0001)); + plane.normal, cog, std::optional(), i + 0.0001)); plane.borders.clear(); plane.borders.shrink_to_fit(); @@ -526,11 +535,48 @@ static AngleAndEdges angle_edge_plane(const std::pair& e, const st edge_on_plane = { origin, origin - e1e2_len * edge_on_plane_unit }; AngleAndEdges ret = angle_edge_edge({ e1, e2 }, edge_on_plane); - const Vec3d e1e2copy_mid = 0.5 * (e1 + e2); - ret.radius = (inters - e1e2copy_mid).norm(); + ret.radius = (inters - 0.5 * (e1 + e2)).norm(); return ret; } +static AngleAndEdges angle_plane_plane(const std::tuple& p1, const std::tuple& p2) +{ + const auto& [idx1, normal1, origin1] = p1; + const auto& [idx2, normal2, origin2] = p2; + + // are planes parallel ? + if (are_parallel(normal1, normal2)) + return AngleAndEdges::Dummy; + + auto intersection_plane_plane = [](const Vec3d& n1, const Vec3d& o1, const Vec3d& n2, const Vec3d& o2) { + Eigen::MatrixXd m(2, 3); + m << n1.x(), n1.y(), n1.z(), n2.x(), n2.y(), n2.z(); + Eigen::VectorXd b(2); + b << o1.dot(n1), o2.dot(n2); + Eigen::VectorXd x = m.colPivHouseholderQr().solve(b); + return std::make_pair(n1.cross(n2).normalized(), Vec3d(x(0), x(1), x(2))); + }; + + // Calculate intersection line between planes + const auto [intersection_line_direction, intersection_line_origin] = intersection_plane_plane(normal1, origin1, normal2, origin2); + + // Project planes' origin on intersection line + const Eigen::ParametrizedLine intersection_line = Eigen::ParametrizedLine(intersection_line_origin, intersection_line_direction); + const Vec3d origin1_proj = intersection_line.projection(origin1); + const Vec3d origin2_proj = intersection_line.projection(origin2); + + // Calculate edges on planes + const Vec3d edge_on_plane1_unit = (origin1 - origin1_proj).normalized(); + const Vec3d edge_on_plane2_unit = (origin2 - origin2_proj).normalized(); + const double edges_angle = std::acos(std::clamp(edge_on_plane1_unit.dot(edge_on_plane2_unit), -1.0, 1.0)); + const double radius = std::max(10.0, std::max((origin1 - origin1_proj).norm(), (origin2 - origin2_proj).norm())); + const std::pair edge_on_plane1 = { origin1_proj + radius * edge_on_plane1_unit, origin1_proj + 2.0 * radius * edge_on_plane1_unit }; + const std::pair edge_on_plane2 = { origin2_proj + radius * edge_on_plane2_unit, origin2_proj + 2.0 * radius * edge_on_plane2_unit }; + + AngleAndEdges ret = angle_edge_edge(edge_on_plane1, edge_on_plane2); + ret.radius = radius; + return ret; +} @@ -684,7 +730,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& // Planes are not parallel, calculate angle. angle = std::acos(std::abs(normal1.dot(normal2))); } - result.angle = std::make_optional(AngleAndEdges(angle, Vec3d::Zero(), { Vec3d::Zero(), Vec3d::Zero() }, { Vec3d::Zero(), Vec3d::Zero() }, 0., false)); // TODO + result.angle = angle_plane_plane(f1.get_plane(), f2.get_plane()); result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index db015bf1c2..b790e43306 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -946,6 +946,19 @@ void GLGizmoMeasure::render_dimensioning() Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, e2.first, e2.second), calc_radius); }; + auto arc_plane_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { + assert(f1.get_type() == Measure::SurfaceFeatureType::Plane && f2.get_type() == Measure::SurfaceFeatureType::Plane); + const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); + const std::pair e1 = res.angle->e1; + const std::pair e2 = res.angle->e2; + const double calc_radius = res.angle->radius; + if (calc_radius == 0.0) + return; + + arc_edge_edge(Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, e1.first, e1.second), + Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, e2.first, e2.second), calc_radius); + }; + shader->start_using(); if (!m_dimensioning.line.is_initialized()) { @@ -1015,6 +1028,8 @@ void GLGizmoMeasure::render_dimensioning() arc_edge_edge(*f1, *f2); else if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Plane) arc_edge_plane(*f1, *f2); + else if (ft1 == Measure::SurfaceFeatureType::Plane && ft2 == Measure::SurfaceFeatureType::Plane) + arc_plane_plane(*f1, *f2); } glsafe(::glEnable(GL_DEPTH_TEST)); From ab3eb723c9686674593e952868a29dfd965af653 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 3 Oct 2022 10:50:38 +0200 Subject: [PATCH 186/250] Measuring - Gizmo measure shows value of distance dimensioning in 3D scene --- src/libslic3r/Measure.cpp | 8 ++-- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 51 ++++++++++++++++-------- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 4d37ea712c..529c6f1231 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -663,10 +663,10 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& distances.emplace_back((e2.second - e1.first).norm(), e1.first, e2.second); distances.emplace_back((e2.first - e1.second).norm(), e1.second, e2.first); distances.emplace_back((e2.second - e1.second).norm(), e1.second, e2.second); - add_point_edge_distance(e1.first, e2); - add_point_edge_distance(e1.second, e2); - add_point_edge_distance(e2.first, e1); - add_point_edge_distance(e2.second, e1); +// add_point_edge_distance(e1.first, e2); +// add_point_edge_distance(e1.second, e2); +// add_point_edge_distance(e2.first, e1); +// add_point_edge_distance(e2.second, e1); auto it = std::min_element(distances.begin(), distances.end(), [](const DistAndPoints& item1, const DistAndPoints& item2) { return item1.dist < item2.dist; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index b790e43306..4efaf67d78 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -44,6 +44,20 @@ static const std::string CTRL_STR = #endif //__APPLE__ ; +static std::string format_double(double value) +{ + char buf[1024]; + sprintf(buf, "%.3f", value); + return std::string(buf); +} + +static std::string format_vec3(const Vec3d& v) +{ + char buf[1024]; + sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", v.x(), v.y(), v.z()); + return std::string(buf); +} + static std::string surface_feature_type_as_string(Measure::SurfaceFeatureType type) { switch (type) @@ -778,7 +792,7 @@ void GLGizmoMeasure::render_dimensioning() if (shader == nullptr) return; - auto point_point = [this, shader](const Vec3d& v1, const Vec3d& v2) { + auto point_point = [this, shader](const Vec3d& v1, const Vec3d& v2, float distance) { if (v1.isApprox(v2)) return; @@ -825,6 +839,23 @@ void GLGizmoMeasure::render_dimensioning() ss_to_ndc_matrix * Geometry::translation_transform(v2ss_3) * q21ss : ss_to_ndc_matrix * Geometry::translation_transform(v2ss_3) * q12ss); m_dimensioning.triangle.render(); + + if (distance > 0.0) { + const Vec2d label_position = 0.5 * (v1ss + v2ss); + m_imgui->set_next_window_pos(label_position.x(), viewport[3] - label_position.y(), ImGuiCond_Always, 0.0f, 1.0f); + m_imgui->set_next_window_bg_alpha(0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + m_imgui->begin(_L("##distance"), ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); + ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); + std::string txt = format_double(distance) + " "; + if (wxGetApp().app_config->get("use_inches") == "1") + txt += _u8L("in"); + else + txt += _u8L("mm"); + m_imgui->text(txt); + m_imgui->end(); + ImGui::PopStyleVar(); + } }; auto point_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { @@ -872,7 +903,7 @@ void GLGizmoMeasure::render_dimensioning() const double calc_radius = res.angle->radius; const bool coplanar = res.angle->coplanar; - if (calc_radius == 0.0) + if (std::abs(angle) < EPSILON || std::abs(calc_radius) < EPSILON) return; const double draw_radius = (radius > 0.0) ? radius : calc_radius; @@ -1006,7 +1037,7 @@ void GLGizmoMeasure::render_dimensioning() const Measure::DistAndPoints& dap = m_measurement_result.distance_infinite.has_value() ? *m_measurement_result.distance_infinite : *m_measurement_result.distance_strict; - point_point(dap.from, dap.to); + point_point(dap.from, dap.to, dap.dist); const Measure::SurfaceFeature* f1 = &(*m_selected_features.first.feature); const Measure::SurfaceFeature* f2 = &(*m_selected_features.second.feature); @@ -1052,20 +1083,6 @@ static void add_strings_row_to_table(ImGuiWrapper& imgui, const std::string& col add_row_to_table([&]() { imgui.text_colored(col_1_color, col_1); }, [&]() { imgui.text_colored(col_2_color, col_2); }); }; -static std::string format_double(double value) -{ - char buf[1024]; - sprintf(buf, "%.3f", value); - return std::string(buf); -} - -static std::string format_vec3(const Vec3d& v) -{ - char buf[1024]; - sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", v.x(), v.y(), v.z()); - return std::string(buf); -} - #if ENABLE_MEASURE_GIZMO_DEBUG void GLGizmoMeasure::render_debug_dialog() { From 5127d47fe04eb7ff6283581d62801e5cd442b9ad Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 3 Oct 2022 11:36:08 +0200 Subject: [PATCH 187/250] Measuring - Gizmo measure shows value of angle dimensioning in 3D scene --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 63 ++++++++++++++---------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 4efaf67d78..8a4cd17d94 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -840,22 +840,18 @@ void GLGizmoMeasure::render_dimensioning() ss_to_ndc_matrix * Geometry::translation_transform(v2ss_3) * q12ss); m_dimensioning.triangle.render(); - if (distance > 0.0) { - const Vec2d label_position = 0.5 * (v1ss + v2ss); - m_imgui->set_next_window_pos(label_position.x(), viewport[3] - label_position.y(), ImGuiCond_Always, 0.0f, 1.0f); - m_imgui->set_next_window_bg_alpha(0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); - m_imgui->begin(_L("##distance"), ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); - ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); - std::string txt = format_double(distance) + " "; - if (wxGetApp().app_config->get("use_inches") == "1") - txt += _u8L("in"); - else - txt += _u8L("mm"); - m_imgui->text(txt); - m_imgui->end(); - ImGui::PopStyleVar(); - } + const Vec2d label_position = 0.5 * (v1ss + v2ss); + m_imgui->set_next_window_pos(label_position.x(), viewport[3] - label_position.y(), ImGuiCond_Always, 0.0f, 1.0f); + m_imgui->set_next_window_bg_alpha(0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + m_imgui->begin(_L("##distance"), ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); + ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); + const bool use_inches = wxGetApp().app_config->get("use_inches") == "1"; + const std::string txt = use_inches ? format_double(ObjectManipulation::mm_to_in * distance) + " " + _u8L("in") : + format_double(distance) + " " + _u8L("mm"); + m_imgui->text(txt); + m_imgui->end(); + ImGui::PopStyleVar(); }; auto point_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { @@ -911,8 +907,11 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d e1_unit = Measure::edge_direction(e1); const Vec3d e2_unit = Measure::edge_direction(e2); + const unsigned int resolution = std::max(2, 64 * angle / double(PI)); + const double step = angle / double(resolution); + const Vec3d normal = e1_unit.cross(e2_unit).normalized(); + if (!m_dimensioning.arc.is_initialized()) { - const unsigned int resolution = std::max(2, 64 * angle / double(PI)); GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3 }; init_data.color = ColorRGBA::WHITE(); @@ -920,8 +919,6 @@ void GLGizmoMeasure::render_dimensioning() init_data.reserve_indices(resolution + 1); // vertices + indices - const Vec3d normal = e1_unit.cross(e2_unit).normalized(); - const double step = angle / double(resolution); for (unsigned int i = 0; i <= resolution; ++i) { const double a = step * double(i); const Vec3d v = draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(a, normal)) * e1_unit); @@ -943,8 +940,6 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d e11center = center - e1.first; const double e11center_len = e11center.norm(); if (e11center_len > EPSILON && e11center.dot(e11e12) < 0.0) { - const Camera& camera = wxGetApp().plater()->get_camera(); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e1.first, e1.second)) * Geometry::scale_transform({ e11center_len, 1.0f, 1.0f })); @@ -955,13 +950,29 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d e21center = center - e2.first; const double e21center_len = e21center.norm(); if (e21center_len > EPSILON) { - const Camera& camera = wxGetApp().plater()->get_camera(); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e2.first, e2.second)) * Geometry::scale_transform({ (coplanar && radius > 0.0) ? e21center_len : draw_radius, 1.0f, 1.0f })); m_dimensioning.line.render(); } + + // world coordinates + const Vec3d label_position_world = Geometry::translation_transform(center) * (draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(step * 0.5 * double(resolution), normal)) * e1_unit)); + + // screen coordinates + const std::array& viewport = camera.get_viewport(); + const Vec2d label_position_ss = DimensioningHelper::model_to_ss(label_position_world, m_volume_matrix, + camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix(), viewport); + + m_imgui->set_next_window_pos(label_position_ss.x(), viewport[3] - label_position_ss.y(), ImGuiCond_Always, 0.0f, 1.0f); + m_imgui->set_next_window_bg_alpha(0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + m_imgui->begin(_L("##angle"), ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); + ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); + std::string txt = format_double(Geometry::rad2deg(angle)) + "°"; + m_imgui->text(txt); + m_imgui->end(); + ImGui::PopStyleVar(); }; auto arc_edge_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { @@ -1341,7 +1352,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } - if (measure.distance_infinite.has_value()) { + if (measure.distance_infinite.has_value() && measure.distance_infinite->dist > 0.0) { double distance = measure.distance_infinite->dist; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; @@ -1350,7 +1361,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } - if (measure.distance_strict.has_value()) { + if (measure.distance_strict.has_value() && measure.distance_strict->dist > 0.0) { double distance = measure.distance_strict->dist; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; @@ -1359,7 +1370,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } - if (measure.distance_xyz.has_value()) { + if (measure.distance_xyz.has_value() && measure.distance_xyz->norm() > EPSILON) { Vec3d distance = *measure.distance_xyz; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; From 14fc691b36fffd6a37d943a2fa3cdb3ffad58207 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 3 Oct 2022 12:54:22 +0200 Subject: [PATCH 188/250] Measuring - Gizmo measure shows arrows at endpoints of angle dimensioning --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 35 ++++++++++++++++++------ 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 8a4cd17d94..f55874071d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -929,13 +929,30 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.arc.init_from(std::move(init_data)); } - // render arc + // arc const Camera& camera = wxGetApp().plater()->get_camera(); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center)); m_dimensioning.arc.render(); - // render edge 1 extension + // arrows + auto render_arrow = [this, shader, &camera, &normal, ¢er, &e1_unit, draw_radius, step, resolution](unsigned int endpoint_id) { + const double angle = (endpoint_id == 1) ? 0.0 : step * double(resolution); + const Vec3d position_model = Geometry::translation_transform(center) * (draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(angle, normal)) * e1_unit)); + const Vec3d direction_model = (endpoint_id == 1) ? -normal.cross(position_model - center).normalized() : normal.cross(position_model - center).normalized(); + const Transform3d view_model_matrix = camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(position_model) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), direction_model) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal) * + Geometry::scale_transform(camera.get_inv_zoom()); + shader->set_uniform("view_model_matrix", view_model_matrix); + m_dimensioning.triangle.render(); + }; + + glsafe(::glDisable(GL_CULL_FACE)); + render_arrow(1); + render_arrow(2); + glsafe(::glEnable(GL_CULL_FACE)); + + // edge 1 extension const Vec3d e11e12 = e1.second - e1.first; const Vec3d e11center = center - e1.first; const double e11center_len = e11center.norm(); @@ -946,7 +963,7 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.line.render(); } - // render edge 2 extension + // edge 2 extension const Vec3d e21center = center - e2.first; const double e21center_len = e21center.norm(); if (e21center_len > EPSILON) { @@ -956,12 +973,13 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.line.render(); } - // world coordinates - const Vec3d label_position_world = Geometry::translation_transform(center) * (draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(step * 0.5 * double(resolution), normal)) * e1_unit)); + // label + // label model coordinates + const Vec3d label_position_model = Geometry::translation_transform(center) * (draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(step * 0.5 * double(resolution), normal)) * e1_unit)); - // screen coordinates + // label screen coordinates const std::array& viewport = camera.get_viewport(); - const Vec2d label_position_ss = DimensioningHelper::model_to_ss(label_position_world, m_volume_matrix, + const Vec2d label_position_ss = DimensioningHelper::model_to_ss(label_position_model, m_volume_matrix, camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix(), viewport); m_imgui->set_next_window_pos(label_position_ss.x(), viewport[3] - label_position_ss.y(), ImGuiCond_Always, 0.0f, 1.0f); @@ -969,8 +987,7 @@ void GLGizmoMeasure::render_dimensioning() ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); m_imgui->begin(_L("##angle"), ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); - std::string txt = format_double(Geometry::rad2deg(angle)) + "°"; - m_imgui->text(txt); + m_imgui->text(format_double(Geometry::rad2deg(angle)) + "°"); m_imgui->end(); ImGui::PopStyleVar(); }; From f4304b15c736334a3b9b4f0e522b87ef42bbd176 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 3 Oct 2022 13:53:14 +0200 Subject: [PATCH 189/250] Follow-up of a5a4fc4dcfb3e5f4ea267e137e70e49b89499d1f - Fixed arrows orientations --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index f55874071d..ff59ba0a5c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -940,9 +940,10 @@ void GLGizmoMeasure::render_dimensioning() const double angle = (endpoint_id == 1) ? 0.0 : step * double(resolution); const Vec3d position_model = Geometry::translation_transform(center) * (draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(angle, normal)) * e1_unit)); const Vec3d direction_model = (endpoint_id == 1) ? -normal.cross(position_model - center).normalized() : normal.cross(position_model - center).normalized(); + const auto qz = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); + const auto qx = Eigen::Quaternion::FromTwoVectors(qz * Vec3d::UnitX(), direction_model); const Transform3d view_model_matrix = camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(position_model) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), direction_model) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal) * - Geometry::scale_transform(camera.get_inv_zoom()); + qx * qz * Geometry::scale_transform(camera.get_inv_zoom()); shader->set_uniform("view_model_matrix", view_model_matrix); m_dimensioning.triangle.render(); }; From afa003f3cbae0bf9558ac8bd851c665492633b99 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 3 Oct 2022 13:59:11 +0200 Subject: [PATCH 190/250] Fixed warnings --- src/libslic3r/Measure.cpp | 21 ++++++++++----------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 4 ++-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 529c6f1231..cce63e6465 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -568,7 +568,6 @@ static AngleAndEdges angle_plane_plane(const std::tuple& p1, // Calculate edges on planes const Vec3d edge_on_plane1_unit = (origin1 - origin1_proj).normalized(); const Vec3d edge_on_plane2_unit = (origin2 - origin2_proj).normalized(); - const double edges_angle = std::acos(std::clamp(edge_on_plane1_unit.dot(edge_on_plane2_unit), -1.0, 1.0)); const double radius = std::max(10.0, std::max((origin1 - origin1_proj).norm(), (origin2 - origin2_proj).norm())); const std::pair edge_on_plane1 = { origin1_proj + radius * edge_on_plane1_unit, origin1_proj + 2.0 * radius * edge_on_plane1_unit }; const std::pair edge_on_plane2 = { origin2_proj + radius * edge_on_plane2_unit, origin2_proj + 2.0 * radius * edge_on_plane2_unit }; @@ -645,16 +644,16 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& if (f2.get_type() == SurfaceFeatureType::Edge) { std::vector distances; - auto add_point_edge_distance = [&distances](const Vec3d& v, const std::pair& e) { - const MeasurementResult res = get_measurement(SurfaceFeature(v), SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second)); - double distance = res.distance_strict->dist; - Vec3d v2 = res.distance_strict->to; - - const Vec3d e1e2 = e.second - e.first; - const Vec3d e1v2 = v2 - e.first; - if (e1v2.dot(e1e2) >= 0.0 && e1v2.norm() < e1e2.norm()) - distances.emplace_back(distance, v, v2); - }; +// auto add_point_edge_distance = [&distances](const Vec3d& v, const std::pair& e) { +// const MeasurementResult res = get_measurement(SurfaceFeature(v), SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second)); +// double distance = res.distance_strict->dist; +// Vec3d v2 = res.distance_strict->to; +// +// const Vec3d e1e2 = e.second - e.first; +// const Vec3d e1v2 = v2 - e.first; +// if (e1v2.dot(e1e2) >= 0.0 && e1v2.norm() < e1e2.norm()) +// distances.emplace_back(distance, v, v2); +// }; std::pair e1 = f1.get_edge(); std::pair e2 = f2.get_edge(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index ff59ba0a5c..13415877f9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -993,7 +993,7 @@ void GLGizmoMeasure::render_dimensioning() ImGui::PopStyleVar(); }; - auto arc_edge_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { + auto arc_edge_plane = [arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Plane); const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); const std::pair e1 = res.angle->e1; @@ -1006,7 +1006,7 @@ void GLGizmoMeasure::render_dimensioning() Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, e2.first, e2.second), calc_radius); }; - auto arc_plane_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { + auto arc_plane_plane = [arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { assert(f1.get_type() == Measure::SurfaceFeatureType::Plane && f2.get_type() == Measure::SurfaceFeatureType::Plane); const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); const std::pair e1 = res.angle->e1; From 29d61277740f2ebcde3dd7d0989348861c6827f3 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 4 Oct 2022 08:17:43 +0200 Subject: [PATCH 191/250] Measuring - Fixes in plane-plane measurement - Measurements validation - Fixes in dimensioning rendering --- src/libslic3r/Measure.cpp | 20 +++++++++++--------- src/libslic3r/Measure.hpp | 4 ++++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 20 ++++++++++++-------- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index cce63e6465..2905f82553 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -719,21 +719,23 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& const auto [idx1, normal1, pt1] = f1.get_plane(); const auto [idx2, normal2, pt2] = f2.get_plane(); - double angle = 0.; if (are_parallel(normal1, normal2)) { // The planes are parallel, calculate distance. - Eigen::Hyperplane plane(normal1, pt1); - result.distance_infinite = std::make_optional(DistAndPoints{plane.absDistance(pt2), Vec3d::Zero(), Vec3d::Zero()}); - } else { - // Planes are not parallel, calculate angle. - angle = std::acos(std::abs(normal1.dot(normal2))); + const Eigen::Hyperplane plane(normal1, pt1); + result.distance_infinite = std::make_optional(DistAndPoints{ plane.absDistance(pt2), pt2, plane.projection(pt2) }); // TODO } - result.angle = angle_plane_plane(f1.get_plane(), f2.get_plane()); - result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO + else + result.angle = angle_plane_plane(f1.get_plane(), f2.get_plane()); } - + // validation + if (result.distance_infinite.has_value() && result.distance_infinite->dist < EPSILON) + result.distance_infinite.reset(); + if (result.distance_strict.has_value() && result.distance_strict->dist < EPSILON) + result.distance_strict.reset(); + if (result.angle.has_value() && std::abs(result.angle->angle) < EPSILON) + result.angle.reset(); return result; } diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index c59c9bbbc7..df148da761 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -136,6 +136,10 @@ struct MeasurementResult { std::optional distance_strict; std::optional distance_xyz; + bool has_distance_data() const { + return distance_infinite.has_value() || distance_strict.has_value(); + } + bool has_any_data() const { return angle.has_value() || distance_infinite.has_value() || distance_strict.has_value() || distance_xyz.has_value(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 13415877f9..5c467e0203 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1062,11 +1062,14 @@ void GLGizmoMeasure::render_dimensioning() glsafe(::glDisable(GL_DEPTH_TEST)); if (m_selected_features.second.feature.has_value()) { - // Render the arrow between the points that the backend passed: - const Measure::DistAndPoints& dap = m_measurement_result.distance_infinite.has_value() - ? *m_measurement_result.distance_infinite - : *m_measurement_result.distance_strict; - point_point(dap.from, dap.to, dap.dist); + const bool has_distance = m_measurement_result.has_distance_data(); + if (has_distance) { + // Render the arrow between the points that the backend passed: + const Measure::DistAndPoints& dap = m_measurement_result.distance_infinite.has_value() + ? *m_measurement_result.distance_infinite + : *m_measurement_result.distance_strict; + point_point(dap.from, dap.to, dap.dist); + } const Measure::SurfaceFeature* f1 = &(*m_selected_features.first.feature); const Measure::SurfaceFeature* f2 = &(*m_selected_features.second.feature); @@ -1080,7 +1083,7 @@ void GLGizmoMeasure::render_dimensioning() } // Where needed, draw also the extension of the edge to where the dist is measured: - if (ft1 == Measure::SurfaceFeatureType::Point && ft2 == Measure::SurfaceFeatureType::Edge) + if (has_distance && ft1 == Measure::SurfaceFeatureType::Point && ft2 == Measure::SurfaceFeatureType::Edge) point_edge(*f1, *f2); // Now if there is an angle to show, draw the arc: @@ -1370,7 +1373,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } - if (measure.distance_infinite.has_value() && measure.distance_infinite->dist > 0.0) { + if (measure.distance_infinite.has_value()) { double distance = measure.distance_infinite->dist; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; @@ -1379,7 +1382,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } - if (measure.distance_strict.has_value() && measure.distance_strict->dist > 0.0) { + if (measure.distance_strict.has_value() && + (!measure.distance_infinite.has_value() || std::abs(measure.distance_strict->dist - measure.distance_infinite->dist) > EPSILON)) { double distance = measure.distance_strict->dist; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; From 3ef040cba8f49b2c92902d06705324a97e1522c1 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 4 Oct 2022 08:45:39 +0200 Subject: [PATCH 192/250] Measuring - Refactoring in GLGizmoMeasure imgui dialog related to units --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 5c467e0203..84b4fc0a97 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1232,7 +1232,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } const bool use_inches = wxGetApp().app_config->get("use_inches") == "1"; - const std::string units = use_inches ? _u8L(" (in)") : _u8L(" (mm)"); + const std::string units = use_inches ? " " + _u8L("in") : " " + _u8L("mm"); if (m_curr_feature.has_value()) { const Measure::SurfaceFeatureType feature_type = m_curr_feature->get_type(); @@ -1263,7 +1263,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } add_strings_row_to_table(*m_imgui, _u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, _u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, _u8L("Length") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Length"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } case Measure::SurfaceFeatureType::Circle: @@ -1276,7 +1276,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit radius = ObjectManipulation::mm_to_in * radius; } add_strings_row_to_table(*m_imgui, _u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, _u8L("Radius") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Radius"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; } @@ -1369,7 +1369,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (ImGui::BeginTable("Measure", 3)) { if (measure.angle.has_value()) { ImGui::PushID((void*)(intptr_t)1); - add_measure_row_to_table(_u8L("Angle") + _u8L(" (°)"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(measure.angle->angle)), + add_measure_row_to_table(_u8L("Angle"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(measure.angle->angle)) + "°", ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } @@ -1378,7 +1378,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (use_inches) distance = ObjectManipulation::mm_to_in * distance; ImGui::PushID((void*)(intptr_t)2); - add_measure_row_to_table(_u8L("Distance Infinite") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), + add_measure_row_to_table(_u8L("Distance Infinite"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } @@ -1388,7 +1388,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (use_inches) distance = ObjectManipulation::mm_to_in * distance; ImGui::PushID((void*)(intptr_t)3); - add_measure_row_to_table(_u8L("Distance Strict") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance), + add_measure_row_to_table(_u8L("Distance Strict"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } @@ -1397,7 +1397,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (use_inches) distance = ObjectManipulation::mm_to_in * distance; ImGui::PushID((void*)(intptr_t)4); - add_measure_row_to_table(_u8L("Distance XYZ") + units, ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), + add_measure_row_to_table(_u8L("Distance XYZ"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); } From e37187a5461f3447a7abeaddf0287139f02ce4f7 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 4 Oct 2022 11:26:11 +0200 Subject: [PATCH 193/250] Measuring - Gizmo measure shows dimensioning for distance plane-circle --- src/libslic3r/Measure.cpp | 58 +++++++++++++++++------- src/libslic3r/Measure.hpp | 5 +- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 2905f82553..852e9268cc 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -47,6 +47,7 @@ public: std::vector get_all_features() const; std::optional get_feature(size_t face_idx, const Vec3d& point) const; std::vector> get_planes_triangle_indices() const; + const std::vector& get_plane_features(unsigned int plane_id) const; private: void update_planes(); @@ -398,6 +399,11 @@ std::vector> MeasuringImpl::get_planes_triangle_indices() const return out; } +const std::vector& MeasuringImpl::get_plane_features(unsigned int plane_id) const +{ + assert(plane_id < m_planes.size()); + return m_planes[plane_id].surface_features; +} @@ -435,6 +441,10 @@ std::vector> Measuring::get_planes_triangle_indices() const return priv->get_planes_triangle_indices(); } +const std::vector& Measuring::get_plane_features(unsigned int plane_id) const +{ + return priv->get_plane_features(plane_id); +} const AngleAndEdges AngleAndEdges::Dummy = { 0.0, Vec3d::Zero(), { Vec3d::Zero(), Vec3d::Zero() }, { Vec3d::Zero(), Vec3d::Zero() }, 0.0, true }; @@ -583,7 +593,7 @@ static AngleAndEdges angle_plane_plane(const std::tuple& p1, -MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b) +MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b, const Measuring* measuring) { assert(a.get_type() != SurfaceFeatureType::Undef && b.get_type() != SurfaceFeatureType::Undef); @@ -604,25 +614,25 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Edge) { - const auto& [s,e] = f2.get_edge(); - Eigen::ParametrizedLine line(s, (e-s).normalized()); - double dist_inf = line.distance(f1.get_point()); - Vec3d proj = line.projection(f1.get_point()); - double len_sq = (e-s).squaredNorm(); - double dist_start_sq = (proj-s).squaredNorm(); - double dist_end_sq = (proj-e).squaredNorm(); + const auto [s,e] = f2.get_edge(); + const Eigen::ParametrizedLine line(s, (e-s).normalized()); + const double dist_inf = line.distance(f1.get_point()); + const Vec3d proj = line.projection(f1.get_point()); + const double len_sq = (e-s).squaredNorm(); + const double dist_start_sq = (proj-s).squaredNorm(); + const double dist_end_sq = (proj-e).squaredNorm(); if (dist_start_sq < len_sq && dist_end_sq < len_sq) { // projection falls on the line - the strict distance is the same as infinite result.distance_strict = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); } else { // the result is the closer of the endpoints - bool s_is_closer = dist_start_sq < dist_end_sq; - result.distance_strict = std::make_optional(DistAndPoints{std::sqrt(std::min(dist_start_sq, dist_end_sq) + dist_inf), f1.get_point(), s_is_closer ? s : e}); + const bool s_is_closer = dist_start_sq < dist_end_sq; + result.distance_strict = std::make_optional(DistAndPoints{std::sqrt(std::min(dist_start_sq, dist_end_sq) + sqr(dist_inf)), f1.get_point(), s_is_closer ? s : e}); } result.distance_infinite = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Circle) { // Find a plane containing normal, center and the point. - const auto& [c, radius, n] = f2.get_circle(); + const auto [c, radius, n] = f2.get_circle(); Eigen::Hyperplane circle_plane(n, c); Vec3d proj = circle_plane.projection(f1.get_point()); double dist = std::sqrt(std::pow((proj - c).norm() - radius, 2.) + @@ -632,7 +642,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& result.distance_strict = std::make_optional(DistAndPoints{dist, f1.get_point(), p_on_circle}); // TODO /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { - const auto& [idx, normal, pt] = f2.get_plane(); + const auto [idx, normal, pt] = f2.get_plane(); Eigen::Hyperplane plane(normal, pt); result.distance_infinite = std::make_optional(DistAndPoints{plane.absDistance(f1.get_point()), f1.get_point(), plane.projection(f1.get_point())}); // TODO // TODO: result.distance_strict = @@ -678,7 +688,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& const std::pair e = f1.get_edge(); const auto& [center, radius, normal] = f2.get_circle(); const Vec3d e1e2 = (e.second - e.first); - const Vec3d e1e2_unit = (e.second - e.first).normalized(); + const Vec3d e1e2_unit = e1e2.normalized(); std::vector distances; distances.emplace_back(*get_measurement(SurfaceFeature(e.first), f2).distance_strict); @@ -709,14 +719,30 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { - result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO + assert(measuring != nullptr); + + const auto [center, radius, normal1] = f1.get_circle(); + const auto [idx2, normal2, origin2] = f2.get_plane(); + + const bool coplanar = are_parallel(normal1, normal2) && Eigen::Hyperplane(normal1, center).absDistance(origin2) < EPSILON; + if (!coplanar) { + const std::vector& plane_features = measuring->get_plane_features(idx2); + std::vector distances; + for (const SurfaceFeature& sf : plane_features) { + if (sf.get_type() == SurfaceFeatureType::Edge) + distances.push_back(*get_measurement(sf, f1).distance_infinite); + } + auto it = std::min_element(distances.begin(), distances.end(), + [](const DistAndPoints& item1, const DistAndPoints& item2) { + return item1.dist < item2.dist; + }); + result.distance_infinite = std::make_optional(DistAndPoints{ it->dist, it->from, it->to }); + } } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// } else if (f1.get_type() == SurfaceFeatureType::Plane) { - assert(f2.get_type() == SurfaceFeatureType::Plane); - const auto [idx1, normal1, pt1] = f1.get_plane(); const auto [idx2, normal2, pt2] = f2.get_plane(); diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index df148da761..2e17eea5c5 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -105,6 +105,9 @@ public: // call too often. std::vector> get_planes_triangle_indices() const; + // Returns the surface features of the plane with the given index + const std::vector& get_plane_features(unsigned int plane_id) const; + private: std::unique_ptr priv; }; @@ -146,7 +149,7 @@ struct MeasurementResult { }; // Returns distance/angle between two SurfaceFeatures. -MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b); +MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& b, const Measuring* measuring = nullptr); inline Vec3d edge_direction(const Vec3d& from, const Vec3d& to) { return (to - from).normalized(); } inline Vec3d edge_direction(const std::pair& e) { return edge_direction(e.first, e.second); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 84b4fc0a97..31ce08fa74 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -175,7 +175,7 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) } if (m_selected_features != selected_features_old && m_selected_features.second.feature.has_value()) - m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature); + m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); return true; } From d561fb97c72930946c7f7b39d3c11ee380d49813 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 4 Oct 2022 12:36:38 +0200 Subject: [PATCH 194/250] Measuring - Gizmo measure shows dimensioning for distance edge-plane --- src/libslic3r/Measure.cpp | 63 +++++++++++++++++++++--- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 39 ++++++++------- 2 files changed, 77 insertions(+), 25 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 852e9268cc..ea68503254 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -708,7 +708,45 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& result.distance_infinite = std::make_optional(DistAndPoints{it->dist, it->from, it->to}); /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { - result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO + assert(measuring != nullptr); + + const auto [from, to] = f1.get_edge(); + const auto [idx, normal, origin] = f2.get_plane(); + + const Vec3d edge_unit = (to - from).normalized(); + if (are_perpendicular(edge_unit, normal)) { + std::vector distances; + const Eigen::Hyperplane plane(normal, origin); + distances.push_back(DistAndPoints{ plane.absDistance(from), from, plane.projection(from) }); + distances.push_back(DistAndPoints{ plane.absDistance(to), to, plane.projection(to) }); + auto it = std::min_element(distances.begin(), distances.end(), + [](const DistAndPoints& item1, const DistAndPoints& item2) { + return item1.dist < item2.dist; + }); + result.distance_infinite = std::make_optional(DistAndPoints{ it->dist, it->from, it->to }); + } + else { + const std::vector& plane_features = measuring->get_plane_features(idx); + std::vector distances; + for (const SurfaceFeature& sf : plane_features) { + if (sf.get_type() == SurfaceFeatureType::Edge) { + const auto m = get_measurement(sf, f1); + if (!m.distance_infinite.has_value()) { + distances.clear(); + break; + } + else + distances.push_back(*m.distance_infinite); + } + } + if (!distances.empty()) { + auto it = std::min_element(distances.begin(), distances.end(), + [](const DistAndPoints& item1, const DistAndPoints& item2) { + return item1.dist < item2.dist; + }); + result.distance_infinite = std::make_optional(DistAndPoints{ it->dist, it->from, it->to }); + } + } result.angle = angle_edge_plane(f1.get_edge(), f2.get_plane()); } /////////////////////////////////////////////////////////////////////////// @@ -729,14 +767,23 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& const std::vector& plane_features = measuring->get_plane_features(idx2); std::vector distances; for (const SurfaceFeature& sf : plane_features) { - if (sf.get_type() == SurfaceFeatureType::Edge) - distances.push_back(*get_measurement(sf, f1).distance_infinite); + if (sf.get_type() == SurfaceFeatureType::Edge) { + const auto m = get_measurement(sf, f1); + if (!m.distance_infinite.has_value()) { + distances.clear(); + break; + } + else + distances.push_back(*m.distance_infinite); + } + } + if (!distances.empty()) { + auto it = std::min_element(distances.begin(), distances.end(), + [](const DistAndPoints& item1, const DistAndPoints& item2) { + return item1.dist < item2.dist; + }); + result.distance_infinite = std::make_optional(DistAndPoints{ it->dist, it->from, it->to }); } - auto it = std::min_element(distances.begin(), distances.end(), - [](const DistAndPoints& item1, const DistAndPoints& item2) { - return item1.dist < item2.dist; - }); - result.distance_infinite = std::make_optional(DistAndPoints{ it->dist, it->from, it->to }); } } /////////////////////////////////////////////////////////////////////////// diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 31ce08fa74..051a7ee40a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -891,13 +891,15 @@ void GLGizmoMeasure::render_dimensioning() auto arc_edge_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2, double radius = 0.0) { assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Edge); - const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); - const double angle = res.angle->angle; - const Vec3d center = res.angle->center; - const std::pair e1 = res.angle->e1; - const std::pair e2 = res.angle->e2; - const double calc_radius = res.angle->radius; - const bool coplanar = res.angle->coplanar; + if (!m_measurement_result.angle.has_value()) + return; + + const double angle = m_measurement_result.angle->angle; + const Vec3d center = m_measurement_result.angle->center; + const std::pair e1 = m_measurement_result.angle->e1; + const std::pair e2 = m_measurement_result.angle->e2; + const double calc_radius = m_measurement_result.angle->radius; + const bool coplanar = m_measurement_result.angle->coplanar; if (std::abs(angle) < EPSILON || std::abs(calc_radius) < EPSILON) return; @@ -993,12 +995,15 @@ void GLGizmoMeasure::render_dimensioning() ImGui::PopStyleVar(); }; - auto arc_edge_plane = [arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { + auto arc_edge_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Plane); - const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); - const std::pair e1 = res.angle->e1; - const std::pair e2 = res.angle->e2; - const double calc_radius = res.angle->radius; + if (!m_measurement_result.angle.has_value()) + return; + + const std::pair e1 = m_measurement_result.angle->e1; + const std::pair e2 = m_measurement_result.angle->e2; + const double calc_radius = m_measurement_result.angle->radius; + if (calc_radius == 0.0) return; @@ -1006,12 +1011,12 @@ void GLGizmoMeasure::render_dimensioning() Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, e2.first, e2.second), calc_radius); }; - auto arc_plane_plane = [arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { + auto arc_plane_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { assert(f1.get_type() == Measure::SurfaceFeatureType::Plane && f2.get_type() == Measure::SurfaceFeatureType::Plane); - const Measure::MeasurementResult res = Measure::get_measurement(f1, f2); - const std::pair e1 = res.angle->e1; - const std::pair e2 = res.angle->e2; - const double calc_radius = res.angle->radius; + const std::pair e1 = m_measurement_result.angle->e1; + const std::pair e2 = m_measurement_result.angle->e2; + const double calc_radius = m_measurement_result.angle->radius; + if (calc_radius == 0.0) return; From 395cab88baa90f17f26a0d8dfce74d32828ed26a Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 6 Oct 2022 14:23:45 +0200 Subject: [PATCH 195/250] Measuring: prototype for uniformly scale a volume by editing the value of the shown distance Fixed conflicts while rebasing to master --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 111 ++++++++++++++++------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 + src/slic3r/GUI/ImGuiWrapper.cpp | 63 ++++++------- src/slic3r/GUI/ImGuiWrapper.hpp | 4 +- 4 files changed, 110 insertions(+), 69 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 051a7ee40a..3e83418ef4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -220,6 +220,7 @@ void GLGizmoMeasure::data_changed() m_last_plane_idx = -1; m_selected_features.reset(); m_selection_raycasters.clear(); + m_editing_distance = false; } bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) @@ -256,6 +257,7 @@ void GLGizmoMeasure::on_set_state() m_curr_feature.reset(); m_curr_point_on_feature_position.reset(); restore_scene_raycasters_state(); + m_editing_distance = false; } else { m_mode = EMode::BasicSelection; @@ -840,18 +842,79 @@ void GLGizmoMeasure::render_dimensioning() ss_to_ndc_matrix * Geometry::translation_transform(v2ss_3) * q12ss); m_dimensioning.triangle.render(); + const bool use_inches = wxGetApp().app_config->get("use_inches") == "1"; + const double value = use_inches ? ObjectManipulation::mm_to_in * distance : distance; + const std::string value_str = format_double(value); + const std::string units = use_inches ? _u8L("in") : _u8L("mm"); + const float value_str_width = 20.0f + ImGui::CalcTextSize(value_str.c_str()).x; + static double edit_value = 0.0; + const Vec2d label_position = 0.5 * (v1ss + v2ss); m_imgui->set_next_window_pos(label_position.x(), viewport[3] - label_position.y(), ImGuiCond_Always, 0.0f, 1.0f); m_imgui->set_next_window_bg_alpha(0.0f); + + if (!m_editing_distance) { + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 1.0f, 1.0f }); + m_imgui->begin(std::string("distance"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration); + ImGui::AlignTextToFramePadding(); + m_imgui->text(value_str + " " + units); + ImGui::SameLine(); + if (m_imgui->image_button(ImGui::SliderFloatEditBtnIcon, _L("Edit to scale"))) { + m_editing_distance = true; + edit_value = value; + m_imgui->requires_extra_frame(); + } + m_imgui->end(); + ImGui::PopStyleVar(3); + } + + auto perform_scale = [this, value](double new_value, double old_value) { + if (new_value == old_value || new_value <= 0.0) + return; + + const double ratio = new_value / old_value; + wxGetApp().plater()->take_snapshot(_L("Scale")); + + TransformationType type; + type.set_world(); + type.set_relative(); + type.set_joint(); + + // apply scale + Selection& selection = m_parent.get_selection(); + selection.setup_cache(); + selection.scale(ratio * Vec3d::Ones(), type); + wxGetApp().plater()->canvas3D()->do_scale(""); // avoid storing another snapshot + wxGetApp().obj_manipul()->set_dirty(); + }; + + if (m_editing_distance && !ImGui::IsPopupOpen("distance_popup")) + ImGui::OpenPopup("distance_popup"); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); - m_imgui->begin(_L("##distance"), ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); - ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); - const bool use_inches = wxGetApp().app_config->get("use_inches") == "1"; - const std::string txt = use_inches ? format_double(ObjectManipulation::mm_to_in * distance) + " " + _u8L("in") : - format_double(distance) + " " + _u8L("mm"); - m_imgui->text(txt); - m_imgui->end(); - ImGui::PopStyleVar(); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 1.0f, 1.0f }); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 4.0f, 0.0f }); + if (ImGui::BeginPopupModal("distance_popup", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration)) { + ImGui::PushItemWidth(value_str_width); + if (ImGui::InputDouble("##distance", &edit_value, 0.0f, 0.0f, "%.3f")) { + } + ImGui::SameLine(); + if (m_imgui->button(_u8L("Scale"))) { + perform_scale(edit_value, value); + m_editing_distance = false; + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (m_imgui->button(_u8L("Cancel"))) { + m_editing_distance = false; + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + ImGui::PopStyleVar(4); }; auto point_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { @@ -1194,7 +1257,10 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit static float last_y = 0.0f; static float last_h = 0.0f; - m_imgui->begin(_L("Measure tool"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + if (m_editing_distance) + return; + + m_imgui->begin(_u8L("Measure tool"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); // adjust window position to avoid overlap the view toolbar const float win_h = ImGui::GetWindowHeight(); @@ -1341,28 +1407,11 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::TableSetColumnIndex(1); m_imgui->text_colored(col_2_color, col_2); ImGui::TableSetColumnIndex(2); - ImGuiIO& io = ImGui::GetIO(); - const ImTextureID tex_id = io.Fonts->TexID; - assert(io.Fonts->TexWidth > 0 && io.Fonts->TexHeight > 0); - float inv_tex_w = 1.0f / float(io.Fonts->TexWidth); - float inv_tex_h = 1.0f / float(io.Fonts->TexHeight); - const ImFontAtlasCustomRect* const rect = m_imgui->GetTextureCustomRect(ImGui::ClipboardBtnIcon); - const ImVec2 size = { float(rect->Width), float(rect->Height) }; - const ImVec2 uv0 = ImVec2(float(rect->X) * inv_tex_w, float(rect->Y) * inv_tex_h); - const ImVec2 uv1 = ImVec2(float(rect->X + rect->Width) * inv_tex_w, float(rect->Y + rect->Height) * inv_tex_h); - ImGui::PushStyleColor(ImGuiCol_Button, { 0.25f, 0.25f, 0.25f, 0.0f }); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 0.4f, 0.4f, 0.4f, 1.0f }); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0.25f, 0.25f, 0.25f, 1.0f }); - if (m_imgui->image_button(tex_id, size, uv0, uv1)) { + if (m_imgui->image_button(ImGui::ClipboardBtnIcon, _L("Copy to clipboard"))) { wxTheClipboard->Open(); wxTheClipboard->SetData(new wxTextDataObject(col_1 + ": " + col_2)); wxTheClipboard->Close(); } - ImGui::PopStyleColor(3); - if (ImGui::IsItemHovered()) { - const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; - m_imgui->tooltip(into_u8(_L("Copy to clipboard")).c_str(), max_tooltip_width); - } }; if (m_selected_features.second.feature.has_value()) { @@ -1373,7 +1422,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit m_imgui->text(_u8L("Measure") + ":"); if (ImGui::BeginTable("Measure", 3)) { if (measure.angle.has_value()) { - ImGui::PushID((void*)(intptr_t)1); + ImGui::PushID("ClipboardAngle"); add_measure_row_to_table(_u8L("Angle"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(measure.angle->angle)) + "°", ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); @@ -1382,7 +1431,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit double distance = measure.distance_infinite->dist; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - ImGui::PushID((void*)(intptr_t)2); + ImGui::PushID("ClipboardDistanceInfinite"); add_measure_row_to_table(_u8L("Distance Infinite"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); @@ -1392,7 +1441,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit double distance = measure.distance_strict->dist; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - ImGui::PushID((void*)(intptr_t)3); + ImGui::PushID("ClipboardDistanceStrict"); add_measure_row_to_table(_u8L("Distance Strict"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); @@ -1401,7 +1450,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit Vec3d distance = *measure.distance_xyz; if (use_inches) distance = ObjectManipulation::mm_to_in * distance; - ImGui::PushID((void*)(intptr_t)4); + ImGui::PushID("ClipboardDistanceXYZ"); add_measure_row_to_table(_u8L("Distance XYZ"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::PopID(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 7e65b8c89c..72f9098f2b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -118,6 +118,7 @@ class GLGizmoMeasure : public GLGizmoBase KeyAutoRepeatFilter m_ctrl_kar_filter; SelectedFeatures m_selected_features; + bool m_editing_distance{ false }; void update_if_needed(); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index b8c6c463f5..f1be9d2771 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -426,36 +426,6 @@ bool ImGuiWrapper::draw_radio_button(const std::string& name, float size, bool a return pressed; } -bool ImGuiWrapper::input_double(const std::string &label, const double &value, const std::string &format) -{ - return ImGui::InputDouble(label.c_str(), const_cast(&value), 0.0f, 0.0f, format.c_str(), ImGuiInputTextFlags_CharsDecimal); -} - -bool ImGuiWrapper::input_double(const wxString &label, const double &value, const std::string &format) -{ - auto label_utf8 = into_u8(label); - return input_double(label_utf8, value, format); -} - -bool ImGuiWrapper::input_vec3(const std::string &label, const Vec3d &value, float width, const std::string &format) -{ - bool value_changed = false; - - ImGui::BeginGroup(); - - for (int i = 0; i < 3; ++i) - { - std::string item_label = (i == 0) ? "X" : ((i == 1) ? "Y" : "Z"); - ImGui::PushID(i); - ImGui::PushItemWidth(width); - value_changed |= ImGui::InputDouble(item_label.c_str(), const_cast(&value(i)), 0.0f, 0.0f, format.c_str()); - ImGui::PopID(); - } - ImGui::EndGroup(); - - return value_changed; -} - bool ImGuiWrapper::checkbox(const wxString &label, bool &value) { auto label_utf8 = into_u8(label); @@ -514,20 +484,20 @@ void ImGuiWrapper::text_wrapped(const wxString &label, float wrap_width) void ImGuiWrapper::tooltip(const char *label, float wrap_width) { + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 4.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 8.0f, 8.0f }); ImGui::BeginTooltip(); ImGui::PushTextWrapPos(wrap_width); ImGui::TextUnformatted(label); ImGui::PopTextWrapPos(); ImGui::EndTooltip(); + ImGui::PopStyleVar(3); } void ImGuiWrapper::tooltip(const wxString &label, float wrap_width) { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(wrap_width); - ImGui::TextUnformatted(label.ToUTF8().data()); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); + tooltip(label.ToUTF8().data(), wrap_width); } ImVec2 ImGuiWrapper::get_slider_icon_size() const @@ -669,6 +639,29 @@ bool ImGuiWrapper::image_button(ImTextureID user_texture_id, const ImVec2& size, return image_button_ex(id, user_texture_id, size, uv0, uv1, padding, bg_col, tint_col, flags); } +bool ImGuiWrapper::image_button(const wchar_t icon, const wxString& tooltip) +{ + const ImGuiIO& io = ImGui::GetIO(); + const ImTextureID tex_id = io.Fonts->TexID; + assert(io.Fonts->TexWidth > 0 && io.Fonts->TexHeight > 0); + const float inv_tex_w = 1.0f / float(io.Fonts->TexWidth); + const float inv_tex_h = 1.0f / float(io.Fonts->TexHeight); + const ImFontAtlasCustomRect* const rect = GetTextureCustomRect(icon); + const ImVec2 size = { float(rect->Width), float(rect->Height) }; + const ImVec2 uv0 = ImVec2(float(rect->X) * inv_tex_w, float(rect->Y) * inv_tex_h); + const ImVec2 uv1 = ImVec2(float(rect->X + rect->Width) * inv_tex_w, float(rect->Y + rect->Height) * inv_tex_h); + ImGui::PushStyleColor(ImGuiCol_Button, { 0.25f, 0.25f, 0.25f, 0.0f }); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 0.4f, 0.4f, 0.4f, 1.0f }); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0.25f, 0.25f, 0.25f, 1.0f }); + const bool res = image_button(tex_id, size, uv0, uv1); + ImGui::PopStyleColor(3); + + if (!tooltip.empty() && ImGui::IsItemHovered()) + this->tooltip(tooltip, ImGui::GetFontSize() * 20.0f); + + return res; +} + bool ImGuiWrapper::combo(const wxString& label, const std::vector& options, int& selection, ImGuiComboFlags flags) { // this is to force the label to the left of the widget: diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 769deccb81..dc5f5517ce 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -89,9 +89,6 @@ public: bool button(const wxString& label, float width, float height); bool radio_button(const wxString &label, bool active); bool draw_radio_button(const std::string& name, float size, bool active, std::function draw_callback); - bool input_double(const std::string &label, const double &value, const std::string &format = "%.3f"); - bool input_double(const wxString &label, const double &value, const std::string &format = "%.3f"); - bool input_vec3(const std::string &label, const Vec3d &value, float width, const std::string &format = "%.3f"); bool checkbox(const wxString &label, bool &value); void text(const char *label); void text(const std::string &label); @@ -112,6 +109,7 @@ public: bool slider_float(const wxString& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true, const wxString& tooltip = {}, bool show_edit_btn = true); bool image_button(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0.0, 0.0), const ImVec2& uv1 = ImVec2(1.0, 1.0), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0.0, 0.0, 0.0, 0.0), const ImVec4& tint_col = ImVec4(1.0, 1.0, 1.0, 1.0), ImGuiButtonFlags flags = 0); + bool image_button(const wchar_t icon, const wxString& tooltip = L""); // Use selection = -1 to not mark any option as selected bool combo(const wxString& label, const std::vector& options, int& selection, ImGuiComboFlags flags = 0); From 75baf95d71484ceee6f6413bd26e2cc677a80e1b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 6 Oct 2022 14:47:25 +0200 Subject: [PATCH 196/250] Measuring: Fixed rendering of point features when the object is scaled --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 157 ++++++++++++----------- 1 file changed, 79 insertions(+), 78 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 3e83418ef4..a6efc09e78 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -467,93 +467,94 @@ void GLGizmoMeasure::on_render() auto render_feature = [this, set_matrix_uniforms](const Measure::SurfaceFeature& feature, const std::vector& colors, const Transform3d& model_matrix, float inv_zoom, bool update_raycasters) { - switch (feature.get_type()) - { - default: { assert(false); break; } - case Measure::SurfaceFeatureType::Point: - { - const Vec3d& position = feature.get_point(); - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); - set_matrix_uniforms(feature_matrix); - m_sphere.model.set_color(colors.front()); - m_sphere.model.render(); - if (update_raycasters) { - auto it = m_raycasters.find(POINT_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(feature_matrix); - } - break; - } - case Measure::SurfaceFeatureType::Circle: - { - const auto& [center, radius, normal] = feature.get_circle(); - // render center - const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); - set_matrix_uniforms(center_matrix); - m_sphere.model.set_color(colors.front()); - m_sphere.model.render(); - if (update_raycasters) { - auto it = m_raycasters.find(POINT_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(center_matrix); - } - // render circle - const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); - set_matrix_uniforms(circle_matrix); - m_circle.model.set_color(colors.back()); - m_circle.model.render(); - if (update_raycasters) { - auto it = m_raycasters.find(CIRCLE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(circle_matrix); - } - break; - } - case Measure::SurfaceFeatureType::Edge: - { - const auto& [start, end] = feature.get_edge(); - // render extra point - const std::optional extra = feature.get_extra_point(); - if (extra.has_value()) { - const Transform3d point_matrix = model_matrix * Geometry::translation_transform(*extra) * Geometry::scale_transform(inv_zoom); - set_matrix_uniforms(point_matrix); + const Transform3d model_matrix_scale_inverse = Geometry::Transformation(model_matrix).get_scaling_factor_matrix().inverse(); + switch (feature.get_type()) + { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + const Vec3d& position = feature.get_point(); + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * model_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(feature_matrix); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); if (update_raycasters) { auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(point_matrix); + it->second->set_transform(feature_matrix); } + break; } - // render edge - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start) * - Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); - set_matrix_uniforms(feature_matrix); - m_cylinder.model.set_color(colors.back()); - m_cylinder.model.render(); - if (update_raycasters) { - auto it = m_raycasters.find(EDGE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(feature_matrix); + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, normal] = feature.get_circle(); + // render center + const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * model_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(center_matrix); + m_sphere.model.set_color(colors.front()); + m_sphere.model.render(); + if (update_raycasters) { + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(center_matrix); + } + // render circle + const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); + set_matrix_uniforms(circle_matrix); + m_circle.model.set_color(colors.back()); + m_circle.model.render(); + if (update_raycasters) { + auto it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(circle_matrix); + } + break; + } + case Measure::SurfaceFeatureType::Edge: + { + const auto& [start, end] = feature.get_edge(); + // render extra point + const std::optional extra = feature.get_extra_point(); + if (extra.has_value()) { + const Transform3d point_matrix = model_matrix * Geometry::translation_transform(*extra) * model_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(point_matrix); + m_sphere.model.set_color(colors.front()); + m_sphere.model.render(); + if (update_raycasters) { + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(point_matrix); + } + } + // render edge + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start) * + Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); + set_matrix_uniforms(feature_matrix); + m_cylinder.model.set_color(colors.back()); + m_cylinder.model.render(); + if (update_raycasters) { + auto it = m_raycasters.find(EDGE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); + } + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto& [idx, normal, pt] = feature.get_plane(); + assert(idx < m_plane_models_cache.size()); + set_matrix_uniforms(model_matrix); + m_plane_models_cache[idx].set_color(colors.front()); + m_plane_models_cache[idx].render(); + if (update_raycasters) { + auto it = m_raycasters.find(PLANE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(model_matrix); + } + break; } - break; - } - case Measure::SurfaceFeatureType::Plane: - { - const auto& [idx, normal, pt] = feature.get_plane(); - assert(idx < m_plane_models_cache.size()); - set_matrix_uniforms(model_matrix); - m_plane_models_cache[idx].set_color(colors.front()); - m_plane_models_cache[idx].render(); - if (update_raycasters) { - auto it = m_raycasters.find(PLANE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(model_matrix); } - break; - } - } }; auto hover_selection_color = [this]() { From 7002b94419aa78ff7d4b4b329a965bf05e15c6e7 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 7 Oct 2022 08:40:23 +0200 Subject: [PATCH 197/250] Measuring - Gizmo measure disabled for scaled volumes --- src/libslic3r/Technologies.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 04ecfae670..817136e7a4 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -68,6 +68,7 @@ #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) // Enable Measure Gizmo #define ENABLE_MEASURE_GIZMO (1 && ENABLE_RAYCAST_PICKING) +#define DISABLE_MEASURE_GIZMO_FOR_SCALED_VOLUMES (1 && ENABLE_MEASURE_GIZMO) #define ENABLE_MEASURE_GIZMO_DEBUG (0 && ENABLE_MEASURE_GIZMO) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index a6efc09e78..f2638d0588 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -290,8 +290,12 @@ bool GLGizmoMeasure::on_is_activable() const bool res = (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) ? selection.is_single_full_instance() : selection.is_single_volume() || selection.is_single_volume_instance(); - if (res) + if (res) { res &= !selection.get_first_volume()->is_sinking(); +#if DISABLE_MEASURE_GIZMO_FOR_SCALED_VOLUMES + res &= Geometry::Transformation(selection.get_first_volume()->world_matrix()).get_scaling_factor().isApprox(Vec3d::Ones()); +#endif // DISABLE_MEASURE_GIZMO_FOR_SCALED_VOLUMES + } return res; } From 908634d5b7c5a8a8d4037f1da23120c53f6f0fee Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 7 Oct 2022 09:57:13 +0200 Subject: [PATCH 198/250] Measuring - Gizmo measure - Disable background fadeout animation when showing imgui modal dialog to edit distance --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 1 + src/slic3r/GUI/ImGuiWrapper.cpp | 7 +++++++ src/slic3r/GUI/ImGuiWrapper.hpp | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index f2638d0588..d18584a870 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -903,6 +903,7 @@ void GLGizmoMeasure::render_dimensioning() ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 1.0f, 1.0f }); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 4.0f, 0.0f }); if (ImGui::BeginPopupModal("distance_popup", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration)) { + m_imgui->disable_background_fadeout_animation(); ImGui::PushItemWidth(value_str_width); if (ImGui::InputDouble("##distance", &edit_value, 0.0f, 0.0f, "%.3f")) { } diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index f1be9d2771..2d36727849 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -1124,6 +1124,13 @@ ImFontAtlasCustomRect* ImGuiWrapper::GetTextureCustomRect(const wchar_t& tex_id) return (item != m_custom_glyph_rects_ids.end()) ? ImGui::GetIO().Fonts->GetCustomRectByIndex(m_custom_glyph_rects_ids[tex_id]) : nullptr; } +#if ENABLE_MEASURE_GIZMO +void ImGuiWrapper::disable_background_fadeout_animation() +{ + GImGui->DimBgRatio = 1.0f; +} +#endif // ENABLE_MEASURE_GIZMO + ImU32 ImGuiWrapper::to_ImU32(const ColorRGBA& color) { return ImGui::GetColorU32({ color.r(), color.g(), color.b(), color.a() }); diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index dc5f5517ce..8be16fcd0b 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -130,6 +130,10 @@ public: void set_requires_extra_frame() { m_requires_extra_frame = true; } void reset_requires_extra_frame() { m_requires_extra_frame = false; } +#if ENABLE_MEASURE_GIZMO + void disable_background_fadeout_animation(); +#endif // ENABLE_MEASURE_GIZMO + static ImU32 to_ImU32(const ColorRGBA& color); static ImVec4 to_ImVec4(const ColorRGBA& color); static ColorRGBA from_ImU32(const ImU32& color); From 4b2cc2167d32acd20666f5cb69ee444f395535bc Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 7 Oct 2022 10:42:01 +0200 Subject: [PATCH 199/250] Measuring - Gizmo measure - Handle [Enter] and [Esc] keys input events in imgui modal dialog to edit distance --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 78 +++++++++++++----------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index d18584a870..3e1d9824d4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -848,10 +848,10 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.triangle.render(); const bool use_inches = wxGetApp().app_config->get("use_inches") == "1"; - const double value = use_inches ? ObjectManipulation::mm_to_in * distance : distance; - const std::string value_str = format_double(value); + const double curr_value = use_inches ? ObjectManipulation::mm_to_in * distance : distance; + const std::string curr_value_str = format_double(curr_value); const std::string units = use_inches ? _u8L("in") : _u8L("mm"); - const float value_str_width = 20.0f + ImGui::CalcTextSize(value_str.c_str()).x; + const float value_str_width = 20.0f + ImGui::CalcTextSize(curr_value_str.c_str()).x; static double edit_value = 0.0; const Vec2d label_position = 0.5 * (v1ss + v2ss); @@ -864,37 +864,17 @@ void GLGizmoMeasure::render_dimensioning() ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 1.0f, 1.0f }); m_imgui->begin(std::string("distance"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration); ImGui::AlignTextToFramePadding(); - m_imgui->text(value_str + " " + units); + m_imgui->text(curr_value_str + " " + units); ImGui::SameLine(); if (m_imgui->image_button(ImGui::SliderFloatEditBtnIcon, _L("Edit to scale"))) { m_editing_distance = true; - edit_value = value; + edit_value = curr_value; m_imgui->requires_extra_frame(); } m_imgui->end(); ImGui::PopStyleVar(3); } - auto perform_scale = [this, value](double new_value, double old_value) { - if (new_value == old_value || new_value <= 0.0) - return; - - const double ratio = new_value / old_value; - wxGetApp().plater()->take_snapshot(_L("Scale")); - - TransformationType type; - type.set_world(); - type.set_relative(); - type.set_joint(); - - // apply scale - Selection& selection = m_parent.get_selection(); - selection.setup_cache(); - selection.scale(ratio * Vec3d::Ones(), type); - wxGetApp().plater()->canvas3D()->do_scale(""); // avoid storing another snapshot - wxGetApp().obj_manipul()->set_dirty(); - }; - if (m_editing_distance && !ImGui::IsPopupOpen("distance_popup")) ImGui::OpenPopup("distance_popup"); @@ -903,21 +883,51 @@ void GLGizmoMeasure::render_dimensioning() ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 1.0f, 1.0f }); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 4.0f, 0.0f }); if (ImGui::BeginPopupModal("distance_popup", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration)) { + auto perform_scale = [this](double new_value, double old_value) { + if (new_value == old_value || new_value <= 0.0) + return; + + const double ratio = new_value / old_value; + wxGetApp().plater()->take_snapshot(_L("Scale")); + + TransformationType type; + type.set_world(); + type.set_relative(); + type.set_joint(); + + // apply scale + Selection& selection = m_parent.get_selection(); + selection.setup_cache(); + selection.scale(ratio * Vec3d::Ones(), type); + wxGetApp().plater()->canvas3D()->do_scale(""); // avoid storing another snapshot + wxGetApp().obj_manipul()->set_dirty(); + }; + auto action_exit = [this]() { + m_editing_distance = false; + ImGui::CloseCurrentPopup(); + }; + auto action_scale = [this, perform_scale, action_exit](double new_value, double old_value) { + perform_scale(new_value, old_value); + action_exit(); + }; + m_imgui->disable_background_fadeout_animation(); ImGui::PushItemWidth(value_str_width); if (ImGui::InputDouble("##distance", &edit_value, 0.0f, 0.0f, "%.3f")) { } + + // handle keys input + if (ImGui::IsKeyPressedMap(ImGuiKey_Enter) || ImGui::IsKeyPressedMap(ImGuiKey_KeyPadEnter)) + action_scale(edit_value, curr_value); + else if (ImGui::IsKeyPressedMap(ImGuiKey_Escape)) + action_exit(); + ImGui::SameLine(); - if (m_imgui->button(_u8L("Scale"))) { - perform_scale(edit_value, value); - m_editing_distance = false; - ImGui::CloseCurrentPopup(); - } + if (m_imgui->button(_u8L("Scale"))) + action_scale(edit_value, curr_value); ImGui::SameLine(); - if (m_imgui->button(_u8L("Cancel"))) { - m_editing_distance = false; - ImGui::CloseCurrentPopup(); - } + if (m_imgui->button(_u8L("Cancel"))) + action_exit(); ImGui::EndPopup(); } ImGui::PopStyleVar(4); From 594e91e86a37e96a12c9706c356288a7ce93f279 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 7 Oct 2022 12:42:30 +0200 Subject: [PATCH 200/250] easuring - Gizmo measure - Reworked imgui dialog layout to avoid change in size in dependence of hovered or selected features --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 266 +++++++++++++---------- 1 file changed, 151 insertions(+), 115 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 3e1d9824d4..15d6ea761f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -63,7 +63,7 @@ static std::string surface_feature_type_as_string(Measure::SurfaceFeatureType ty switch (type) { default: - case Measure::SurfaceFeatureType::Undef: { return _u8L("Undefined"); } + case Measure::SurfaceFeatureType::Undef: { return _u8L("No feature"); } case Measure::SurfaceFeatureType::Point: { return _u8L("Vertex"); } case Measure::SurfaceFeatureType::Edge: { return _u8L("Edge"); } case Measure::SurfaceFeatureType::Circle: { return _u8L("Circle"); } @@ -1292,6 +1292,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } if (ImGui::BeginTable("Commands", 2)) { + unsigned int row_count = 1; add_row_to_table( [this]() { m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Left mouse button")); @@ -1310,93 +1311,121 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } ); - if (m_selected_features.first.feature.has_value()) + if (m_selected_features.first.feature.has_value()) { add_strings_row_to_table(*m_imgui, CTRL_STR + "+" + _u8L("Right mouse button"), ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ++row_count; + } - if (m_mode == EMode::BasicSelection && m_hover_id != -1) + if (m_mode == EMode::BasicSelection && m_hover_id != -1) { add_strings_row_to_table(*m_imgui, CTRL_STR, ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable point selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ++row_count; + } + + // add dummy rows to keep dialog size fixed + for (unsigned int i = row_count; i < 3; ++i) { + add_strings_row_to_table(*m_imgui, " ", ImGuiWrapper::COL_ORANGE_LIGHT, " ", ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + ImGui::EndTable(); } const bool use_inches = wxGetApp().app_config->get("use_inches") == "1"; const std::string units = use_inches ? " " + _u8L("in") : " " + _u8L("mm"); - if (m_curr_feature.has_value()) { - const Measure::SurfaceFeatureType feature_type = m_curr_feature->get_type(); + const Measure::SurfaceFeatureType feature_type = m_curr_feature.has_value() ? m_curr_feature->get_type() : Measure::SurfaceFeatureType::Undef; + bool data_text_set = false; + ImGui::Separator(); + if (feature_type != Measure::SurfaceFeatureType::Undef) { if (m_mode == EMode::BasicSelection) { - if (feature_type != Measure::SurfaceFeatureType::Undef) { - ImGui::Separator(); - m_imgui->text(surface_feature_type_as_string(feature_type) + ":"); - if (ImGui::BeginTable("Data", 2)) { - switch (feature_type) - { - default: { assert(false); break; } - case Measure::SurfaceFeatureType::Point: - { - Vec3d position = m_volume_matrix * m_curr_feature->get_point(); - if (use_inches) - position = ObjectManipulation::mm_to_in * position; - add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - break; - } - case Measure::SurfaceFeatureType::Edge: - { - auto [from, to] = m_curr_feature->get_edge(); - from = m_volume_matrix * from; - to = m_volume_matrix * to; - if (use_inches) { - from = ObjectManipulation::mm_to_in * from; - to = ObjectManipulation::mm_to_in * to; - } - add_strings_row_to_table(*m_imgui, _u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, _u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, _u8L("Length"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); - break; - } - case Measure::SurfaceFeatureType::Circle: - { - auto [center, radius, normal] = m_curr_feature->get_circle(); - center = m_volume_matrix * center; - normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; - if (use_inches) { - center = ObjectManipulation::mm_to_in * center; - radius = ObjectManipulation::mm_to_in * radius; - } - add_strings_row_to_table(*m_imgui, _u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, _u8L("Radius"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - auto [idx, normal, origin] = m_curr_feature->get_plane(); - origin = m_volume_matrix * origin; - normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; - if (use_inches) - origin = ObjectManipulation::mm_to_in * origin; - add_strings_row_to_table(*m_imgui, _u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - break; - } - } - ImGui::EndTable(); - } - } + m_imgui->text(surface_feature_type_as_string(feature_type)); + data_text_set = true; } else if (m_mode == EMode::ExtendedSelection) { if (m_hover_id != -1 && m_curr_point_on_feature_position.has_value()) { - ImGui::Separator(); - m_imgui->text(point_on_feature_type_as_string(feature_type, m_hover_id) + ":"); - if (ImGui::BeginTable("Data", 2)) { - Vec3d position = m_volume_matrix * *m_curr_point_on_feature_position; - if (use_inches) - position = ObjectManipulation::mm_to_in * position; - add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - ImGui::EndTable(); - } + m_imgui->text(point_on_feature_type_as_string(feature_type, m_hover_id)); + data_text_set = true; } } } + if (!data_text_set) + m_imgui->text(_u8L("No feature")); + + const unsigned int max_data_row_count = 3; + unsigned int data_row_count = 0; + if (ImGui::BeginTable("Data", 2)) { + if (m_mode == EMode::BasicSelection) { + switch (feature_type) + { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + Vec3d position = m_volume_matrix * m_curr_feature->get_point(); + if (use_inches) + position = ObjectManipulation::mm_to_in * position; + add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + data_row_count = 1; + break; + } + case Measure::SurfaceFeatureType::Edge: + { + auto [from, to] = m_curr_feature->get_edge(); + from = m_volume_matrix * from; + to = m_volume_matrix * to; + if (use_inches) { + from = ObjectManipulation::mm_to_in * from; + to = ObjectManipulation::mm_to_in * to; + } + add_strings_row_to_table(*m_imgui, _u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Length"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); + data_row_count = 3; + break; + } + case Measure::SurfaceFeatureType::Circle: + { + auto [center, radius, normal] = m_curr_feature->get_circle(); + center = m_volume_matrix * center; + normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + if (use_inches) { + center = ObjectManipulation::mm_to_in * center; + radius = ObjectManipulation::mm_to_in * radius; + } + add_strings_row_to_table(*m_imgui, _u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Radius"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + data_row_count = 3; + break; + } + case Measure::SurfaceFeatureType::Plane: + { + auto [idx, normal, origin] = m_curr_feature->get_plane(); + origin = m_volume_matrix * origin; + normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + if (use_inches) + origin = ObjectManipulation::mm_to_in * origin; + add_strings_row_to_table(*m_imgui, _u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + data_row_count = 2; + break; + } + } + } + else { + if (m_hover_id != -1 && m_curr_point_on_feature_position.has_value()) { + Vec3d position = m_volume_matrix * *m_curr_point_on_feature_position; + if (use_inches) + position = ObjectManipulation::mm_to_in * position; + add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + data_row_count = 1; + } + } + + // add dummy rows to keep dialog size fixed + for (unsigned int i = data_row_count; i < max_data_row_count; ++i) { + add_strings_row_to_table(*m_imgui, " ", ImGuiWrapper::COL_ORANGE_LIGHT, " ", ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + ImGui::EndTable(); + } ImGui::Separator(); const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; @@ -1430,52 +1459,59 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } }; - if (m_selected_features.second.feature.has_value()) { - const Measure::MeasurementResult& measure = m_measurement_result; + ImGui::Separator(); + m_imgui->text(_u8L("Measure")); - ImGui::Separator(); - if (measure.has_any_data()) { - m_imgui->text(_u8L("Measure") + ":"); - if (ImGui::BeginTable("Measure", 3)) { - if (measure.angle.has_value()) { - ImGui::PushID("ClipboardAngle"); - add_measure_row_to_table(_u8L("Angle"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(measure.angle->angle)) + "°", - ImGui::GetStyleColorVec4(ImGuiCol_Text)); - ImGui::PopID(); - } - if (measure.distance_infinite.has_value()) { - double distance = measure.distance_infinite->dist; - if (use_inches) - distance = ObjectManipulation::mm_to_in * distance; - ImGui::PushID("ClipboardDistanceInfinite"); - add_measure_row_to_table(_u8L("Distance Infinite"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, - ImGui::GetStyleColorVec4(ImGuiCol_Text)); - ImGui::PopID(); - } - if (measure.distance_strict.has_value() && - (!measure.distance_infinite.has_value() || std::abs(measure.distance_strict->dist - measure.distance_infinite->dist) > EPSILON)) { - double distance = measure.distance_strict->dist; - if (use_inches) - distance = ObjectManipulation::mm_to_in * distance; - ImGui::PushID("ClipboardDistanceStrict"); - add_measure_row_to_table(_u8L("Distance Strict"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, - ImGui::GetStyleColorVec4(ImGuiCol_Text)); - ImGui::PopID(); - } - if (measure.distance_xyz.has_value() && measure.distance_xyz->norm() > EPSILON) { - Vec3d distance = *measure.distance_xyz; - if (use_inches) - distance = ObjectManipulation::mm_to_in * distance; - ImGui::PushID("ClipboardDistanceXYZ"); - add_measure_row_to_table(_u8L("Distance XYZ"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), - ImGui::GetStyleColorVec4(ImGuiCol_Text)); - ImGui::PopID(); - } - ImGui::EndTable(); + const unsigned int max_measure_row_count = 2; + unsigned int measure_row_count = 0; + if (ImGui::BeginTable("Measure", 4)) { + if (m_selected_features.second.feature.has_value()) { + const Measure::MeasurementResult& measure = m_measurement_result; + if (measure.angle.has_value()) { + ImGui::PushID("ClipboardAngle"); + add_measure_row_to_table(_u8L("Angle"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(Geometry::rad2deg(measure.angle->angle)) + "°", + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ++measure_row_count; + ImGui::PopID(); + } + if (measure.distance_infinite.has_value()) { + double distance = measure.distance_infinite->dist; + if (use_inches) + distance = ObjectManipulation::mm_to_in * distance; + ImGui::PushID("ClipboardDistanceInfinite"); + add_measure_row_to_table(_u8L("Distance Infinite"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ++measure_row_count; + ImGui::PopID(); + } + if (measure.distance_strict.has_value() && + (!measure.distance_infinite.has_value() || std::abs(measure.distance_strict->dist - measure.distance_infinite->dist) > EPSILON)) { + double distance = measure.distance_strict->dist; + if (use_inches) + distance = ObjectManipulation::mm_to_in * distance; + ImGui::PushID("ClipboardDistanceStrict"); + add_measure_row_to_table(_u8L("Distance Strict"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ++measure_row_count; + ImGui::PopID(); + } + if (measure.distance_xyz.has_value() && measure.distance_xyz->norm() > EPSILON) { + Vec3d distance = *measure.distance_xyz; + if (use_inches) + distance = ObjectManipulation::mm_to_in * distance; + ImGui::PushID("ClipboardDistanceXYZ"); + add_measure_row_to_table(_u8L("Distance XYZ"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(distance), + ImGui::GetStyleColorVec4(ImGuiCol_Text)); + ++measure_row_count; + ImGui::PopID(); } } - else - m_imgui->text(_u8L("No measure available")); + + // add dummy rows to keep dialog size fixed + for (unsigned int i = measure_row_count; i < max_measure_row_count; ++i) { + add_strings_row_to_table(*m_imgui, " ", ImGuiWrapper::COL_ORANGE_LIGHT, " ", ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + ImGui::EndTable(); } if (last_feature != m_curr_feature || last_mode != m_mode || last_selected_features != m_selected_features) { From 0b85569c3d1b99b6d2bf13c5af680d5bd7bcec16 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 10 Oct 2022 08:29:51 +0200 Subject: [PATCH 201/250] Follow-up of 2fb59e66c2b6f07a25cfa873fdeb1d820b2d78c4 - Removed obsolete assert --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 15d6ea761f..79a800bf2e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1356,7 +1356,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (m_mode == EMode::BasicSelection) { switch (feature_type) { - default: { assert(false); break; } + default: { break; } case Measure::SurfaceFeatureType::Point: { Vec3d position = m_volume_matrix * m_curr_feature->get_point(); From 6971b727667a1717bc4ed92b2e9c4e8fa7b83581 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 10 Oct 2022 09:46:12 +0200 Subject: [PATCH 202/250] Measuring - Gizmo measure - Auto-select text when opening imgui modal dialog to edit distance --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 10 ++++++++++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 + 2 files changed, 11 insertions(+) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 79a800bf2e..b4c35b1563 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -221,6 +221,7 @@ void GLGizmoMeasure::data_changed() m_selected_features.reset(); m_selection_raycasters.clear(); m_editing_distance = false; + m_is_editing_distance_first_frame = true; } bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) @@ -258,6 +259,7 @@ void GLGizmoMeasure::on_set_state() m_curr_point_on_feature_position.reset(); restore_scene_raycasters_state(); m_editing_distance = false; + m_is_editing_distance_first_frame = true; } else { m_mode = EMode::BasicSelection; @@ -904,6 +906,7 @@ void GLGizmoMeasure::render_dimensioning() }; auto action_exit = [this]() { m_editing_distance = false; + m_is_editing_distance_first_frame = true; ImGui::CloseCurrentPopup(); }; auto action_scale = [this, perform_scale, action_exit](double new_value, double old_value) { @@ -916,6 +919,13 @@ void GLGizmoMeasure::render_dimensioning() if (ImGui::InputDouble("##distance", &edit_value, 0.0f, 0.0f, "%.3f")) { } + // trick to auto-select text in the input widgets on 1st frame + if (m_is_editing_distance_first_frame) { + ImGui::SetKeyboardFocusHere(0); + m_is_editing_distance_first_frame = false; + m_imgui->set_requires_extra_frame(); + } + // handle keys input if (ImGui::IsKeyPressedMap(ImGuiKey_Enter) || ImGui::IsKeyPressedMap(ImGuiKey_KeyPadEnter)) action_scale(edit_value, curr_value); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 72f9098f2b..8200325f19 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -119,6 +119,7 @@ class GLGizmoMeasure : public GLGizmoBase SelectedFeatures m_selected_features; bool m_editing_distance{ false }; + bool m_is_editing_distance_first_frame{ true }; void update_if_needed(); From bc1e5a027255c2645805fea01bfb6a181048adad Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 10 Oct 2022 10:12:14 +0200 Subject: [PATCH 203/250] Follow-up of 8312dc24547df8e622bde814efb1b3e0b15bab40 - Fixed rendering of point on locked features when the object is scaled --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 34 ++++++++++++------------ src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 + 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index b4c35b1563..1976cbcdab 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -317,7 +317,6 @@ void GLGizmoMeasure::on_render() (selection.is_single_volume() || selection.is_single_volume_instance())) { update_if_needed(); - m_volume_matrix = selection.get_first_volume()->world_matrix(); const Camera& camera = wxGetApp().plater()->get_camera(); const float inv_zoom = (float)camera.get_inv_zoom(); @@ -397,7 +396,6 @@ void GLGizmoMeasure::on_render() Vec3f n; const Transform3d& trafo = it->second->get_transform(); bool res = it->second->get_raycaster()->closest_hit(m_mouse_pos, trafo, camera, p, n); - assert(res); if (res) { if (callback) p = callback(p); @@ -472,15 +470,14 @@ void GLGizmoMeasure::on_render() }; auto render_feature = [this, set_matrix_uniforms](const Measure::SurfaceFeature& feature, const std::vector& colors, - const Transform3d& model_matrix, float inv_zoom, bool update_raycasters) { - const Transform3d model_matrix_scale_inverse = Geometry::Transformation(model_matrix).get_scaling_factor_matrix().inverse(); + float inv_zoom, bool update_raycasters) { switch (feature.get_type()) { default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { const Vec3d& position = feature.get_point(); - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * model_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); + const Transform3d feature_matrix = m_volume_matrix * Geometry::translation_transform(position) * m_volume_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(feature_matrix); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); @@ -495,7 +492,7 @@ void GLGizmoMeasure::on_render() { const auto& [center, radius, normal] = feature.get_circle(); // render center - const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * model_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); + const Transform3d center_matrix = m_volume_matrix * Geometry::translation_transform(center) * m_volume_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(center_matrix); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); @@ -505,7 +502,7 @@ void GLGizmoMeasure::on_render() it->second->set_transform(center_matrix); } // render circle - const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); + const Transform3d circle_matrix = m_volume_matrix * Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); set_matrix_uniforms(circle_matrix); m_circle.model.set_color(colors.back()); m_circle.model.render(); @@ -522,7 +519,7 @@ void GLGizmoMeasure::on_render() // render extra point const std::optional extra = feature.get_extra_point(); if (extra.has_value()) { - const Transform3d point_matrix = model_matrix * Geometry::translation_transform(*extra) * model_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); + const Transform3d point_matrix = m_volume_matrix * Geometry::translation_transform(*extra) * m_volume_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(point_matrix); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); @@ -533,16 +530,16 @@ void GLGizmoMeasure::on_render() } } // render edge - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * + const Transform3d edge_matrix = m_volume_matrix * Geometry::translation_transform(start) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start) * Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); - set_matrix_uniforms(feature_matrix); + set_matrix_uniforms(edge_matrix); m_cylinder.model.set_color(colors.back()); m_cylinder.model.render(); if (update_raycasters) { auto it = m_raycasters.find(EDGE_ID); if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(feature_matrix); + it->second->set_transform(edge_matrix); } break; } @@ -550,13 +547,13 @@ void GLGizmoMeasure::on_render() { const auto& [idx, normal, pt] = feature.get_plane(); assert(idx < m_plane_models_cache.size()); - set_matrix_uniforms(model_matrix); + set_matrix_uniforms(m_volume_matrix); m_plane_models_cache[idx].set_color(colors.front()); m_plane_models_cache[idx].render(); if (update_raycasters) { auto it = m_raycasters.find(PLANE_ID); if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(model_matrix); + it->second->set_transform(m_volume_matrix); } break; } @@ -601,13 +598,13 @@ void GLGizmoMeasure::on_render() } } - render_feature(*m_curr_feature, colors, m_volume_matrix, inv_zoom, true); + render_feature(*m_curr_feature, colors, inv_zoom, true); } if (m_selected_features.first.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.first.feature)) { std::vector colors; colors.emplace_back(SELECTED_1ST_COLOR); - render_feature(*m_selected_features.first.feature, colors, m_volume_matrix, inv_zoom, false); + render_feature(*m_selected_features.first.feature, colors, inv_zoom, false); if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point) { auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_1_ID; }); @@ -618,7 +615,7 @@ void GLGizmoMeasure::on_render() if (m_selected_features.second.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.second.feature)) { std::vector colors; colors.emplace_back(SELECTED_2ND_COLOR); - render_feature(*m_selected_features.second.feature, colors, m_volume_matrix, inv_zoom, false); + render_feature(*m_selected_features.second.feature, colors, inv_zoom, false); if (m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_2_ID; }); @@ -629,7 +626,7 @@ void GLGizmoMeasure::on_render() if (is_hovering_on_locked_feature && m_curr_point_on_feature_position.has_value()) { if (m_hover_id != POINT_ID) { - const Transform3d matrix = m_volume_matrix * Geometry::translation_transform(*m_curr_point_on_feature_position) * Geometry::scale_transform(inv_zoom); + const Transform3d matrix = m_volume_matrix * Geometry::translation_transform(*m_curr_point_on_feature_position) * m_volume_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(matrix); m_sphere.model.set_color(hover_selection_color()); m_sphere.model.render(); @@ -675,6 +672,9 @@ void GLGizmoMeasure::update_if_needed() } m_old_model_object = object; m_old_model_volume = volume; + + m_volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); + m_volume_matrix_scale_inverse = Geometry::Transformation(m_volume_matrix).get_scaling_factor_matrix().inverse(); }; const ModelObject* mo = m_c->selection_info()->model_object(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 8200325f19..401feca5db 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -87,6 +87,7 @@ class GLGizmoMeasure : public GLGizmoBase Dimensioning m_dimensioning; Transform3d m_volume_matrix{ Transform3d::Identity() }; + Transform3d m_volume_matrix_scale_inverse{ Transform3d::Identity() }; std::vector m_plane_models_cache; std::map> m_raycasters; std::vector> m_selection_raycasters; From ada7618ddb1575a48a815e619efad0de6d747885 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 11 Oct 2022 10:47:20 +0200 Subject: [PATCH 204/250] Measuring: Gizmo measure shows dimensioning for distance circle-circle --- src/libslic3r/CMakeLists.txt | 1 + src/libslic3r/Measure.cpp | 241 +++++++++++++++++++- src/libslic3r/Measure.hpp | 4 + src/libslic3r/MeasureUtils.hpp | 390 +++++++++++++++++++++++++++++++++ 4 files changed, 632 insertions(+), 4 deletions(-) create mode 100644 src/libslic3r/MeasureUtils.hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index a52848b229..79e0e6355b 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -182,6 +182,7 @@ set(SLIC3R_SOURCES MeshNormals.cpp Measure.hpp Measure.cpp + MeasureUtils.hpp CustomGCode.cpp CustomGCode.hpp Arrange.hpp diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index ea68503254..27a4f8a90d 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -1,10 +1,11 @@ #include "libslic3r/libslic3r.h" #include "Measure.hpp" +#include "MeasureUtils.hpp" #include "libslic3r/Geometry/Circle.hpp" #include "libslic3r/SurfaceMesh.hpp" - +#if ENABLE_MEASURE_GIZMO namespace Slic3r { namespace Measure { @@ -13,8 +14,6 @@ namespace Measure { constexpr double feature_hover_limit = 0.5; // how close to a feature the mouse must be to highlight it constexpr double edge_endpoint_limit = 0.5; // how close to an edge endpoint the mouse ... - - static std::pair get_center_and_radius(const std::vector& border, int start_idx, int end_idx, const Transform3d& trafo) { Vec2ds pts; @@ -754,7 +753,238 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& /////////////////////////////////////////////////////////////////////////// } else if (f1.get_type() == SurfaceFeatureType::Circle) { if (f2.get_type() == SurfaceFeatureType::Circle) { - result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO + const auto [c0, r0, n0] = f1.get_circle(); + const auto [c1, r1, n1] = f2.get_circle(); + + // The following code is an adaptation of the algorithm found in: + // https://github.com/davideberly/GeometricTools/blob/master/GTE/Mathematics/DistCircle3Circle3.h + // and described in: + // https://www.geometrictools.com/Documentation/DistanceToCircle3.pdf + + struct ClosestInfo + { + double sqrDistance{ 0.0 }; + Vec3d circle0Closest{ Vec3d::Zero() }; + Vec3d circle1Closest{ Vec3d::Zero() }; + + inline bool operator < (const ClosestInfo& other) const { return sqrDistance < other.sqrDistance; } + }; + std::array candidates{}; + + const double zero = 0.0; + + const Vec3d D = c1 - c0; + + if (!are_parallel(n0, n1)) { + auto orthonormal_basis = [](const Vec3d& v) { + std::array ret; + ret[2] = v.normalized(); + int index; + ret[2].maxCoeff(&index); + switch (index) + { + case 0: { ret[0] = Vec3d(ret[2].y(), -ret[2].x(), 0.0).normalized(); break; } + case 1: { ret[0] = Vec3d(0.0, ret[2].z(), -ret[2].y()).normalized(); break; } + case 2: { ret[0] = Vec3d(-ret[2].z(), 0.0, ret[2].x()).normalized(); break; } + } + ret[1] = ret[2].cross(ret[0]).normalized(); + return ret; + }; + + // Get parameters for constructing the degree-8 polynomial phi. + const double one = 1.0; + const double two = 2.0; + const double r0sqr = sqr(r0); + const double r1sqr = sqr(r1); + + // Compute U1 and V1 for the plane of circle1. + const std::array basis = orthonormal_basis(n1); + const Vec3d U1 = basis[0]; + const Vec3d V1 = basis[1]; + + // Construct the polynomial phi(cos(theta)). + const Vec3d N0xD = n0.cross(D); + const Vec3d N0xU1 = n0.cross(U1); + const Vec3d N0xV1 = n0.cross(V1); + const double a0 = r1 * D.dot(U1); + const double a1 = r1 * D.dot(V1); + const double a2 = N0xD.dot(N0xD); + const double a3 = r1 * N0xD.dot(N0xU1); + const double a4 = r1 * N0xD.dot(N0xV1); + const double a5 = r1sqr * N0xU1.dot(N0xU1); + const double a6 = r1sqr * N0xU1.dot(N0xV1); + const double a7 = r1sqr * N0xV1.dot(N0xV1); + Polynomial1 p0{ a2 + a7, two * a3, a5 - a7 }; + Polynomial1 p1{ two * a4, two * a6 }; + Polynomial1 p2{ zero, a1 }; + Polynomial1 p3{ -a0 }; + Polynomial1 p4{ -a6, a4, two * a6 }; + Polynomial1 p5{ -a3, a7 - a5 }; + Polynomial1 tmp0{ one, zero, -one }; + Polynomial1 tmp1 = p2 * p2 + tmp0 * p3 * p3; + Polynomial1 tmp2 = two * p2 * p3; + Polynomial1 tmp3 = p4 * p4 + tmp0 * p5 * p5; + Polynomial1 tmp4 = two * p4 * p5; + Polynomial1 p6 = p0 * tmp1 + tmp0 * p1 * tmp2 - r0sqr * tmp3; + Polynomial1 p7 = p0 * tmp2 + p1 * tmp1 - r0sqr * tmp4; + + // Parameters for polynomial root finding. The roots[] array + // stores the roots. We need only the unique ones, which is + // the responsibility of the set uniqueRoots. The pairs[] + // array stores the (cosine,sine) information mentioned in the + // PDF. TODO: Choose the maximum number of iterations for root + // finding based on specific polynomial data? + const uint32_t maxIterations = 128; + int32_t degree = 0; + size_t numRoots = 0; + std::array roots{}; + std::set uniqueRoots{}; + size_t numPairs = 0; + std::array, 16> pairs{}; + double temp = zero; + double sn = zero; + + if (p7.GetDegree() > 0 || p7[0] != zero) { + // H(cs,sn) = p6(cs) + sn * p7(cs) + Polynomial1 phi = p6 * p6 - tmp0 * p7 * p7; + degree = static_cast(phi.GetDegree()); + assert(degree > 0); + numRoots = RootsPolynomial::Find(degree, &phi[0], maxIterations, roots.data()); + for (size_t i = 0; i < numRoots; ++i) { + uniqueRoots.insert(roots[i]); + } + + for (auto const& cs : uniqueRoots) { + if (std::fabs(cs) <= one) { + temp = p7(cs); + if (temp != zero) { + sn = -p6(cs) / temp; + pairs[numPairs++] = std::make_pair(cs, sn); + } + else { + temp = std::max(one - sqr(cs), zero); + sn = std::sqrt(temp); + pairs[numPairs++] = std::make_pair(cs, sn); + if (sn != zero) + pairs[numPairs++] = std::make_pair(cs, -sn); + } + } + } + } + else { + // H(cs,sn) = p6(cs) + degree = static_cast(p6.GetDegree()); + assert(degree > 0); + numRoots = RootsPolynomial::Find(degree, &p6[0], maxIterations, roots.data()); + for (size_t i = 0; i < numRoots; ++i) { + uniqueRoots.insert(roots[i]); + } + + for (auto const& cs : uniqueRoots) { + if (std::fabs(cs) <= one) { + temp = std::max(one - sqr(cs), zero); + sn = std::sqrt(temp); + pairs[numPairs++] = std::make_pair(cs, sn); + if (sn != zero) + pairs[numPairs++] = std::make_pair(cs, -sn); + } + } + } + + for (size_t i = 0; i < numPairs; ++i) { + ClosestInfo& info = candidates[i]; + Vec3d delta = D + r1 * (pairs[i].first * U1 + pairs[i].second * V1); + info.circle1Closest = c0 + delta; + const double N0dDelta = n0.dot(delta); + const double lenN0xDelta = n0.cross(delta).norm(); + if (lenN0xDelta > 0.0) { + const double diff = lenN0xDelta - r0; + info.sqrDistance = sqr(N0dDelta) + sqr(diff); + delta -= N0dDelta * n0; + delta.normalize(); + info.circle0Closest = c0 + r0 * delta; + } + else { + const Vec3d r0U0 = r0 * get_orthogonal(n0, true); + const Vec3d diff = delta - r0U0; + info.sqrDistance = diff.dot(diff); + info.circle0Closest = c0 + r0U0; + } + } + + std::sort(candidates.begin(), candidates.begin() + numPairs); + } + else { + ClosestInfo& info = candidates[0]; + + const double N0dD = n0.dot(D); + const Vec3d normProj = N0dD * n0; + const Vec3d compProj = D - normProj; + Vec3d U = compProj; + const double d = U.norm(); + U.normalize(); + + // The configuration is determined by the relative location of the + // intervals of projection of the circles on to the D-line. + // Circle0 projects to [-r0,r0] and circle1 projects to + // [d-r1,d+r1]. + const double dmr1 = d - r1; + double distance; + if (dmr1 >= r0) { + // d >= r0 + r1 + // The circles are separated (d > r0 + r1) or tangent with one + // outside the other (d = r0 + r1). + distance = dmr1 - r0; + info.circle0Closest = c0 + r0 * U; + info.circle1Closest = c1 - r1 * U; + } + else { + // d < r0 + r1 + // The cases implicitly use the knowledge that d >= 0. + const double dpr1 = d + r1; + if (dpr1 <= r0) { + // Circle1 is inside circle0. + distance = r0 - dpr1; + if (d > 0.0) { + info.circle0Closest = c0 + r0 * U; + info.circle1Closest = c1 + r1 * U; + } + else { + // The circles are concentric, so U = (0,0,0). + // Construct a vector perpendicular to N0 to use for + // closest points. + U = get_orthogonal(n0, true); + info.circle0Closest = c0 + r0 * U; + info.circle1Closest = c1 + r1 * U; + } + } + else if (dmr1 <= -r0) { + // Circle0 is inside circle1. + distance = -r0 - dmr1; + if (d > 0.0) { + info.circle0Closest = c0 - r0 * U; + info.circle1Closest = c1 - r1 * U; + } + else { + // The circles are concentric, so U = (0,0,0). + // Construct a vector perpendicular to N0 to use for + // closest points. + U = get_orthogonal(n0, true); + info.circle0Closest = c0 + r0 * U; + info.circle1Closest = c1 + r1 * U; + } + } + else { + distance = (c1 - c0).norm(); + info.circle0Closest = c0; + info.circle1Closest = c1; + } + } + + info.sqrDistance = distance * distance + N0dD * N0dD; + } + + result.distance_infinite = std::make_optional(DistAndPoints{ std::sqrt(candidates[0].sqrDistance), candidates[0].circle0Closest, candidates[0].circle1Closest }); // TODO /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { assert(measuring != nullptr); @@ -823,3 +1053,6 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& } // namespace Measure } // namespace Slic3r + + +#endif // ENABLE_MEASURE_GIZMO diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 2e17eea5c5..f310d8f9fa 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -1,6 +1,8 @@ #ifndef Slic3r_Measure_hpp_ #define Slic3r_Measure_hpp_ +#if ENABLE_MEASURE_GIZMO + #include #include @@ -191,3 +193,5 @@ inline bool are_perpendicular(const SurfaceFeature& f1, const SurfaceFeature& f2 } // namespace Slic3r #endif // Slic3r_Measure_hpp_ + +#endif // ENABLE_MEASURE_GIZMO diff --git a/src/libslic3r/MeasureUtils.hpp b/src/libslic3r/MeasureUtils.hpp new file mode 100644 index 0000000000..4f84624eac --- /dev/null +++ b/src/libslic3r/MeasureUtils.hpp @@ -0,0 +1,390 @@ +#ifndef Slic3r_MeasureUtils_hpp_ +#define Slic3r_MeasureUtils_hpp_ + +#if ENABLE_MEASURE_GIZMO + +#include + +namespace Slic3r { +namespace Measure { + +// Utility class used to calculate distance circle-circle +// Adaptation of code found in: +// https://github.com/davideberly/GeometricTools/blob/master/GTE/Mathematics/Polynomial1.h + +class Polynomial1 +{ +public: + Polynomial1(std::initializer_list values) + { + // C++ 11 will call the default constructor for + // Polynomial1 p{}, so it is guaranteed that + // values.size() > 0. + m_coefficient.resize(values.size()); + std::copy(values.begin(), values.end(), m_coefficient.begin()); + EliminateLeadingZeros(); + } + + // Construction and destruction. The first constructor creates a + // polynomial of the specified degree but sets all coefficients to + // zero (to ensure initialization). You are responsible for setting + // the coefficients, presumably with the degree-term set to a nonzero + // number. In the second constructor, the degree is the number of + // initializers plus 1, but then adjusted so that coefficient[degree] + // is not zero (unless all initializer values are zero). + explicit Polynomial1(uint32_t degree) + : m_coefficient(static_cast(degree) + 1, 0.0) + {} + + // Eliminate any leading zeros in the polynomial, except in the case + // the degree is 0 and the coefficient is 0. The elimination is + // necessary when arithmetic operations cause a decrease in the degree + // of the result. For example, (1 + x + x^2) + (1 + 2*x - x^2) = + // (2 + 3*x). The inputs both have degree 2, so the result is created + // with degree 2. After the addition we find that the degree is in + // fact 1 and resize the array of coefficients. This function is + // called internally by the arithmetic operators, but it is exposed in + // the public interface in case you need it for your own purposes. + void EliminateLeadingZeros() + { + const size_t size = m_coefficient.size(); + if (size > 1) { + const double zero = 0.0; + int32_t leading; + for (leading = static_cast(size) - 1; leading > 0; --leading) { + if (m_coefficient[leading] != zero) + break; + } + + m_coefficient.resize(++leading); + } + } + + // Set all coefficients to the specified value. + void SetCoefficients(double value) + { + std::fill(m_coefficient.begin(), m_coefficient.end(), value); + } + + inline uint32_t GetDegree() const + { + // By design, m_coefficient.size() > 0. + return static_cast(m_coefficient.size() - 1); + } + + inline const double& operator[](uint32_t i) const { return m_coefficient[i]; } + inline double& operator[](uint32_t i) { return m_coefficient[i]; } + + // Evaluate the polynomial. If the polynomial is invalid, the + // function returns zero. + double operator()(double t) const + { + int32_t i = static_cast(m_coefficient.size()); + double result = m_coefficient[--i]; + for (--i; i >= 0; --i) { + result *= t; + result += m_coefficient[i]; + } + return result; + } + +protected: + // The class is designed so that m_coefficient.size() >= 1. + std::vector m_coefficient; +}; + +Polynomial1 operator * (const Polynomial1& p0, const Polynomial1& p1) +{ + const uint32_t p0Degree = p0.GetDegree(); + const uint32_t p1Degree = p1.GetDegree(); + Polynomial1 result(p0Degree + p1Degree); + result.SetCoefficients(0.0); + for (uint32_t i0 = 0; i0 <= p0Degree; ++i0) { + for (uint32_t i1 = 0; i1 <= p1Degree; ++i1) { + result[i0 + i1] += p0[i0] * p1[i1]; + } + } + return result; +} + +Polynomial1 operator + (const Polynomial1& p0, const Polynomial1& p1) +{ + const uint32_t p0Degree = p0.GetDegree(); + const uint32_t p1Degree = p1.GetDegree(); + uint32_t i; + if (p0Degree >= p1Degree) { + Polynomial1 result(p0Degree); + for (i = 0; i <= p1Degree; ++i) { + result[i] = p0[i] + p1[i]; + } + for (/**/; i <= p0Degree; ++i) { + result[i] = p0[i]; + } + result.EliminateLeadingZeros(); + return result; + } + else { + Polynomial1 result(p1Degree); + for (i = 0; i <= p0Degree; ++i) { + result[i] = p0[i] + p1[i]; + } + for (/**/; i <= p1Degree; ++i) { + result[i] = p1[i]; + } + result.EliminateLeadingZeros(); + return result; + } +} + +Polynomial1 operator - (const Polynomial1& p0, const Polynomial1& p1) +{ + const uint32_t p0Degree = p0.GetDegree(); + const uint32_t p1Degree = p1.GetDegree(); + uint32_t i; + if (p0Degree >= p1Degree) { + Polynomial1 result(p0Degree); + for (i = 0; i <= p1Degree; ++i) { + result[i] = p0[i] - p1[i]; + } + for (/**/; i <= p0Degree; ++i) { + result[i] = p0[i]; + } + result.EliminateLeadingZeros(); + return result; + } + else { + Polynomial1 result(p1Degree); + for (i = 0; i <= p0Degree; ++i) { + result[i] = p0[i] - p1[i]; + } + for (/**/; i <= p1Degree; ++i) { + result[i] = -p1[i]; + } + result.EliminateLeadingZeros(); + return result; + } +} + +Polynomial1 operator * (double scalar, const Polynomial1& p) +{ + const uint32_t degree = p.GetDegree(); + Polynomial1 result(degree); + for (uint32_t i = 0; i <= degree; ++i) { + result[i] = scalar * p[i]; + } + return result; +} + +// Utility class used to calculate distance circle-circle +// Adaptation of code found in: +// https://github.com/davideberly/GeometricTools/blob/master/GTE/Mathematics/RootsPolynomial.h + +class RootsPolynomial +{ +public: + // General equations: sum_{i=0}^{d} c(i)*t^i = 0. The input array 'c' + // must have at least d+1 elements and the output array 'root' must + // have at least d elements. + + // Find the roots on (-infinity,+infinity). + static int32_t Find(int32_t degree, const double* c, uint32_t maxIterations, double* roots) + { + if (degree >= 0 && c != nullptr) { + const double zero = 0.0; + while (degree >= 0 && c[degree] == zero) { + --degree; + } + + if (degree > 0) { + // Compute the Cauchy bound. + const double one = 1.0; + const double invLeading = one / c[degree]; + double maxValue = zero; + for (int32_t i = 0; i < degree; ++i) { + const double value = std::fabs(c[i] * invLeading); + if (value > maxValue) + maxValue = value; + } + const double bound = one + maxValue; + + return FindRecursive(degree, c, -bound, bound, maxIterations, roots); + } + else if (degree == 0) + // The polynomial is a nonzero constant. + return 0; + else { + // The polynomial is identically zero. + roots[0] = zero; + return 1; + } + } + else + // Invalid degree or c. + return 0; + } + + // If you know that p(tmin) * p(tmax) <= 0, then there must be at + // least one root in [tmin, tmax]. Compute it using bisection. + static bool Find(int32_t degree, const double* c, double tmin, double tmax, uint32_t maxIterations, double& root) + { + const double zero = 0.0; + double pmin = Evaluate(degree, c, tmin); + if (pmin == zero) { + root = tmin; + return true; + } + double pmax = Evaluate(degree, c, tmax); + if (pmax == zero) { + root = tmax; + return true; + } + + if (pmin * pmax > zero) + // It is not known whether the interval bounds a root. + return false; + + if (tmin >= tmax) + // Invalid ordering of interval endpoitns. + return false; + + for (uint32_t i = 1; i <= maxIterations; ++i) { + root = 0.5 * (tmin + tmax); + + // This test is designed for 'float' or 'double' when tmin + // and tmax are consecutive floating-point numbers. + if (root == tmin || root == tmax) + break; + + const double p = Evaluate(degree, c, root); + const double product = p * pmin; + if (product < zero) { + tmax = root; + pmax = p; + } + else if (product > zero) { + tmin = root; + pmin = p; + } + else + break; + } + + return true; + } + + // Support for the Find functions. + static int32_t FindRecursive(int32_t degree, double const* c, double tmin, double tmax, uint32_t maxIterations, double* roots) + { + // The base of the recursion. + const double zero = 0.0; + double root = zero; + if (degree == 1) { + int32_t numRoots; + if (c[1] != zero) { + root = -c[0] / c[1]; + numRoots = 1; + } + else if (c[0] == zero) { + root = zero; + numRoots = 1; + } + else + numRoots = 0; + + if (numRoots > 0 && tmin <= root && root <= tmax) { + roots[0] = root; + return 1; + } + return 0; + } + + // Find the roots of the derivative polynomial scaled by 1/degree. + // The scaling avoids the factorial growth in the coefficients; + // for example, without the scaling, the high-order term x^d + // becomes (d!)*x through multiple differentiations. With the + // scaling we instead get x. This leads to better numerical + // behavior of the root finder. + const int32_t derivDegree = degree - 1; + std::vector derivCoeff(static_cast(derivDegree) + 1); + std::vector derivRoots(derivDegree); + for (int32_t i = 0, ip1 = 1; i <= derivDegree; ++i, ++ip1) { + derivCoeff[i] = c[ip1] * (double)(ip1) / (double)degree; + } + const int32_t numDerivRoots = FindRecursive(degree - 1, &derivCoeff[0], tmin, tmax, maxIterations, &derivRoots[0]); + + int32_t numRoots = 0; + if (numDerivRoots > 0) { + // Find root on [tmin,derivRoots[0]]. + if (Find(degree, c, tmin, derivRoots[0], maxIterations, root)) + roots[numRoots++] = root; + + // Find root on [derivRoots[i],derivRoots[i+1]]. + for (int32_t i = 0, ip1 = 1; i <= numDerivRoots - 2; ++i, ++ip1) { + if (Find(degree, c, derivRoots[i], derivRoots[ip1], maxIterations, root)) + roots[numRoots++] = root; + } + + // Find root on [derivRoots[numDerivRoots-1],tmax]. + if (Find(degree, c, derivRoots[static_cast(numDerivRoots) - 1], tmax, maxIterations, root)) + roots[numRoots++] = root; + } + else { + // The polynomial is monotone on [tmin,tmax], so has at most one root. + if (Find(degree, c, tmin, tmax, maxIterations, root)) + roots[numRoots++] = root; + } + return numRoots; + } + + static double Evaluate(int32_t degree, const double* c, double t) + { + int32_t i = degree; + double result = c[i]; + while (--i >= 0) { + result = t * result + c[i]; + } + return result; + } +}; + +// Adaptation of code found in: +// https://github.com/davideberly/GeometricTools/blob/master/GTE/Mathematics/Vector.h + +// Construct a single vector orthogonal to the nonzero input vector. If +// the maximum absolute component occurs at index i, then the orthogonal +// vector U has u[i] = v[i+1], u[i+1] = -v[i], and all other components +// zero. The index addition i+1 is computed modulo N. +Vec3d get_orthogonal(const Vec3d& v, bool unitLength) +{ + double cmax = std::fabs(v[0]); + int32_t imax = 0; + for (int32_t i = 1; i < 3; ++i) { + double c = std::fabs(v[i]); + if (c > cmax) { + cmax = c; + imax = i; + } + } + + Vec3d result = Vec3d::Zero(); + int32_t inext = imax + 1; + if (inext == 3) + inext = 0; + + result[imax] = v[inext]; + result[inext] = -v[imax]; + if (unitLength) { + const double sqrDistance = result[imax] * result[imax] + result[inext] * result[inext]; + const double invLength = 1.0 / std::sqrt(sqrDistance); + result[imax] *= invLength; + result[inext] *= invLength; + } + return result; +} + +} // namespace Slic3r +} // namespace Measure + +#endif // Slic3r_MeasureUtils_hpp_ + +#endif // ENABLE_MEASURE_GIZMO From 1a67da32f247689c649cf6cf89aca4f23cad6f6f Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 11 Oct 2022 11:41:15 +0200 Subject: [PATCH 205/250] Fixed warning --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 1976cbcdab..0d53c69385 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -909,7 +909,7 @@ void GLGizmoMeasure::render_dimensioning() m_is_editing_distance_first_frame = true; ImGui::CloseCurrentPopup(); }; - auto action_scale = [this, perform_scale, action_exit](double new_value, double old_value) { + auto action_scale = [perform_scale, action_exit](double new_value, double old_value) { perform_scale(new_value, old_value); action_exit(); }; From dc27dbb6ff72a6b6e22833108ec70f04249c81df Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 11 Oct 2022 13:38:07 +0200 Subject: [PATCH 206/250] Measuring: Gizmo measure - Fixed rendering of selected circle features --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 34 ++++++++++++++---------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 0d53c69385..db33135dda 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -329,7 +329,8 @@ void GLGizmoMeasure::on_render() if (m_mode == EMode::BasicSelection) { std::optional curr_feature = mouse_on_object ? m_measuring->get_feature(model_facet_idx, position_on_model.cast()) : std::nullopt; m_curr_point_on_feature_position.reset(); - if (m_curr_feature != curr_feature) { + if (m_curr_feature != curr_feature || + (curr_feature.has_value() && curr_feature->get_type() == Measure::SurfaceFeatureType::Circle && (m_curr_feature != curr_feature || m_last_inv_zoom != inv_zoom))) { m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID); m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID); m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID); @@ -470,7 +471,7 @@ void GLGizmoMeasure::on_render() }; auto render_feature = [this, set_matrix_uniforms](const Measure::SurfaceFeature& feature, const std::vector& colors, - float inv_zoom, bool update_raycasters) { + float inv_zoom, bool update_raycasters_transform) { switch (feature.get_type()) { default: { assert(false); break; } @@ -481,7 +482,7 @@ void GLGizmoMeasure::on_render() set_matrix_uniforms(feature_matrix); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); - if (update_raycasters) { + if (update_raycasters_transform) { auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) it->second->set_transform(feature_matrix); @@ -496,7 +497,7 @@ void GLGizmoMeasure::on_render() set_matrix_uniforms(center_matrix); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); - if (update_raycasters) { + if (update_raycasters_transform) { auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) it->second->set_transform(center_matrix); @@ -504,13 +505,20 @@ void GLGizmoMeasure::on_render() // render circle const Transform3d circle_matrix = m_volume_matrix * Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); set_matrix_uniforms(circle_matrix); - m_circle.model.set_color(colors.back()); - m_circle.model.render(); - if (update_raycasters) { + if (update_raycasters_transform) { + m_circle.model.set_color(colors.back()); + m_circle.model.render(); auto it = m_raycasters.find(CIRCLE_ID); if (it != m_raycasters.end() && it->second != nullptr) it->second->set_transform(circle_matrix); } + else { + GLModel circle; + GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); + circle.init_from(std::move(circle_geometry)); + circle.set_color(colors.back()); + circle.render(); + } break; } case Measure::SurfaceFeatureType::Edge: @@ -523,7 +531,7 @@ void GLGizmoMeasure::on_render() set_matrix_uniforms(point_matrix); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); - if (update_raycasters) { + if (update_raycasters_transform) { auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) it->second->set_transform(point_matrix); @@ -536,7 +544,7 @@ void GLGizmoMeasure::on_render() set_matrix_uniforms(edge_matrix); m_cylinder.model.set_color(colors.back()); m_cylinder.model.render(); - if (update_raycasters) { + if (update_raycasters_transform) { auto it = m_raycasters.find(EDGE_ID); if (it != m_raycasters.end() && it->second != nullptr) it->second->set_transform(edge_matrix); @@ -550,7 +558,7 @@ void GLGizmoMeasure::on_render() set_matrix_uniforms(m_volume_matrix); m_plane_models_cache[idx].set_color(colors.front()); m_plane_models_cache[idx].render(); - if (update_raycasters) { + if (update_raycasters_transform) { auto it = m_raycasters.find(PLANE_ID); if (it != m_raycasters.end() && it->second != nullptr) it->second->set_transform(m_volume_matrix); @@ -602,8 +610,7 @@ void GLGizmoMeasure::on_render() } if (m_selected_features.first.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.first.feature)) { - std::vector colors; - colors.emplace_back(SELECTED_1ST_COLOR); + const std::vector colors = { SELECTED_1ST_COLOR }; render_feature(*m_selected_features.first.feature, colors, inv_zoom, false); if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point) { auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), @@ -613,8 +620,7 @@ void GLGizmoMeasure::on_render() } } if (m_selected_features.second.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.second.feature)) { - std::vector colors; - colors.emplace_back(SELECTED_2ND_COLOR); + const std::vector colors = { SELECTED_2ND_COLOR }; render_feature(*m_selected_features.second.feature, colors, inv_zoom, false); if (m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), From e3db1879b128ecf5af383c7c23a103f5b6300e4d Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 12 Oct 2022 10:05:45 +0200 Subject: [PATCH 207/250] Fixed differences after rebase to master --- src/slic3r/GUI/GLCanvas3D.cpp | 26 ++- src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | 252 +++++++++++------------ src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 - 3 files changed, 133 insertions(+), 146 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 7d8ca616b4..62912fa5e1 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5537,15 +5537,19 @@ void GLCanvas3D::_picking_pass() imgui.text_colored(col_2_color, col_2.c_str()); }; - char buf[1024]; if (hit.type != SceneRaycaster::EType::None) { if (ImGui::BeginTable("Hit", 2)) { - add_strings_row_to_table("Object ID", ImGuiWrapper::COL_ORANGE_LIGHT, std::to_string(hit.raycaster_id), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table("Type", ImGuiWrapper::COL_ORANGE_LIGHT, object_type, ImGui::GetStyleColorVec4(ImGuiCol_Text)); + char buf[1024]; + add_strings_row_to_table("Object ID:", ImGuiWrapper::COL_ORANGE_LIGHT, + std::to_string(hit.raycaster_id), ImGuiWrapper::to_ImVec4(ColorRGBA::WHITE())); + add_strings_row_to_table("Type:", ImGuiWrapper::COL_ORANGE_LIGHT, + object_type, ImGuiWrapper::to_ImVec4(ColorRGBA::WHITE())); sprintf(buf, "%.3f, %.3f, %.3f", hit.position.x(), hit.position.y(), hit.position.z()); - add_strings_row_to_table("Position", ImGuiWrapper::COL_ORANGE_LIGHT, std::string(buf), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table("Position:", ImGuiWrapper::COL_ORANGE_LIGHT, + std::string(buf), ImGuiWrapper::to_ImVec4(ColorRGBA::WHITE())); sprintf(buf, "%.3f, %.3f, %.3f", hit.normal.x(), hit.normal.y(), hit.normal.z()); - add_strings_row_to_table("Normal", ImGuiWrapper::COL_ORANGE_LIGHT, std::string(buf), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table("Normal:", ImGuiWrapper::COL_ORANGE_LIGHT, + std::string(buf), ImGuiWrapper::to_ImVec4(ColorRGBA::WHITE())); ImGui::EndTable(); } } @@ -5554,13 +5558,17 @@ void GLCanvas3D::_picking_pass() ImGui::Separator(); imgui.text("Registered for picking:"); - if (ImGui::BeginTable("Raycasters", 2)) { + if (ImGui::BeginTable("Counters", 2)) { + char buf[1024]; sprintf(buf, "%d (%d)", (int)m_scene_raycaster.beds_count(), (int)m_scene_raycaster.active_beds_count()); - add_strings_row_to_table("Beds", ImGuiWrapper::COL_ORANGE_LIGHT, std::string(buf), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table("Beds:", ImGuiWrapper::COL_ORANGE_LIGHT, + std::string(buf), ImGuiWrapper::to_ImVec4(ColorRGBA::WHITE())); sprintf(buf, "%d (%d)", (int)m_scene_raycaster.volumes_count(), (int)m_scene_raycaster.active_volumes_count()); - add_strings_row_to_table("Volumes", ImGuiWrapper::COL_ORANGE_LIGHT, std::string(buf), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table("Volumes:", ImGuiWrapper::COL_ORANGE_LIGHT, + std::string(buf), ImGuiWrapper::to_ImVec4(ColorRGBA::WHITE())); sprintf(buf, "%d (%d)", (int)m_scene_raycaster.gizmos_count(), (int)m_scene_raycaster.active_gizmos_count()); - add_strings_row_to_table("Gizmo elements", ImGuiWrapper::COL_ORANGE_LIGHT, std::string(buf), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table("Gizmo elements:", ImGuiWrapper::COL_ORANGE_LIGHT, + std::string(buf), ImGuiWrapper::to_ImVec4(ColorRGBA::WHITE())); ImGui::EndTable(); } imgui.end(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index 70bbc92107..3af58dd960 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -10,7 +10,6 @@ #include "libslic3r/Geometry/ConvexHull.hpp" #include "libslic3r/Model.hpp" -#include "libslic3r/SurfaceMesh.hpp" #include @@ -22,31 +21,9 @@ namespace GUI { static const Slic3r::ColorRGBA DEFAULT_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.5f }; static const Slic3r::ColorRGBA DEFAULT_HOVER_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.75f }; - - - -// TESTING: -static Halfedge_index hi; -static bool hi_initialized = false; -static std::unique_ptr sm_ptr; -static Vertex_index src; -static Vertex_index tgt; - - - - - - GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) -{ - indexed_triangle_set a = its_make_cone(0.05, .2); - its_rotate_x(a, M_PI); - its_translate(a, stl_vertex(0., 0., .8)); - indexed_triangle_set b = its_make_cylinder(.02, 0.8); - its_merge(a, b); - arrow.init_from(a); -} +{} bool GLGizmoFlatten::on_mouse(const wxMouseEvent &mouse_event) { @@ -60,7 +37,9 @@ bool GLGizmoFlatten::on_mouse(const wxMouseEvent &mouse_event) m_mouse_left_down = true; Selection &selection = m_parent.get_selection(); if (selection.is_single_full_instance()) { - hi = sm_ptr->halfedge(Face_index(m_hover_id)); + // Rotate the object so the normal points downward: + selection.flattening_rotate(m_planes[m_hover_id].normal); + m_parent.do_rotate(L("Gizmo-Place on Face")); } return true; } @@ -122,18 +101,6 @@ void GLGizmoFlatten::on_render() const Selection& selection = m_parent.get_selection(); #if ENABLE_LEGACY_OPENGL_REMOVAL - - - - if (!hi_initialized) { - const indexed_triangle_set & its = m_c->selection_info()->model_object()->volumes.front()->mesh().its; - sm_ptr.reset(new SurfaceMesh(its)); - hi = sm_ptr->halfedge(Face_index(0)); - hi_initialized = true; - } - SurfaceMesh & sm = *sm_ptr; - - GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader == nullptr) return; @@ -169,13 +136,8 @@ void GLGizmoFlatten::on_render() m_planes[i].vbo.model.set_color(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); m_planes[i].vbo.model.render(); #else - int cur_face = hi.is_invalid() ? 1000000 : sm.face(hi); - for (int i = 0; i < m_planes.size(); ++i) { - m_planes[i].vbo.set_color(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); - if (i == cur_face) - m_planes[i].vbo.set_color(i == m_hover_id ? ColorRGBA(.5f, 0.f, 0.f, 1.f) : ColorRGBA(1.f, 0.f, 0.f, 1.f)); - m_planes[i].vbo.render(); - } + m_planes[i].vbo.set_color(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); + m_planes[i].vbo.render(); #endif // ENABLE_RAYCAST_PICKING #else glsafe(::glColor4fv(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR.data() : DEFAULT_PLANE_COLOR.data())); @@ -188,90 +150,6 @@ void GLGizmoFlatten::on_render() #endif // !ENABLE_LEGACY_OPENGL_REMOVAL } - - - - - ///////////////// - //////////////// - ////////////////// - - auto draw_arrow = [&](const Vec3d& from, const Vec3d& to) -> void { - Vec3d desired_pos = from; - Vec3d desired_dir = to - from; - double desired_len = desired_dir.norm(); - desired_dir.normalize(); - - Transform3d m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); - m.translate(desired_pos); - Eigen::Quaterniond q; - Transform3d rot = Transform3d::Identity(); - rot.matrix().block(0, 0, 3, 3) = q.setFromTwoVectors(Vec3d::UnitZ(), desired_dir).toRotationMatrix(); - Transform3d sc = Transform3d::Identity(); - sc.scale(desired_len); - m = m * sc * rot; - - const Camera & camera = wxGetApp().plater()->get_camera(); - Transform3d view_model_matrix = camera.get_view_matrix() * - Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m; - - shader->set_uniform("view_model_matrix", view_model_matrix); - arrow.render(); - }; - - m_imgui->begin(std::string("DEBUG")); - bool invalid = hi.is_invalid(); - if (invalid) { - if (m_imgui->button(std::string("HALFEDGE INVALID (Click to reset)"))) - hi = sm.halfedge(Face_index(0)); - } - else { - m_imgui->text(sm.is_border(hi) ? "BORDER HALFEDGE !" : "Halfedge is not border"); - m_imgui->text((std::string("Face: ") + std::to_string(int(hi.face()))).c_str()); - m_imgui->text(std::string("Target degree:" + std::to_string(sm.degree(sm.target(hi))))); - m_imgui->text(std::string("Face degree:" + std::to_string(sm.degree(sm.face(hi))))); - } - m_imgui->disabled_begin(invalid); - if (m_imgui->button(std::string("next"))) - hi = sm.next(hi); - if (m_imgui->button(std::string("prev"))) - hi = sm.prev(hi); - if (m_imgui->button(std::string("opposite"))) - hi = sm.opposite(hi); - if (m_imgui->button(std::string("next_around_target"))) - hi = sm.next_around_target(hi); - if (m_imgui->button(std::string("prev_around_target"))) - hi = sm.prev_around_target(hi); - if (m_imgui->button(std::string("next_around_source"))) - hi = sm.next_around_source(hi); - if (m_imgui->button(std::string("prev_around_source"))) - hi = sm.prev_around_source(hi); - if (m_imgui->button(std::string("remember one"))) - src = sm.target(hi); - if (m_imgui->button(std::string("switch to halfedge"))) { - tgt = sm.target(hi); - hi = sm.halfedge(src, tgt); - } - - if (invalid) - m_imgui->disabled_end(); - m_imgui->end(); - - if (!hi.is_invalid()) { - Vec3d a = sm.point(sm.source(hi)).cast(); - Vec3d b = sm.point(sm.target(hi)).cast(); - draw_arrow(a, b); - } - - - ///////////////// - //////////////// - ////////////////// - - - - - glsafe(::glEnable(GL_CULL_FACE)); glsafe(::glDisable(GL_BLEND)); @@ -375,11 +253,11 @@ void GLGizmoFlatten::update_planes() for (const ModelVolume* vol : mo->volumes) { if (vol->type() != ModelVolumeType::MODEL_PART) continue; - TriangleMesh vol_ch = vol->mesh(); //vol->get_convex_hull(); + TriangleMesh vol_ch = vol->get_convex_hull(); vol_ch.transform(vol->get_matrix()); ch.merge(vol_ch); } - //ch = ch.convex_hull_3d(); + ch = ch.convex_hull_3d(); m_planes.clear(); #if ENABLE_RAYCAST_PICKING on_unregister_raycasters_for_picking(); @@ -403,17 +281,47 @@ void GLGizmoFlatten::update_planes() std::vector facet_visited(num_of_facets, false); int facet_queue_cnt = 0; const stl_normal* normal_ptr = nullptr; + int facet_idx = 0; + while (1) { + // Find next unvisited triangle: + for (; facet_idx < num_of_facets; ++ facet_idx) + if (!facet_visited[facet_idx]) { + facet_queue[facet_queue_cnt ++] = facet_idx; + facet_visited[facet_idx] = true; + normal_ptr = &face_normals[facet_idx]; + m_planes.emplace_back(); + break; + } + if (facet_idx == num_of_facets) + break; // Everything was visited already + + while (facet_queue_cnt > 0) { + int facet_idx = facet_queue[-- facet_queue_cnt]; + const stl_normal& this_normal = face_normals[facet_idx]; + if (std::abs(this_normal(0) - (*normal_ptr)(0)) < 0.001 && std::abs(this_normal(1) - (*normal_ptr)(1)) < 0.001 && std::abs(this_normal(2) - (*normal_ptr)(2)) < 0.001) { + const Vec3i face = ch.its.indices[facet_idx]; + for (int j=0; j<3; ++j) + m_planes.back().vertices.emplace_back(ch.its.vertices[face[j]].cast()); + + facet_visited[facet_idx] = true; + for (int j = 0; j < 3; ++ j) + if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && ! facet_visited[neighbor_idx]) + facet_queue[facet_queue_cnt ++] = neighbor_idx; + } + } + m_planes.back().normal = normal_ptr->cast(); - for (size_t i = 0; i < ch.its.indices.size(); ++i) { - const Vec3i & face = ch.its.indices[i]; - m_planes.emplace_back(); - for (int j = 0; j < 3; ++j) - m_planes.back().vertices.emplace_back(ch.its.vertices[face[j]].cast()); - m_planes.back().normal = face_normals[i].cast(); Pointf3s& verts = m_planes.back().vertices; // Now we'll transform all the points into world coordinates, so that the areas, angles and distances // make real sense. verts = transform(verts, inst_matrix); + + // if this is a just a very small triangle, remove it to speed up further calculations (it would be rejected later anyway): + if (verts.size() == 3 && + ((verts[0] - verts[1]).norm() < minimal_side + || (verts[0] - verts[2]).norm() < minimal_side + || (verts[1] - verts[2]).norm() < minimal_side)) + m_planes.pop_back(); } // Let's prepare transformation of the normal vector from mesh to instance coordinates. @@ -445,12 +353,84 @@ void GLGizmoFlatten::update_planes() polygon = Slic3r::Geometry::convex_hull(polygon); polygon = transform(polygon, tr.inverse()); + // Calculate area of the polygons and discard ones that are too small + float& area = m_planes[polygon_id].area; + area = 0.f; + for (unsigned int i = 0; i < polygon.size(); i++) // Shoelace formula + area += polygon[i](0)*polygon[i + 1 < polygon.size() ? i + 1 : 0](1) - polygon[i + 1 < polygon.size() ? i + 1 : 0](0)*polygon[i](1); + area = 0.5f * std::abs(area); + + bool discard = false; + if (area < minimal_area) + discard = true; + else { + // We also check the inner angles and discard polygons with angles smaller than the following threshold + const double angle_threshold = ::cos(10.0 * (double)PI / 180.0); + + for (unsigned int i = 0; i < polygon.size(); ++i) { + const Vec3d& prec = polygon[(i == 0) ? polygon.size() - 1 : i - 1]; + const Vec3d& curr = polygon[i]; + const Vec3d& next = polygon[(i == polygon.size() - 1) ? 0 : i + 1]; + + if ((prec - curr).normalized().dot((next - curr).normalized()) > angle_threshold) { + discard = true; + break; + } + } + } + + if (discard) { + m_planes[polygon_id--] = std::move(m_planes.back()); + m_planes.pop_back(); + continue; + } + // We will shrink the polygon a little bit so it does not touch the object edges: Vec3d centroid = std::accumulate(polygon.begin(), polygon.end(), Vec3d(0.0, 0.0, 0.0)); centroid /= (double)polygon.size(); for (auto& vertex : polygon) vertex = 0.9f*vertex + 0.1f*centroid; + // Polygon is now simple and convex, we'll round the corners to make them look nicer. + // The algorithm takes a vertex, calculates middles of respective sides and moves the vertex + // towards their average (controlled by 'aggressivity'). This is repeated k times. + // In next iterations, the neighbours are not always taken at the middle (to increase the + // rounding effect at the corners, where we need it most). + const unsigned int k = 10; // number of iterations + const float aggressivity = 0.2f; // agressivity + const unsigned int N = polygon.size(); + std::vector> neighbours; + if (k != 0) { + Pointf3s points_out(2*k*N); // vector long enough to store the future vertices + for (unsigned int j=0; j Date: Wed, 12 Oct 2022 12:27:04 +0200 Subject: [PATCH 208/250] Measuring - Gizmo measure - Fixed update of volume matrix --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index db33135dda..6f8743e15b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -678,11 +678,11 @@ void GLGizmoMeasure::update_if_needed() } m_old_model_object = object; m_old_model_volume = volume; - - m_volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); - m_volume_matrix_scale_inverse = Geometry::Transformation(m_volume_matrix).get_scaling_factor_matrix().inverse(); }; + m_volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); + m_volume_matrix_scale_inverse = Geometry::Transformation(m_volume_matrix).get_scaling_factor_matrix().inverse(); + const ModelObject* mo = m_c->selection_info()->model_object(); const ModelVolume* mv = m_c->selection_info()->model_volume(); if (m_state != On || (mo == nullptr && mv == nullptr)) From cf11101d16ef82d1795fdc1cf1dee1211e108943 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 12 Oct 2022 13:38:53 +0200 Subject: [PATCH 209/250] Measuring - Gizmo measure - Measuring data converted to world coordinates --- src/libslic3r/Measure.cpp | 20 +++ src/libslic3r/Measure.hpp | 4 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 196 +++++++++++++---------- 3 files changed, 131 insertions(+), 89 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 27a4f8a90d..20ae7f4138 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -1043,6 +1043,26 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& return result; } +void DistAndPoints::transform(const Transform3d& trafo) { + from = trafo * from; + to = trafo * to; + dist = (to - from).norm(); +} + +void AngleAndEdges::transform(const Transform3d& trafo) { + const Vec3d old_e1 = e1.second - e1.first; + const Vec3d old_e2 = e2.second - e2.first; + center = trafo * center; + e1.first = trafo * e1.first; + e1.second = trafo * e1.second; + e2.first = trafo * e2.first; + e2.second = trafo * e2.second; + angle = std::acos(std::clamp(Measure::edge_direction(e1).dot(Measure::edge_direction(e2)), -1.0, 1.0)); + const Vec3d new_e1 = e1.second - e1.first; + const Vec3d new_e2 = e2.second - e2.first; + const double average_scale = 0.5 * (new_e1.norm() / old_e1.norm() + new_e2.norm() / old_e2.norm()); + radius = average_scale * radius; +} diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index f310d8f9fa..ff1757d7ae 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -120,6 +120,8 @@ struct DistAndPoints { double dist; Vec3d from; Vec3d to; + + void transform(const Transform3d& trafo); }; struct AngleAndEdges { @@ -132,6 +134,8 @@ struct AngleAndEdges { double radius; bool coplanar; + void transform(const Transform3d& trafo); + static const AngleAndEdges Dummy; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 6f8743e15b..5400a7a586 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -108,6 +108,81 @@ static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const return init_data; } +class TransformHelper +{ + struct Cache + { + std::array viewport; + Matrix4d ndc_to_ss_matrix; + Transform3d ndc_to_ss_matrix_inverse; + }; + + static Cache s_cache; + +public: + static Vec3d model_to_world(const Vec3d& model, const Transform3d& world_matrix) { + return world_matrix * model; + } + + static Vec4d world_to_clip(const Vec3d& world, const Matrix4d& projection_view_matrix) { + return projection_view_matrix * Vec4d(world.x(), world.y(), world.z(), 1.0); + } + + static Vec3d clip_to_ndc(const Vec4d& clip) { + return Vec3d(clip.x(), clip.y(), clip.z()) / clip.w(); + } + + static Vec2d ndc_to_ss(const Vec3d& ndc, const std::array& viewport) { + const double half_w = 0.5 * double(viewport[2]); + const double half_h = 0.5 * double(viewport[3]); + return { half_w * ndc.x() + double(viewport[0]) + half_w, half_h * ndc.y() + double(viewport[1]) + half_h }; + }; + + static Vec4d model_to_clip(const Vec3d& model, const Transform3d& world_matrix, const Matrix4d& projection_view_matrix) { + return world_to_clip(model_to_world(model, world_matrix), projection_view_matrix); + } + + static Vec3d model_to_ndc(const Vec3d& model, const Transform3d& world_matrix, const Matrix4d& projection_view_matrix) { + return clip_to_ndc(world_to_clip(model_to_world(model, world_matrix), projection_view_matrix)); + } + + static Vec2d model_to_ss(const Vec3d& model, const Transform3d& world_matrix, const Matrix4d& projection_view_matrix, const std::array& viewport) { + return ndc_to_ss(clip_to_ndc(world_to_clip(model_to_world(model, world_matrix), projection_view_matrix)), viewport); + } + + static Vec2d world_to_ss(const Vec3d& world, const Matrix4d& projection_view_matrix, const std::array& viewport) { + return ndc_to_ss(clip_to_ndc(world_to_clip(world, projection_view_matrix)), viewport); + } + + static const Matrix4d& ndc_to_ss_matrix(const std::array& viewport) { + update(viewport); + return s_cache.ndc_to_ss_matrix; + } + + static const Transform3d ndc_to_ss_matrix_inverse(const std::array& viewport) { + update(viewport); + return s_cache.ndc_to_ss_matrix_inverse; + } + +private: + static void update(const std::array& viewport) { + if (s_cache.viewport == viewport) + return; + + const double half_w = 0.5 * double(viewport[2]); + const double half_h = 0.5 * double(viewport[3]); + s_cache.ndc_to_ss_matrix << half_w, 0.0, 0.0, double(viewport[0]) + half_w, + 0.0, half_h, 0.0, double(viewport[1]) + half_h, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0; + + s_cache.ndc_to_ss_matrix_inverse = s_cache.ndc_to_ss_matrix.inverse(); + s_cache.viewport = viewport; + } +}; + +TransformHelper::Cache TransformHelper::s_cache = { { 0, 0, 0, 0 }, Matrix4d::Identity(), Transform3d::Identity() }; + GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) { @@ -174,8 +249,18 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) m_selection_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SELECTION_1_ID, *m_sphere.mesh_raycaster)); } - if (m_selected_features != selected_features_old && m_selected_features.second.feature.has_value()) + if (m_selected_features != selected_features_old && m_selected_features.second.feature.has_value()) { m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); + // transform to world coordinates + if (m_measurement_result.angle.has_value()) + m_measurement_result.angle->transform(m_volume_matrix); + if (m_measurement_result.distance_infinite.has_value()) + m_measurement_result.distance_infinite->transform(m_volume_matrix); + if (m_measurement_result.distance_strict.has_value()) + m_measurement_result.distance_strict->transform(m_volume_matrix); + if (m_measurement_result.distance_xyz.has_value()) + m_measurement_result.distance_xyz = TransformHelper::model_to_world(*m_measurement_result.distance_xyz, m_volume_matrix); + } return true; } @@ -725,77 +810,6 @@ void GLGizmoMeasure::restore_scene_raycasters_state() } } -class DimensioningHelper -{ - struct Cache - { - std::array viewport; - Matrix4d ndc_to_ss_matrix; - Transform3d ndc_to_ss_matrix_inverse; - }; - - static Cache s_cache; - -public: - static Vec3d model_to_world(const Vec3d& model, const Transform3d& world_matrix) { - return world_matrix * model; - } - - static Vec4d world_to_clip(const Vec3d& world, const Matrix4d& projection_view_matrix) { - return projection_view_matrix * Vec4d(world.x(), world.y(), world.z(), 1.0); - } - - static Vec3d clip_to_ndc(const Vec4d& clip) { - return Vec3d(clip.x(), clip.y(), clip.z()) / clip.w(); - } - - static Vec2d ndc_to_ss(const Vec3d& ndc, const std::array& viewport) { - const double half_w = 0.5 * double(viewport[2]); - const double half_h = 0.5 * double(viewport[3]); - return { half_w * ndc.x() + double(viewport[0]) + half_w, half_h * ndc.y() + double(viewport[1]) + half_h }; - }; - - static Vec4d model_to_clip(const Vec3d& model, const Transform3d& world_matrix, const Matrix4d& projection_view_matrix) { - return world_to_clip(model_to_world(model, world_matrix), projection_view_matrix); - } - - static Vec3d model_to_ndc(const Vec3d& model, const Transform3d& world_matrix, const Matrix4d& projection_view_matrix) { - return clip_to_ndc(world_to_clip(model_to_world(model, world_matrix), projection_view_matrix)); - } - - static Vec2d model_to_ss(const Vec3d& model, const Transform3d& world_matrix, const Matrix4d& projection_view_matrix, const std::array& viewport) { - return ndc_to_ss(clip_to_ndc(world_to_clip(model_to_world(model, world_matrix), projection_view_matrix)), viewport); - } - - static const Matrix4d& ndc_to_ss_matrix(const std::array& viewport) { - update(viewport); - return s_cache.ndc_to_ss_matrix; - } - - static const Transform3d ndc_to_ss_matrix_inverse(const std::array& viewport) { - update(viewport); - return s_cache.ndc_to_ss_matrix_inverse; - } - -private: - static void update(const std::array& viewport) { - if (s_cache.viewport == viewport) - return; - - const double half_w = 0.5 * double(viewport[2]); - const double half_h = 0.5 * double(viewport[3]); - s_cache.ndc_to_ss_matrix << half_w, 0.0, 0.0, double(viewport[0]) + half_w, - 0.0, half_h, 0.0, double(viewport[1]) + half_h, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0; - - s_cache.ndc_to_ss_matrix_inverse = s_cache.ndc_to_ss_matrix.inverse(); - s_cache.viewport = viewport; - } -}; - -DimensioningHelper::Cache DimensioningHelper::s_cache = { { 0, 0, 0, 0 }, Matrix4d::Identity(), Transform3d::Identity() }; - void GLGizmoMeasure::render_dimensioning() { static SelectedFeatures last_selected_features; @@ -816,8 +830,8 @@ void GLGizmoMeasure::render_dimensioning() const std::array& viewport = camera.get_viewport(); // screen coordinates - const Vec2d v1ss = DimensioningHelper::model_to_ss(v1, m_volume_matrix, projection_view_matrix, viewport); - const Vec2d v2ss = DimensioningHelper::model_to_ss(v2, m_volume_matrix, projection_view_matrix, viewport); + const Vec2d v1ss = TransformHelper::world_to_ss(v1, projection_view_matrix, viewport); + const Vec2d v2ss = TransformHelper::world_to_ss(v2, projection_view_matrix, viewport); if (v1ss.isApprox(v2ss)) return; @@ -835,7 +849,7 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d v1ss_3 = { v1ss.x(), v1ss.y(), 0.0 }; const Vec3d v2ss_3 = { v2ss.x(), v2ss.y(), 0.0 }; - const Transform3d ss_to_ndc_matrix = DimensioningHelper::ndc_to_ss_matrix_inverse(viewport); + const Transform3d ss_to_ndc_matrix = TransformHelper::ndc_to_ss_matrix_inverse(viewport); // stem shader->set_uniform("view_model_matrix", overlap ? @@ -951,8 +965,12 @@ void GLGizmoMeasure::render_dimensioning() auto point_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { assert(f1.get_type() == Measure::SurfaceFeatureType::Point && f2.get_type() == Measure::SurfaceFeatureType::Edge); - const std::pair e = f2.get_edge(); - const Vec3d v_proj = m_measurement_result.distance_infinite->to; + std::pair e = f2.get_edge(); + // Transform to world coordinates + e.first = TransformHelper::model_to_world(e.first, m_volume_matrix); + e.second = TransformHelper::model_to_world(e.second, m_volume_matrix); + + const Vec3d v_proj = m_measurement_result.distance_infinite->to; const Vec3d e1e2 = e.second - e.first; const Vec3d v_proje1 = v_proj - e.first; @@ -962,11 +980,11 @@ void GLGizmoMeasure::render_dimensioning() 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 Transform3d ss_to_ndc_matrix = DimensioningHelper::ndc_to_ss_matrix_inverse(viewport); + const Transform3d ss_to_ndc_matrix = TransformHelper::ndc_to_ss_matrix_inverse(viewport); - const Vec2d v_projss = DimensioningHelper::model_to_ss(v_proj, m_volume_matrix, projection_view_matrix, viewport); + const Vec2d v_projss = TransformHelper::world_to_ss(v_proj, projection_view_matrix, viewport); auto render_extension = [this, &v_projss, &projection_view_matrix, &viewport, &ss_to_ndc_matrix, shader](const Vec3d& p) { - const Vec2d pss = DimensioningHelper::model_to_ss(p, m_volume_matrix, projection_view_matrix, viewport); + const Vec2d pss = TransformHelper::world_to_ss(p, projection_view_matrix, viewport); if (!pss.isApprox(v_projss)) { const Vec2d pv_projss = v_projss - pss; const double pv_projss_len = pv_projss.norm(); @@ -1029,7 +1047,7 @@ void GLGizmoMeasure::render_dimensioning() // arc const Camera& camera = wxGetApp().plater()->get_camera(); shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center)); + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * Geometry::translation_transform(center)); m_dimensioning.arc.render(); // arrows @@ -1039,7 +1057,7 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d direction_model = (endpoint_id == 1) ? -normal.cross(position_model - center).normalized() : normal.cross(position_model - center).normalized(); const auto qz = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); const auto qx = Eigen::Quaternion::FromTwoVectors(qz * Vec3d::UnitX(), direction_model); - const Transform3d view_model_matrix = camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(position_model) * + const Transform3d view_model_matrix = camera.get_view_matrix() * Geometry::translation_transform(position_model) * qx * qz * Geometry::scale_transform(camera.get_inv_zoom()); shader->set_uniform("view_model_matrix", view_model_matrix); m_dimensioning.triangle.render(); @@ -1055,8 +1073,8 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d e11center = center - e1.first; const double e11center_len = e11center.norm(); if (e11center_len > EPSILON && e11center.dot(e11e12) < 0.0) { - shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e1.first, e1.second)) * + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * Geometry::translation_transform(center)* + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e1.first, e1.second))* Geometry::scale_transform({ e11center_len, 1.0f, 1.0f })); m_dimensioning.line.render(); } @@ -1065,19 +1083,19 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d e21center = center - e2.first; const double e21center_len = e21center.norm(); if (e21center_len > EPSILON) { - shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_volume_matrix * Geometry::translation_transform(center) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e2.first, e2.second)) * + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * Geometry::translation_transform(center)* + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e2.first, e2.second))* Geometry::scale_transform({ (coplanar && radius > 0.0) ? e21center_len : draw_radius, 1.0f, 1.0f })); m_dimensioning.line.render(); } // label - // label model coordinates - const Vec3d label_position_model = Geometry::translation_transform(center) * (draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(step * 0.5 * double(resolution), normal)) * e1_unit)); + // label world coordinates + const Vec3d label_position_world = Geometry::translation_transform(center) * (draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(step * 0.5 * double(resolution), normal)) * e1_unit)); // label screen coordinates const std::array& viewport = camera.get_viewport(); - const Vec2d label_position_ss = DimensioningHelper::model_to_ss(label_position_model, m_volume_matrix, + const Vec2d label_position_ss = TransformHelper::world_to_ss(label_position_world, camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix(), viewport); m_imgui->set_next_window_pos(label_position_ss.x(), viewport[3] - label_position_ss.y(), ImGuiCond_Always, 0.0f, 1.0f); From a62a167c1d53a66c2e8b273db1b7194a1a6baf10 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 14 Oct 2022 09:05:36 +0200 Subject: [PATCH 210/250] Measuring - Fixed crash when clicking on Delete All command while the Gizmo measure is active --- src/slic3r/GUI/Plater.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 326bd79e26..0fc8dbcd1a 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3024,6 +3024,9 @@ void Plater::priv::delete_all_objects_from_model() gcode_result.reset(); view3D->get_canvas3d()->reset_sequential_print_clearance(); +#if ENABLE_MEASURE_GIZMO + view3D->get_canvas3d()->reset_all_gizmos(); +#endif // ENABLE_MEASURE_GIZMO m_worker.cancel_all(); From 844d30f64e5f1e7bffad0f2fbe805084fdf8e4b5 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 14 Oct 2022 09:13:40 +0200 Subject: [PATCH 211/250] Measuring - Gizmo measure - Definition and rendering of point and edge features in world coordinates --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 24 ++++++++++++++---------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 - 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 5400a7a586..40b0c96aa0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -562,8 +562,8 @@ void GLGizmoMeasure::on_render() default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { - const Vec3d& position = feature.get_point(); - const Transform3d feature_matrix = m_volume_matrix * Geometry::translation_transform(position) * m_volume_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); + const Vec3d position = TransformHelper::model_to_world(feature.get_point(), m_volume_matrix); + const Transform3d feature_matrix = Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(feature_matrix); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); @@ -578,7 +578,8 @@ void GLGizmoMeasure::on_render() { const auto& [center, radius, normal] = feature.get_circle(); // render center - const Transform3d center_matrix = m_volume_matrix * Geometry::translation_transform(center) * m_volume_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); + const Vec3d center_world = TransformHelper::model_to_world(center, m_volume_matrix); + const Transform3d center_matrix = Geometry::translation_transform(center_world) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(center_matrix); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); @@ -608,11 +609,12 @@ void GLGizmoMeasure::on_render() } case Measure::SurfaceFeatureType::Edge: { - const auto& [start, end] = feature.get_edge(); + const auto& [from, to] = feature.get_edge(); // render extra point const std::optional extra = feature.get_extra_point(); if (extra.has_value()) { - const Transform3d point_matrix = m_volume_matrix * Geometry::translation_transform(*extra) * m_volume_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); + const Vec3d extra_world = TransformHelper::model_to_world(*extra, m_volume_matrix); + const Transform3d point_matrix = Geometry::translation_transform(extra_world) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(point_matrix); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); @@ -623,9 +625,11 @@ void GLGizmoMeasure::on_render() } } // render edge - const Transform3d edge_matrix = m_volume_matrix * Geometry::translation_transform(start) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start) * - Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); + const Vec3d from_world = TransformHelper::model_to_world(from, m_volume_matrix); + const Vec3d to_world = TransformHelper::model_to_world(to, m_volume_matrix); + const Transform3d edge_matrix = Geometry::translation_transform(from_world) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), to_world - from_world) * + Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (to_world - from_world).norm() }); set_matrix_uniforms(edge_matrix); m_cylinder.model.set_color(colors.back()); m_cylinder.model.render(); @@ -717,7 +721,8 @@ void GLGizmoMeasure::on_render() if (is_hovering_on_locked_feature && m_curr_point_on_feature_position.has_value()) { if (m_hover_id != POINT_ID) { - const Transform3d matrix = m_volume_matrix * Geometry::translation_transform(*m_curr_point_on_feature_position) * m_volume_matrix_scale_inverse * Geometry::scale_transform(inv_zoom); + const Vec3d position = TransformHelper::model_to_world(*m_curr_point_on_feature_position, m_volume_matrix); + const Transform3d matrix = Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(matrix); m_sphere.model.set_color(hover_selection_color()); m_sphere.model.render(); @@ -766,7 +771,6 @@ void GLGizmoMeasure::update_if_needed() }; m_volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); - m_volume_matrix_scale_inverse = Geometry::Transformation(m_volume_matrix).get_scaling_factor_matrix().inverse(); const ModelObject* mo = m_c->selection_info()->model_object(); const ModelVolume* mv = m_c->selection_info()->model_volume(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index fd93ba4aac..9db2a73aa3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -87,7 +87,6 @@ class GLGizmoMeasure : public GLGizmoBase Dimensioning m_dimensioning; Transform3d m_volume_matrix{ Transform3d::Identity() }; - Transform3d m_volume_matrix_scale_inverse{ Transform3d::Identity() }; std::vector m_plane_models_cache; std::map> m_raycasters; std::vector> m_selection_raycasters; From 83db044f0490708ae651ec175893d2b97c0ac6b2 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 19 Oct 2022 08:17:53 +0200 Subject: [PATCH 212/250] Measuring - Gizmo measure - Definition and rendering of circle features in world coordinates --- src/slic3r/GUI/GLModel.cpp | 44 +++++----- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 105 +++++++++++++++++++---- 2 files changed, 108 insertions(+), 41 deletions(-) diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 70af07b7d7..2d4d25f8c8 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -2348,37 +2348,37 @@ GLModel::Geometry smooth_cylinder(unsigned int resolution, float radius, float h GLModel::Geometry smooth_torus(unsigned int primary_resolution, unsigned int secondary_resolution, float radius, float thickness) { - primary_resolution = std::max(4, primary_resolution); - secondary_resolution = std::max(4, secondary_resolution); - const unsigned int torusSectorCount = primary_resolution; - const float torusSectorStep = 2.0f * float(M_PI) / float(torusSectorCount); - const unsigned int sectionSectorCount = secondary_resolution; - const float sectionSectorStep = 2.0f * float(M_PI) / float(sectionSectorCount); + const unsigned int torus_sector_count = std::max(4, primary_resolution); + const float torus_sector_step = 2.0f * float(M_PI) / float(torus_sector_count); + const unsigned int section_sector_count = std::max(4, secondary_resolution); + const float section_sector_step = 2.0f * float(M_PI) / float(section_sector_count); GLModel::Geometry data; data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; - data.reserve_vertices(torusSectorCount * sectionSectorCount); - data.reserve_indices(torusSectorCount * sectionSectorCount * 2 * 3); + data.reserve_vertices(torus_sector_count * section_sector_count); + data.reserve_indices(torus_sector_count * section_sector_count * 2 * 3); // vertices - for (unsigned int i = 0; i < torusSectorCount; ++i) { - const float sectionAngle = torusSectorStep * i; - const Vec3f sectionCenter(radius * std::cos(sectionAngle), radius * std::sin(sectionAngle), 0.0f); - for (unsigned int j = 0; j < sectionSectorCount; ++j) { - const float circleAngle = sectionSectorStep * j; - const float thickness_xy = thickness * std::cos(circleAngle); - const float thickness_z = thickness * std::sin(circleAngle); - const Vec3f v(thickness_xy * std::cos(sectionAngle), thickness_xy * std::sin(sectionAngle), thickness_z); - data.add_vertex(sectionCenter + v, (Vec3f)v.normalized()); + for (unsigned int i = 0; i < torus_sector_count; ++i) { + const float section_angle = torus_sector_step * i; + const float csa = std::cos(section_angle); + const float ssa = std::sin(section_angle); + const Vec3f section_center(radius * csa, radius * ssa, 0.0f); + for (unsigned int j = 0; j < section_sector_count; ++j) { + const float circle_angle = section_sector_step * j; + const float thickness_xy = thickness * std::cos(circle_angle); + const float thickness_z = thickness * std::sin(circle_angle); + const Vec3f v(thickness_xy * csa, thickness_xy * ssa, thickness_z); + data.add_vertex(section_center + v, (Vec3f)v.normalized()); } } // triangles - for (unsigned int i = 0; i < torusSectorCount; ++i) { - const unsigned int ii = i * sectionSectorCount; - const unsigned int ii_next = ((i + 1) % torusSectorCount) * sectionSectorCount; - for (unsigned int j = 0; j < sectionSectorCount; ++j) { - const unsigned int j_next = (j + 1) % sectionSectorCount; + for (unsigned int i = 0; i < torus_sector_count; ++i) { + const unsigned int ii = i * section_sector_count; + const unsigned int ii_next = ((i + 1) % torus_sector_count) * section_sector_count; + for (unsigned int j = 0; j < section_sector_count; ++j) { + const unsigned int j_next = (j + 1) % section_sector_count; const unsigned int i0 = ii + j; const unsigned int i1 = ii_next + j; const unsigned int i2 = ii_next + j_next; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 40b0c96aa0..fdd94120a4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -108,6 +108,54 @@ static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const return init_data; } +static GLModel::Geometry init_torus_data(unsigned int primary_resolution, unsigned int secondary_resolution, const Vec3f& center, + float radius, float thickness, const Vec3f& model_axis, const Transform3f& world_trafo) +{ + const unsigned int torus_sector_count = std::max(4, primary_resolution); + const unsigned int section_sector_count = std::max(4, secondary_resolution); + const float torus_sector_step = 2.0f * float(M_PI) / float(torus_sector_count); + const float section_sector_step = 2.0f * float(M_PI) / float(section_sector_count); + + GLModel::Geometry data; + data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + data.reserve_vertices(torus_sector_count * section_sector_count); + data.reserve_indices(torus_sector_count * section_sector_count * 2 * 3); + + // vertices + const Transform3f local_to_world_matrix = world_trafo * Geometry::translation_transform(center.cast()).cast() * + Eigen::Quaternion::FromTwoVectors(Vec3f::UnitZ(), model_axis); + for (unsigned int i = 0; i < torus_sector_count; ++i) { + const float section_angle = torus_sector_step * i; + const Vec3f radius_dir(std::cos(section_angle), std::sin(section_angle), 0.0f); + const Vec3f local_section_center = radius * radius_dir; + const Vec3f world_section_center = local_to_world_matrix * local_section_center; + const Vec3f local_section_normal = local_section_center.normalized().cross(Vec3f::UnitZ()).normalized(); + const Vec3f world_section_normal = (Vec3f)(local_to_world_matrix.matrix().block(0, 0, 3, 3) * local_section_normal).normalized(); + const Vec3f base_v = thickness * radius_dir; + for (unsigned int j = 0; j < section_sector_count; ++j) { + const Vec3f v = Eigen::AngleAxisf(section_sector_step * j, world_section_normal) * base_v; + data.add_vertex(world_section_center + v, (Vec3f)v.normalized()); + } + } + + // triangles + for (unsigned int i = 0; i < torus_sector_count; ++i) { + const unsigned int ii = i * section_sector_count; + const unsigned int ii_next = ((i + 1) % torus_sector_count) * section_sector_count; + for (unsigned int j = 0; j < section_sector_count; ++j) { + const unsigned int j_next = (j + 1) % section_sector_count; + const unsigned int i0 = ii + j; + const unsigned int i1 = ii_next + j; + const unsigned int i2 = ii_next + j_next; + const unsigned int i3 = ii + j_next; + data.add_triangle(i0, i1, i2); + data.add_triangle(i0, i2, i3); + } + } + + return data; +} + class TransformHelper { struct Cache @@ -411,6 +459,20 @@ void GLGizmoMeasure::on_render() const bool mouse_on_object = m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, m_volume_matrix, camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); const bool is_hovering_on_locked_feature = m_mode == EMode::ExtendedSelection && m_hover_id != -1; + auto update_circle = [this, inv_zoom]() { + if (m_last_inv_zoom != inv_zoom || m_last_circle != m_curr_feature) { + m_last_inv_zoom = inv_zoom; + m_last_circle = m_curr_feature; + m_circle.reset(); + const auto [center, radius, normal] = m_curr_feature->get_circle(); + GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), m_volume_matrix.cast()); + m_circle.mesh_raycaster = std::make_unique(std::make_shared(circle_geometry.get_as_indexed_triangle_set())); + m_circle.model.init_from(std::move(circle_geometry)); + return true; + } + return false; + }; + if (m_mode == EMode::BasicSelection) { std::optional curr_feature = mouse_on_object ? m_measuring->get_feature(model_facet_idx, position_on_model.cast()) : std::nullopt; m_curr_point_on_feature_position.reset(); @@ -441,16 +503,7 @@ void GLGizmoMeasure::on_render() } case Measure::SurfaceFeatureType::Circle: { - const auto [center, radius, normal] = m_curr_feature->get_circle(); - if (m_last_inv_zoom != inv_zoom || m_last_circle != m_curr_feature) { - m_last_inv_zoom = inv_zoom; - m_last_circle = m_curr_feature; - m_circle.reset(); - GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); - m_circle.mesh_raycaster = std::make_unique(std::make_shared(circle_geometry.get_as_indexed_triangle_set())); - m_circle.model.init_from(std::move(circle_geometry)); - } - + update_circle(); m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); break; @@ -519,18 +572,32 @@ void GLGizmoMeasure::on_render() if (m_hover_id == POINT_ID) m_curr_point_on_feature_position = center; else { - const float r = radius; // needed for the following lambda - m_curr_point_on_feature_position = m_volume_matrix.inverse() * position_on_feature(CIRCLE_ID, camera, [r](const Vec3f& v) { - float angle = std::atan2(v.y(), v.x()); - if (angle < 0.0f) - angle += 2.0f * float(M_PI); - return Vec3f(float(r) * std::cos(angle), float(r) * std::sin(angle), 0.0f); - }); + const Vec3d world_pof = position_on_feature(CIRCLE_ID, camera, [](const Vec3f& v) { return v; }); + const Eigen::Hyperplane plane(m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose()* normal, m_volume_matrix * center); + const Transform3d local_to_model_matrix = Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); + const Vec3d local_proj = local_to_model_matrix.inverse() * m_volume_matrix.inverse() * plane.projection(world_pof); + double angle = std::atan2(local_proj.y(), local_proj.x()); + if (angle < 0.0) + angle += 2.0 * double(M_PI); + + const Vec3d local_pos = radius * Vec3d(std::cos(angle), std::sin(angle), 0.0); + m_curr_point_on_feature_position = local_to_model_matrix * local_pos; } break; } } } + else { + if (m_curr_feature.has_value() && m_curr_feature->get_type() == Measure::SurfaceFeatureType::Circle) { + if (update_circle()) { + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); + auto it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end()) + m_raycasters.erase(it); + m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); + } + } + } if (!m_curr_feature.has_value() && !m_selected_features.first.feature.has_value()) return; @@ -589,7 +656,7 @@ void GLGizmoMeasure::on_render() it->second->set_transform(center_matrix); } // render circle - const Transform3d circle_matrix = m_volume_matrix * Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); + const Transform3d circle_matrix = Transform3d::Identity(); set_matrix_uniforms(circle_matrix); if (update_raycasters_transform) { m_circle.model.set_color(colors.back()); @@ -600,7 +667,7 @@ void GLGizmoMeasure::on_render() } else { GLModel circle; - GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); + GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), m_volume_matrix.cast()); circle.init_from(std::move(circle_geometry)); circle.set_color(colors.back()); circle.render(); From 03f2f1478af2aa24a272cc1a2cc2dec9762f58b5 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 19 Oct 2022 08:38:50 +0200 Subject: [PATCH 213/250] Removed tech DISABLE_MEASURE_GIZMO_FOR_SCALED_VOLUMES --- src/libslic3r/Technologies.hpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 817136e7a4..04ecfae670 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -68,7 +68,6 @@ #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) // Enable Measure Gizmo #define ENABLE_MEASURE_GIZMO (1 && ENABLE_RAYCAST_PICKING) -#define DISABLE_MEASURE_GIZMO_FOR_SCALED_VOLUMES (1 && ENABLE_MEASURE_GIZMO) #define ENABLE_MEASURE_GIZMO_DEBUG (0 && ENABLE_MEASURE_GIZMO) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index fdd94120a4..2eff5bb2ad 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -425,12 +425,9 @@ bool GLGizmoMeasure::on_is_activable() const bool res = (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) ? selection.is_single_full_instance() : selection.is_single_volume() || selection.is_single_volume_instance(); - if (res) { + if (res) res &= !selection.get_first_volume()->is_sinking(); -#if DISABLE_MEASURE_GIZMO_FOR_SCALED_VOLUMES - res &= Geometry::Transformation(selection.get_first_volume()->world_matrix()).get_scaling_factor().isApprox(Vec3d::Ones()); -#endif // DISABLE_MEASURE_GIZMO_FOR_SCALED_VOLUMES - } + return res; } From a331c9d018f82543b0e979145debe5e6e830e188 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 24 Oct 2022 12:57:29 +0200 Subject: [PATCH 214/250] Measuring - Gizmo measure - Fixed measurements for circles for scaled volumes --- src/libslic3r/MeasureUtils.hpp | 10 +++++----- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 6 +++++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/MeasureUtils.hpp b/src/libslic3r/MeasureUtils.hpp index 4f84624eac..34fea9855c 100644 --- a/src/libslic3r/MeasureUtils.hpp +++ b/src/libslic3r/MeasureUtils.hpp @@ -93,7 +93,7 @@ protected: std::vector m_coefficient; }; -Polynomial1 operator * (const Polynomial1& p0, const Polynomial1& p1) +inline Polynomial1 operator * (const Polynomial1& p0, const Polynomial1& p1) { const uint32_t p0Degree = p0.GetDegree(); const uint32_t p1Degree = p1.GetDegree(); @@ -107,7 +107,7 @@ Polynomial1 operator * (const Polynomial1& p0, const Polynomial1& p1) return result; } -Polynomial1 operator + (const Polynomial1& p0, const Polynomial1& p1) +inline Polynomial1 operator + (const Polynomial1& p0, const Polynomial1& p1) { const uint32_t p0Degree = p0.GetDegree(); const uint32_t p1Degree = p1.GetDegree(); @@ -136,7 +136,7 @@ Polynomial1 operator + (const Polynomial1& p0, const Polynomial1& p1) } } -Polynomial1 operator - (const Polynomial1& p0, const Polynomial1& p1) +inline Polynomial1 operator - (const Polynomial1& p0, const Polynomial1& p1) { const uint32_t p0Degree = p0.GetDegree(); const uint32_t p1Degree = p1.GetDegree(); @@ -165,7 +165,7 @@ Polynomial1 operator - (const Polynomial1& p0, const Polynomial1& p1) } } -Polynomial1 operator * (double scalar, const Polynomial1& p) +inline Polynomial1 operator * (double scalar, const Polynomial1& p) { const uint32_t degree = p.GetDegree(); Polynomial1 result(degree); @@ -354,7 +354,7 @@ public: // the maximum absolute component occurs at index i, then the orthogonal // vector U has u[i] = v[i+1], u[i+1] = -v[i], and all other components // zero. The index addition i+1 is computed modulo N. -Vec3d get_orthogonal(const Vec3d& v, bool unitLength) +inline Vec3d get_orthogonal(const Vec3d& v, bool unitLength) { double cmax = std::fabs(v[0]); int32_t imax = 0; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 2eff5bb2ad..14caa193de 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -9,6 +9,7 @@ #include "libslic3r/Model.hpp" #include "libslic3r/PresetBundle.hpp" +#include "libslic3r/MeasureUtils.hpp" #include @@ -1486,8 +1487,11 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit case Measure::SurfaceFeatureType::Circle: { auto [center, radius, normal] = m_curr_feature->get_circle(); + // generic point on circle, used to recalculate radius after transformation + const Vec3d on_circle = m_volume_matrix * (center + radius * Measure::get_orthogonal(normal, true)); center = m_volume_matrix * center; - normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + normal = (m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal).normalized(); + radius = (on_circle - center).norm(); if (use_inches) { center = ObjectManipulation::mm_to_in * center; radius = ObjectManipulation::mm_to_in * radius; From 121b0f9a604503b777f6b2de1dc59fb65ea3333a Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 24 Oct 2022 14:07:56 +0200 Subject: [PATCH 215/250] Measuring - Gizmo measure - Fixed crash when creating a new project using CTRL+N while the gizmo is active --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 14caa193de..86fa9ff5c3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -835,7 +835,11 @@ void GLGizmoMeasure::update_if_needed() m_old_model_volume = volume; }; - m_volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); + const Selection& selection = m_parent.get_selection(); + if (selection.is_empty()) + return; + + m_volume_matrix = selection.get_first_volume()->world_matrix(); const ModelObject* mo = m_c->selection_info()->model_object(); const ModelVolume* mv = m_c->selection_info()->model_volume(); From ca923c084fa02389e397106478c909dce1526d3c Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 24 Oct 2022 15:13:56 +0200 Subject: [PATCH 216/250] Measuring - Gizmo measure - Fixed measure of distance point-circle when the point is the circle's center --- src/libslic3r/Measure.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 20ae7f4138..c060ae8938 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -632,13 +632,21 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& } else if (f2.get_type() == SurfaceFeatureType::Circle) { // Find a plane containing normal, center and the point. const auto [c, radius, n] = f2.get_circle(); - Eigen::Hyperplane circle_plane(n, c); - Vec3d proj = circle_plane.projection(f1.get_point()); - double dist = std::sqrt(std::pow((proj - c).norm() - radius, 2.) + - (f1.get_point() - proj).squaredNorm()); + const Eigen::Hyperplane circle_plane(n, c); + const Vec3d proj = circle_plane.projection(f1.get_point()); + if (proj.isApprox(c)) { + const Vec3d p_on_circle = c + radius * get_orthogonal(n, true); + result.distance_strict = std::make_optional(DistAndPoints{ radius, c, p_on_circle }); + } + else { + const Eigen::Hyperplane circle_plane(n, c); + const Vec3d proj = circle_plane.projection(f1.get_point()); + const double dist = std::sqrt(std::pow((proj - c).norm() - radius, 2.) + + (f1.get_point() - proj).squaredNorm()); - const Vec3d p_on_circle = c + radius * (circle_plane.projection(f1.get_point()) - c).normalized(); - result.distance_strict = std::make_optional(DistAndPoints{dist, f1.get_point(), p_on_circle}); // TODO + const Vec3d p_on_circle = c + radius * (proj - c).normalized(); + result.distance_strict = std::make_optional(DistAndPoints{ dist, f1.get_point(), p_on_circle }); // TODO + } /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Plane) { const auto [idx, normal, pt] = f2.get_plane(); From 59f1c349fcf580b57c3e1a2d42d149b40746a5b5 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 25 Oct 2022 08:25:31 +0200 Subject: [PATCH 217/250] Measuring - Gizmo measure - Show dimensioning while the user pans/rotates the 3D view --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 86fa9ff5c3..0e9b33b26b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -438,9 +438,9 @@ void GLGizmoMeasure::on_render() render_debug_dialog(); #endif // ENABLE_MEASURE_GIZMO_DEBUG - // do not render if the user is panning/rotating the 3d scene - if (m_parent.is_mouse_dragging()) - return; +// // do not render if the user is panning/rotating the 3d scene +// if (m_parent.is_mouse_dragging()) +// return; const Selection& selection = m_parent.get_selection(); @@ -610,6 +610,8 @@ void GLGizmoMeasure::on_render() glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); glsafe(::glEnable(GL_DEPTH_TEST)); + const bool old_cullface = ::glIsEnabled(GL_CULL_FACE); + glsafe(::glDisable(GL_CULL_FACE)); const Transform3d& view_matrix = camera.get_view_matrix(); @@ -795,6 +797,9 @@ void GLGizmoMeasure::on_render() } shader->stop_using(); + + if (old_cullface) + glsafe(::glEnable(GL_CULL_FACE)); } render_dimensioning(); From 5561e22ba7499a7246d18f481f7c3e10097bf0be Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 25 Oct 2022 09:25:05 +0200 Subject: [PATCH 218/250] Measuring - Gizmo measure - Render dimensioning auxiliary lines in light gray color --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 0e9b33b26b..b89b6785d0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -933,7 +933,8 @@ void GLGizmoMeasure::render_dimensioning() shader->set_uniform("view_model_matrix", overlap ? ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q12ss * Geometry::translation_transform(-2.0 * TRIANGLE_HEIGHT * Vec3d::UnitX()) * Geometry::scale_transform({ v12ss_len + 4.0 * TRIANGLE_HEIGHT, 1.0f, 1.0f }) : ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q12ss * Geometry::scale_transform({ v12ss_len, 1.0f, 1.0f })); - m_dimensioning.line.render(); + m_dimensioning.line.set_color(ColorRGBA::WHITE()); + m_dimensioning.line.render(); // arrow 1 shader->set_uniform("view_model_matrix", overlap ? @@ -1072,6 +1073,7 @@ void GLGizmoMeasure::render_dimensioning() shader->set_uniform("projection_matrix", Transform3d::Identity()); shader->set_uniform("view_model_matrix", ss_to_ndc_matrix * Geometry::translation_transform({ pss.x(), pss.y(), 0.0 }) * q * Geometry::scale_transform({ pv_projss_len, 1.0f, 1.0f })); + m_dimensioning.line.set_color(ColorRGBA::LIGHT_GRAY()); m_dimensioning.line.render(); } }; @@ -1154,6 +1156,7 @@ void GLGizmoMeasure::render_dimensioning() shader->set_uniform("view_model_matrix", camera.get_view_matrix() * Geometry::translation_transform(center)* Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e1.first, e1.second))* Geometry::scale_transform({ e11center_len, 1.0f, 1.0f })); + m_dimensioning.line.set_color(ColorRGBA::LIGHT_GRAY()); m_dimensioning.line.render(); } @@ -1164,6 +1167,7 @@ void GLGizmoMeasure::render_dimensioning() shader->set_uniform("view_model_matrix", camera.get_view_matrix() * Geometry::translation_transform(center)* Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e2.first, e2.second))* Geometry::scale_transform({ (coplanar && radius > 0.0) ? e21center_len : draw_radius, 1.0f, 1.0f })); + m_dimensioning.line.set_color(ColorRGBA::LIGHT_GRAY()); m_dimensioning.line.render(); } From 402fe908c16d5cdf9fbf2356b98e1ce95a6cf262 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 25 Oct 2022 10:03:35 +0200 Subject: [PATCH 219/250] Measuring - Gizmo measure - Fixed crash when selecting two parallel planes --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index b89b6785d0..172992db93 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1208,6 +1208,9 @@ void GLGizmoMeasure::render_dimensioning() auto arc_plane_plane = [this, arc_edge_edge](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { assert(f1.get_type() == Measure::SurfaceFeatureType::Plane && f2.get_type() == Measure::SurfaceFeatureType::Plane); + if (!m_measurement_result.angle.has_value()) + return; + const std::pair e1 = m_measurement_result.angle->e1; const std::pair e2 = m_measurement_result.angle->e2; const double calc_radius = m_measurement_result.angle->radius; From 2f130ca6e1f8c4c12c9f5f2175bdb1423015c227 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 25 Oct 2022 12:12:33 +0200 Subject: [PATCH 220/250] Measuring - Gizmo measure - Do not close the gizmo when the user clicks outside of any volume --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 172992db93..1fc063822e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -325,6 +325,9 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) m_mouse_left_down = false; return true; } + if (m_hover_id == -1 && !m_parent.is_mouse_dragging()) + // avoid closing the gizmo if the user clicks outside of any volume + return true; } else if (mouse_event.RightDown() && mouse_event.CmdDown()) { m_selected_features.reset(); @@ -1153,8 +1156,8 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d e11center = center - e1.first; const double e11center_len = e11center.norm(); if (e11center_len > EPSILON && e11center.dot(e11e12) < 0.0) { - shader->set_uniform("view_model_matrix", camera.get_view_matrix() * Geometry::translation_transform(center)* - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e1.first, e1.second))* + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * Geometry::translation_transform(center) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e1.first, e1.second)) * Geometry::scale_transform({ e11center_len, 1.0f, 1.0f })); m_dimensioning.line.set_color(ColorRGBA::LIGHT_GRAY()); m_dimensioning.line.render(); @@ -1164,8 +1167,8 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d e21center = center - e2.first; const double e21center_len = e21center.norm(); if (e21center_len > EPSILON) { - shader->set_uniform("view_model_matrix", camera.get_view_matrix() * Geometry::translation_transform(center)* - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e2.first, e2.second))* + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * Geometry::translation_transform(center) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitX(), Measure::edge_direction(e2.first, e2.second)) * Geometry::scale_transform({ (coplanar && radius > 0.0) ? e21center_len : draw_radius, 1.0f, 1.0f })); m_dimensioning.line.set_color(ColorRGBA::LIGHT_GRAY()); m_dimensioning.line.render(); From a0c1648f365284c4bd2bf4fc1e76ad825fb6bad0 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 25 Oct 2022 14:09:27 +0200 Subject: [PATCH 221/250] Measuring - Gizmo measure - Allow to unselect the first feature by clicking on it (also reworked the imgui dialog to show the action taken by left click in dependence of mouse position) --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 41 +++++++++++++++++++----- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 1fc063822e..d5ad0e4090 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -290,6 +290,10 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) m_selection_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SELECTION_2_ID, *m_sphere.mesh_raycaster)); } } + else { + if (!m_selected_features.second.feature.has_value()) + m_selected_features.first.reset(); + } } else { const SelectedFeatures::Item item = item_from_feature(); @@ -1398,7 +1402,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (m_editing_distance) return; - m_imgui->begin(_u8L("Measure tool"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + m_imgui->begin(get_name(), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); // adjust window position to avoid overlap the view toolbar const float win_h = ImGui::GetWindowHeight(); @@ -1417,18 +1421,39 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit unsigned int row_count = 1; add_row_to_table( [this]() { - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Left mouse button")); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Left mouse button")); }, [this]() { - m_imgui->text_colored(ImGui::GetStyleColorVec4(ImGuiCol_Text), - m_selected_features.second.feature.has_value() ? - ((m_mode == EMode::BasicSelection) ? _u8L("Select/Unselect feature") : _u8L("Select/Unselect point")) : - ((m_mode == EMode::BasicSelection) ? _u8L("Select feature") : _u8L("Select point"))); + std::string text; + ColorRGBA color; + if (m_selected_features.second.feature.has_value()) { + if (m_selected_features.second.feature == m_curr_feature && m_mode == EMode::BasicSelection) + text = _u8L("Unselect feature"); + else if (m_hover_id == SELECTION_2_ID) + text = _u8L("Unselect point"); + else + text = (m_mode == EMode::BasicSelection) ? _u8L("Select feature") : _u8L("Select point"); + color = SELECTED_2ND_COLOR; + } + else { + if (m_selected_features.first.feature.has_value()) { + if (m_selected_features.first.feature == m_curr_feature) + text = _u8L("Unselect feature"); + else if (m_hover_id == SELECTION_1_ID) + text = _u8L("Unselect point"); + color = SELECTED_1ST_COLOR; + } + if (text.empty()) { + text = (m_mode == EMode::BasicSelection) ? _u8L("Select feature") : _u8L("Select point"); + color = m_selected_features.first.feature.has_value() ? SELECTED_2ND_COLOR : SELECTED_1ST_COLOR; + } + } + + m_imgui->text_colored(ImGui::GetStyleColorVec4(ImGuiCol_Text), text); ImGui::SameLine(); const ImVec2 pos = ImGui::GetCursorScreenPos(); const float rect_size = ImGui::GetTextLineHeight(); - ImGui::GetWindowDrawList()->AddRectFilled({ pos.x + 1.0f, pos.y + 1.0f }, { pos.x + rect_size, pos.y + rect_size }, - ImGuiWrapper::to_ImU32(m_selected_features.first.feature.has_value() ? SELECTED_2ND_COLOR : SELECTED_1ST_COLOR)); + ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + 1.0f, pos.y + 1.0f), ImVec2(pos.x + rect_size, pos.y + rect_size), ImGuiWrapper::to_ImU32(color)); ImGui::Dummy(ImVec2(rect_size, rect_size)); } ); From 377ff4a5194a4c633abcc072ed82377148e24c89 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 25 Oct 2022 14:50:54 +0200 Subject: [PATCH 222/250] Measuring - Gizmo measure - Commented out hovered feature section from imgui dialog --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 190 +++++++++++------------ 1 file changed, 95 insertions(+), 95 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index d5ad0e4090..58e23b695f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1479,103 +1479,103 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit const bool use_inches = wxGetApp().app_config->get("use_inches") == "1"; const std::string units = use_inches ? " " + _u8L("in") : " " + _u8L("mm"); - const Measure::SurfaceFeatureType feature_type = m_curr_feature.has_value() ? m_curr_feature->get_type() : Measure::SurfaceFeatureType::Undef; - bool data_text_set = false; - ImGui::Separator(); - if (feature_type != Measure::SurfaceFeatureType::Undef) { - if (m_mode == EMode::BasicSelection) { - m_imgui->text(surface_feature_type_as_string(feature_type)); - data_text_set = true; - } - else if (m_mode == EMode::ExtendedSelection) { - if (m_hover_id != -1 && m_curr_point_on_feature_position.has_value()) { - m_imgui->text(point_on_feature_type_as_string(feature_type, m_hover_id)); - data_text_set = true; - } - } - } - if (!data_text_set) - m_imgui->text(_u8L("No feature")); + //const Measure::SurfaceFeatureType feature_type = m_curr_feature.has_value() ? m_curr_feature->get_type() : Measure::SurfaceFeatureType::Undef; + //bool data_text_set = false; + //ImGui::Separator(); + //if (feature_type != Measure::SurfaceFeatureType::Undef) { + // if (m_mode == EMode::BasicSelection) { + // m_imgui->text(surface_feature_type_as_string(feature_type)); + // data_text_set = true; + // } + // else if (m_mode == EMode::ExtendedSelection) { + // if (m_hover_id != -1 && m_curr_point_on_feature_position.has_value()) { + // m_imgui->text(point_on_feature_type_as_string(feature_type, m_hover_id)); + // data_text_set = true; + // } + // } + //} + //if (!data_text_set) + // m_imgui->text(_u8L("No feature")); - const unsigned int max_data_row_count = 3; - unsigned int data_row_count = 0; - if (ImGui::BeginTable("Data", 2)) { - if (m_mode == EMode::BasicSelection) { - switch (feature_type) - { - default: { break; } - case Measure::SurfaceFeatureType::Point: - { - Vec3d position = m_volume_matrix * m_curr_feature->get_point(); - if (use_inches) - position = ObjectManipulation::mm_to_in * position; - add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - data_row_count = 1; - break; - } - case Measure::SurfaceFeatureType::Edge: - { - auto [from, to] = m_curr_feature->get_edge(); - from = m_volume_matrix * from; - to = m_volume_matrix * to; - if (use_inches) { - from = ObjectManipulation::mm_to_in * from; - to = ObjectManipulation::mm_to_in * to; - } - add_strings_row_to_table(*m_imgui, _u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, _u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, _u8L("Length"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); - data_row_count = 3; - break; - } - case Measure::SurfaceFeatureType::Circle: - { - auto [center, radius, normal] = m_curr_feature->get_circle(); - // generic point on circle, used to recalculate radius after transformation - const Vec3d on_circle = m_volume_matrix * (center + radius * Measure::get_orthogonal(normal, true)); - center = m_volume_matrix * center; - normal = (m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal).normalized(); - radius = (on_circle - center).norm(); - if (use_inches) { - center = ObjectManipulation::mm_to_in * center; - radius = ObjectManipulation::mm_to_in * radius; - } - add_strings_row_to_table(*m_imgui, _u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, _u8L("Radius"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - data_row_count = 3; - break; - } - case Measure::SurfaceFeatureType::Plane: - { - auto [idx, normal, origin] = m_curr_feature->get_plane(); - origin = m_volume_matrix * origin; - normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; - if (use_inches) - origin = ObjectManipulation::mm_to_in * origin; - add_strings_row_to_table(*m_imgui, _u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - data_row_count = 2; - break; - } - } - } - else { - if (m_hover_id != -1 && m_curr_point_on_feature_position.has_value()) { - Vec3d position = m_volume_matrix * *m_curr_point_on_feature_position; - if (use_inches) - position = ObjectManipulation::mm_to_in * position; - add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - data_row_count = 1; - } - } + //const unsigned int max_data_row_count = 3; + //unsigned int data_row_count = 0; + //if (ImGui::BeginTable("Data", 2)) { + // if (m_mode == EMode::BasicSelection) { + // switch (feature_type) + // { + // default: { break; } + // case Measure::SurfaceFeatureType::Point: + // { + // Vec3d position = m_volume_matrix * m_curr_feature->get_point(); + // if (use_inches) + // position = ObjectManipulation::mm_to_in * position; + // add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + // data_row_count = 1; + // break; + // } + // case Measure::SurfaceFeatureType::Edge: + // { + // auto [from, to] = m_curr_feature->get_edge(); + // from = m_volume_matrix * from; + // to = m_volume_matrix * to; + // if (use_inches) { + // from = ObjectManipulation::mm_to_in * from; + // to = ObjectManipulation::mm_to_in * to; + // } + // add_strings_row_to_table(*m_imgui, _u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + // add_strings_row_to_table(*m_imgui, _u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + // add_strings_row_to_table(*m_imgui, _u8L("Length"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); + // data_row_count = 3; + // break; + // } + // case Measure::SurfaceFeatureType::Circle: + // { + // auto [center, radius, normal] = m_curr_feature->get_circle(); + // // generic point on circle, used to recalculate radius after transformation + // const Vec3d on_circle = m_volume_matrix * (center + radius * Measure::get_orthogonal(normal, true)); + // center = m_volume_matrix * center; + // normal = (m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal).normalized(); + // radius = (on_circle - center).norm(); + // if (use_inches) { + // center = ObjectManipulation::mm_to_in * center; + // radius = ObjectManipulation::mm_to_in * radius; + // } + // add_strings_row_to_table(*m_imgui, _u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + // add_strings_row_to_table(*m_imgui, _u8L("Radius"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); + // add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + // data_row_count = 3; + // break; + // } + // case Measure::SurfaceFeatureType::Plane: + // { + // auto [idx, normal, origin] = m_curr_feature->get_plane(); + // origin = m_volume_matrix * origin; + // normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; + // if (use_inches) + // origin = ObjectManipulation::mm_to_in * origin; + // add_strings_row_to_table(*m_imgui, _u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + // add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + // data_row_count = 2; + // break; + // } + // } + // } + // else { + // if (m_hover_id != -1 && m_curr_point_on_feature_position.has_value()) { + // Vec3d position = m_volume_matrix * *m_curr_point_on_feature_position; + // if (use_inches) + // position = ObjectManipulation::mm_to_in * position; + // add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + // data_row_count = 1; + // } + // } - // add dummy rows to keep dialog size fixed - for (unsigned int i = data_row_count; i < max_data_row_count; ++i) { - add_strings_row_to_table(*m_imgui, " ", ImGuiWrapper::COL_ORANGE_LIGHT, " ", ImGui::GetStyleColorVec4(ImGuiCol_Text)); - } - ImGui::EndTable(); - } + // // add dummy rows to keep dialog size fixed + // for (unsigned int i = data_row_count; i < max_data_row_count; ++i) { + // add_strings_row_to_table(*m_imgui, " ", ImGuiWrapper::COL_ORANGE_LIGHT, " ", ImGui::GetStyleColorVec4(ImGuiCol_Text)); + // } + // ImGui::EndTable(); + //} ImGui::Separator(); const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; From cdf07c3cce81fd2653c571809a59cc9518ec3445 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 27 Oct 2022 15:34:23 +0200 Subject: [PATCH 223/250] Fix for #8800 - Switching to a physical printer based on same printer preset requires reslicing --- src/slic3r/GUI/Plater.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 22c819ab47..656a7f3379 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4191,8 +4191,10 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt) wxGetApp().get_tab(preset_type)->select_preset(preset_name); } - // update plater with new config - q->on_config_change(wxGetApp().preset_bundle->full_config()); + if (preset_type != Preset::TYPE_PRINTER || select_preset) { + // update plater with new config + q->on_config_change(wxGetApp().preset_bundle->full_config()); + } if (preset_type == Preset::TYPE_PRINTER) { /* Settings list can be changed after printer preset changing, so * update all settings items for all item had it. From ece63f5d81aa492c2fe358030a2aa5b0edfa1099 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 27 Oct 2022 17:16:44 +0200 Subject: [PATCH 224/250] Follow up previous https://github.com/Prusa-Development/PrusaSlicerPrivate/commit/cdf07c3cce81fd2653c571809a59cc9518ec3445 - code improvements --- src/slic3r/GUI/Plater.cpp | 7 ------- src/slic3r/GUI/PresetComboBoxes.cpp | 19 +++++++++++++++---- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 656a7f3379..6fb7988906 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4180,13 +4180,6 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt) combo->update(); } else if (select_preset) { - if (preset_type == Preset::TYPE_PRINTER) { - PhysicalPrinterCollection& physical_printers = wxGetApp().preset_bundle->physical_printers; - if(combo->is_selected_physical_printer()) - preset_name = physical_printers.get_selected_printer_preset_name(); - else - physical_printers.unselect_printer(); - } wxWindowUpdateLocker noUpdates(sidebar->presets_panel()); wxGetApp().get_tab(preset_type)->select_preset(preset_name); } diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index 65469e6a03..c63c20685a 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -515,12 +515,24 @@ bool PresetComboBox::is_selected_physical_printer() bool PresetComboBox::selection_is_changed_according_to_physical_printers() { - if (m_type != Preset::TYPE_PRINTER || !is_selected_physical_printer()) + if (m_type != Preset::TYPE_PRINTER) return false; - PhysicalPrinterCollection& physical_printers = m_preset_bundle->physical_printers; + const std::string selected_string = into_u8(this->GetString(this->GetSelection())); + PhysicalPrinterCollection& physical_printers = m_preset_bundle->physical_printers; + Tab* tab = wxGetApp().get_tab(Preset::TYPE_PRINTER); - std::string selected_string = this->GetString(this->GetSelection()).ToUTF8().data(); + if (!is_selected_physical_printer()) { + if (!physical_printers.has_selection()) + return false; + + const bool is_changed = selected_string == physical_printers.get_selected_printer_preset_name(); + if (is_changed) + tab->select_preset(selected_string); + physical_printers.unselect_printer(); + + return is_changed; + } std::string old_printer_full_name, old_printer_preset; if (physical_printers.has_selection()) { @@ -548,7 +560,6 @@ bool PresetComboBox::selection_is_changed_according_to_physical_printers() return true; } - Tab* tab = wxGetApp().get_tab(Preset::TYPE_PRINTER); if (tab) tab->select_preset(preset_name, false, old_printer_full_name); return true; From e32d03318dd5d8066a9a232baa152cddee6fe1d7 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 31 Oct 2022 10:42:54 +0100 Subject: [PATCH 225/250] Fix for #9104 - MMU can't change extruder when Split to Objects is used in PS2.5. --- src/libslic3r/Model.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 3c4e004544..52ddbea9b4 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1661,6 +1661,12 @@ void ModelObject::split(ModelObjectPtrs* new_objects) new_object->add_instance(*model_instance); ModelVolume* new_vol = new_object->add_volume(*volume, std::move(mesh)); + // Invalidate extruder value in volume's config, + // otherwise there will no way to change extruder for object after splitting, + // because volume's extruder value overrides object's extruder value. + if (new_vol->config.has("extruder")) + new_vol->config.set_key_value("extruder", new ConfigOptionInt(0)); + for (ModelInstance* model_instance : new_object->instances) { #if ENABLE_WORLD_COORDINATE Vec3d shift = model_instance->get_transformation().get_matrix_no_offset() * new_vol->get_offset(); From 7742ebb81362f596fa4baeaa4692fc7d8bd06384 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 31 Oct 2022 12:55:43 +0100 Subject: [PATCH 226/250] ObjectList: Fixed position of the added sub-object, when it is Slab --- src/slic3r/GUI/GUI_ObjectList.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 164679645a..d6bbbeba11 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1698,11 +1698,16 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode new_volume->set_transformation(Geometry::Transformation::volume_to_bed_transformation(v->get_instance_transformation(), mesh_bb)); #endif // ENABLE_WORLD_COORDINATE // Set the modifier position. - auto offset = (type_name == "Slab") ? - // Slab: Lift to print bed - Vec3d(0., 0., 0.5 * mesh_bb.size().z() + instance_bb.min.z() - v->get_instance_offset().z()) : + Vec3d offset; + if (type_name == "Slab") { + Vec3d inst_center = instance_bb.center() - v->get_instance_offset(); + // Slab: Lift to print bed and and push to the center of instance + offset = Vec3d(inst_center.x(), inst_center.y(), 0.5 * mesh_bb.size().z() + instance_bb.min.z() - v->get_instance_offset().z()); + } + else { // Translate the new modifier to be pickable: move to the left front corner of the instance's bounding box, lift to print bed. - Vec3d(instance_bb.max.x(), instance_bb.min.y(), instance_bb.min.z()) + 0.5 * mesh_bb.size() - v->get_instance_offset(); + offset = Vec3d(instance_bb.max.x(), instance_bb.min.y(), instance_bb.min.z()) + 0.5 * mesh_bb.size() - v->get_instance_offset(); + } #if ENABLE_WORLD_COORDINATE new_volume->set_offset(v->get_instance_transformation().get_matrix_no_offset().inverse() * offset); #else From f5e782233e172c0d807bfd303a2936be18631f4e Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 1 Nov 2022 09:15:38 +0100 Subject: [PATCH 227/250] Tech ENABLE_RAYCAST_PICKING - Fixed update of raycaster active state in GLCanvas3D::reload_scene() --- src/slic3r/GUI/GLCanvas3D.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 25ac882955..619f09901c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2438,8 +2438,10 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re // refresh volume raycasters for picking m_scene_raycaster.remove_raycasters(SceneRaycaster::EType::Volume); for (size_t i = 0; i < m_volumes.volumes.size(); ++i) { - assert(m_volumes.volumes[i]->mesh_raycaster != nullptr); - add_raycaster_for_picking(SceneRaycaster::EType::Volume, i, *m_volumes.volumes[i]->mesh_raycaster, m_volumes.volumes[i]->world_matrix()); + const GLVolume* v = m_volumes.volumes[i]; + assert(v->mesh_raycaster != nullptr); + std::shared_ptr raycaster = add_raycaster_for_picking(SceneRaycaster::EType::Volume, i, *v->mesh_raycaster, v->world_matrix()); + raycaster->set_active(v->is_active); } // refresh gizmo elements raycasters for picking From 8914dfa1f654c663ef14635725ab3f8b82c686b4 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 1 Nov 2022 14:55:19 +0100 Subject: [PATCH 228/250] Next fix, related to #8800 * PrintApply: Suppress to apply print when just a physical printer was changed, but printer preset stays the same * Tab: Layout the buttons bar when switch from the physical printer to printer preset and vice versa --- src/libslic3r/PrintApply.cpp | 5 ++++ src/slic3r/GUI/PresetComboBoxes.cpp | 9 ++++--- src/slic3r/GUI/Tab.cpp | 41 ++++++++++++++++------------- src/slic3r/GUI/Tab.hpp | 1 + 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index c3792779c3..330ad533c5 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -988,6 +988,11 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ DynamicPrintConfig filament_overrides; t_config_option_keys print_diff = print_config_diffs(m_config, new_full_config, filament_overrides); t_config_option_keys full_config_diff = full_print_config_diffs(m_full_print_config, new_full_config); + // If just a physical printer was changed, but printer preset is the same, then there is no need to apply whole print + // see https://github.com/prusa3d/PrusaSlicer/issues/8800 + if (full_config_diff.size() == 1 && full_config_diff[0] == "physical_printer_settings_id") + full_config_diff.clear(); + // Collect changes to object and region configs. t_config_option_keys object_diff = m_default_object_config.diff(new_full_config); t_config_option_keys region_diff = m_default_region_config.diff(new_full_config); diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index c63c20685a..200cd8a30c 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -527,10 +527,9 @@ bool PresetComboBox::selection_is_changed_according_to_physical_printers() return false; const bool is_changed = selected_string == physical_printers.get_selected_printer_preset_name(); + physical_printers.unselect_printer(); if (is_changed) tab->select_preset(selected_string); - physical_printers.unselect_printer(); - return is_changed; } @@ -547,16 +546,18 @@ bool PresetComboBox::selection_is_changed_according_to_physical_printers() // if new preset wasn't selected, there is no need to call update preset selection if (old_printer_preset == preset_name) { + tab->update_preset_choice(); + wxGetApp().plater()->show_action_buttons(false); + // we need just to update according Plater<->Tab PresetComboBox if (dynamic_cast(this)!=nullptr) { - wxGetApp().get_tab(m_type)->update_preset_choice(); // Synchronize config.ini with the current selections. m_preset_bundle->export_selections(*wxGetApp().app_config); + this->update(); } else if (dynamic_cast(this)!=nullptr) wxGetApp().sidebar().update_presets(m_type); - this->update(); return true; } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 8f38a1525e..7e441342f8 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -215,26 +215,30 @@ void Tab::create_preset_tab() sizer->Add(m_hsizer, 0, wxEXPAND | wxBOTTOM, 3); m_hsizer->Add(m_presets_choice, 0, wxLEFT | wxRIGHT | wxTOP | wxALIGN_CENTER_VERTICAL, 3); m_hsizer->AddSpacer(int(4*scale_factor)); - m_hsizer->Add(m_btn_save_preset, 0, wxALIGN_CENTER_VERTICAL); - m_hsizer->AddSpacer(int(4*scale_factor)); - m_hsizer->Add(m_btn_rename_preset, 0, wxALIGN_CENTER_VERTICAL); - m_hsizer->AddSpacer(int(4 * scale_factor)); - m_hsizer->Add(m_btn_delete_preset, 0, wxALIGN_CENTER_VERTICAL); + + m_h_buttons_sizer = new wxBoxSizer(wxHORIZONTAL); + m_h_buttons_sizer->Add(m_btn_save_preset, 0, wxALIGN_CENTER_VERTICAL); + m_h_buttons_sizer->AddSpacer(int(4*scale_factor)); + m_h_buttons_sizer->Add(m_btn_rename_preset, 0, wxALIGN_CENTER_VERTICAL); + m_h_buttons_sizer->AddSpacer(int(4 * scale_factor)); + m_h_buttons_sizer->Add(m_btn_delete_preset, 0, wxALIGN_CENTER_VERTICAL); if (m_btn_edit_ph_printer) { - m_hsizer->AddSpacer(int(4 * scale_factor)); - m_hsizer->Add(m_btn_edit_ph_printer, 0, wxALIGN_CENTER_VERTICAL); + m_h_buttons_sizer->AddSpacer(int(4 * scale_factor)); + m_h_buttons_sizer->Add(m_btn_edit_ph_printer, 0, wxALIGN_CENTER_VERTICAL); } - m_hsizer->AddSpacer(int(/*16*/8 * scale_factor)); - m_hsizer->Add(m_btn_hide_incompatible_presets, 0, wxALIGN_CENTER_VERTICAL); - m_hsizer->AddSpacer(int(8 * scale_factor)); - m_hsizer->Add(m_question_btn, 0, wxALIGN_CENTER_VERTICAL); - m_hsizer->AddSpacer(int(32 * scale_factor)); - m_hsizer->Add(m_undo_to_sys_btn, 0, wxALIGN_CENTER_VERTICAL); - m_hsizer->Add(m_undo_btn, 0, wxALIGN_CENTER_VERTICAL); - m_hsizer->AddSpacer(int(32 * scale_factor)); - m_hsizer->Add(m_search_btn, 0, wxALIGN_CENTER_VERTICAL); - m_hsizer->AddSpacer(int(8*scale_factor)); - m_hsizer->Add(m_btn_compare_preset, 0, wxALIGN_CENTER_VERTICAL); + m_h_buttons_sizer->AddSpacer(int(/*16*/8 * scale_factor)); + m_h_buttons_sizer->Add(m_btn_hide_incompatible_presets, 0, wxALIGN_CENTER_VERTICAL); + m_h_buttons_sizer->AddSpacer(int(8 * scale_factor)); + m_h_buttons_sizer->Add(m_question_btn, 0, wxALIGN_CENTER_VERTICAL); + m_h_buttons_sizer->AddSpacer(int(32 * scale_factor)); + m_h_buttons_sizer->Add(m_undo_to_sys_btn, 0, wxALIGN_CENTER_VERTICAL); + m_h_buttons_sizer->Add(m_undo_btn, 0, wxALIGN_CENTER_VERTICAL); + m_h_buttons_sizer->AddSpacer(int(32 * scale_factor)); + m_h_buttons_sizer->Add(m_search_btn, 0, wxALIGN_CENTER_VERTICAL); + m_h_buttons_sizer->AddSpacer(int(8*scale_factor)); + m_h_buttons_sizer->Add(m_btn_compare_preset, 0, wxALIGN_CENTER_VERTICAL); + + m_hsizer->Add(m_h_buttons_sizer, 1, wxEXPAND); m_hsizer->AddSpacer(int(16*scale_factor)); // m_hsizer->AddStretchSpacer(32); // StretchSpacer has a strange behavior under OSX, so @@ -3192,6 +3196,7 @@ void Tab::update_btns_enabling() if (m_btn_edit_ph_printer) m_btn_edit_ph_printer->SetToolTip( m_preset_bundle->physical_printers.has_selection() ? _L("Edit physical printer") : _L("Add physical printer")); + m_h_buttons_sizer->Layout(); } void Tab::update_preset_choice() diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 448e4be050..5adeb278a4 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -173,6 +173,7 @@ protected: ScalableButton* m_btn_edit_ph_printer {nullptr}; ScalableButton* m_btn_hide_incompatible_presets; wxBoxSizer* m_hsizer; + wxBoxSizer* m_h_buttons_sizer; wxBoxSizer* m_left_sizer; wxTreeCtrl* m_treectrl; From 4325608a56d3638b74f1f2ad0616eef26200c9dc Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 1 Nov 2022 16:52:42 +0100 Subject: [PATCH 229/250] Disable webrequest for wxWidgets as we don't need it It requires CURL and doesn't like our static build so it links to the system curl instead which is bad. --- deps/wxWidgets/wxWidgets.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/deps/wxWidgets/wxWidgets.cmake b/deps/wxWidgets/wxWidgets.cmake index 8056a01d3a..95f54c1a29 100644 --- a/deps/wxWidgets/wxWidgets.cmake +++ b/deps/wxWidgets/wxWidgets.cmake @@ -38,6 +38,7 @@ prusaslicer_add_cmake_project(wxWidgets -DwxUSE_LIBSDL=OFF -DwxUSE_XTEST=OFF -DwxUSE_GLCANVAS_EGL=OFF + -DwxUSE_WEBREQUEST=OFF ) if (MSVC) From da5a9277faa5cbc54eec0bba04942d7e8ba1cdaf Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 2 Nov 2022 08:50:12 +0100 Subject: [PATCH 230/250] Tech ENABLE_MEASURE_GIZMO set as default --- src/imgui/imconfig.h | 22 ++-------------------- src/libslic3r/Measure.cpp | 4 ---- src/libslic3r/Measure.hpp | 4 ---- src/libslic3r/MeasureUtils.hpp | 4 ---- src/libslic3r/Technologies.hpp | 5 ++--- src/slic3r/GUI/GLCanvas3D.cpp | 8 +------- src/slic3r/GUI/GLCanvas3D.hpp | 14 -------------- src/slic3r/GUI/GUI_Utils.hpp | 2 -- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 4 ---- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 4 ---- src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 2 -- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 10 ---------- src/slic3r/GUI/ImGuiWrapper.cpp | 4 ---- src/slic3r/GUI/ImGuiWrapper.hpp | 2 -- src/slic3r/GUI/Plater.cpp | 2 -- 15 files changed, 5 insertions(+), 86 deletions(-) diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h index 2fb6d7daf7..6dabace5b5 100644 --- a/src/imgui/imconfig.h +++ b/src/imgui/imconfig.h @@ -157,8 +157,8 @@ namespace ImGui const wchar_t InfoMarker = 0x2603; const wchar_t SliderFloatEditBtnIcon = 0x2604; const wchar_t SliderFloatEditBtnPressedIcon = 0x2605; -#if ENABLE_MEASURE_GIZMO const wchar_t ClipboardBtnIcon = 0x2606; + const wchar_t LegendTravel = 0x2701; const wchar_t LegendWipe = 0x2702; const wchar_t LegendRetract = 0x2703; @@ -175,25 +175,7 @@ namespace ImGui const wchar_t ExpandBtn = 0x2714; const wchar_t CollapseBtn = 0x2715; const wchar_t InfoMarkerSmall = 0x2716; -#else - const wchar_t LegendTravel = 0x2606; - const wchar_t LegendWipe = 0x2607; - const wchar_t LegendRetract = 0x2608; - const wchar_t LegendDeretract = 0x2609; - const wchar_t LegendSeams = 0x2610; - const wchar_t LegendToolChanges = 0x2611; - const wchar_t LegendColorChanges = 0x2612; - const wchar_t LegendPausePrints = 0x2613; - const wchar_t LegendCustomGCodes = 0x2614; - const wchar_t LegendCOG = 0x2615; - const wchar_t LegendShells = 0x2616; - const wchar_t LegendToolMarker = 0x2617; - const wchar_t WarningMarkerSmall = 0x2618; - const wchar_t ExpandBtn = 0x2619; - const wchar_t CollapseBtn = 0x2620; - const wchar_t InfoMarkerSmall = 0x2621; -#endif // ENABLE_MEASURE_GIZMO -// void MyFunction(const char* name, const MyMatrix44& v); + // void MyFunction(const char* name, const MyMatrix44& v); } diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index c060ae8938..f64b79e22f 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -5,8 +5,6 @@ #include "libslic3r/Geometry/Circle.hpp" #include "libslic3r/SurfaceMesh.hpp" -#if ENABLE_MEASURE_GIZMO - namespace Slic3r { namespace Measure { @@ -1082,5 +1080,3 @@ void AngleAndEdges::transform(const Transform3d& trafo) { } // namespace Measure } // namespace Slic3r - -#endif // ENABLE_MEASURE_GIZMO diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index ff1757d7ae..d1a0e3866c 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -1,8 +1,6 @@ #ifndef Slic3r_Measure_hpp_ #define Slic3r_Measure_hpp_ -#if ENABLE_MEASURE_GIZMO - #include #include @@ -197,5 +195,3 @@ inline bool are_perpendicular(const SurfaceFeature& f1, const SurfaceFeature& f2 } // namespace Slic3r #endif // Slic3r_Measure_hpp_ - -#endif // ENABLE_MEASURE_GIZMO diff --git a/src/libslic3r/MeasureUtils.hpp b/src/libslic3r/MeasureUtils.hpp index 34fea9855c..0ab4ac121d 100644 --- a/src/libslic3r/MeasureUtils.hpp +++ b/src/libslic3r/MeasureUtils.hpp @@ -1,8 +1,6 @@ #ifndef Slic3r_MeasureUtils_hpp_ #define Slic3r_MeasureUtils_hpp_ -#if ENABLE_MEASURE_GIZMO - #include namespace Slic3r { @@ -386,5 +384,3 @@ inline Vec3d get_orthogonal(const Vec3d& v, bool unitLength) } // namespace Measure #endif // Slic3r_MeasureUtils_hpp_ - -#endif // ENABLE_MEASURE_GIZMO diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 10db1e57ec..e390ff209e 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -26,6 +26,8 @@ #define ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW 0 // Disable using instanced models to render options in gcode preview #define DISABLE_GCODEVIEWER_INSTANCED_MODELS 1 +// Enable Measure Gizmo debug window +#define ENABLE_MEASURE_GIZMO_DEBUG 0 // Enable rendering of objects using environment map @@ -64,9 +66,6 @@ // Enable picking using raytracing #define ENABLE_RAYCAST_PICKING (1 && ENABLE_LEGACY_OPENGL_REMOVAL) #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) -// Enable Measure Gizmo -#define ENABLE_MEASURE_GIZMO (1 && ENABLE_RAYCAST_PICKING) -#define ENABLE_MEASURE_GIZMO_DEBUG (0 && ENABLE_MEASURE_GIZMO) #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 3475221818..440f97facb 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5441,15 +5441,9 @@ void GLCanvas3D::_picking_pass() const GLVolume* volume = m_volumes.volumes[hit.raycaster_id]; if (volume->is_active && !volume->disabled && (volume->composite_id.volume_id >= 0 || m_render_sla_auxiliaries)) { // do not add the volume id if any gizmo is active and CTRL is pressed - if (m_gizmos.get_current_type() == GLGizmosManager::EType::Undefined || !wxGetKeyState(WXK_CONTROL)) { + if (m_gizmos.get_current_type() == GLGizmosManager::EType::Undefined || !wxGetKeyState(WXK_CONTROL)) m_hover_volume_idxs.emplace_back(hit.raycaster_id); -#if !ENABLE_MEASURE_GIZMO - m_gizmos.set_hover_id(-1); -#endif // !ENABLE_MEASURE_GIZMO - } -#if ENABLE_MEASURE_GIZMO m_gizmos.set_hover_id(-1); -#endif // ENABLE_MEASURE_GIZMO } } else diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 7ce488ae54..a5ec9c1914 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -19,9 +19,7 @@ #if ENABLE_RAYCAST_PICKING #include "SceneRaycaster.hpp" #endif // ENABLE_RAYCAST_PICKING -#if ENABLE_MEASURE_GIZMO #include "GUI_Utils.hpp" -#endif // ENABLE_MEASURE_GIZMO #include "libslic3r/Slicing.hpp" @@ -138,18 +136,6 @@ private: wxTimer* m_timer; }; -#if !ENABLE_MEASURE_GIZMO -class KeyAutoRepeatFilter -{ - size_t m_count{ 0 }; - -public: - void increase_count() { ++m_count; } - void reset_count() { m_count = 0; } - bool is_first() const { return m_count == 0; } -}; -#endif // !ENABLE_MEASURE_GIZMO - wxDECLARE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); using Vec2dEvent = Event; diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index e2152edd6d..55ca432480 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -416,7 +416,6 @@ public: ~TaskTimer(); }; -#if ENABLE_MEASURE_GIZMO class KeyAutoRepeatFilter { size_t m_count{ 0 }; @@ -426,7 +425,6 @@ public: void reset_count() { m_count = 0; } bool is_first() const { return m_count == 0; } }; -#endif // ENABLE_MEASURE_GIZMO }} diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 58e23b695f..74be878f11 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -19,8 +19,6 @@ #include -#if ENABLE_MEASURE_GIZMO - namespace Slic3r { namespace GUI { @@ -1691,5 +1689,3 @@ void GLGizmoMeasure::on_unregister_raycasters_for_picking() } // namespace GUI } // namespace Slic3r - -#endif // ENABLE_MEASURE_GIZMO diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 9db2a73aa3..7d20ca26ae 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -1,8 +1,6 @@ #ifndef slic3r_GLGizmoMeasure_hpp_ #define slic3r_GLGizmoMeasure_hpp_ -#if ENABLE_MEASURE_GIZMO - #include "GLGizmoBase.hpp" #include "slic3r/GUI/GLModel.hpp" #include "slic3r/GUI/GUI_Utils.hpp" @@ -162,6 +160,4 @@ protected: } // namespace GUI } // namespace Slic3r -#endif // ENABLE_MEASURE_GIZMO - #endif // slic3r_GLGizmoMeasure_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index f2a668f870..7579402261 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -24,10 +24,8 @@ enum class SLAGizmoEventType : unsigned char { Dragging, Delete, SelectAll, -#if ENABLE_MEASURE_GIZMO CtrlDown, CtrlUp, -#endif // ENABLE_MEASURE_GIZMO ShiftUp, AltUp, ApplyChanges, diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index f0617f5248..51a0386ed3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -21,9 +21,7 @@ #include "slic3r/GUI/Gizmos/GLGizmoSeam.hpp" #include "slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp" #include "slic3r/GUI/Gizmos/GLGizmoSimplify.hpp" -#if ENABLE_MEASURE_GIZMO #include "slic3r/GUI/Gizmos/GLGizmoMeasure.hpp" -#endif // ENABLE_MEASURE_GIZMO #include "libslic3r/format.hpp" #include "libslic3r/Model.hpp" @@ -109,9 +107,7 @@ bool GLGizmosManager::init() m_gizmos.emplace_back(new GLGizmoSeam(m_parent, "seam.svg", 8)); m_gizmos.emplace_back(new GLGizmoMmuSegmentation(m_parent, "mmu_segmentation.svg", 9)); m_gizmos.emplace_back(new GLGizmoSimplify(m_parent, "cut.svg", 10)); -#if ENABLE_MEASURE_GIZMO m_gizmos.emplace_back(new GLGizmoMeasure(m_parent, "measure.svg", 11)); -#endif // ENABLE_MEASURE_GIZMO m_common_gizmos_data.reset(new CommonGizmosDataPool(&m_parent)); @@ -294,10 +290,8 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p return dynamic_cast(m_gizmos[Seam].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); else if (m_current == MmuSegmentation) return dynamic_cast(m_gizmos[MmuSegmentation].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); -#if ENABLE_MEASURE_GIZMO else if (m_current == Measure) return dynamic_cast(m_gizmos[Measure].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); -#endif // ENABLE_MEASURE_GIZMO else if (m_current == Cut) return dynamic_cast(m_gizmos[Cut].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); else @@ -631,11 +625,9 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) processed = true; } } -#if ENABLE_MEASURE_GIZMO else if (m_current == Measure && keyCode == WXK_CONTROL) { gizmo_event(SLAGizmoEventType::CtrlUp, Vec2d::Zero(), false); } -#endif // ENABLE_MEASURE_GIZMO // if (processed) // m_parent.set_cursor(GLCanvas3D::Standard); @@ -670,11 +662,9 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) if (simplify != nullptr) processed = simplify->on_esc_key_down(); } -#if ENABLE_MEASURE_GIZMO else if (m_current == Measure && keyCode == WXK_CONTROL) { gizmo_event(SLAGizmoEventType::CtrlDown, Vec2d::Zero(), true); } -#endif // ENABLE_MEASURE_GIZMO } if (processed) diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 14c9b641f7..01cd8ec30c 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -56,9 +56,7 @@ static const std::map font_icons = { {ImGui::PreferencesHoverButton, "notification_preferences_hover"}, {ImGui::SliderFloatEditBtnIcon, "edit_button" }, {ImGui::SliderFloatEditBtnPressedIcon, "edit_button_pressed" }, -#if ENABLE_MEASURE_GIZMO {ImGui::ClipboardBtnIcon , "copy_menu" }, -#endif // ENABLE_MEASURE_GIZMO {ImGui::ExpandBtn , "expand_btn" }, {ImGui::CollapseBtn , "collapse_btn" }, {ImGui::RevertButton , "undo" }, @@ -1129,12 +1127,10 @@ ImFontAtlasCustomRect* ImGuiWrapper::GetTextureCustomRect(const wchar_t& tex_id) return (item != m_custom_glyph_rects_ids.end()) ? ImGui::GetIO().Fonts->GetCustomRectByIndex(m_custom_glyph_rects_ids[tex_id]) : nullptr; } -#if ENABLE_MEASURE_GIZMO void ImGuiWrapper::disable_background_fadeout_animation() { GImGui->DimBgRatio = 1.0f; } -#endif // ENABLE_MEASURE_GIZMO ImU32 ImGuiWrapper::to_ImU32(const ColorRGBA& color) { diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 8be16fcd0b..040e5e4916 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -130,9 +130,7 @@ public: void set_requires_extra_frame() { m_requires_extra_frame = true; } void reset_requires_extra_frame() { m_requires_extra_frame = false; } -#if ENABLE_MEASURE_GIZMO void disable_background_fadeout_animation(); -#endif // ENABLE_MEASURE_GIZMO static ImU32 to_ImU32(const ColorRGBA& color); static ImVec4 to_ImVec4(const ColorRGBA& color); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ee3a3c3a9f..63b0a4e217 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3034,9 +3034,7 @@ void Plater::priv::delete_all_objects_from_model() gcode_result.reset(); view3D->get_canvas3d()->reset_sequential_print_clearance(); -#if ENABLE_MEASURE_GIZMO view3D->get_canvas3d()->reset_all_gizmos(); -#endif // ENABLE_MEASURE_GIZMO m_worker.cancel_all(); From c1fec355d3dd8c3cf0fbfc609379a45ef649b155 Mon Sep 17 00:00:00 2001 From: rtyr <36745189+rtyr@users.noreply.github.com> Date: Wed, 2 Nov 2022 09:42:50 +0100 Subject: [PATCH 231/250] Initial Anker bundle https://github.com/prusa3d/PrusaSlicer/pull/9075 --- resources/profiles/Anker.idx | 2 + resources/profiles/Anker.ini | 393 ++++++++ resources/profiles/Anker/M5-bed.stl | Bin 0 -> 36084 bytes resources/profiles/Anker/M5-texture.svg | 1003 +++++++++++++++++++++ resources/profiles/Anker/M5_thumbnail.png | Bin 0 -> 37200 bytes 5 files changed, 1398 insertions(+) create mode 100644 resources/profiles/Anker.idx create mode 100644 resources/profiles/Anker.ini create mode 100644 resources/profiles/Anker/M5-bed.stl create mode 100644 resources/profiles/Anker/M5-texture.svg create mode 100644 resources/profiles/Anker/M5_thumbnail.png diff --git a/resources/profiles/Anker.idx b/resources/profiles/Anker.idx new file mode 100644 index 0000000000..4a988bbdff --- /dev/null +++ b/resources/profiles/Anker.idx @@ -0,0 +1,2 @@ +min_slic3r_version = 2.6.0-alpha1 +1.0.0 Initial Version diff --git a/resources/profiles/Anker.ini b/resources/profiles/Anker.ini new file mode 100644 index 0000000000..c7408f6e4d --- /dev/null +++ b/resources/profiles/Anker.ini @@ -0,0 +1,393 @@ +# Print profiles for the AnkerMake printers. +# https://github.com/prusa3d/PrusaSlicer/pull/9075 by @just-trey + +[vendor] +# Vendor name will be shown by the Config Wizard. +name = Anker +# Configuration version of this file. Config file will only be installed, if the config_version differs. +# This means, the server may force the PrusaSlicer configuration to be downgraded. +config_version = 1.0.0 +# Where to get the updates from? +config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Anker/ + +# The printer models will be shown by the Configuration Wizard in this order, +# also the first model installed & the first nozzle installed will be activated after install. +# Printer model name will be shown by the installation wizard. + +[printer_model:M5] +name = AnkerMake M5 +variants = 0.4 +technology = FFF +family = AnkerMake +bed_model = M5-bed.stl +bed_texture = M5-texture.svg +default_materials = Generic PLA+ @ANKER; Generic PLA @ANKER; Generic PET @ANKER; Generic ABS @ANKER + +# All presets starting with asterisk, for example *common*, are intermediate and they will +# not make it into the user interface. + +# Common print preset +[print:*common*] +avoid_crossing_perimeters = 0 +bridge_acceleration = 2500 +bridge_angle = 0 +bridge_flow_ratio = 0.95 +bridge_speed = 150 +brim_separation = 0.1 +brim_type = outer_only +brim_width = 0 +clip_multipart_objects = 1 +complete_objects = 0 +default_acceleration = 2500 +dont_support_bridges = 1 +elefant_foot_compensation = 0.1 +ensure_vertical_shell_thickness = 1 +external_perimeter_speed = 150 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 30 +extruder_clearance_radius = 45 +fill_angle = 45 +fill_density = 15% +fill_pattern = cubic +first_layer_acceleration = 2500 +first_layer_acceleration_over_raft = 0 +first_layer_extrusion_width = 200% +first_layer_speed = 50% +first_layer_speed_over_raft = 30 +gap_fill_enabled = 1 +gap_fill_speed = 150 +gcode_comments = 0 +infill_acceleration = 2500 +infill_anchor = 600% +infill_anchor_max = 50 +infill_every_layers = 1 +infill_extruder = 1 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 23% +infill_speed = 250 +interface_shells = 0 +max_print_speed = 250 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = {input_filename_base}_{digits(layer_height,1,2)}mm_{filament_type[0]}_{printer_model}.gcode +overhangs = 1 +perimeter_acceleration = 2500 +perimeter_extruder = 1 +perimeter_extrusion_width = 0 +perimeter_generator = arachne +perimeter_speed = 250 +perimeters = 3 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = aligned +single_extruder_multi_material_priming = 0 +skirt_distance = 3 +skirt_height = 1 +skirts = 3 +small_perimeter_speed = 150 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_speed = 175 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0.15 +support_material_enforce_layers = 0 +support_material_extruder = 0 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 0 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 125 +support_material_synchronize_layers = 0 +support_material_threshold = 40 +support_material_with_sheath = 0 +support_material_xy_spacing = 60% +thick_bridges = 1 +thin_walls = 0 +top_solid_infill_speed = 150 +travel_speed = 300 +travel_speed_z = 10 +wipe_tower = 0 +wipe_tower_bridging = 10 +wipe_tower_rotation_angle = 0 +wipe_tower_width = 60 +wipe_tower_x = 170 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:*0.08mm*] +inherits = *common* +layer_height = 0.08 +first_layer_height = 0.12 +bottom_solid_layers = 9 +top_solid_layers = 11 +bridge_flow_ratio = 0.70 + +[print:*0.10mm*] +inherits = *common* +layer_height = 0.10 +first_layer_height = 0.14 +bottom_solid_layers = 7 +top_solid_layers = 9 +bridge_flow_ratio = 0.70 + +[print:*0.12mm*] +inherits = *common* +layer_height = 0.12 +first_layer_height = 0.16 +bottom_solid_layers = 6 +top_solid_layers = 7 +bridge_flow_ratio = 0.70 + +[print:*0.16mm*] +inherits = *common* +layer_height = 0.16 +first_layer_height = 0.20 +bottom_solid_layers = 5 +top_solid_layers = 7 +bridge_flow_ratio = 0.85 + +[print:*0.20mm*] +inherits = *common* +layer_height = 0.20 +first_layer_height = 0.24 +bottom_solid_layers = 4 +top_solid_layers = 5 + +[print:*0.24mm*] +inherits = *common* +layer_height = 0.24 +first_layer_height = 0.28 +bottom_solid_layers = 3 +top_solid_layers = 4 + +[print:*0.28mm*] +inherits = *common* +layer_height = 0.28 +first_layer_height = 0.28 +bottom_solid_layers = 3 +top_solid_layers = 4 + +[print:0.08 mm SUPERDETAIL (0.4 mm nozzle) @ANKER] +inherits = *0.08mm* +compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4 + +[print:0.10 mm HIGHDETAIL (0.4 mm nozzle) @ANKER] +inherits = *0.10mm* +compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4 + +[print:0.12 mm DETAIL (0.4 mm nozzle) @ANKER] +inherits = *0.12mm* +compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4 + +[print:0.16 mm OPTIMAL (0.4 mm nozzle) @ANKER] +inherits = *0.16mm* +compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4 + +[print:0.20 mm NORMAL (0.4 mm nozzle) @ANKER] +inherits = *0.20mm* +compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4 + +[print:0.24 mm DRAFT (0.4 mm nozzle) @ANKER] +inherits = *0.24mm* +compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4 + +[print:0.28 mm SUPERDRAFT (0.4 mm nozzle) @ANKER] +inherits = *0.28mm* +compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4 + +[filament:*common*] +cooling = 0 +compatible_printers = +extrusion_multiplier = 1 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_notes = "" +filament_settings_id = "" +filament_soluble = 0 +min_print_speed = 30 +slowdown_below_layer_time = 8 +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_ANKERMAKE.*/ + +[filament:*PLA*] +inherits = *common* +bed_temperature = 60 +fan_below_layer_time = 100 +filament_colour = #DDDDDD +filament_type = PLA +filament_density = 1.24 +filament_cost = 20 +first_layer_bed_temperature = 60 +first_layer_temperature = 210 +fan_always_on = 1 +max_fan_speed = 100 +min_fan_speed = 100 +bridge_fan_speed = 100 +disable_fan_first_layers = 2 +temperature = 205 + +[filament:*PLA+*] +inherits = *common* +bed_temperature = 60 +fan_below_layer_time = 100 +filament_colour = #DDDDDD +filament_type = PLA +filament_density = 1.24 +filament_cost = 20 +first_layer_bed_temperature = 60 +first_layer_temperature = 220 +fan_always_on = 1 +max_fan_speed = 100 +min_fan_speed = 100 +bridge_fan_speed = 100 +disable_fan_first_layers = 2 +temperature = 210 + +[filament:*PET*] +inherits = *common* +bed_temperature = 70 +disable_fan_first_layers = 2 +fan_below_layer_time = 20 +filament_colour = #DDDDDD +filament_type = PETG +filament_density = 1.27 +filament_cost = 30 +first_layer_bed_temperature = 70 +first_layer_temperature = 240 +fan_always_on = 1 +max_fan_speed = 50 +min_fan_speed = 50 +bridge_fan_speed = 100 +temperature = 240 + +[filament:*ABS*] +inherits = *common* +bed_temperature = 90 +disable_fan_first_layers = 2 +fan_below_layer_time = 20 +filament_colour = #DDDDDD +filament_type = ABS +filament_density = 1.04 +filament_cost = 20 +first_layer_bed_temperature = 100 +first_layer_temperature = 245 +fan_always_on = 0 +max_fan_speed = 0 +min_fan_speed = 0 +bridge_fan_speed = 30 +top_fan_speed = 0 +temperature = 245 + +[filament:Generic PLA @ANKER] +inherits = *PLA* +filament_vendor = Generic + +[filament:Generic PLA+ @ANKER] +inherits = *PLA+* +filament_vendor = Generic + +[filament:Generic PETG @ANKER] +inherits = *PET* +filament_vendor = Generic + +[filament:Generic ABS @ANKER] +inherits = *ABS* +first_layer_bed_temperature = 90 +bed_temperature = 90 +filament_vendor = Generic + + +# Common printer preset +[printer:*common*] +printer_technology = FFF +before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;{layer_z} +between_objects_gcode = +pause_print_gcode = +deretract_speed = 60 +extruder_colour = #FCE94F +extruder_offset = 0x0 +gcode_flavor = marlin +silent_mode = 0 +remaining_times = 0 +machine_max_acceleration_e = 2500 +machine_max_acceleration_extruding = 2500 +machine_max_acceleration_retracting = 2500 +machine_max_acceleration_travel = 1500,1250 +machine_max_acceleration_x = 2500 +machine_max_acceleration_y = 2500 +machine_max_acceleration_z = 2500 +machine_max_feedrate_e = 100 +machine_max_feedrate_x = 300 +machine_max_feedrate_y = 300 +machine_max_feedrate_z = 20 +machine_max_jerk_e = 3 +machine_max_jerk_x = 30 +machine_max_jerk_y = 30 +machine_max_jerk_z = 0.3 +machine_min_extruding_rate = 0 +machine_min_travel_rate = 0 +layer_gcode = ;AFTER_LAYER_CHANGE\n;{layer_z} +max_print_height = 250 +printer_notes = +printer_settings_id = +retract_before_travel = 2 +retract_before_wipe = 70% +retract_layer_change = 1 +retract_length_toolchange = 1 +retract_lift = 0 +retract_lift_above = 0 +retract_lift_below = 0 +retract_restart_extra = 0 +retract_restart_extra_toolchange = 0 +retract_speed = 60 +single_extruder_multi_material = 0 +thumbnails = 64x64,256x256 +thumbnails_format = JPG +toolchange_gcode = +use_firmware_retraction = 0 +use_relative_e_distances = 0 +use_volumetric_e = 0 +variable_layer_height = 1 +wipe = 1 +z_offset = 0 +default_filament_profile = "Generic PLA+ @ANKER" +start_gcode = M104 S{first_layer_temperature[0]} ; set final nozzle temp\nM190 S{first_layer_bed_temperature[0]} ; set and wait for nozzle temp to stabilize\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG28 ;Home\nG1 E10 F3600; push out retracted filament(fix for over retraction after prime) +end_gcode = M104 S0\nM140 S0\n;Retract the filament\nG92 E1\nG1 E-1 F300\nG28 X0 Y0\nM84 + +[printer:*M5*] +inherits = *common* +bed_shape = 0x0,235-0,235x235,0x235 +max_print_height = 250 +printer_model = M5 +retract_length = 1.25 +retract_speed = 60 +deretract_speed = 60 +retract_before_travel = 1 +retract_before_wipe = 0% +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_ANKERMAKE\nPRINTER_MODEL_M5 + +[printer:AnkerMake M5 (0.4 mm nozzle)] +inherits = *M5* +nozzle_diameter = 0.4 +printer_variant = 0.4 +min_layer_height = 0.08 +max_layer_height = 0.32 +retract_lift_above = 0.2 +default_print_profile = "0.16 mm OPTIMAL (0.4 mm nozzle) @ANKER" \ No newline at end of file diff --git a/resources/profiles/Anker/M5-bed.stl b/resources/profiles/Anker/M5-bed.stl new file mode 100644 index 0000000000000000000000000000000000000000..72e12a23cd4624ccca34f1337631111be8b8793d GIT binary patch literal 36084 zcmb`Q4X`Ceb;p}Ue9AWqlv;jZ5pfq0BBF*MyczB)X!(hnh$|{c5)(xt8Uz&FMpoGc zblE2e0tOHljR;vl6G*XdhHDm9tPqS?DiJKy2#TRFL2zY-^y$;5|Novh^X{W6Q?>W? z-afx``fK{T`#Sgk``oce^!diLZsndBKe*omW9RBt+|zGc^)~~GFFxq=Xj0^jKb`EZd$B_@6 zI6Hg#$&p|mxSc!n>fek%de0w12;~_fSPE{j@%{I1ntjoEABZ;C2X5y!p7QYc#;dm^ z8$$$3!QGc1mWr@Zw+ka!YR{)VI=*PP$70^Z$fpm@bF;xx$G&0n__F72oBp67Vd=+tSJ(=oZQ^H_JnBT#@WZm8{hk2w88e^UKrsVGzoFw{wtcV zuldpjaU(@ps%{4f&jj2|bV_0cDYns#xr9a^-@v-oK32vM^Z9H*s+)smA=Exas5sZk zQZhua6v{EA#Z}s1DZDH55iEuGQHX2LSkhc{{-Lq7L#l4!c8={iw|duQ&6{r7D-sBM z-Le$E?}VyBikA6-bd&s;Y@@U{91ji^++ySQf0}B3weve-Jdh@3%#jN75ulv|(TRCc zN|->6Iv>GO+?Fs?mJ*gi+m+e9xZYp+l3E4Sg!F&&9uLwf;CuoT>Q z2P5J8iI6whwi3CQQ4lO8?(a@Lky``RFX4lfx=jj1j79$N75f~t`?{pJ)D*?N#k?z} zHcESDKtt9~)GfZ3n6LhaFK@VWAMKa?>cdxz*X%7ZbPiJN?hwA8s9St5#DRbM(b-p? zrahS*@4I|_>Dg)nQqIBMA$&hkxAIe_@4ja1(%NRI8ALpD)gwb?GEAliMqx2LY#W)lIDjOYc1Mr{^GcL zLTy0GIk-E7?p#C$NW%`{AQd!`6x<=%?eWs$ zu+Ki*95Zg7{rgzPSd#%R5+7W8$@p#cqL_nBuqNj|e)#fc*PFF}#Xg|x7H+X{^TEe8 z*N-lZ;!W5 zHi#g-&ao8SVk13XQkQ)=tzZw*;wp*lesJ#i;UlN!q;z6}xDao>;jCUMrXwNJ@%>VXqHgiM5MP}+Y4(=) zX?=Ce;jgmd^_h(!l4Y0mkc)>r2pwtD=MD>WXF znuqZHMBUS8mV!IzwZ}_oXCHo}SW^Uo zv^*uT!~LtqZ@f=afoTv{Oe@wDWiui1IC3YI>Jp~Oxral{*Sz{mhX~8oLDwzZB6axH zp>BWiN2bNiK5*Bq~@(jaqZR*%%_ET{0=S#Ri@-bzwtWHKidfu99HA($?0$)>O}o?-DE}J%BmH z92+e4)aR}pKl;GpSQeZ+=iGH0K9Ocpk7=O-feMM>gC(d<; zv`%Cn(9Xdvp$a3fDvj01$GNRfo5|y|CrgyHbH~4NdG#;f)H)G*ojc+yGil^ixA?xB zR_w#Xa9Uk?%S;-dm1)Iv?6+5;-yUl?_&CQjzL!vip8f=)q@8>0>XWORp8t_(1A3kN z#9cFKJXp8*UTjPzO4_;g`>&{;ag5fYtQT(QUVHCM9$5|(ECqMUk5n9e!|4tibvuXf z0SW(n!#?7+5hQC8_1d=*7YKD5f$ud`lZcWID~BPi-ux~dK_VoYqB{Q6c$hs2OMJY= z!+a#>Mo2uY?J{Zk>l?{i8(Xpz(>c%M2$Fq3Yq>H_xgCLAFb7l z#`hAc$wWyz_dh!?t+sjgq0xraqB{DmTMi-I65oEpxqey*JicOGNGqlxEiPY4`(Yzq z*x;Uw$c3?U73LE=@o=u6mb4);&d@`uZs86ir#!}0-MKGX@wkse z(wkOZ%2oe6QPy3_O8is4=cuE)Z!H*Kp|&ign9lNELWR1dd}~p!NNGOe_IJZwFJ3D#5+lIOPO!31l{ zgtt65LQ00N-IQ_4L~xY-MCjGL(fCnGY=mXK974FesVk-3RS%x!Ay?<;wboAO`yF0W9kh ze(yjh{a*i;1o{cwt4V}`aa3fX;vNU+6!UBYKIPooU@xP=d>hY;b$b9INZAI6at?7} zHXz0GiIjuEj<0w&lUqylQ9_95@eO=*rpWpw(9}&U`0$)A_iDtz(2Ov*=iJUypu+nB z8)c|KNT`PTSLh*?^l;yYLj||k80yJz?*(olj+r@e_A_Vd4v79$fY9dCioh@dnhB(o z&W-XKOK^wTI$in0_aMYou17I(^%<*2wz|lSuReF!>XEHfvfh$dS1qaj<_;aJu@BsJ z%bJ|)Cs>Nz5+)u&E?>NQWGk+$7jDUq$wb{klMvh^XFHc`^e@NbR+1mue-s-$1Ia$1HQg+0J(w;=5!hANQgj?^GX|^40crnnm!SwL%X!gO5&(KCuXrqnv;VXHctsl)a+sidW z?2$3SQgBNS@_c(gp|y|o2Fq0dsmZKQ%{1I%gVzoE39UuZvkW`WD%*J`wX^lSnTA_z zOeX3UnuOrq>oYd39$7COQenSmw!JW-ZlOttuv=u>b^>l(eAdYN?T~T~?u8NIL{-)# z1h2%s^w_gTw%P}&aL#LxU?0$R3%3gouid@nhOK2-W&`0|Wp@)=g zuv8e;WZNKwi|d0uMBMQ^I_R0U8#fu5LxlabS?bDt)}}NR8&~bIZo?HXihEK$eByjk zwukS9SabeKvlpfvri)KqoAVq}VVK5ONjWCXy4Ku0nJ%9DBYjfF!lyh)* z2;WcCExs3GhjXTy%l6TeFYC9PN$(&_Iad-cKfdWF;*8hG-6(76VgpY}gwa-(dev)Y zQXM12FLqqo-2R-nYU$w<+D8f@z88Y_ixvb+op$O>s$DyTgOqbD1vlcLtpWQW9cX-IM?D_MoMY%`Qults5X4zGTWVy3AO>Z zq}601u8b#5LL9!+Db?%#7yNa!vD1B*kDhhBo=0 z3xUTs>=W{Nq^I-hmNi9ruT(r!J+kwzEXB0QV#LBe;#NAAn5-$D`mOBLZ#Z8&vXjLi z;@QqjFNBEad6Omy)ACzRuFgGIPcI*^=<$)AkY;;uFN_E~WwRzB!YS;^PGKK;=a!M3 z4Tn_NXZa+F&_BwW#KvB)SY9o^TX((eUOhIllj)GETeufSgnjQ>lMt`iby;;?I+6S1 z*KZ!#d3i{Mo&8Uea1NTp##2`=sos*#34d|w(UG0vhg99dy)eQ#XcFSe+oq~dJ|&;X z9qIiAbqgtWFN}ycAtX&ggqski>F$J)-op^@GRXGA>D(tp#2X!wCb98`O(#wtxKiig zPPyvAk=-*9&hTb?a4(E-4w{5$#_JB*vQ+C5*(s-W2}{*&NeHD+JoTI3&VJft!(X4; zk8A_)c{pj8>#;|nXIHxaY)2%Cze5H`RMQ!YSA+6 zOb@3nhaIVlc!-g*-eoDKIb3CafasPhFr^KYCC>9ssO0>4&T|mm_hZNg-if*eJ)aE_ z-S>RR2EXT^=d%H#TVD;?Kpn+($$U0IbnD$A8>nl!PMpsMh;I8aWCLvm*X{G!0MTs+ zhistj<2H(H_)yv_ZiTswfrfr@m1P$+x3y{`_Dg~d?tiG;`ab1b8*U@1?pYJ}^~v2L zxrZb+c3b(sVSR#W`5zvQhe^qsO1smA!B#Sd-b%UK#tq9qYv0 zpPxfypMFA8_pq<6+i>vSdMYJIC8BQS)`;zYveh!tiSNyV{w?FdM5r0YKU<+RGbO=N z;XNOJ>OL3k4HGOSH*6gE>`4Sm$-N(cS3Mqbw0z1?v6S3j^3{hQn?SIX++VWo(VKe+ zx$$KEIgdmiPSKLsGu#Mt{k|LHstkO>Y#q_~UgGgcxTk1p!#0(;5fZ&ONJGMIk-`(- z!LhwX&|9~x3G(T!%>+v!-Kb^=Xla9`kT>%YEQS1^k6F;TB@I7cOf)wtlZzO5juGGjdZ1JY^1|Byzc$FLgt`JJuSN%drqggxePO zUwc9fSr@J3e(;TBIUB_XawEjqa*>Wy-!sVA5A*n6ecVCaqFcLi>V`Q$dL zY_EjDnsCU2Q0MB+fw)hGTTUs7^~QCFJi1idLFswhyUjG*Vt@$WPv|JjT2bfj*?8jg zyH{#m5@I;g7E=4_W)GUg1`)oW(6Is9+K?a9R{MmyWTZKzeRZ=3O=5!x-%se+0C|4@ z*QTnYo~iYf^t`Q(Vj6C-L4@xobZmh3{C#1b;Sc9&4JSQsE!EmrH+#?|Hi+>3gpLjH zezbcntL{#9qV&AArPsc?*@GsrL4@xobZme=!@*(R=VfnuHQYmu3TTWk>F`w1Nz zpqCNqtIGNe(%aU$Py6a-51PaV5x$?$u>oq)W5Yb$@7HKejefND)y*C>i47urKcRDd z*4Gxso_LdIerusO-U*oc@ZA;%Z)YjRBLLGM=Q8BB&}@UHcsE2Qf};!-OUeBV*fRmf zH@GRJJfm0=>DCBY&F~J?e_aohx5m#kcFWZBgEl8+14|rXkZ8PI5F4f4*ZrKG><{;>@978^Ys^YhkZGdKZ zi3g-~Om6iGh)&t9xRwFktxI61v;n%b2YHDH*OqJpG|PA60lKUonei3Z`fLL<%Xe*n zF6((_e8sI7+W?*9efS&x`38i}?^>G(x|<)|3PY;f)~bHB0itYcL3eGSR*NI-R1cs+^?1gCE>f1!G9G>I8jin$L& zG53l%@w!^F5v1iQZSV>o=w!o3AP_9Y>yC2>1pW&B}*&Vr;W&<>+p5sLBv7B<5u*l&kuj2XH&N zE0Fd9AR^_eekeve#kU4~r zkPk05P~v!}(_8{;!q^p}drItl1HSK+5;+AiGO5?xJCk?d4ih4!J7vp#L`=sh#BwWf z0pT3nb=ymXn6s3+ZC@}5kqVEGpCPTFmx=Dq8YaS7tF(W&w1=3h?)d2?KbT;ta8@eq z#ueGH8@Hhw1oA#zrc2_19gl0Sd+sfc;bGIcJO8_vFN3_JLbVqLpc}5+5&l zj59o0Ej5OsOjB}RosawfSJ9UBYB`hh==OIcup3P|N1_9O!ciqbFJ-ba{m|!Wm zB~;<@@iU|q`*2#po=VzhNyx51J0HWeNy}efv6So=w7UU@3HD(koJt$%T~DGp+|X3f z4NbWuvJ~9%)=nn$t+iG{tmL#R+7H%?5K_(H0~q(D+WicOlkRA>+y3&t*H}t8t>Eqw zXD(jaT=^`WjY1CAEfa9ZSm;L#6%!mP5EPHV`9^m3+FgSjTTTVC5{PiNZ)7)rFRrDnFlPdzIdYqU9U z=Cgq^>f*^D&HwobwvIBUV_c(iOuWQ{rBIFsh=BSE??)-cbeOw6;>79m&eq+Z@Cj!O z@*CwG+YTodZ(4WAcIj?h_|z@j-I(+F^ZwM;b6!?IhVeb!Y{a?7`GN1dZxqkObLm5> zcZuK==6dw)WO`u)?szUwwH7(p;C|{-is^XLyRoz3AY8m*-g@^Xk*r85X>elu2s4|PddGoY53j{qI!EU8{`?svN^ ztCptQjk%ADK1$gqlDOOBD-dP>ifNOMty)nhqQ_Czk4ETz&i?%9Cxp}!pq6Xgr-Hqd z=Uy%O2JzrtUzootdiq0Y1)9@Jb=#+}xE~F@-4Tn)OZ$QGQrYunO^_D?qqve_O_A`* zmE%F^<*|XJRXSxF-&!6`z}+Q=MvxrB!BABg6~$Zq^4tRKN%+&b)EFv^k@Zxg^?gdB ze|)YdGOccBO`1yj=^GxOV;-hwW+Gv}VJXZ&%}4OKp9#!_rLvoCFu_uo(Gw!g2*+79 z_{2NN@?928m%p2VSwNlHwEH<&)9}n4>*YA5D8xVI>>$#O*APT-C?0GBZXx*hKl4b{B8i_-Bfw~11Z|GHW5p@*pfWgv(shz za9PM<@=`NMy4zhAOiN1JZ4!B2v?^6Ya|o<4L|&F&pzy=*TNUQ!o6ApQ5m+h4{Af;nxvo|LmA=dKftbys}y-~e3 zgs9jC>jfQE$5^WkzHfy`5Fn`RMjP-c(+8TmHu&BcwgIAJqhW$?wqZKoW);^tA*HuV z*{(T!-?0&I7qeS#IIUn?;=wn*Ll@g%ce3F%1$=|sg~|~mGzl?u3l!gf#J3!&_GF`C zAHHcwzSnhbmX}f@dTq6jrI==>Bv?w~XKRIF7ZcsB&U)D%+}*SSQKprAkG3}5O(lIF z&${5|+r=mrJ^(R4Y`iRaU?btOT!GTNsVs&ZbI_31xjy)mH@pqnDCPj9^x3R|ydTz+ zB`YBwtc#`O-JCq1$Wm~#1t}%a%lFR3k#L&b=@J<0>m5tBYRThhW3>H%56|hcjZP`4 zaED>}n^B?l8F%OUbPfQ&oD^HmB*njpBw-5k3=@8-DeN%Kztm;1(7)v`H9;zrWBUED z%y=n@?8CDy%}Ra`GWHcQ55vEM#=m{mO)J>o6y@JR%VCNRy^qXR*-?&5dU#e1 zA>>&jQ9U$A#`9uu3lVNG>z%*iIV-q@Nc*YdsEFsqF#E-`YC_;C-zcU-y)w2D667TZ z*$2NxSk_&U@XGlLdij>ccxzpYgy;52I^bMrSU!d&`mDp%tLu)nb`_3VJvQbIxV|`rEWt>zt z5slQGHXdNT&_pFM*ztu8jx98?1&IfI%HJtwd(7x>1KNm1S{ZYf1mBFuQgG{C#Ws?O zHbNZaDSxdQA)F_zWcOzZNgP3@-=^-`px-6)VLX_n;EwYe>4teqT?tha#(?>EwK=v- z#|Wg4k_e;8^o!u-36+vyDf}Y%0O2LA5UMhLph+yyFO7TXEr0(UL^tLj%3osVR4C&S z_E4u^elLF?zL$vc08z#x?99%;Q(xMEPx(9dy*2{sD-h*aE$rDIzk4^m->b9%pStaw zoD3`OdZMx*DiEa&&@3Q^7WV!UQ=xnnElbND;=q$V@IVqH8|gC>?28wc&aZv5S; zxi&y_^L)>>*N^SoL`cybD%KRO`0yG2`3gSHL2sD~kw_n9sKlOykZnidpkHmk$2qpg zso>nLUs<>Lku>*;m9jVJ{t{fTE~#&#Ey=(T&p*=z%5e$2M3}E&;S4c literal 0 HcmV?d00001 diff --git a/resources/profiles/Anker/M5-texture.svg b/resources/profiles/Anker/M5-texture.svg new file mode 100644 index 0000000000..8b04342e3f --- /dev/null +++ b/resources/profiles/Anker/M5-texture.svg @@ -0,0 +1,1003 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/profiles/Anker/M5_thumbnail.png b/resources/profiles/Anker/M5_thumbnail.png new file mode 100644 index 0000000000000000000000000000000000000000..e137319201a97ffd20f0b60af13aa928900f02d3 GIT binary patch literal 37200 zcmb5V1yr0(vo1RLAi-S%3{G%|;0*2(oZ#;6Zi9PphY&otyGw!v2yVfHTkt#i{=N5q z_TA^4yY8&TV&1Oq>Z+%!s;lemiBeILeuF}c0ssKs$jX4#p#K{I02lxe5&DgIOMe#t zKq$A?(00>SR1h$Av}Z9kb2Kq$@v?V<(g6TL5iciWQ(JR43KMfnYX>3FSw|0u!rDv- zq{XesrsyPLZe=aw<6^GvqoiT#V{6K91`-iQ5%dy(GO#yyGp6vew{vh6@Dc+3!&daYPXDFAf1BdJ$p2#?6u$rc5HDk=|6ONA#s7PEd;9;UhO3*T2Na0^0QJAg^q&*B zYIr-Dv#Oc9I=Z`Um zm${t~i1XhZ{t9X5{&&a+2WzNW9RDV1|C=TR;^kmv|2IkJe@ptii~|2mp$)dSH+T4# zhW{z>zo|O^3-v$s{D&&xXy@pn4s{xHsQldAoZSD+_+KjxMGi_=bTosK|E0peNwN|W zDlU!|)^<>uv@FyuOx&&Q+?cH$C|uQ~#sA?0wF?30U~3C+u(2Do8wVTI{Mq=J**P`X zI0U#k1vuH5*|-GQ{)O*9y`gBD8M_((fA#ob^8>`v;PLEA>Bw|CiSPOKgIU`&Sz@=0Sre>wiU0=)-@- zUvmd&&~<@E*Mo0(VbBO3V-2;I|7j%v0DY2wl90@RDCv-)x+DW0)_Vvae3cSDIEGIS zFUF{_5l`2ht?e2$i;J3pB|gNquP~-~98yH#a08U*B-|Zi$ zU(&+)fi6hr-o$u?dRffP@}J>EYRjrYrlRQ3+9@um7R}Q)_z1}Gy(~sYOZK8922JWh zchN0qBxvHXBk?{I`%xa(_j|`Q=$6+l2;HNGdfU@{bI+oJm?9%nQ;JKyG1oAn6t9$u zj>0_|5quhm7m;Pj)Hi2yVJbkuOWr|x4c%DF3O{7vWgvuWH?(^+MLSqR$Z}tK5pF)& zL*5KTtZ8iSSq4~$$kw(ronuY+ywTTh;r7O8U4@Cra~n$}9aC1P#|^sUeE3Yt=7kEs zu)41M$mb8>_%VO^#>oj7OTgf}wzJli+x6`Gd42<9#MEVMwJBK|x?v(a$>_KO0H`>B z|6l-FIfMWJ1wa-ors0+IyURO+RLh&?C179ULv4dK*D}FGJyWfhA$tZUoe}n^)alh% zet1|uW7!~iYzn^B32x^aoMiIhI#aYhOz~DxSZXGi_dL)~_AbK2GSgUclYGOC+oH?& zyXP0a5A#A70v#0nxov*@!lSC$kH? zbDkCEprmsZJ+lnPAKKcUft*?C*oL#K)dly0Pz&$I>vf0ND>ZUTy^l`Dp^QV9HqNfj zfn;gOerj(WOZhP7iMj4c;5D`5>i5Yt0zK0*C?#T=b0+g98Fl6=n6*Qs3Z~KXCw_?8 zPBF0Om4^Db8}@5vc1o_0fLR`;5=xrsXT*Zo(}5AjGV;DQ zR`D&#TDY4U*s~Sna`KF421Rh>q-z*X@-*j##h?97?9RJGS&==1W7XE9rh)?CJU52N zM!-)4=Jhx$_`O44thHC~b8R%Cudo%XX@Lr2ST78g#a=hI1zH9$$Zxz}X#pGq??@xj zGxss+NDD20TXx?nZbtMvJZ=rz^C5ot)Nl9<3kb?;fu9M@&u`6*Gj0)v?QkVQN$-SJ zi9|4g6d-*nbh?M$i%H&9G)iM z<^t&KVsa8UlhXCO*5`f9I2dgYGzSj@385h%07bwhA=t2z@R@PhGN&nXMhU$E+?8%)JuOE-)U4WkoOVg`AghMoZN$C;Vki>wyOZM+?ckeH>OD z6GZGmY}z3vZr`$9aazF~Fu`@Na)Fkekrfbdw3*b&s6dq@EV1T{fx4M+x# zFUPl|f~TTr9mmM$!HOpV?vayIaPfL9BNr5$fFN8SVK0p9qBI;~o9xLsX($aRUOwbp zKQS}%ma6@AZtm5^IP5Oax_^a??+OoH)@agPV zCY^xU3xD60+(8>fgHU7H{Y5=DCsk89)q~jFyFvmcq{DtJj|?mUGhuYEb)XQPz!mS= z;HY#UnZ=6ww{I3QN9XJBDQOV_Uu;-I2)ev=AITBOILPS)SwF_Nfn5K5OMv|x{HJUq zBJkmZN*5deFu#WJI$4P&@?bzgWPA3$2@Fv39ZKhMQg1`Euqim!{nN zl@^|$8>M17`?LdaLG@aDq7GdKI^4aSY0mGK0YfWB&5mR00;SC@&#bw4Z7S{!{uuVBd=vxdzeR86Ip`g5YJL}ytnv6ljztI_uE9$S4L$q&~Kok=i6 zDnH3PJ>*IFkP~^NcP8pJWk9yLI>r83@?b~IqH8)$F7xD={gSsfC&sSTV}|ld7SjA7 zen-}Vot=228_E$qKDwFu`hwQ=L_IL#S5$4&^GyRZ>d~>sGZtDVbC*3RhkB0d>}(tx zIQ{rBiJtjBgE{`7Ioo;vsm@=9r%J-9ulASFcIU3GSXUW^_vQPHNrMIGrsf*VfGl+U z{hn&7N%3eYS?4AfrGh0#@oW!0Gf;_*p>V%q$?JVd9x8`t*D(uj?UVhWvLGK06q_g4 zFyyejV?5miu+7zPbyslxMSq9M#>t`X4Jh5{hUp_p z7r#Ll-Nqb?ATNGt>Ona3wi|z@P5E%e$1;%FuR;UKXsluB&s%Y5%)PxNU^AofcZ z>LpKOP0BM0Zta7C%IhJUav=HFi!gt>lpj8QmsIW79B!kleKQ5Gzh}E0o4cAWRek0o zRsFx^@3)`9Cx*2Ab^{U^@vMm)(#|;_?i&8x{_RCymrDJ~9c<-m!;bVs;*sgYMEpTNYYcy*;N9M>#Ri{kM4=* z)2)i;cC5r3tzGws~jY-N>1-L7vGzm8tI;YelfGK%{nkAfLkWh{AL(2ezpPg8Y?dv z&Vd;T;e7&b1#Td8+ypy6nwL1ZAF9@&L4ytYG7_2JV?`88xDL~_`a|4n_-t+G)+mWi zXx(co*~}Vw_W8_Kz|r3|M5q10FW2Kd@W-42{Z#6DqlN6o=*7Dybe6mJ{X>flM%soS zQfEVeeZO?|5i}lm3b@(*zlgh z>&!=Hhr-MYXrk2GK;u2FHS>+ zS;b&or4AdG6hjRe|}o3rk2ae%p{_qz&-Q(vx}*>S>Nw1{`!UNj7M?im`twm_4n5$ zXsSB*QQ-R=mdJJONuD?~(R`nQJ!iAPhgU9N>$lG*;XKYt!iO`@yOHxsCi2qj*1iWv z#^LFNtMHaVa9JtkzPv>^YMHJkdseynK}m9vd;>vfW7h(joIpcY4<}{cA@Cs4JL}JM zq_9FXZuAgn{WVx5_geV%WaCB1-TlMGLd#2Eqqh^tL@EsNv-A>++wZ6aWwrdPJ7$rg_cBQ&zN@Wm)y1HiP=0>{9 z>~p}h@l>|ebzo{#0_N?scUnJueSM^q-k&r+tkj6KMG2XT!<{7g)Z{;5-3IQ{Vm0^Tl;QVd`ohkKm)1cYc$Ltje{PZMCm|sSnP8!Oho?WW=PuiAbua zuKY!`Tdh>>*E{dstGPL|2Y*uIW8DfVv+6c}5$*|Gr`))^edrEU4h($7IeVPDQ^=F^ z#x^>#>)=T|{83$UtCbsi^j4H)5 zndl!89FgHcL82MR0KMa>d=c`zGL2+vV=6m+leo+TLo;zW^~8tNhU|Rhlu3-iiHp() zV$73Z&?Rmm7at!u@S?D1aJE$bB66|k17Ne(@r7i$#Zlz>S6RZg^7_?B#x%KU-5B$Td(c}k^2-+r3W^@?S+*unw5Qb{tzI_5U9PQ z{oHr4>!nphaLB|w5BS~1>~mvJbO=x)gOZ6JABB)GBjNt)(fubxp64W2oEm^y#eMD% zl^zUcg7F7ola5Seaa)v1DD(ZK7Py%l^%H>aUGM5Jj=a25r({B79+RIa$Y5_d3Nsii02(FaD=-QI)U(Zmz*E3bzy|@aj44C3ErNk`!`jW7 zK0dxBWgU9sY0*qNo!S*?6_eS#%IlX48&hXvBC9?~I<}M`uSN3LBtUP+`u)eQfai#G z$eHKE|u)Ilb4rO zdeg1@>)l?DkC!HxFFr$E9BxNe2!|uEt&S&~pw4sSt+uJ1r{`40tso*rKMxjG1SSJW zQjP&L7_!OtYZM++JFE{DFldsQ2?Gl((QmMkeMO$ldoK>JHva6uJTl4CY-b7tmEz&h zn|wk9s3!F@{gukF{O5TJeueTsV_a<1^6;&tEW&o*ETi{anV8;9td?oa=D6vH0E%4bRmg>31OsZsK*@ty)tIa)-oJT0t zRH9`V5ULv=%ez2WVi`D)!3EtppafBM!cBZU`a4q-+z{;OaO@Cqz|>VD82P6_+L4tJ zmdve5aN-{%^xt#}rr$bnkX@CmC}?grUZhqGM9&gFZN1xCemb+`l7yc`v#lO4`!HgP zO>^H2AnR^Mgn1sig_FAeV`t zETA=iX&{AMonrGk83>EbyGw5&l|0A>g5XHpNEyVgJ=z}!c&6L23pC09`M*i$}|&pDYR^T9c#8wV-~)-<+5 zEK#5HTYL?*I{xt4>I0qP<;vih9D?mQUCYhj30*f8KQo=*f}c%Jk;Lf*KQ;%^6tfx* zH6~^T41RAtf*vAr0fd6-t8DBv@t|y&xC(sIz6EoU+aztIEZP^9(VFxyenKMaTHROh zU@ZQ6&bz0cleaI>B$z>DiW<^{7*B>mB+msTPOT(HFMn9AU%O`Odd}f-sj}Qt2#^;r zE!{vphHvL{&Laxrq2Z2^ZGrI$X>=O-AeR*a8>AMUIYdH6b|Q0dxIOV6*3ZrqOa9XX z{ikROxf>O_VG7VWYA|K42_ro`Jg8JQ7ywEuCr*7qHgiN3 zEl19bn$Jne{Nj;qdA9e!uV^IIzBPC#sY}CCnvEd^I}Yv>a9`UMV`>Y;>4R-(23Tt~Ds_GG~xqkAnrcDhvjLL7-G`Q?Sc3!9px1lXv$)XffP2ZMiio#HwHF;lnqd0N#_ITfVM1p~q3htnVvW)fS4 zoWVLrW>4T6%UekL&M_YbMHvR;$-o_4q8bqP`;Dq86H2(6gy=^tt*J%n2*e(vxbT=G z8-(C^#osX7oPz|t1kG4N`>kitTs-i_7=+??4}z@bV4(m#q_W>Rk|oeHU|GD;i&(H#WrWh8H zh}UElzzU=`Srsm+Qzs0s%TS82-G-Ei$6zI?%V32NLfab(QigepYHJ!xE8f=8@fbdD zvp6)QR)>r0SB)zs5!#r*C#zD+`_-rq)cI$KwQne0KNb!N!w6dZl@XE#DT$wLw5UT8 z1uq71RIx`MCrW2Cn*7w-e+TU+P3LdeUGzmtJDs+1GdUl^V_I&t5+x%ro$l`G(@s>S zs%3>2sVnIOcL;N~m?2IR-+IjS@LcTizEb)hskeOl%A_D_IET^hV4et0Qrx< zMVd|n8%^VUr$0U)E%p*;!;2M!6acHasz%DC>H7|}-}IxsgN+y`d+ZNk!bG6QL`7@J zpq5Rhj>1j}TgVvH^_`VFFgMyH!H1YbICr=K zdW`r9H|2R;GTSNutO=%JrwY_}^pYxa9at8!hUM?FhVEG>;SZw?NFipM1=(>VWdC~EVaiC1VM4&7ndIQ(^0r=NrG`*oVq0Ku zO{ymafK|%pMu-Afv{MnR>+KtWh2|4X3mjq0dOQpD>~!`4uXXDD-RV`mTEBIGjq2|N zSpi8QiQ@+K-VhR*Ir>#)=Xk3SQ7kMbJ)+9Rg!%G3KTHHs2EbeRaRe_QIC;ORm8fng zeE-s<9@#Vrq{&qH}OnGRRJOEo2&Ve&#~ks8sBuD~8p^FtckSDvCo@ zZ|wuuQgU1ppe=lh)s}+v9UlwdIhv?+opRg-Fq?te0cHW@>}tcPco)b3W#qNd;O(k+ z`IMZJ_h?}F5E(~``-uLmjxzo#&O+MAiW1)01*4YSQ^}i}*7e)9>1LYDR~w4bOX`H= z%TIns2#Q4=Le1*$lT^&6%9g}rz-WeDAdD))G$vH~^F0N@Rqi1FkFB%gmW#@x7|avZDj!+N?^|zz*+63;X&~H1{)b#6<{M{owSpyF!EU`Eq6BMVj?pnw*wa@^^J;(D#6{|y_yQ7 zTkmFFf7M2Y2TILgKJoJK-7yq?Wu>arswFe1GZ~uhx(o2!7T5;PV+83ct z*I?XuIe(tB$CG(?f+ac`%NH+cw?YJz82HKS(bbp8`wQ?p9DZgWPO+#drg*Sy*Q-l%2aA(#T_kvg$kM=jf) zLak#P%bx&Q(6(j$eRAyU=jLXnOiDKpE^b_+LVtdK?zA;s2saT$@8vOa>%X5LI1}$W zC1iQ-n%`mjeW}kbw;3iYLlSKLCA!|1?Y<<5zW^7K3VI_-WQsWwHBrYe%dRdS_|Mxi zzkxH=>Bc+KBnD-w?-A|RXw85AjJ$%?TWtNQ=_ktRil{SvgLwmAo_0H+smL(}@DqnC zA$;Ek*35wJaiRCs-aKpjfk{Wev--<=mv6d`?NsgJF)PQgzR!7Y@Z9+B)YE@o8n?il$C}SJMX>2md@P=xcsMIC$1BT3ZO6LML+y9rZY%W zA63$@or&UUW!0!Ie+?=Cb3I|cB@e(frrL9r)^WnPKNPw&P5&M*8({Oh>hG4!&hxpnoD#hGH3hJ|p_PybHHF&oi*YelUYqB} zdV|A3=*7l*|V0ZboKizx=9izOwH<@^1KDEs!|0ZZ(_KdGSI%VUQ8~4VY`` zYYII5fv#5kHs2~?c-(NI1kz$&V4q|-|NDE*>5_r`-di_|6^V z*h5So@j#38P+R_QK`@u%nk9WFpJC`twpM){#LW~Ggg;kdy6J;eWo+Y4^V%q{che1P z?tU*_fdE>td>V{t4qm_OMs8ait_n$n!7I)7Bwyxj2yjutyGqp#$0Q=r-*jEXIi|XP z=a<&3{rGGQd$h33$t&D-5i-`jzu6ahqigS`M=D8U@llYDE`J~{Z}i9gN}Dg2q~;6v z)^0OC!Kw-MFomqr`mYiXWFhN@3nteIYcy*Ug_uW{D~(1ov4jRJjPx0CMH02?A`eWf zn)(wS`{hn;@JC57&BooCZnNFe=Yf{C8=RI~BGUzYlyEqxFAX$I3BUj3e|y~Xa(wwK zML8Z(>|9wkxr%2v$8`v`HlvYz73p<5qN{27K&E&`+vgiMYj(raB9n$tcSN0gsKy## z(*~)G58eE2!jsaky9+bP_hEVUt^sZO9^85G<8b9Ul6O|gPq6(OTh*)fNL;x~?e*EM$7XlQ7ERB=C=$F^xR+ypH=yo|i{waXE4y4W82U?Dtz)%m5i)^X>1?t79H zGI`r)%%D+S-|>ZNJ-U;j^X}LCw==r-Z!729?@l&EDsPU5sU}hiKN~Dw>PYR;mS?xL zm8!IOSH(WC+-THa&!u2VzrUhlfm5Z&-$dvxYb0Kr?zisoo+ME+#ZLrjv9q6|bCm{< z#}cNIaO$K`MsF|q^2?Q~<+JbIfE(q(rv_~);M$Xz8k7dgacc*JqHxJsQlde)$wr?`xel3tR5eHVYbd1d( zFzpQB!L^ZyTL(a(yU|nrl+2duBA0WuwveLk;n;v`@^B@GKePKuX|bSEyV*SBefMDp zNJUOoS=sPWiyI*#GSUzlISZQt?2L>yrH>b?Ny%*@}aooj6jcniPb{V1H~ED(P%`=cUTgq{_P< ztNIAD;}x#x7DT3os4+IBWsA2jeUVRWflv8iAE~hD;oy(hYoeEh*qlQetp6UhKe=?m z!Y2+8gv#3a^*!2v2qP{ENt)UQ)Du?t4m*tcLWo3#y0S*)-z9B0^BX*57M3?`qpsAZ(uO#RDaYBt!BWN$r z&?Qtj1%%FfM~AoO&2rYAKxhs+eR4Q(WUJqm}2 z!-zRu-U^E3OwZ{F#1YBWmru;g$SiZJYwIGeB?(P@bGPTA)18ZSZz1*^_>6+t82WhH z;i!l!*;C%MZpeiH`n(lM{(=!&hKc`Fc<%!A|U zYABE>Zf*Hit8*;b1N|E{hwE}zna)rC_@6t6Np;#|XukQK`$A_QLPJAq@BB9~XH55V zT)!*piu635`hNLH{=P|t-lbe){U((BseqZTs>5m);8lV9T@yl~D)%V8QbT68A$7Q# zfz^1}XQjCLO$}QkrPb<1CH^M}v(9dakc!SV$xiBkh{cBg`)g>GZhw6+7OF)y?QHC^ zSdRJ3Zmn}NA@jY0Qe*_A_h;stO9M~;Jq3$yQFx#APVfBov+l=XvI9j&pE>cVE5t^% zj+(ApJX3YDeWzAAEY;+qxD(TRZFd%E8{rM;qS_)1vsKk8Jp;rbMq9~7vk3l1SDOkkOY5nk)cq7N zycR0^w{;2r3iHP|hI6`}SX+69&-3YVdUN;TS|9NUO_i^N0yV%MtIi`Q_R4V9DzatO zlkx2v=jSR#kWSyz`?JhrB?jU+#BDx~NjtzIJO?ij-~rk23t*${-clc~IYLQ53N;(;m|Nc%mAa0ZC_s|hVE!<& z+p+UvxIyxlxGjGMZ|&=XJZl%%Ytin6*7P28_9DDkpP~Qq(arn(6?W#jR4onEWvuCg zlj9g-C3ov5 zB8ShgDIfwTJOo>21=6y?IGE;wsyZG$?Udd@L_4&fKR>Hw6n!Aa#j>idbJ-oY&Rwba zP$_rg^GuATv-`MC5E&VH%W8P4A6V-(^e&a%0y!zm(Z2pB&-XNsBZz~BR3|mDHLp-Q zST;FnW@e`UuIF{Lsu({_4q?bd_FXkzY4Xxo%mSN745j$@nmV3bqU!J_#9?B-u5j%z zns}<%*x2dwb1Z{%=(})*gM>a_?_Oi8SMdhwq?EFN(}+bb6z+c*7R zg6S)$qQ$|g5X~-DI@bnF-0m~^wjbRi$L_VhWMq6!n+jNMS&&<3?c5NWGLJPaetg%m z=0Q@e*HS|~a={@Qk?Fm!P}9?1p>>zv@x^zS+qS~;B>{D>>$sAf52WfZ@G|oAo z!VC4NQxwh~v|hF98%xyie%B>S-gPfi%IKmrU0aqkIlUGKe+#Jvi&s>{=%L{8%!wMl z>J|;gJZ?4edq;qJbaRts4tqN^jigY*Chsk|r#uOni)AgUQu)GtmpPmwKqlF8o+yv{ z&CM!X&K8RnI7n!kLY+DNV?STyPBMB2-kDSa9#TX|TSt$NN}m>eaC9nOuF?C>@W$nS zk@bnh{L%C7*65|z&#IadbS{YDfG1pr(Y5(|ZeI|!g87r(>es>*?H8QVu1dkFtEL5L z<%r}{4O?`(w3Ji_FmG{jF=0+wgiNdF&(J|WFZr$<0ti|>h!7hTwQ+;A4h2O>MO^$y zQ8t0@($E(%UKjH{VJ@YDEL2m>&I{dzCe=bKgjdIT`_NGM`l8kI;AvYMa8r5M68PAn zK^RflxbR`)t_7AuAVmx=Nc6F*{fpM8_UIBJT^hLxE6VF{o-cuomRAn+v|+}ONb&%_ z=$%1~Vy}ffbb{gW&eBNR_vOA2mk%Vc`+7>reB7gCnQ5ROHryOhGrzMsY`@~ZE1eCw zn(6_wH&`+szdk1=e32?H+~Kg^t_3q&C_rQWwXcqeC$9yFcx!I97qoo3ds?;W z@uG)J7}#ZJqH%Wyzfj8pDVRPs;-(vV&_J_Qgi@~IBU39baWn4{7L16?53t32eR*9- z=X3d01K)F3>g?`a^!>(43Kyf)#y<>S_%#hevaICA$>#c_48}ZVtq(U=JYDN z%_sSVUQGRDflj`Q_PiUnp!!C&cdw$Qv+j<}#BXPUZ>6QA+l3$MUVRVX&hF=kHo&%X z4xfl|eq&H@;^ew%mM;zvhx&BoRgm!Tj`rNgInEr6I^9ecN|X&d`}zO0(&rTv#4SCh zN!HX&T~H~J_3bvXs1&M|(j}w+Bq!FUdr|b2U8)2&$frPqB8UTeABRK%-n?2?OUPU{ z-C_`$aoq{O{Mj*VeJEvp?*DA*0k%~#5T+|}h?&;4Rg)t?6=R@Jf43{ww2U{BB*Mj! z{LPBxmm=)OB0YW#0Qu-m+U+J_6$Q0TG1#UjOQW4 z*_{NDa`d;PCBCO^=|%K~gS05NFJ>&H%$k$AGoj*gBv zwTH35`}C=^o`<8#72+J_fJ>$J=UZh~8?OF4hEhXV$|0tJe&q0D;(2nRC(*$EDAo{| zp`#wg@FSItC+|>$H6eW+ZD#r}VhH9sKlNmeIIx73DQYhSMSeE;_Q++E69F#}J^YXg6=WR;a^+_3M zrK07qbMyGHd}_Kg9odin$-Q5#lVqj#uINrrUc{2%D}zO9UY?#%7**!I2K2!)IE2!V)EROx!- zfAqPTP+>{Wj^eRaD$$Fj?qUCw*`y}N-CzFb()qNUUWo)v1iXz2Ul_2+aFfVyZ*GKe zBDU^jlW`jtkf61;r^(`k7q=<{4!GXUO-#o5qb%{dC*L7)*%X(qAOxoOojAbEYG=%ZV5nzOTJ?8!1Z>KYe5;h=Z)#A7! zN71x$6>>vWOqDM-o@7!dv+(t{aY1L;;H`e4a}fnb97zfViUe0b(DIw9r0(d=Sd@ciUyDnlg>H2Jgho`IBb z33A0Eh_P#fWmHgBMlgR58{JTj%>u_7N1QxC;tr#OZ*0LKJ9|0J>%3&1ju&t~jqyEx z=MP5X0(a?;2(|KSFkwWQb@d(2%xzv?-gAQR!<@A*=h2P8_%3$pWzqc=!8JaLSf2qo z721f*yEwJBBA>^-do9D~J%X{6)Kx+hA7}JLU|bsPR@$T_#r~3n1yupDiyXLtxB- z=uAo#z5SzUImo@b@QPqp8Fuz-n_O|CwQSI=%JMhNY+n1`^zQ3gAW0k---3oW$C{97 zn4JF>0D3QA>a%U&3GXwXtRHB0;WFogXp5xPEgCnYgjI%5qw8Z$|H0;0-9{%$(HabC zp0T+6-$B$-Gcq2=_x0wj=Q-)c9kV-bV1G<825}SpkAi*QVw`b}_v0;R2uVWO7tqKA zdI7xsQe6*Q7_US1L-L=pOeoK{`7Y9mOmHPp^S!pC@IWr{3qGO@P0*5sbmJ{g)TmhX z&8YjL0l}KvoFXR&pYYQb$*DtnuggFqDGvz?+Yz4lfnn1kjOQClGL&A0+hv2 zw6Ae~ECWyaJ?faS&iZ8xQbW`O-AL)I^AzPD$!(H#G&p;AuiZ|ti*QTt`4HoV=_AnJ zd}csLQyNkl-gRz@(=FV5)Nc1;k1oX?K6-N!t9&AK+YslrPTG304B|on-RQ>sY>>n2 zjnk#dW>4}|nV3h{8XxF4;!&vx_V!0rVbmyO2wDgUgZ)Y-5fhDuCHBM0XeZ(Zy0>BT z5YLRBcS|WNn+M`95TO1FDNy;sP;FoLr5Kvv(-apM?{m6}U@>0{o*9E4TIi$EZ}09B z9G2>bV0#sL*SL22?x!PPl1~FSDF>Zb3EwjQNan*m@iq@~v%{vAg_psLhH#~piH@Gs zxebrwPr03O54_eeW*21X-~#FcXkZa>8SsKeaYQpqtU0}PC2Xs48R@;!9%qK<|Ayf48TTNJVR2E+nGBnWpP!%2Xc$CVd^eup9uX^dZH(nh_1o??yStz-Eltz2 z2lWT+78y%HfX^!Qe(hyt`x~C8t2#(Q%zDGS6yFG;z!4G){^BN%dwKS~)1JCZacLW; zn577>Iem+kfL0h7&;!X<{-6Z0)2??O-x{WLq;zUsQLMKIs>oqMG8yDzt(5{aMOUvy z-`9V^w_Z+-f&NYu*s6m!h~{yd{XX4KPu6lRb+RIDQl}8H)Tg;JV(k5poNKPEr%v_a z&|wBWgbkPB&$y>ndFpI8ujP`8Jyv^R}9`awVBiVSwlEK%ju2XnvCIW6wXB`oUk?VNe;=!X|_I;CN zOHRGlCFX5zI3MrMHdZT4zau!bAJXdfyjYtr^=hkE!W-m?($gb0t71IUOc0o^G@n@9 zU*bt+Xly4#Vn)r~Xb*vmT{ArCA@M(=VKh^x)R#Kbj_sDHya0Rgd1 z=lc1^WvnqI(rL1zehSC}uC8qFM>2rgOyF48FQdQK>zx^Z%)_6HKKUx>Fx@%9wnS_O zcb2+H`5+{k(9_cf$&$Y%&Ej7Mxv8dajeW8GT`FjE>tZFz>6IKushj_#k;5skZej^y zT8p<2A$yrK{-?JJ zsR)n!epK2Ds+-&SW}i4FZhJo)kFM>8_JFQ$GIb%T03U?lqxbyJ@w76j1i{OJ=%&d` zTv)JG4#ciVheDyvu-kgRDXc2I05|Ej)1^>FyErv3A$1zmX5}vY@&jnAc$DR&V4WO0 z+r!!5T;C>KYc)2i0IxM%>Vmw^bY?@otp-@5PWP$Lii@^LxOKBCWE#oDhPn8+{gSudw(k2T&!Ge2wDi7CajEs9x#5k7S=g#6ns5k<-F=)*6ViL zPt)pl`c*TvN;5Dp;C0urA*8jFxbr#Np~!xvxg45D-*6M(XxUT;j@|jcDV5QmPr(Zk zsD?CT|o-KM!Dz=L6z8=%+0C-@sSvIDPC==x%|#Bt?mO&($RjiivDfZK`p;G zl4-Nz9{w=miyF-xQHnR)$;_1~pP71mtOy^y_a1NcORDO$t)P)akHj%3CwNEIm&W)@?aN9} z_)3e&@rQ~olJETcv1O+(wP&NB@k!cdvv>aR}6<$IRPFT)q?&|!_jeMJxfEW|}uFop9A+Zqi;(8C5!W7>r}OWLd-x}?}974XUL!9|J;rf3si*rRw$@V(NI%BeNl#v`@y5Dlcpjf4!ISY!t$t04}>k-zram!LCxZzPkU=E5l|+rF6`kz>{_S_a7fbl^qUrI?>r;{ z-V}|U6G2SHB&kA^k%)+lnI44L79@QnujCrA)>gVqXCAUtjY9PaBFKxr?WRd2joe~C zamUNO`5B)2&S3EKVVp{dF51yTajCD_O~^uNG>;{6Fe>fm@4RE5l)k^ANT>RSKTNDO zZ^C5vk#=!b)dPJ`-iGnkmFH2Zg;XX>*VqGnXL(t1HJBq##8nAd6d!hM%>y0Ylxdq! zig3}msy8Dnr*CK^XBt`$qB>dcdM~e(VB18@D=pf}8_r1v24G<~8)5r=v#nJxtJRT* z7MJGYd_v*Bg5~rZze!%n*!H@hfI=a5@2Cjn?X-Kuetlym+9U7 z2j>2GYU>E&F{vV!DritByjMJ7V0^WK1`Un3$?b=t6cg2Tf z&gil~eiGWzv7P1aMFugM#BL2@>X~v1rNB>@$RwfSyu(+enE9mG+uz+3<*2w#BU`mI z`pm_n3f<*zw7~>1by_T%5XdOxLo_5-k*oCfEvFvAlojK1p60?8mqbRzd~&M|S&Ul2 zmNiD5G5tHB1RO|;aADJ096J)S10T)BBv`i3SSqxkckKI;50Rk{GRMb@Q0-AO6~mSM zp+KZaW(vw!6d}jl9HVx>OTp#sMt_WMB8%2ARLAtsQ&^-{r;vKjq| zC{wU%hJ}<|^LHRetUKr>7#Kn}D5mrPW0-<1!vPfsx zPmZmU{YHX`WnGHPklrQn+iqCSq!lcOCv968T@1{_AB;j^cw_9Mri{cU)rX<)+E}pJ zhmj-1zaUdzry5M|_86e@b(j!~y*$0uEcV7Ahy#zSjgjddRkVhnK|5n`SF{6Bw5B-u zmP;Eb+YcPT3^zd*uUTh{!hshnG76hZ60z(UjFa+VU29V1=3S)7A%?p8Ez zi_rD4dQ0N{6D)?s0JdXO75#Pxjb%xBm$5Ivs-gJ3wC(EZXGE= z5tJs>qeGc4O%V8vdgvu4fl6IM6g2>+;iTRQ8Mpd$9v~Dz#5xtnEg=G9Euttw6h%m) z5XMAlT4{trvFMD##0AfoT|Hu<5TrIRko75?88We+r$MwTu(L*6gg$g=5NwTV&J8Wr zwQA-d04*-0%w?5&X7&D8!+KR{IuBOWK;^Mqb;+K7&(~PKd>MLsdh@-r!wLXq&SxlL zC&{=aN~Kb#gKMaO*2EdI)*@?jm85yWaU8mq3h5NwXpA8yg1~itYK5~OBv+**C5=*w zRQf6fVjdGN%s+COW&mzc9`3X;PN>ZO#pG+wQ1^>kzg zUQ;E_DuJwxU4ng_pb>`9s*cP^Cs2C5k$ZZP=94hMWWm-+bftZ_eHK{B9Lq<6?%2q6zBeX^6;o*@q2P4y<+lBLFh*dxmfOQCx0Aj^Ssl(*GID@LWG;iu7&9%0S zMJ+nI>%-=b!cH_fFRUv8fryZk;1r*puxwkrYigW&mwU?c_p&p~ z-fWhh<$1^eT1983nvD;?v;%g>Pp3S}T;2KDNiIMcK(+{wfOGZ2U7rD`FDJQe%b2J8 zut2msPn{Z?S(B#J)#jG`%=Cvg(K>W#TcUgv=L&5R+L(kym@v(>sAi6IdfPcodY7gj zHJ^M^Q#UpV8d>w1miTI}$5SR(Qk_0i#hhIz!Y-qjnT6Sk%gYwFHi5CuAz@5HaU4+` zC$LFEahytCb<)~-00_;O)18{-l$2nM%WD7tAOJ~3K~(-d zS$tR~7i`&zgRPlu>Gg>*M(XvkRK;=|rBGQ|+KsQY?B^69<~09VEUaaiRN4|ro_M4b z!Sggk3b59K6hV6)lq1`b}Hu%sFUh z&?cb`n1znq!!MnKTCUQC1zK(pQEnIzHJ{k*6?g%PK>@`=$?Yf3jbKb-EDMW(2}-%> zQuaioF8?%RN)+YK2RU_@MXY5eoAy5@=MM8oYatR+EYKpN*<r5j5v>k;EiPy)hAEa#227F|iHQ&=5sXO?$L=Qplu9KeNeqFj zA5=o z&)%CyTb7;mVZUz==iGCrH`UZtJxgk-CA9|B8nGo5M4U-x@REZG!bA{)Lzt&n7M2BG zHaIu|XF=ix2+XjO6@pk`X)OpyG7tm^iJ{e#TB;tatLjzN8}D$=+0&Ol_TJ~-S3|2> zRaUFiY^|qy{ocLzowLukzv1`&zVADK_8jK(1|&qHTx35M03Uo#2fUSwRt}FAVG4nn zxvuB+_V$IpCeZ)Of#(3cR#Fd!!#A%DhJSl79IgnV1SL1;@WwivvvA%*6$M74F%BO- zhNqr<3XeSUS=7xObv;9$D&Ol0u(P)V2bc*?W1|cP?UJI=?jvToOGLIU{ z`37Fx=VkBdiV47o>ZISNOTRuq$5jcmu_n3+K=OMpek{>(VD<;VNoEFx09=v?TD&Gi zX#)ee>G;if(;MFir4+35?Z^K3W0U*u|0}7r{)x%{-iM@=0Ra1uA~r_1wYfYfB;tFt z06EE?aH9OK4grYKs4<3hp%JW0J1kgf1t}$sS4MC0*8L)f5QJ1E zCvfceZ4d$=jwMamt%%bM7I!T!BhD8y%`z+#N%#OWZ?&fRjef6szmU=^t$DOE?5(YA zj5gK|efem-0vU@|Ap}7R#@^m8_Vy>J`hC3p?|vO#`?`Dad%yGhXj+5WY>LTriv7J^ zOs9L8Om@L6z^tIPM%%VsyRNFLAf>?m{x&9)U3gG(4`Zyr2PU0e^n@=X%$?lDXT}SRZ`LU1v;TNmg?)b?BcqTmk z^cfsFd=x7yYgk)bK{cqL3JqyAq|{Kd2T8NeAV?`uRTX-@9*77^#e3b@Si{=-2IjSe z52AA^7p~K@bvN>x34rGShIc;P{leR>i_`I}xE!2=vW_X2oQ)27z(MUDQ^LqZn2uFP zi?1BD3qjC@L{;^pKzk3Z3oDfr-a9cKkFFcEbG2)2ypHvaL$WIR`slHn!f?=!UI7RE z*`I#`TRS^IA{_|`$b_CVk`|M=ypI_cFxGN1Dyu1Cf`s7UT}u!_3duL$zL)}5r~;<7 zK7`4*(y-PuG z>I#*%k1}qap6v2m31&`Jwg|IkW@|g0IkGhq&jv>qqY#_AW+7yX2SS&q$#{MjVCKsF z_b1z-o&rTd^IzklgIo^f%u zUIHKidKQg1Ki9fSE{EuDq#IOo+5G#(KU?y+FL#fONE1z`z8k9`1<1!4h$7wav*|v1 zz1I51DuOnr8c~1vLNk4<_PsSBg#wY(M_8|{_GD2?(0Yrfnn&WZQ zr`YW?ekP@8Ha_#rF=Ed*{@uzIa?Z`uN)M_3pYd|2n@l9~vPN-#JCg znfo07uIQ@4NyHAYQY&Q3>b=MQ{yv7oAs&3-0XT{f-}crv^sKCM!KrZzgR|C45tHWt=N-4c(KsspV&%}r z|90fq`a|#e<{w;A2?PR35MX~oVh zVKoOXa!IH!<4-YjY;Mwp{^Z z)vWjDX1+K5S;@uw4-eL!_|<>;i+1^%RG}b+Dg=?vtVar*>)krnV>wnKAwV+nnuQ=J zA;Conf>=@*gxPEk9u|1vvD@*uJc}7kK>H4(;SjsKyI2B=01%{9P)c`&)FGA9QC4F4 zl|+z2LMjbLVYn@puGl_mYKK1RaYF14wZEqD6iHBtSgI$;a-;-FLka zqalIW!SWWys~ZR`kvkSHm&-E=Fok^NGi~lUUBCY;AGH8Z133L(ed~Yu@N72uNUtpZ zMPr&*+ui9q`~h`m0|93|rU6huQ7SkvlvK$w6JpDQrEWNg zZVpKSk^(XUG?91X{B?V}SKA*t!RgD}lzm!0a1w!qYgH5qcii$StQ|Up3+*3cFIW`1 zhg*)m624u9wW0Gf7l22?jX584007D7z~#8o`ryxhhymDN{lG8pZtrb<)O-8U@o0sH z{SmW(*qU#{2urdjAq$Ou(dYO5z`Orm=$miQJ^ATM4B!9N-}DWiUGJ@hwZSU&`+X1z zp3J5=vw50)<+-&j9U89U9dG*TOYE`pK6VRTdLp^eOjmx@QAi_WFs2qIlu}SqK`8|y zc|hMH1?K0^p9c$tQc76mVc}q`>x4NY9Vbqlz(4qgcVZB0P9cSY(h8C!q!2*rxRfhY znBp}V=h4g?_C5q_jGayD^kg!L)zxADb(fhj3`GtS~e)^WTzw63&*ey-rMHJ?45Lf2Ab{vn`@{0sP zY7OZev@T(-2MHIs>HxA*L3$Ru7dCPD$PoasCtmanBex|#^V@E{9fvn=O8u(QL9ocg zrR-ArI4sJC0Ph|9;CMQ%jkRXhw$1*NkDuK6)I*=8d+vVWH9ON+mnm#pa?U{)@kAf+ z%_yD1bRu)$!OS3`pmYHuf!S=UJvMjIlUZ2zTt>5&W zIJ>`jRtkx4{#);S#s~K;Z-3V_{+>e0eMS|F4njL%LzmA>?(3}KoJUc{0$6L2Do}u& z;bkyut*L2hoWF1$To6Pc1kZ*+irJ?mEIc!m^G?W)Qp;UH8kUNvVulqK zpIK}7o<8-|{GkUQ*q_z)<+0soxvs8RW7~EY$SGMOM1p@vK#+=ln8@kzs8&f3AW|7+ zh=uqZGMJYSf{d_S9<4w*EgE7vhA9vcYyHKip`XqA>Q`OrI()uMfWVa6%q7e@2Zw?V z;=tLZRZ5{Kdf-%?PGA_L8@5_0HjtNhG^iTLp+9y89dZQ3UM)nEQa zy}fg8zI9=z-?pX{f)qhW4lDu(@*#u}ybnGE?|pDC1ZQn<-g{$>X_~s-pG@kfpL)9f z%x6A5z2nY1&UklyhJ9Xr304Zl+oomPx5VrL?_ye?u&ILzDKMDzykFH7V%5> z$YOsOC@E1@C4?l%vCKc_TdL{ z!!EzB&Xlu9YBr7ENpf*8RIkfS(<#}g<7 zw#GYem=Hj4A#e@g@zHSj^J{CXA9>FYe~*374}Z^f*_*2p=;2_*Z?q=`XD?P)pX06a4S^3N9PLn?);-;ZOfU9_x1NW9^VuM5uF z*^^H`_4I5u`~9jK{LXMV_|wmP`k_mvH2vhi{@3FF`Hc@8ZktAjz^s(=MN!zIDE!Lm zn!n?YJKfzceVM!ar7!gx8ynm!V{vU=&oQrS0Eo>@nAsYGzxBq~@l&TByRLh4RRaA> z|L*7fo8SDE|KIlZ)(?3f-tK)^1H!;sGp^_JqhK5f?90vbr`6eWr>Sk5Xv&fw-OT5( z#=r-MUT=tA)sIhuBn}-qguCu~310t(H{g}8dQ}%#M4}l4hynt0UC*!Ujo;WSvx=gg zUZzn4DL6|dSRs|M2_aDyWvu?zMTAEMA-Fz_FdVDDHG~wjw>Q14`Tv3M|Na1A^BOMv z`lSS~u&$b%^oM`=;rhpZ>|gx$xpU`!dwXk}PMBC;=u>*!`ZW^F`e$<1uuFrUVPWfl0R+n`q#e}Z+^>LQz<>rG4ztE z7KpRL%;y;E_Iz5I7Y|y-CX&`pZCf(6ATT2WNd#SJa8NO@X9fhJP$dP&l1NCUG)W=I zi{~ygd#&qP(MNyeN8Wt^JALba@^@;fR2Yp{hHL8^{eCqNQc38dL|Il4QlTgmq*M?j z5u02`c#oKYAR%?xY4Z#}rQ%Lzz=Mdz=U+4bCAo4ou9N5k@kQ#)&77n?M6W~$Xr;UT z1p`6}%%vb9rJ~sNMJ&co+?eax_O?5)in4@|QkK15Un*6Am^g&kno3H@#FEQ{W|$*% zDx)9OWv_CDL^h9$sZ8*K1XwWi7pMd2jj%eZXp-#9)lcOA3@M{1gn&%_=`tBeDUnhE zq)3pEQc9(j@ZtJEXwSvECV`GPaq37t9sUQ78LlVomHB2N3b< z+Um7j>X+0?g}xy$dr4P%hMCzHx)CNKjejOMJbU_39X0lwLzg!ZVNd`0?Y{a;aZZD|-=GhQS!fb!!YxgHJcGsb$AOW0pz+5-laeOreX! z8A1qBO5@^M(C70KLXh`iK}t*nr7YeZQHhay)-4*@ESmo0!I^2kItf{nMOl`m<{LNw zzb1k9!2{hM<*q=9QMaf=!GdkDq#c$D1(+h^FbZ>6m{bHN5<)3`<2rT!5mqcs1M-d$ z4z_5^PDiQ}Iso%68_JX>&xCX#gp^uolGm@q?+d=JNuUujf}h#s$$g-UswS?8BGZ9y zd0ERuBsvfYQT8g7Wpz!L`lYnI_nq2UH1;`oVHfLR=SZBE7x@8ff)=IAx$Xcl$A=IcP~;J&*U^L zewTR&KIL};zS7WX({JJK!r?dhS z38{5SLP&<}PCo%1S(h2nJ-KA%j92QE&x_KccpwCM@BHz<>JAzF&C7tFB5zoFC4(H9R094Ii0B>0pkxIN$3ul(|_Q5*mi7V^A2qPAN( z4p}IQj6>(~8Mzy3d@RgLM!xbsjg*R4gV{pGA!6!O$` zWJ$m~Vefc$H!{EAdM=xW8O3tTtT`e@ba`c~n3F3PFD4*16V2Q_4n!oS5aN3EYJM)( zHC_2)!+abJc#)RKGWm=FA)_0mu3?uVXSkn7l>@`hgC`>Y`7BGqx=bvc_Dd^k{n zeWjIvXhDLWIoA9lU)P9*(ITIkar-W7wJ>!FM~ZK`XkRlCJ-*&A1&L`EJmT=5JTl>L z7LdsOk`i^4QZr3TtxI_+xfPZI?Zvy}>vFfMG`~lXproL0Tn&AV^ie>>c_cES%Gpg` zin(*(x11%+KhK4nu^CD>k0EuZOe&uV(JlF#g|51umMq^vh;+GKZ>qAt3JooYgcMRr zA%(nwU5;xKXlEVEXr&}0fP)8t5V|(8z@_d6FTPUmGwx;$CUQ;S1>BT^!W-BMUe_fA zEwZY4mnrdQvhqkHKslAUg%DdoURpZeSxq7mB1&_7pkJ^Xy3XsGj-u8&Gm{p2mzLY? zc8!maH*Xoh%RlY>=D-MPULbeANSwKOBL^zibG_?b-`vG}%-JMnItCroAG{P4CRzdx zJgub=KBfpMj(NUu_xc*?qXGcu(XElpkv3O!5L`t64;Z|xSdhoO#itWGv?DC}-;w!y zLq{steZ|0}Lyu@#Ko{RJkQ78340h4)f#`Qr5V37^{OpTV&W*LMEhy}!Tc^RGKs1NE zppwS5#OTQG9kMqO+XH9rMjBZ8vcgMu~?~~ICkP8WJyfFTz+MM4}cFYLr$0Z zEKX-4`Z6JPFTGLMHAzWb*O8ZW$!{)Yel5Pg^wr+y(Y-M-lV)-+J|qN|&%sEFFV;ng zR795&X3)V+oJUQ>@z0mMZkZb$E8Rpwn4Z%H^VhnrS?z^HwToJr5@&;R(<5;3U|vd! zWOxo?`74iobE7FI~x7V?hbUTeJu35b6-%yodGKjac~FxpQnrO|sw8 zQ4em=bo0~o$X!9%Y+Ewg%Dz;1%YyY_eL(Qzuv2(6wm@oCL|o1 zv-XX`>0Fw~)oJv_;*NzE!^yxQc<+7i@`jb@YeYE;5|k$UT(r2O*i$K)t}U_REJqU+d`IY_ zoT-Yh$?#jqKvP!SY0E-#GZ<-Xfsd8>!F%EmM0UWHdj6pt|Nes?BIg{w_G@CZ^k4YJ zU!v2ePvfut>aR&CA*B=~a}N}XQ({A4)lNT0%o2DL+$YZ2qt26JrHfQk8qiGs=?_rFAbDna$Tkk#n z`6oV!zyUw<-hT!kJnnzs0ovN$mVr){jN}o52FPYtjL9BY*@$ zDTS)nLsQpIh&am3+8dKQb8VfIVo<_@5Ec!nqED8^FEFE5^--1;tT(8t!O|yCVuYpc z{?4ZdKtSYj2mr(!zMx!=U;1~yLR;J0w7UkK5YQjVn%10h8z zgdC4XqoGn-pFO*I@9C${R0Kg%3KY6TQ5GnBJ?u^P(KH5HTTCYV*xA`eS@mJ9g;J_( z&nAR`Qabe@6agR$g4bG$x^BK;`+YsvHCC)hNTmdkkewGDQsxgKwlrYij@w^|jkTlj z?67g@P-JFsG>XJPa3Kk@hxf@viL-?BXsiRN#-IJSKS!sYIwj7WIU}~Vw#ClQwkpa} z3STaT7BcM+tdL%?iLn4y)FBO>Yx4kd#nGc%Eh z-RUBllSo~OYDmOF2q~o0Qp!>gNs!P=YXJx@ilVHWT1=TqA(SjB_4T^MIUs^A3TzzSKyG%jyci7UeH;nwLN|>xcu(GYNkp=3 znxPN^Kl6Y5@A5tG{wHtyr|XzuzUueo>e_0hwCW2f2Z4D2&=^ERA~67w zmQraVQUFV-AQNFhC1ET9XemV{q#OtmB@r=;*cUZvR7R{=VlcZjBuNpGqyt%wjx#|q zI!??^Atc47U4c7be!)Dv93YfwGDIYSsOi&8Z<11?C<8BC@eEdT)_3lP6&{7Bx^^3ANtPA}Wk9_8l;!i&Iu`|Jk3-A1g|LuO@up8L# zYgOzVKYo02?C8;1uUGQ7f7`cx(Fyytxg1iUkWx#n%C6lEG4gnXj)&XjW)G5QVw@Pz z8jHXT=RB-65x(;tZPRLJZGSeKZ73!qQClfQ9&BAOp3oEOu zVr_Lz7DZ7=sY<1EPfA%zDP;B?yX&GQpeqJTL_`89wv8$MSQQy7M9_TzL4ZY~BX>8K zeA)Cv$|-(|`vPW&=tilW=&eu+5AqKyyIOjC1oRpE}h(@x-Z#Gj{Xs zfA{O2ZcV%8oZAMl)2phjni67tH-TiH))SY$H z+)1F@P21cVfC2}pQXhIe$lyMjOa`QnI4%VaBu(sAOJ~3K~#6}^;cTmUM=>^IoGAK zm5LK#UBa4)V$W@G)X*|bag8{CK%kJ4Fbs5!9H~ph#;hTMNEA}Zjo?Ecj5Z!sMhGmV zl*EBO2ka^3Hm!F%6vD(gHDd?l0y6>+i&wP{DcU@Z> z11Zuhlr-FD*^y3bQJ_hkkT3u1y~lhugLMwIY2niYv&Nxr>H>hRs@`mGGND(0*=zWR zfB1j;)KC1xkAKQqBigp5q9|$JG_Q8v{Un25%gm*jNva7K}Z?YOxRj(VxF7I zN8uEy0ck2@LkI!RSQsGo?G`e%I*vhouP7j74`o@P-|u5QUcqQIq^e(*0zwKQN+|@G znRfPe{jr;F@}@PD>10;#?e5GcvuWM7O>ou~#+crPt@E!aisEPA_=Y$9PFZOCsr&x= z^WMMDXI)!jCH|AqqQy|b^Z*topAMMRC2AAm#ojxuqz1Fx z+uIArPu$Gk_kG{b-|-#)sLO@-hhsxTwP)W7B1Hrdf)my@sAtjslT=W;7lWZ*552ZU zGoNE`dneAomIXwbg`Hoc3yrFZ54$Le2#*N?#-b}~p%erO*s-Hs%n`#A0j1&y5T)Y1=t83?3uvX|{mJNt zL=Py(EP!(s)*3ixqw8lZd*WEY{IMkVK(N^m;v%y*`SvL{avVZ>r)zb}6Bhgj52B*6_^O+uOx( zIK*r3eJyUi`DSRP&?L7h=1v#BdZxrW=Mby|6JdX{kKNr}v`qsaJdPedgq4+5G&*OE3i0cO*;JoR4Z|_3oVz_?Tt_XtA16D*4Nf{-};ufd}cnM*>C)B{sI5kKmT#6svd4ScGI8GE< z?(San$vI{|Bm9`PpHIPVysyylzCAY2oWc2Xn{eJG;qx%g!Wavm4tQiB#?R~b2e|v? z_oV5sX}>}7z#{qSDXAioKfEYXCUD4BBgHpTK&08GlmvLujWCUE%1TNQbh1Vyh^wkk zqv7z#$wyD#w6{0e{(&EQ_uLr6qu~%rDgNEx{V+)>@wT^p#TOI_xvW6{{Lj6gK6U^7 z<=*bzxM|y!5JH~_nnUP;AOS%SJ@{!-N);r7d#D$lMOj8a-tHlDj?= zSwnZ4+8H=+!5qZO%IYgt*H(|e?Ci{1 z)6AT+Gp*EIkhqys)+0Bv0WBDPNN$4=B2MU%5+tHlCINV7!5puzP6j9YtXdVAPNw)j zf9==M)KeTfatv#S4}lUa7DvTI;mQ1psOkc`$yESOpE-jwXU^uRFMd%x2)ZaSURgm1 z9^2d7u+{)HfL0Ph#>bYM_e2H3os#g(9VIvZD!^Eakb}eE;n{bDrA+GgAwUSia5zR) zRq)=UuIF&h;T8A10{7l~Z-xn7Yg!|KH#JRrL_+uz+hb7t#P_uaP}Lf8{R zUii@;{g>M>zUxIZr8TGhV<7~}qCkI8;mg1LjRyq&V}J5-5<=n)umAk;?@I*wYrp1e zZ~f4RKKOPi)rypwq?CdLNhxzBCIv9OlsYJ_WNX{oY-^-|KoGGFtM?YpsfDkcHqOH* zo-QTf4lt&HwGKX}dsE4f>wH6i#QOT$@jGt6{m^Z<+>)E12qfCv%3T59Y&)u*4NfhmL;6C*xK60laD_J=Odz#4~nxE>^)l3#!!~xY;RqbD0ClS z!fd*awwWWa1E)cT`Tax$@1hke%N~v#iBreCcbLuQFs8-o$_nm&$xEP>LTikiPAApQ z&h}l?>FhQs9T!r!h0={uYPV^cnfGp9*UkPz4?Z}5_~D0V045=XJqB-EW45G}7ly;( z`G55j|I5xjuXuSIU8jJ}&GQg~@cSSB1HA1k-}0=5`VxT-0k;DDZ47@aASMi)5hTtA z#@Rxv^IDg-EP9pJg;rXYr%pXJ-rL=!vR9$dC8QK+ng$`lJWHRwkyW-1{2ziV}5Q<2Qfv1Ni7iKZ5CWf{l%J^r{jW z&UocLFT*?D@%N#%!q(On?*G*NxbIWoPu*6Qpal$Qoy?aMFR7B z4qX)R!9(i;>%AWOy%Klc`7#{ZSdB`>d05k8cYg;vds{en{w(%(cQI>c(FGI^^=yVc zB@seEJD)=;h2d}j;s6c~0xWuEZ@96xUJd&L?;VqKHngp=#zs4WTH8AB*@xh~ zb3SkgP1DSprr9^fG@F~}_D`OCboN`n{o8vCYzZlMgrEymuR33r<(YTC=Y3~i_qx~4 z4C@QWzJTxg&VO`?z+WoR(cxt+lu(5}tdzP*#Lgq+9dig~#({Rh zm`GVolq_yKeR>mu2&&M~N?|&k0n;?jEi=LLA4pk@++S^fe;-N}F_F@?>8nYa+ad%< z01tY-3Rr3v)_q)Lj8!3o;GK6;idHFU>v@g6{r%pq^<`}6Epg(+tvGSwX1w*SZ$+NH?AKt*mp$!yTL+b)cX@Gr-0is(XiAZa$h)4xTaKWN1%U%eB z90)T2vfg&Q`8U7iEBCjzx9w;&n*Yhi{*W&#(8d@C&^Xb!P z@W>;NkTE8rEFx!pV$dgqh}i3(!gw^si4!OAqPt#%vMAx4!-ef_oZCE$kAC#SICt(` z%mY$%KO(JSQ5z9Bz!;19Yz83(OfyID4!yF6^JmWkev#U)n-(XI-;9-&6*%j=1jukW z#C$f#XHPx~aJnUJptt=!Eo)$3yJw9>%<$qG{(CkH;vB5=tl(WdWsR3TmT8 zp)^Gcf}u#pcJ~CZAP5%3A)p`?c|JV2@*x~8t{nUqrb;KO`2=lOhU0PF_bFrDG;aKX?9KBQ7Gtwo_#4ASZvb=|-kgVwaz-;d#*`X#+PN!ltp=7>+&y; zA3xT~@g)L%$DMbaz3;yJey*{y3n|oBmu2r*RaHV4TIiyns#l>bd+1d?^sD$i zFL*C;vjt&L4KU~rIy3=@Jloc^Fe!-w#6T=C!v%&l7RDF|#4bUrE2~gS!+8g-D>FrUpM{MNSE-QDhDhYVj5k{>Q(>RPJ!{d6*eE;OW+05fK@ zIjnWDiibTsJCM$>1`x@JNsu@)N%DV37?I!uz)T2%(#VfEwptW1(A7nOvM5m&k$T!I zd#L&`0i}x)h1RI5J^%@012h<=l2B!VUdp}-DIrKj1t$`2oeg5*b|vK$?I12CtAgND))h1TemJq(8<3`Zjj1_KO-BMgS4n3YOb zo9owrhQd=3vC4wq@2T1YY)DtQsXe_0n zbrEBMvR6TIiK6JiTMH=_Adr$EE*{!8CXlT6kS-pk*0vC}OneMR)7EIr93gOWk^1Nl zS5Xu(OReykTK1b6u-nR9e1Mhhs&>C}Pfd+tI|MmZyfA9x?D4aNPeCvrPPW|y@ zRzIM1ac5DK!{B|dp3i79onktjVz=In+E5CRj8K;lgfii%>#OTnSzW>E>I%l=m3WHN zpO=z4Eh7^3QOS6YnM?EsQIPic_wna{{s{;o6k20A9$`ElW4toPcr?Pwcol{2q2I4y zjD>X;>-9PgO=oCL3zw1=wlQei8f|0HwgydG!#WFV9c*i0TugrWq!o>^&_xeSKBlA- zYMFIStWNh393MCdg~_bW$!iD*6lEX7;ShsCA636Xuc{!0f=(&+ve$zyHFQy+sw#{I zee?$-=p?97i)tvLqM#%UpHp%@TOSgDRvJ=7mkEhRDkUJ5i2RL6Jc`g{vH~)(??lr0 z+3G+LkS5Tk)Ir4ALn1aM_aSf`s^byT(1nP#$Crip86jfx3H|Rfs31<3ILZ#v`&n>G zNLe)X9FzSC=JN^W(|z9FI%l`HFF4b-J~;1#_a~)5-RYsr33OiXeeXY`M<0ER9)I%8 zPb*b?W3Sg6N}*MJs2Rr%sOuWj$pq8s6#J7s%;$4>=h959d7>&m`eB>xrR>oLe zTgA%C8p@)Gers|8@_T&8S6dzsnK=%53~)5FSp$IyBy*mDJM$ackww_5ty>slqA%}F z^oy4^LsIk+NeT$1qL4@lr8Kg;rF0CG2EzfyqXCA)0jmBGd%@4i85m@?jtC;e|>k>-I z_>dN23?iAW9;|cNn@lm;n_ynoXzCiRZQ(lM5vT?O9NIXHTW-A-_q^(bxZ{r7arE#Z zjD`c0{R&D-FaT#A+SXuNH<-<)nAZ)Q^&Kgxqr@U=I3<&tAfoB^0ccy-HLdJuvqTU= zL5Rh+FRJ51H#d+|zh_1y;>fq(M@ z|5vx4&nVDDkv0fI-Bo5>rf0(f8_pUPsHy?_{XRAh9fAPCdz&__LDQOqcr>uKg=uP> zdTI(E9!Ky2LP%6qAEVV3jD{l&hC>Voee|meRj-073lxP$S@a-u)`anp38}%N0jB^j z@|>f_mr6sZIN#d3fYvw|7vKUz`Lwyru*Rb`Hf1p5VNeRo;4p#!1Y}nL%S;dqP+;Ui zuYtLX5pq()C%-*InbxJC4^c3^^O0<1ebVNf0^Q{QyJ(8r*1%emER8vUAjN{)s4bm$ zn9ZiJCURz4lU~;}9n~NUS+sxx95QH;T$@E(iB9;sEO0usGFQta zbmv}X#7PPPrdYi$b1|<_2u$(%qEf0Ecu*34@vaxX;CEl~ikI_G|J48dxf3hPE5dFq zz;Ll{km;Ek`5mB$hD9(Q|CK0;3T4^P#|41{tZ8AApKDD-D6%`Sy}gCa&9iXMf&f%y ziNSD)UR6cm?hi5O_tCEg==FL42^izxT+BWSh%`e42?v_mPSjeR*pPoOKCXw+o(1`dO;>PClc9vFUflp|u94 zZDC9uS%}uarN0vbcWzSD#sJfTvYG|%wp(w*$&;T2k?7cUxkQJgNJ1DbjF2%16v(I# zbplEm0TLAXE+nF0cE3-r6;W^n#o{#*X*f}b9LdfN5=ualS_pCa%C4em4fdz|sOK{{ zXG3f3zW2ebt*>HZWBsx+_&Ef+i6#nMGP4LNAh@c<7k`_!o)3z-)+Mwq6P%T%S9=fJ znJ)`x1KOrR(?q{(XJ@yo+R!TE#6{VQJ~W{-w;BAWPZZQ=@GowKdW=qXxCk!MkW$b3uZ)7QrQtB zy!3J*Q4|uOBL4(PEU~~I0WtMk&*qrVW~k>gOegzjY?EN1gb`<4Jl8ZPzc*h_6n@b? zP%wAfxOjhtmf}5eSIrU+H>cZ6^ZpW?$K3>uEWa_hjM%SCFqx7%!kzcA)l2WP5`O(XZ7k8L$kQV^^vsjBW!N~+F2q-WFv<7;`0PE`;kccMBvcY6F z!F)2qWHP~QK7(y*_>0=f`b4eF*{hH~KjWkTI&&HYtVqJ9p|$R+LZqT7ph`o@BJmz1 z3SFe%$1g~N%y@13H)FMttDNAkX#JoW=L|W?O_(=lo(DgUo@xB7OZUytTT~en0$TXT#5?}T&jo}4M%vv3tj}F z$|&Y^P>e5KNrk8D6VEUh^oj!g!4H0rE?l?(r4`L4(|HJdelDj2t&36@MNes^1;yNE zHZ;qXDztpa4t|4Wld`PIYyqDKenMhASi^X@g2RUcCX;yhYaN`mDWQ=be6B`Ggm@qdS+)kT(|`ac zQ;H;H3OjzXGOD+>-a~!L0a^JOV(mNN6mpJE4DF+nN_2n_t z9J7wz104C@v6x`tRsoE8Jp(uvF~>cLF@Q7Cl`__(I3pxVsY6*RIA@`xLI^Px-Ghrbg%TGFb0-X^73&x@&?d8@L1$sK2VqVXwY33-4 z;zQfpJ5%TEZBoh?D6MZV%igeG_4`t(*nkvEr}v_>wmA9uA~W`R>6y%_+vU%@@@v!2 z54a2H%<1B`1rm6aPI)Bhm%W(881#pcufcJ!CAf|4d^s}O;q)=st;@1D(+SLHHL9w@6Hh)0l5%NU zz~y9=4*mzT00%UUp)0)M$^!lMU;p*|Z~o0sv-cif^`E}=6Q6nHk^4S%{{!oj$@F!B z{k=t@k4u5$QsO2c9P;cdXT9)&A%()SKZP7XP@eOVaNElWHs!#9vVWGVK9=|pSomj4 z$2XB|q8abBXZG82@Y7ujB~!OBv-z-b3S%-ta?t1QlrIPb?+xaY8LTm}Tq=0D0}b0F zJ{*JCTq_uB{bJpp1ql%=Qh*phf??V=!&Lwxja4a)#xy9(9>APj4u&o?jIkggQI!Q; zO1BdcTvhb2qm$#eICb- z9>bZlXHgaf2tZlH7-w~LEj6yGpp}MFx5E zrCs?u)ZZU{6Owg8mLba|w4kv}w(NVTtWi>pC3_kgV~NHdDZ8mbmXBp7lYJXSSwC5` z3>v24V~Y$L!c6$i|M0!f{q_EEpZnbBzV12abq;jbGAdopePq=nW(paN+^;HPcvO>i zJ=^ObuVgw{THRP@MRR4@Rd zu#99G=PU#y=9cu$y7BPQi9y6J=aRiFau;ssFT_rl zD1Uh-9}9}AY2qg}sLOSaTjMN(h#R?=^vCf8#$>^F#*{(jSNi(0ItIF>654^o&vjFck}Yj5o#SOy+C~OAZu>rTl?uvd z{|-Erd;HE&B^*ZL*hF6m^dAqaYzmCNzgg`&83m)0#Fr8Tx$gU|jW(GF1r-Kjx>moC zyzfjQG{qb?-*;6x+|cS2W7%DD>-v-FV#D7-=q&r8oH0KH-Pb`hA=myCS5mKdYxMk= z7n;sJm$;IsvK+KKuC9maIXO8@5()M__;|Bpmp(Nr_F+3b?eH+#plD=;!c@2a+A->O zy}I$V@$C8I<3BV{i@H*t6I(G5+E6=2vki|Y!{U6I{L@<;`)sc{!{;@H+E0Gz*GoK! z`i$n6zFqs92NmZ=xy^-a_G-luFRE{fgbW|J&c6Qzt22VZ{EVXPt*XHGt^1dHB^4j) zvDL`C_K9}|z_ON}Tv)9AW$o(KcO^i^TtcXg(6i+CayKGwsJurj?Xg{8BGbu5e&_=0@U_S`VWo z>3?;r!zAe`@WjKV1EhKxM~8H5Z$>$oQB0Tp>{ty>l(U^Ou3Dy#7&5rxxxGwAxyvS( z%y2kdAi0tKHpZ8$Yy@Q!=DvPK0Q|5)-0UHrcVRUF{e!rd5f4%l5`V~Q7aT}Um1(0# z8YVlXN#nH!z3YFdiVpQP2hDvQ(T_|G?l??R9a?b_*kPIBcTai5uo~pS-`@?s37W8$)CBefSIi-Qv?n&R5{;4 zdo_ww-xGX9;iDk5=8$pTfLYV#a)%WG$?iXrDRLUe_YT0 z(2IT_?j8RQrXMu&47Kksq;_ji)qn$*HNHPv)B>%UNO((R7Gka${pRSj1u7uF@Cu8J+2y{Mz(@|f%XaiFy_o}Yz5q9qrAs^ykxzic;HIvlD}B5@Vj_I@W(sQJt^}*`pLddy`L!tzZNs#|@E_p@p*r-&vs1 zOe_9GCc@rM@MjBtjjEwuFAb{3&xp&nR1r)U?$bUdR|0XCH`NE^IF>|A5yh6hzA%rjj(oL4A4(M6R-zBOh`r=gJr`Y!Ck6loyZ#gYyX-6N%DCB7(m$h43%Ka)N`=)HWjXFL_*%vdLwe!YT^T(OIOpyna^37 zcuYG+Q_tw$c(I#}ZV25q?&IN!ySlCES?h{gtb!M6-iW2=o0n%VXbF6?iN0v5UoFxa zj8rild}4>BMK$Q?9*3sYT6?Fr6@~>8|KMu4*2j<6*r}5$tB$Wq=W>cG@nE|5a5)C9U-T8)Ext{O+>9=L@K+(q|M?Mw z6>yQb6RmpTAK;yU5E#u1Tt^x}P^Q1Z|2kw&vE4nf$kF*3_KOM0&tQr23!GM1I2=~* zACbgQedU3*l=mo9?Ltpn>ip-plU)&wq!6hDDqrX6*a{Qw$pDzo_+@cC7_?X#S4v-c zGLuQ55rAw{q33KRG#JkB!y6_R;YSW5&b+?^TuWi=G}jc2<%6iP_s5oro1_<8gFFq@ z`c1D?Ex&)`=rmcNUu`rt=L>m!diz4!_&Nw;*1aA<3v;i3amIvu)?ivu7F&4r#qGW2{MTB%r8EypQdKMlCkxK&U zx1#7(2Ai83MM>f?Sr~^oOOt61oa+o5n`oO!APUk5kbZgP-qpp>DuT^*D2*olpW_h@ z=l6qzP_RF-nj9Gk6vvVCRtuHyoWM^cnX3~A;ry8{ZLqfE;U57ER?85ER@V@Hi~t hXk Date: Wed, 2 Nov 2022 13:34:38 +0100 Subject: [PATCH 232/250] CutGizmo: Bug Fixing : * Crash - when click to Whipe-tower * Crash - when the bed is empty and the top bar is pressed +. Note: There was a bug in detection if we can increase/recrease instances * After cutting the object in SLA does not work clipping of view Improvements : * Connectors mode of CutGizmo : Add "Cancel" button to Discard all conectors and switch to the CutPlane mode --- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 37 ++++++++++++++++++++++------ src/slic3r/GUI/Gizmos/GLGizmoCut.hpp | 6 +++-- src/slic3r/GUI/Plater.cpp | 9 +++++-- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 14b31d7c50..818872bb41 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -864,7 +864,10 @@ void GLGizmoCut3D::on_set_state() m_parent.request_extra_frame(); } else { - m_c->object_clipper()->release(); + if (auto oc = m_c->object_clipper()) { + oc->set_behavior(true, true, 0.); + oc->release(); + } m_selected.clear(); } force_update_clipper_on_render = m_state == On; @@ -1000,7 +1003,7 @@ bool GLGizmoCut3D::on_is_activable() const { const Selection& selection = m_parent.get_selection(); const int object_idx = selection.get_object_idx(); - if (object_idx < 0) + if (object_idx < 0 || selection.is_wipe_tower()) return false; bool is_dowel_object = false; @@ -1391,7 +1394,7 @@ void GLGizmoCut3D::on_render() void GLGizmoCut3D::render_debug_input_window() { m_imgui->begin(wxString("DEBUG")); - +/* static bool hide_clipped = false; static bool fill_cut = false; static float contour_width = 0.4f; @@ -1405,7 +1408,7 @@ void GLGizmoCut3D::render_debug_input_window() oc->set_behavior(hide_clipped || m_connectors_editing, fill_cut || m_connectors_editing, double(contour_width)); ImGui::Separator(); - +*/ if (m_imgui->checkbox(_L("Render cut plane as circle"), m_cut_plane_as_circle)) m_plane.reset(); @@ -1527,10 +1530,18 @@ void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors) ImGui::Separator(); if (m_imgui->button(_L("Confirm connectors"))) { - m_clp_normal = m_c->object_clipper()->get_clipping_plane()->get_normal(); + m_clp_normal = m_c->object_clipper()->get_clipping_plane()->get_normal(); unselect_all_connectors(); set_connectors_editing(false); } + + ImGui::SameLine(2.75f * m_label_width); + + if (m_imgui->button(_L("Cancel"))) { + m_clp_normal = m_c->object_clipper()->get_clipping_plane()->get_normal(); + reset_connectors(); + set_connectors_editing(false); + } } void GLGizmoCut3D::render_build_size() @@ -1573,6 +1584,8 @@ void GLGizmoCut3D::set_connectors_editing(bool connectors_editing) m_connectors_editing = connectors_editing; update_raycasters_for_picking(); + m_c->object_clipper()->set_behavior(m_connectors_editing, m_connectors_editing, double(m_contour_width)); + m_parent.request_extra_frame(); } @@ -1603,6 +1616,13 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors) reset_cut_plane(); m_imgui->disabled_end(); + ImGui::SameLine(2.25f * m_label_width); + ImGui::PushItemWidth(0.75f * m_label_width); + m_is_contour_changed = m_imgui->slider_float("contour width", &m_contour_width, 0.f, 3.f); + + if (auto oc = m_c->object_clipper(); oc && m_is_contour_changed) + oc->set_behavior(m_connectors_editing, m_connectors_editing, double(m_contour_width)); + if (wxGetApp().plater()->printer_technology() == ptFFF) { m_imgui->disabled_begin(!m_keep_upper || !m_keep_lower); if (m_imgui->button(_L("Add/Edit connectors"))) @@ -1641,7 +1661,7 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors) ImGui::Separator(); - m_imgui->disabled_begin(!can_perform_cut()); + m_imgui->disabled_begin(!m_is_contour_changed && !can_perform_cut()); if(m_imgui->button(_L("Perform cut"))) perform_cut(m_parent.get_selection()); m_imgui->disabled_end(); @@ -1729,6 +1749,8 @@ void GLGizmoCut3D::init_input_window_data(CutConnectors &connectors) void GLGizmoCut3D::render_input_window_warning() const { + if (m_is_contour_changed) + return; if (wxGetApp().plater()->printer_technology() == ptFFF && m_has_invalid_connector) { wxString out = wxString(ImGui::WarningMarkerSmall) + _L("Invalid connectors detected") + ":"; if (m_info_stats.outside_cut_contour > size_t(0)) @@ -1829,7 +1851,8 @@ void GLGizmoCut3D::render_connectors() { ::glEnable(GL_DEPTH_TEST); - if (cut_line_processing() || m_connector_mode == CutConnectorMode::Auto || !m_c->selection_info()) + if (m_is_contour_changed || cut_line_processing() || + m_connector_mode == CutConnectorMode::Auto || !m_c->selection_info()) return; const ModelObject* mo = m_c->selection_info()->model_object(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index 35b6a92cec..8a3ee6d074 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -96,7 +96,7 @@ class GLGizmoCut3D : public GLGizmoBase bool m_hide_cut_plane{ false }; bool m_connectors_editing{ false }; - bool m_cut_plane_as_circle{ false }; + bool m_cut_plane_as_circle{ true }; float m_connector_depth_ratio{ 3.f }; float m_connector_size{ 2.5f }; @@ -109,6 +109,9 @@ class GLGizmoCut3D : public GLGizmoBase bool m_imperial_units{ false }; bool force_update_clipper_on_render{false}; + float m_contour_width{ 0.4f }; + bool m_is_contour_changed{ false }; + mutable std::vector m_selected; // which pins are currently selected int m_selected_count{ 0 }; @@ -170,7 +173,6 @@ public: void put_connectors_on_cut_plane(const Vec3d& cp_normal, double cp_offset); void update_clipper(); void update_clipper_on_render(); - void set_connectors_editing() { m_connectors_editing = true; } void invalidate_cut_plane(); BoundingBoxf3 bounding_box() const; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 63b0a4e217..dd47325b5f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4934,7 +4934,9 @@ bool Plater::priv::can_increase_instances() const || q->canvas3D()->get_gizmos_manager().is_in_editing_mode()) return false; - return !sidebar->obj_list()->has_selected_cut_object(); + const int obj_idx = get_selected_object_idx(); + return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && + !sidebar->obj_list()->has_selected_cut_object(); } bool Plater::priv::can_decrease_instances() const @@ -4943,7 +4945,10 @@ bool Plater::priv::can_decrease_instances() const || q->canvas3D()->get_gizmos_manager().is_in_editing_mode()) return false; - return !sidebar->obj_list()->has_selected_cut_object(); + const int obj_idx = get_selected_object_idx(); + return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && + (model.objects[obj_idx]->instances.size() > 1) && + !sidebar->obj_list()->has_selected_cut_object(); } bool Plater::priv::can_split_to_objects() const From 0468250298e76c7be5b4ca9e96175204f7847ebc Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 2 Nov 2022 16:26:09 +0100 Subject: [PATCH 233/250] ObjectDataViewModel: Fixed a check of m_bitmap_cache existence. There was a crash after app's recreation, when we try to get some bitmap from m_bitmap_cache, but it is null for this moment --- src/slic3r/GUI/ObjectDataViewModel.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index 50577771bc..066fc45223 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -19,6 +19,14 @@ wxDEFINE_EVENT(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED, wxCommandEvent); BitmapCache* m_bitmap_cache = nullptr; +wxBitmapBundle* find_bndl(const std::string& bmp_name) +{ + if (!m_bitmap_cache) + m_bitmap_cache = new BitmapCache; + + return m_bitmap_cache->find_bndl(bmp_name); +} + // ***************************************************************************** // ---------------------------------------------------------------------------- // ObjectDataViewModelNode @@ -186,7 +194,7 @@ void ObjectDataViewModelNode::update_settings_digest_bitmaps() std::string scaled_bitmap_name = m_name.ToUTF8().data(); scaled_bitmap_name += (wxGetApp().dark_mode() ? "-dm" : ""); - wxBitmapBundle *bmp = m_bitmap_cache->find_bndl(scaled_bitmap_name); + wxBitmapBundle *bmp = find_bndl(scaled_bitmap_name); if (bmp == nullptr) { std::vector bmps; for (auto& category : m_opt_categories) @@ -321,8 +329,6 @@ static int get_root_idx(ObjectDataViewModelNode *parent_node, const ItemType roo ObjectDataViewModel::ObjectDataViewModel() { - m_bitmap_cache = new Slic3r::GUI::BitmapCache; - m_volume_bmps = MenuFactory::get_volume_bitmaps(); m_warning_bmp = *get_bmp_bundle(WarningIcon); m_warning_manifold_bmp = *get_bmp_bundle(WarningManifoldIcon); @@ -359,7 +365,7 @@ void ObjectDataViewModel::UpdateBitmapForNode(ObjectDataViewModelNode* node) scaled_bitmap_name += std::to_string(vol_type); scaled_bitmap_name += (wxGetApp().dark_mode() ? "-dm" : "-lm"); - wxBitmapBundle* bmp = m_bitmap_cache->find_bndl(scaled_bitmap_name); + wxBitmapBundle* bmp = find_bndl(scaled_bitmap_name); if (!bmp) { std::vector bmps; if (node->has_warning_icon()) From a59f8aea6ef7dd5ff04eda5835617caf2b774c35 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 2 Nov 2022 16:27:49 +0100 Subject: [PATCH 234/250] Follow-up https://github.com/Prusa-Development/PrusaSlicerPrivate/commit/ba22eb600e62ddaee0a83f2037c4bc0c3ccd3cdd - Fix for string formatting (by @bubnikv) --- src/slic3r/GUI/format.hpp | 69 ++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 41 deletions(-) diff --git a/src/slic3r/GUI/format.hpp b/src/slic3r/GUI/format.hpp index 51beafff13..15a3f04c38 100644 --- a/src/slic3r/GUI/format.hpp +++ b/src/slic3r/GUI/format.hpp @@ -7,12 +7,35 @@ // though C++20 format uses a different template pattern for position independent parameters. // This wrapper also manages implicit conversion from wxString to UTF8 and format_wxstr() variants are provided to format into wxString. -#include - #include -namespace Slic3r { -namespace GUI { +namespace Slic3r::internal::format { + // Wrapper around wxScopedCharBuffer to indicate that the content is UTF8 formatted. + struct utf8_buffer { + // wxScopedCharBuffer is reference counted, therefore copying by value is cheap. + wxScopedCharBuffer data; + }; + inline std::ostream& operator<<(std::ostream& os, const utf8_buffer &v) { + os << v.data.data(); + return os; + } + // Accept wxString and convert it to UTF8 to be processed by Slic3r::format(). + inline const utf8_buffer cook(const wxString& arg) { + return utf8_buffer{ arg.ToUTF8() }; + } + // Vojtech seemingly does not understand perfect forwarding: + // Why Slic3r::internal::format::cook(T&& arg) is taken for non-const wxString reference? + inline const utf8_buffer cook(wxString& arg) { + return utf8_buffer{ arg.ToUTF8() }; + } + inline const utf8_buffer cook(wxString&& arg) { + return utf8_buffer{ arg.ToUTF8() }; + } +} + +#include + +namespace Slic3r::GUI { // Format input mixing UTF8 encoded strings (const char*, std::string) and wxStrings, return a wxString. template @@ -42,42 +65,6 @@ inline std::string format(const wxString& fmt, TArgs&&... args) { return Slic3r::format(fmt.ToUTF8().data(), std::forward(args)...); } -} // namespace GUI - -namespace internal { - namespace format { - // Wrapper around wxScopedCharBuffer to indicate that the content is UTF8 formatted. - struct utf8_buffer { - // wxScopedCharBuffer is reference counted, therefore copying by value is cheap. - wxScopedCharBuffer data; - }; - // Accept wxString and convert it to UTF8 to be processed by Slic3r::format(). - inline const utf8_buffer cook(const wxString &arg) { - return utf8_buffer { arg.ToUTF8() }; - } - // Vojtech seemingly does not understand perfect forwarding: - // Why Slic3r::internal::format::cook(T&& arg) is taken for non-const wxString reference? - inline const utf8_buffer cook(wxString &arg) { - return utf8_buffer { arg.ToUTF8() }; - } - inline const utf8_buffer cook(wxString &&arg) { - return utf8_buffer{ arg.ToUTF8() }; - } - } -} - -} // namespace Slic3r - -namespace boost { - namespace io { - namespace detail { - // Adaptor for boost::format to accept wxString converted to UTF8. - inline std::ostream& operator<<(std::ostream& os, const Slic3r::internal::format::utf8_buffer& str) { - os << str.data.data(); - return os; - } - } - } -} +} // namespace Slic3r::GUI #endif /* slic3r_GUI_format_hpp_ */ From dda0b50b5c589a237b128bed2d6547659328414f Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 3 Nov 2022 12:14:27 +0100 Subject: [PATCH 235/250] Fixed a crash in measuring backend when handling broken models --- src/libslic3r/Measure.cpp | 45 +++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index f64b79e22f..6e11b853ab 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -87,6 +87,10 @@ void MeasuringImpl::update_planes() return (std::abs(a(0) - b(0)) < 0.001 && std::abs(a(1) - b(1)) < 0.001 && std::abs(a(2) - b(2)) < 0.001); }; + // First go through all the triangles and fill in m_planes vector. For each "plane" + // detected on the model, it will contain list of facets that are part of it. + // We will also fill in m_face_to_plane, which contains index into m_planes + // for each of the source facets. while (1) { // Find next unvisited triangle: for (; seed_facet_idx < num_of_facets; ++ seed_facet_idx) @@ -117,20 +121,29 @@ void MeasuringImpl::update_planes() m_planes.back().normal = normal_ptr->cast(); std::sort(m_planes.back().facets.begin(), m_planes.back().facets.end()); } - + + // Check that each facet is part of one of the planes. assert(std::none_of(m_face_to_plane.begin(), m_face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); + // Now we will walk around each of the planes and save vertices which form the border. SurfaceMesh sm(m_its); for (int plane_id=0; plane_id < int(m_planes.size()); ++plane_id) { - //int plane_id = 5; { const auto& facets = m_planes[plane_id].facets; m_planes[plane_id].borders.clear(); std::vector> visited(facets.size(), {false, false, false}); + + for (int face_id=0; face_id& border : plane.borders) { - assert(border.size() > 1); + if (border.size() <= 1) + continue; int start_idx = -1; // First calculate angles at all the vertices. From 05e82b1fc569f6fe02d29784a87aa7611164d349 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 3 Nov 2022 13:20:35 +0100 Subject: [PATCH 236/250] Measuring: validation for zero distance moved from backend to frontend --- src/libslic3r/Measure.cpp | 8 -------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 6e11b853ab..ffff12bab1 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -1060,14 +1060,6 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& else result.angle = angle_plane_plane(f1.get_plane(), f2.get_plane()); } - - // validation - if (result.distance_infinite.has_value() && result.distance_infinite->dist < EPSILON) - result.distance_infinite.reset(); - if (result.distance_strict.has_value() && result.distance_strict->dist < EPSILON) - result.distance_strict.reset(); - if (result.angle.has_value() && std::abs(result.angle->angle) < EPSILON) - result.angle.reset(); return result; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 74be878f11..d296bb3c45 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -905,7 +905,7 @@ void GLGizmoMeasure::render_dimensioning() return; auto point_point = [this, shader](const Vec3d& v1, const Vec3d& v2, float distance) { - if (v1.isApprox(v2)) + if ((v2 - v2).squaredNorm() < 0.000001) return; const Camera& camera = wxGetApp().plater()->get_camera(); From a4e4a716179ec9d5605da6959f087614fe33655e Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 3 Nov 2022 13:37:38 +0100 Subject: [PATCH 237/250] Measuring: disabled rectangle selection when the Measure Gizmo is active --- src/slic3r/GUI/GLCanvas3D.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 3fa5c24c67..fd4c705c59 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3460,6 +3460,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_gizmos.get_current_type() != GLGizmosManager::FdmSupports && m_gizmos.get_current_type() != GLGizmosManager::Seam && m_gizmos.get_current_type() != GLGizmosManager::Cut && + m_gizmos.get_current_type() != GLGizmosManager::Measure && m_gizmos.get_current_type() != GLGizmosManager::MmuSegmentation) { m_rectangle_selection.start_dragging(m_mouse.position, evt.ShiftDown() ? GLSelectionRectangle::EState::Select : GLSelectionRectangle::EState::Deselect); m_dirty = true; From 4f6217a54c3c7cdb433b3efdb5bb7b1c540e2aa5 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 3 Nov 2022 14:14:35 +0100 Subject: [PATCH 238/250] Fixed typo introduced with 05e82b1fc569f6fe02d29784a87aa7611164d349 --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index d296bb3c45..4255eb7b99 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -905,7 +905,7 @@ void GLGizmoMeasure::render_dimensioning() return; auto point_point = [this, shader](const Vec3d& v1, const Vec3d& v2, float distance) { - if ((v2 - v2).squaredNorm() < 0.000001) + if ((v2 - v1).squaredNorm() < 0.000001 || distance < 0.001f) return; const Camera& camera = wxGetApp().plater()->get_camera(); From 7650be770c37e39d8a9763d8909fb71fabc19665 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 3 Nov 2022 14:24:28 +0100 Subject: [PATCH 239/250] Measuring: tweak to calculation of edge-edge distance --- src/libslic3r/Measure.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index ffff12bab1..ef685b15d8 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -682,16 +682,16 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& if (f2.get_type() == SurfaceFeatureType::Edge) { std::vector distances; -// auto add_point_edge_distance = [&distances](const Vec3d& v, const std::pair& e) { -// const MeasurementResult res = get_measurement(SurfaceFeature(v), SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second)); -// double distance = res.distance_strict->dist; -// Vec3d v2 = res.distance_strict->to; -// -// const Vec3d e1e2 = e.second - e.first; -// const Vec3d e1v2 = v2 - e.first; -// if (e1v2.dot(e1e2) >= 0.0 && e1v2.norm() < e1e2.norm()) -// distances.emplace_back(distance, v, v2); -// }; + auto add_point_edge_distance = [&distances](const Vec3d& v, const std::pair& e) { + const MeasurementResult res = get_measurement(SurfaceFeature(v), SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second)); + double distance = res.distance_strict->dist; + Vec3d v2 = res.distance_strict->to; + + const Vec3d e1e2 = e.second - e.first; + const Vec3d e1v2 = v2 - e.first; + if (e1v2.dot(e1e2) >= 0.0 && e1v2.norm() < e1e2.norm()) + distances.emplace_back(distance, v, v2); + }; std::pair e1 = f1.get_edge(); std::pair e2 = f2.get_edge(); @@ -700,10 +700,10 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& distances.emplace_back((e2.second - e1.first).norm(), e1.first, e2.second); distances.emplace_back((e2.first - e1.second).norm(), e1.second, e2.first); distances.emplace_back((e2.second - e1.second).norm(), e1.second, e2.second); -// add_point_edge_distance(e1.first, e2); -// add_point_edge_distance(e1.second, e2); -// add_point_edge_distance(e2.first, e1); -// add_point_edge_distance(e2.second, e1); + add_point_edge_distance(e1.first, e2); + add_point_edge_distance(e1.second, e2); + add_point_edge_distance(e2.first, e1); + add_point_edge_distance(e2.second, e1); auto it = std::min_element(distances.begin(), distances.end(), [](const DistAndPoints& item1, const DistAndPoints& item2) { return item1.dist < item2.dist; From 2eb363bc6484bd4270d740ff07da7a5c1e443c5a Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 3 Nov 2022 15:03:10 +0100 Subject: [PATCH 240/250] Measuring: modified rendering order of dimensioning items --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 25 ++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 4255eb7b99..858b4e5cea 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1271,13 +1271,6 @@ void GLGizmoMeasure::render_dimensioning() if (m_selected_features.second.feature.has_value()) { const bool has_distance = m_measurement_result.has_distance_data(); - if (has_distance) { - // Render the arrow between the points that the backend passed: - const Measure::DistAndPoints& dap = m_measurement_result.distance_infinite.has_value() - ? *m_measurement_result.distance_infinite - : *m_measurement_result.distance_strict; - point_point(dap.from, dap.to, dap.dist); - } const Measure::SurfaceFeature* f1 = &(*m_selected_features.first.feature); const Measure::SurfaceFeature* f2 = &(*m_selected_features.second.feature); @@ -1290,17 +1283,25 @@ void GLGizmoMeasure::render_dimensioning() std::swap(f1, f2); } - // Where needed, draw also the extension of the edge to where the dist is measured: - if (has_distance && ft1 == Measure::SurfaceFeatureType::Point && ft2 == Measure::SurfaceFeatureType::Edge) - point_edge(*f1, *f2); - - // Now if there is an angle to show, draw the arc: + // If there is an angle to show, draw the arc: if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Edge) arc_edge_edge(*f1, *f2); else if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Plane) arc_edge_plane(*f1, *f2); else if (ft1 == Measure::SurfaceFeatureType::Plane && ft2 == Measure::SurfaceFeatureType::Plane) arc_plane_plane(*f1, *f2); + + if (has_distance){ + // Where needed, draw the extension of the edge to where the dist is measured: + if (ft1 == Measure::SurfaceFeatureType::Point && ft2 == Measure::SurfaceFeatureType::Edge) + point_edge(*f1, *f2); + + // Render the arrow between the points that the backend passed: + const Measure::DistAndPoints& dap = m_measurement_result.distance_infinite.has_value() + ? *m_measurement_result.distance_infinite + : *m_measurement_result.distance_strict; + point_point(dap.from, dap.to, dap.dist); + } } glsafe(::glEnable(GL_DEPTH_TEST)); From 76064fc2ba9bb81c6eef55e97ecec8550978b49e Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 3 Nov 2022 15:24:23 +0100 Subject: [PATCH 241/250] Fix for #9100 - Search feature in the settings is broken - every time moves the cursor at the end of the text --- src/slic3r/GUI/Search.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp index 52e58193c7..88d3e13763 100644 --- a/src/slic3r/GUI/Search.cpp +++ b/src/slic3r/GUI/Search.cpp @@ -594,8 +594,6 @@ void SearchDialog::ProcessSelection(wxDataViewItem selection) void SearchDialog::OnInputText(wxCommandEvent&) { - search_line->SetInsertionPointEnd(); - wxString input_string = search_line->GetValue(); if (input_string == default_string) input_string.Clear(); From 4b9630c23b7c46d3f7cfdb26837779ee690cc46a Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 3 Nov 2022 15:10:47 +0100 Subject: [PATCH 242/250] Measurement: Circles filtering (part 1) --- src/libslic3r/Measure.cpp | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index ef685b15d8..b309fc56d7 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -196,14 +196,17 @@ void MeasuringImpl::update_planes() if (last_border.size() == 1) m_planes[plane_id].borders.pop_back(); + else { + assert(m_planes[plane_id].borders.front() == m_planes[plane_id].borders.back()); + } } } - continue; // There was no failure. PLANE_FAILURE: m_planes[plane_id].borders.clear(); } + } @@ -233,15 +236,16 @@ void MeasuringImpl::extract_features() for (const std::vector& border : plane.borders) { if (border.size() <= 1) continue; + assert(border.front() == border.back()); int start_idx = -1; // First calculate angles at all the vertices. angles.clear(); lengths.clear(); - for (int i=0; i M_PI) @@ -268,10 +272,24 @@ void MeasuringImpl::extract_features() } } else { if (circle) { - // Add the circle and remember indices into borders. - const auto& [center, radius] = get_center_and_radius(border, start_idx, i, trafo); - circles_idxs.emplace_back(start_idx, i); - circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius)); + // Anything made up of less than 4 points shall not be considered a circle. + if (i-start_idx > 3) { + // This may be just a partial circle, maybe a small one generated by two short edges. + // To qualify as a circle, it should cover at least one quadrant. Check this now. + const auto& [center, radius] = get_center_and_radius(border, start_idx, i, trafo); + const Vec3d& p1 = border[start_idx]; + const Vec3d& p2 = border[i]; + const Vec3d& p3 = border[size_t(start_idx+i)/2]; + + // Measure angle between the first and the second radiuses. If smaller than 90 deg, measure angle + // between first radius and one corresponding to the middle of the circle. + if ((p1-center).normalized().dot((p2-center).normalized()) < 0.05 // exactly 90 deg might get rejected + || (p1-center).normalized().dot((p3-center).normalized()) < 0.) { + // Add the circle and remember indices into borders. + circles_idxs.emplace_back(start_idx, i); + circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius)); + } + } circle = false; } } From d07537c1f047a23082ead5bec131757b0e6598e1 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 3 Nov 2022 17:57:09 +0100 Subject: [PATCH 243/250] Measurement: Merge adjacent edges --- src/libslic3r/Measure.cpp | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index b309fc56d7..965fad9f99 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -206,7 +206,6 @@ void MeasuringImpl::update_planes() PLANE_FAILURE: m_planes[plane_id].borders.clear(); } - } @@ -261,6 +260,7 @@ void MeasuringImpl::extract_features() bool circle = false; std::vector circles; std::vector> circles_idxs; + //std::vector angle_and_vert_num_per_circle; for (int i=1; i<(int)angles.size(); ++i) { if (Slic3r::is_approx(lengths[i], lengths[i-1]) && Slic3r::is_approx(angles[i], angles[i-1]) @@ -288,12 +288,24 @@ void MeasuringImpl::extract_features() // Add the circle and remember indices into borders. circles_idxs.emplace_back(start_idx, i); circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius)); + //angle_and_vert_num_per_circle.emplace_back(..., ...); } } circle = false; } } } +/* + // At this point we must merge the first and last circles. The dicrimination of too small + // circles will follow, so we need a complete picture before that. + assert(circles.size() == angle_and_vert_num_per_circle.size()); + for (size_t i=0; i=0; --i) { + const auto& [first_start, first_end] = plane.surface_features[i==0 ? plane.surface_features.size()-1 : i-1].get_edge(); + const auto& [second_start, second_end] = plane.surface_features[i].get_edge(); + + if (Slic3r::is_approx(first_end, second_start) + && Slic3r::is_approx((first_end-first_start).normalized().dot((second_end-second_start).normalized()), 1.)) { + // The edges have the same direction and share a point. Merge them. + plane.surface_features[i==0 ? plane.surface_features.size()-1 : i-1] = SurfaceFeature(SurfaceFeatureType::Edge, first_start, second_end); + plane.surface_features.erase(plane.surface_features.begin() + i); + } + } + + + // FIXME Throw away / do not create edges which are parts of circles or // which lead to circle points (unless they belong to the same plane.) - // FIXME Check and merge first and last circle if needed. - // Now move the circles into the feature list. assert(std::all_of(circles.begin(), circles.end(), [](const SurfaceFeature& f) { return f.get_type() == SurfaceFeatureType::Circle; From 0c88b5712a0ab67c784c9a8ab4814959f049326c Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 4 Nov 2022 09:05:12 +0100 Subject: [PATCH 244/250] Measurement: Circles filtering (part 2) --- src/libslic3r/Measure.cpp | 187 ++++++++++++++++++++++++-------------- 1 file changed, 120 insertions(+), 67 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 965fad9f99..f15be5bea6 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -197,7 +197,7 @@ void MeasuringImpl::update_planes() if (last_border.size() == 1) m_planes[plane_id].borders.pop_back(); else { - assert(m_planes[plane_id].borders.front() == m_planes[plane_id].borders.back()); + assert(last_border.front() == last_border.back()); } } } @@ -215,9 +215,6 @@ void MeasuringImpl::update_planes() void MeasuringImpl::extract_features() { - auto N_to_angle = [](double N) -> double { return 2.*M_PI / N; }; - constexpr double polygon_upper_threshold = N_to_angle(4.5); - constexpr double polygon_lower_threshold = N_to_angle(8.5); std::vector angles; std::vector lengths; @@ -238,6 +235,8 @@ void MeasuringImpl::extract_features() assert(border.front() == border.back()); int start_idx = -1; + std::vector edges; + // First calculate angles at all the vertices. angles.clear(); lengths.clear(); @@ -251,16 +250,19 @@ void MeasuringImpl::extract_features() angle = 2*M_PI - angle; angles.push_back(angle); - lengths.push_back(v2.squaredNorm()); + lengths.push_back(v2.norm()); } assert(border.size() == angles.size()); assert(border.size() == lengths.size()); + // First go around the border and pick what might be circular segments. + // Save pair of indices to where such potential segments start and end. + // Also remember the length of these segments. bool circle = false; std::vector circles; - std::vector> circles_idxs; - //std::vector angle_and_vert_num_per_circle; + std::vector> circles_idxs; + std::vector circles_lengths; for (int i=1; i<(int)angles.size(); ++i) { if (Slic3r::is_approx(lengths[i], lengths[i-1]) && Slic3r::is_approx(angles[i], angles[i-1]) @@ -272,98 +274,149 @@ void MeasuringImpl::extract_features() } } else { if (circle) { - // Anything made up of less than 4 points shall not be considered a circle. - if (i-start_idx > 3) { - // This may be just a partial circle, maybe a small one generated by two short edges. - // To qualify as a circle, it should cover at least one quadrant. Check this now. - const auto& [center, radius] = get_center_and_radius(border, start_idx, i, trafo); - const Vec3d& p1 = border[start_idx]; - const Vec3d& p2 = border[i]; - const Vec3d& p3 = border[size_t(start_idx+i)/2]; - - // Measure angle between the first and the second radiuses. If smaller than 90 deg, measure angle - // between first radius and one corresponding to the middle of the circle. - if ((p1-center).normalized().dot((p2-center).normalized()) < 0.05 // exactly 90 deg might get rejected - || (p1-center).normalized().dot((p3-center).normalized()) < 0.) { - // Add the circle and remember indices into borders. - circles_idxs.emplace_back(start_idx, i); - circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius)); - //angle_and_vert_num_per_circle.emplace_back(..., ...); - } - } + const auto& [center, radius] = get_center_and_radius(border, start_idx, i, trafo); + // Add the circle and remember indices into borders. + circles_idxs.emplace_back(start_idx, i); + circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius)); + circles_lengths.emplace_back(std::accumulate(lengths.begin() + start_idx + 1, lengths.begin() + i + 1, 0.)); circle = false; } } } -/* - // At this point we must merge the first and last circles. The dicrimination of too small - // circles will follow, so we need a complete picture before that. - assert(circles.size() == angle_and_vert_num_per_circle.size()); - for (size_t i=0; i 1 + && circles_idxs.back().second == angles.size()-1 + && circles_idxs.front().first == 0) { + // Possibly the same circle. Check that the angle and length criterion holds along the combined segment. + bool same = true; + double last_len = -1.; + double last_angle = 0.; + for (int i=circles_idxs.back().first + 1; i != circles_idxs.front().second; ++i) { + if (i == angles.size()) + i = 1; + if (last_len == -1.) { + last_len = lengths[i]; + last_angle = angles[i]; + } else { + if (! Slic3r::is_approx(lengths[i], last_len) || ! Slic3r::is_approx(angles[i], last_angle)) { + same = false; + break; + } + } + } + if (same) { + // This seems to really be the same circle. Better apply ransac again. The parts can be small and inexact. + std::vector points(border.begin() + circles_idxs.back().first, border.end()); + points.insert(points.end(), border.begin(), border.begin() + circles_idxs.front().second+1); + auto [c, radius] = get_center_and_radius(points, 0, points.size()-1, trafo); + // Now replace the first circle with the combined one, remove the last circle. + // First index of the first circle is saved negative - we are going to pick edges + // from the border later, we will need to know where the merged in segment was. + // The sign simplifies the algorithm that picks the remaining edges - see below. + circles.front() = SurfaceFeature(SurfaceFeatureType::Circle, c, plane.normal, std::nullopt, radius); + circles_idxs.front().first = - circles_idxs.back().first; + circles_lengths.front() += circles_lengths.back(); + circles.pop_back(); + circles_idxs.pop_back(); + circles_lengths.pop_back(); + } + } - // Some of the "circles" may actually be polygons. We want them detected as - // edges, but also to remember the center and save it into those edges. - // We will add all such edges manually and delete the detected circles, - // leaving it in circles_idxs so they are not picked again: + // Now throw away all circles that subtend less than 90 deg. + assert(circles.size() == circles_lengths.size()); + for (int i=0; i(circles[i].get_circle()); + if (circles_lengths[i] / r < 0.9*M_PI/2.) { + circles_lengths.erase(circles_lengths.begin() + i); + circles.erase(circles.begin() + i); + circles_idxs.erase(circles_idxs.begin() + i); + --i; + } + } + circles_lengths.clear(); // no longer needed, make it obvious + + // Some of the "circles" may actually be polygons (5-8 vertices). We want them + // detected as edges, but also to remember the center and save it into those edges. + // We will add all such edges manually and delete the detected circles, leaving it + // in circles_idxs so they are not picked again. assert(circles.size() == circles_idxs.size()); for (int i=circles.size()-1; i>=0; --i) { - assert(circles_idxs[i].first + 1 < angles.size() - 1); // Check that this is internal point of the circle, not the first, not the last. - double angle = angles[circles_idxs[i].first + 1]; - if (angle > polygon_lower_threshold) { - if (angle < polygon_upper_threshold) { - const Vec3d center = std::get<0>(circles[i].get_circle()); - for (int j=(int)circles_idxs[i].first + 1; j<=(int)circles_idxs[i].second; ++j) - plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, - border[j - 1], border[j], std::make_optional(center))); - } else { - // This will be handled just like a regular edge. - circles_idxs.erase(circles_idxs.begin() + i); + if (circles_idxs[i].first == 0 && circles_idxs[i].second == border.size()-1) { + int N = circles_idxs[i].second - circles_idxs[i].first; + if (N <= 8) { + if (N >= 5) { // polygon = 5,6,7,8 vertices + const Vec3d center = std::get<0>(circles[i].get_circle()); + for (int j=(int)circles_idxs[i].first + 1; j<=(int)circles_idxs[i].second; ++j) + edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, + border[j - 1], border[j], std::make_optional(center))); + } else { + // This will be handled just like a regular edge (squares, triangles). + circles_idxs.erase(circles_idxs.begin() + i); + } + circles.erase(circles.begin() + i); } - circles.erase(circles.begin() + i); } } - // We have the circles. Now go around again and pick edges. - int cidx = 0; // index of next circle in the way + // Anything under 5 vertices shall not be considered a circle. + assert(circles_idxs.size() == circles.size()); + for (int i=0; i= 0 + ? end - start + (start == 0 && end == border.size()-1 ? 0 : 1) // last point is the same as first + : end + (border.size() + start); + if (N < 5) { + circles.erase(circles.begin() + i); + circles_idxs.erase(circles_idxs.begin() + i); + --i; + } + } + + + // We have the circles. Now go around again and pick edges, while jumping over circles. + // If the first index of the first circle is negative, it means that it was merged + // with a segment that was originally at the back and is no longer there. Ressurect + // its pair of indices so that edges are not picked again. + if (! circles_idxs.empty() && circles_idxs.front().first < 0) + circles_idxs.emplace_back(-circles_idxs.front().first, int(border.size())); + int cidx = 0; // index of next circle to jump over for (int i=1; i (int)circles_idxs[cidx].first) i = circles_idxs[cidx++].second; else - plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[i - 1], border[i])); + edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[i - 1], border[i])); } // Merge adjacent edges where needed. - assert(std::all_of(plane.surface_features.begin(), plane.surface_features.end(), + assert(std::all_of(edges.begin(), edges.end(), [](const SurfaceFeature& f) { return f.get_type() == SurfaceFeatureType::Edge; })); - for (int i=plane.surface_features.size()-1; i>=0; --i) { - const auto& [first_start, first_end] = plane.surface_features[i==0 ? plane.surface_features.size()-1 : i-1].get_edge(); - const auto& [second_start, second_end] = plane.surface_features[i].get_edge(); + for (int i=edges.size()-1; i>=0; --i) { + const auto& [first_start, first_end] = edges[i==0 ? edges.size()-1 : i-1].get_edge(); + const auto& [second_start, second_end] = edges[i].get_edge(); if (Slic3r::is_approx(first_end, second_start) && Slic3r::is_approx((first_end-first_start).normalized().dot((second_end-second_start).normalized()), 1.)) { // The edges have the same direction and share a point. Merge them. - plane.surface_features[i==0 ? plane.surface_features.size()-1 : i-1] = SurfaceFeature(SurfaceFeatureType::Edge, first_start, second_end); - plane.surface_features.erase(plane.surface_features.begin() + i); + edges[i==0 ? edges.size()-1 : i-1] = SurfaceFeature(SurfaceFeatureType::Edge, first_start, second_end); + edges.erase(edges.begin() + i); } } - - - // FIXME Throw away / do not create edges which are parts of circles or - // which lead to circle points (unless they belong to the same plane.) - - // Now move the circles into the feature list. + // Now move the circles and edges into the feature list for the plane. assert(std::all_of(circles.begin(), circles.end(), [](const SurfaceFeature& f) { return f.get_type() == SurfaceFeatureType::Circle; })); + assert(std::all_of(edges.begin(), edges.end(), [](const SurfaceFeature& f) { + return f.get_type() == SurfaceFeatureType::Edge; + })); plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(circles.begin()), - std::make_move_iterator(circles.end())); + std::make_move_iterator(circles.end())); + plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(edges.begin()), + std::make_move_iterator(edges.end())); } // The last surface feature is the plane itself. From a0a0b0d25399b4b037e736ae98ec83dfc8969c02 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 7 Nov 2022 09:58:25 +0100 Subject: [PATCH 245/250] Measuring - Keep showing dimensioning after scaling --- src/libslic3r/Measure.hpp | 11 +++++++++++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 21 ++++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 + 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index d1a0e3866c..6d6dca14fe 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -150,6 +150,17 @@ struct MeasurementResult { bool has_any_data() const { return angle.has_value() || distance_infinite.has_value() || distance_strict.has_value() || distance_xyz.has_value(); } + + void transform(const Transform3d& trafo) { + if (angle.has_value()) + angle->transform(trafo); + if (distance_infinite.has_value()) + distance_infinite->transform(trafo); + if (distance_strict.has_value()) + distance_strict->transform(trafo); + if (distance_xyz.has_value()) + distance_xyz = trafo * *distance_xyz; + } }; // Returns distance/angle between two SurfaceFeatures. diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 858b4e5cea..04e4957d6d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -303,14 +303,7 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) if (m_selected_features != selected_features_old && m_selected_features.second.feature.has_value()) { m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); // transform to world coordinates - if (m_measurement_result.angle.has_value()) - m_measurement_result.angle->transform(m_volume_matrix); - if (m_measurement_result.distance_infinite.has_value()) - m_measurement_result.distance_infinite->transform(m_volume_matrix); - if (m_measurement_result.distance_strict.has_value()) - m_measurement_result.distance_strict->transform(m_volume_matrix); - if (m_measurement_result.distance_xyz.has_value()) - m_measurement_result.distance_xyz = TransformHelper::model_to_world(*m_measurement_result.distance_xyz, m_volume_matrix); + m_measurement_result.transform(m_volume_matrix); } return true; @@ -357,7 +350,14 @@ void GLGizmoMeasure::data_changed() m_last_inv_zoom = 0.0f; m_last_plane_idx = -1; - m_selected_features.reset(); + if (m_pending_scale) { + m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); + // transform to world coordinates + m_measurement_result.transform(m_volume_matrix); + m_pending_scale = false; + } + else + m_selected_features.reset(); m_selection_raycasters.clear(); m_editing_distance = false; m_is_editing_distance_first_frame = true; @@ -1007,6 +1007,9 @@ void GLGizmoMeasure::render_dimensioning() selection.scale(ratio * Vec3d::Ones(), type); wxGetApp().plater()->canvas3D()->do_scale(""); // avoid storing another snapshot wxGetApp().obj_manipul()->set_dirty(); + + // update measure on next call to data_changed() + m_pending_scale = true; }; auto action_exit = [this]() { m_editing_distance = false; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 7d20ca26ae..4426457ff8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -116,6 +116,7 @@ class GLGizmoMeasure : public GLGizmoBase KeyAutoRepeatFilter m_ctrl_kar_filter; SelectedFeatures m_selected_features; + bool m_pending_scale{ false }; bool m_editing_distance{ false }; bool m_is_editing_distance_first_frame{ true }; From 411535ecdf6d5e91a1f074c1b47755fb332975dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Tue, 18 Oct 2022 01:23:47 +0200 Subject: [PATCH 246/250] Fixed undefined behavior (dereferencing std::unique_ptr pointing to nullptr) in the G-Code processing pipeline. --- src/libslic3r/GCode.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index e2bd6ef653..798f7759dd 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1502,27 +1502,27 @@ void GCode::process_layers( } }); const auto spiral_vase = tbb::make_filter(slic3r_tbb_filtermode::serial_in_order, - [&spiral_vase = *this->m_spiral_vase](LayerResult in) -> LayerResult { + [spiral_vase = this->m_spiral_vase.get()](LayerResult in) -> LayerResult { if (in.nop_layer_result) return in; - spiral_vase.enable(in.spiral_vase_enable); - return { spiral_vase.process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush}; + spiral_vase->enable(in.spiral_vase_enable); + return { spiral_vase->process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush}; }); const auto pressure_equalizer = tbb::make_filter(slic3r_tbb_filtermode::serial_in_order, - [&pressure_equalizer = *this->m_pressure_equalizer](LayerResult in) -> LayerResult { - return pressure_equalizer.process_layer(std::move(in)); + [pressure_equalizer = this->m_pressure_equalizer.get()](LayerResult in) -> LayerResult { + return pressure_equalizer->process_layer(std::move(in)); }); const auto cooling = tbb::make_filter(slic3r_tbb_filtermode::serial_in_order, - [&cooling_buffer = *this->m_cooling_buffer](LayerResult in) -> std::string { + [cooling_buffer = this->m_cooling_buffer.get()](LayerResult in) -> std::string { if (in.nop_layer_result) return in.gcode; - return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush); + return cooling_buffer->process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush); }); const auto find_replace = tbb::make_filter(slic3r_tbb_filtermode::serial_in_order, - [&self = *this->m_find_replace](std::string s) -> std::string { - return self.process_layer(std::move(s)); + [find_replace = this->m_find_replace.get()](std::string s) -> std::string { + return find_replace->process_layer(std::move(s)); }); const auto output = tbb::make_filter(slic3r_tbb_filtermode::serial_in_order, [&output_stream](std::string s) { output_stream.write(s); } @@ -1584,25 +1584,25 @@ void GCode::process_layers( } }); const auto spiral_vase = tbb::make_filter(slic3r_tbb_filtermode::serial_in_order, - [&spiral_vase = *this->m_spiral_vase](LayerResult in)->LayerResult { + [spiral_vase = this->m_spiral_vase.get()](LayerResult in)->LayerResult { if (in.nop_layer_result) return in; - spiral_vase.enable(in.spiral_vase_enable); - return { spiral_vase.process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush }; + spiral_vase->enable(in.spiral_vase_enable); + return { spiral_vase->process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush }; }); const auto pressure_equalizer = tbb::make_filter(slic3r_tbb_filtermode::serial_in_order, - [&pressure_equalizer = *this->m_pressure_equalizer](LayerResult in) -> LayerResult { - return pressure_equalizer.process_layer(std::move(in)); + [pressure_equalizer = this->m_pressure_equalizer.get()](LayerResult in) -> LayerResult { + return pressure_equalizer->process_layer(std::move(in)); }); const auto cooling = tbb::make_filter(slic3r_tbb_filtermode::serial_in_order, - [&cooling_buffer = *this->m_cooling_buffer](LayerResult in)->std::string { + [cooling_buffer = this->m_cooling_buffer.get()](LayerResult in)->std::string { if (in.nop_layer_result) return in.gcode; - return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush); + return cooling_buffer->process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush); }); const auto find_replace = tbb::make_filter(slic3r_tbb_filtermode::serial_in_order, - [&self = *this->m_find_replace](std::string s) -> std::string { - return self.process_layer(std::move(s)); + [find_replace = this->m_find_replace.get()](std::string s) -> std::string { + return find_replace->process_layer(std::move(s)); }); const auto output = tbb::make_filter(slic3r_tbb_filtermode::serial_in_order, [&output_stream](std::string s) { output_stream.write(s); } From 8abb8a654630254d5056cf86a369936db6066c25 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 7 Nov 2022 12:52:10 +0100 Subject: [PATCH 247/250] #8252 - GCodeViewer - Fixed crash when importing invalid gcode --- src/slic3r/GUI/3DBed.cpp | 5 ++++- src/slic3r/GUI/MainFrame.cpp | 2 +- src/slic3r/GUI/Plater.cpp | 24 +++++++++++++++++++++++- src/slic3r/GUI/Plater.hpp | 1 + 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 4319a28cf1..7572d4fc46 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -223,7 +223,10 @@ bool Bed3D::set_shape(const Pointfs& bed_shape, const double max_print_height, c #if ENABLE_LEGACY_OPENGL_REMOVAL m_contour = ExPolygon(Polygon::new_scale(bed_shape)); - m_polygon = offset(m_contour.contour, (float)m_contour.contour.bounding_box().radius() * 1.7f, jtRound, scale_(0.5)).front(); + const BoundingBox bbox = m_contour.contour.bounding_box(); + if (!bbox.defined) + throw RuntimeError(std::string("Invalid bed shape")); + m_polygon = offset(m_contour.contour, (float)bbox.radius() * 1.7f, jtRound, scale_(0.5)).front(); m_triangles.reset(); m_gridlines.reset(); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 96959f33b0..5764b283c6 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -538,7 +538,7 @@ void MainFrame::update_layout() case ESettingsLayout::GCodeViewer: { m_main_sizer->Add(m_plater, 1, wxEXPAND); - m_plater->set_bed_shape({ { 0.0, 0.0 }, { 200.0, 0.0 }, { 200.0, 200.0 }, { 0.0, 200.0 } }, 0.0, {}, {}, true); + m_plater->set_default_bed_shape(); m_plater->get_collapse_toolbar().set_enabled(false); m_plater->collapse_sidebar(true); m_plater->Show(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index dd47325b5f..ccaf28ec0f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -5477,10 +5477,27 @@ void Plater::load_gcode(const wxString& filename) p->gcode_result = std::move(processor.extract_result()); // show results - p->preview->reload_print(false); + try + { + p->preview->reload_print(false); + } + catch (const std::exception&) + { + wxEndBusyCursor(); + p->gcode_result.reset(); + reset_gcode_toolpaths(); + set_default_bed_shape(); + p->preview->reload_print(false); + p->get_current_canvas3D()->render(); + MessageDialog(this, _L("The selected file") + ":\n" + filename + "\n" + _L("does not contain valid gcode."), + wxString(GCODEVIEWER_APP_NAME) + " - " + _L("Error while loading .gcode file"), wxOK | wxICON_WARNING | wxCENTRE).ShowModal(); + set_project_filename(wxEmptyString); + return; + } p->preview->get_canvas3d()->zoom_to_gcode(); if (p->preview->get_canvas3d()->get_gcode_layers_zs().empty()) { + wxEndBusyCursor(); //wxMessageDialog(this, _L("The selected file") + ":\n" + filename + "\n" + _L("does not contain valid gcode."), MessageDialog(this, _L("The selected file") + ":\n" + filename + "\n" + _L("does not contain valid gcode."), wxString(GCODEVIEWER_APP_NAME) + " - " + _L("Error while loading .gcode file"), wxOK | wxICON_WARNING | wxCENTRE).ShowModal(); @@ -6646,6 +6663,11 @@ void Plater::set_bed_shape(const Pointfs& shape, const double max_print_height, p->set_bed_shape(shape, max_print_height, custom_texture, custom_model, force_as_custom); } +void Plater::set_default_bed_shape() const +{ + set_bed_shape({ { 0.0, 0.0 }, { 200.0, 0.0 }, { 200.0, 200.0 }, { 0.0, 200.0 } }, 0.0, {}, {}, true); +} + void Plater::force_filament_colors_update() { bool update_scheduled = false; diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 9dc9f63168..ff750d561e 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -399,6 +399,7 @@ public: void set_bed_shape() const; void set_bed_shape(const Pointfs& shape, const double max_print_height, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom = false) const; + void set_default_bed_shape() const; NotificationManager * get_notification_manager(); const NotificationManager * get_notification_manager() const; From 380c746871803d412a07a5f99c33b0fc5694111b Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 7 Nov 2022 13:47:07 +0100 Subject: [PATCH 248/250] Linux specific issue: Prevent ObjectList's events, when updating the volumes in object. On Linux DeleteVolumeChildren() called the update selection event, what caused the unexpected one by one selection of all volumes in object. --- src/slic3r/GUI/GUI_ObjectList.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index d6bbbeba11..abb22392b3 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -2882,6 +2882,9 @@ static bool can_add_volumes_to_object(const ModelObject* object) wxDataViewItemArray ObjectList::add_volumes_to_object_in_list(size_t obj_idx, std::function add_to_selection/* = nullptr*/) { + const bool is_prevent_list_events = m_prevent_list_events; + m_prevent_list_events = true; + wxDataViewItem object_item = m_objects_model->GetItemById(int(obj_idx)); m_objects_model->DeleteVolumeChildren(object_item); @@ -2909,6 +2912,7 @@ wxDataViewItemArray ObjectList::add_volumes_to_object_in_list(size_t obj_idx, st Expand(object_item); } + m_prevent_list_events = is_prevent_list_events; return items; } From 236f97aded731d5100f27b70d8ce42dd2d128915 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 7 Nov 2022 14:15:36 +0100 Subject: [PATCH 249/250] Gizmo Measure - Fixed loss of selection when panning the view --- src/slic3r/GUI/GLCanvas3D.cpp | 5 +++-- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index fd4c705c59..a5698f67b8 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3696,7 +3696,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // if right clicking on volume, propagate event through callback (shows context menu) int volume_idx = get_first_hover_volume_idx(); if (!m_volumes.volumes[volume_idx]->is_wipe_tower // no context menu for the wipe tower - && m_gizmos.get_current_type() != GLGizmosManager::SlaSupports) // disable context menu when the gizmo is open + && (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports && m_gizmos.get_current_type() != GLGizmosManager::Measure)) // disable context menu when the gizmo is open { // forces the selection of the volume /* m_selection.add(volume_idx); // #et_FIXME_if_needed @@ -3720,7 +3720,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (!m_mouse.dragging) { // do not post the event if the user is panning the scene // or if right click was done over the wipe tower - const bool post_right_click_event = m_hover_volume_idxs.empty() || !m_volumes.volumes[get_first_hover_volume_idx()]->is_wipe_tower; + const bool post_right_click_event = (m_hover_volume_idxs.empty() || !m_volumes.volumes[get_first_hover_volume_idx()]->is_wipe_tower) && + m_gizmos.get_current_type() != GLGizmosManager::Measure; if (post_right_click_event) post_event(RBtnEvent(EVT_GLCANVAS_RIGHT_CLICK, { logical_pos, m_hover_volume_idxs.empty() })); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 04e4957d6d..3fa8d8d6f3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -306,6 +306,8 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) m_measurement_result.transform(m_volume_matrix); } + m_imgui->set_requires_extra_frame(); + return true; } @@ -327,7 +329,7 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) else if (mouse_event.RightDown() && mouse_event.CmdDown()) { m_selected_features.reset(); m_selection_raycasters.clear(); - m_imgui->set_requires_extra_frame(); + m_parent.request_extra_frame(); } else if (mouse_event.Leaving()) m_mouse_left_down = false; From 5df27130107b1d70fee09664372afdd2d84e883e Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 7 Nov 2022 14:46:21 +0100 Subject: [PATCH 250/250] Measuring - Fixed transformation of distance_xyz --- src/libslic3r/Measure.cpp | 4 ++-- src/libslic3r/Measure.hpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index f15be5bea6..fc27f0383e 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -723,8 +723,8 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& if (f2.get_type() == SurfaceFeatureType::Point) { Vec3d diff = (f2.get_point() - f1.get_point()); result.distance_strict = std::make_optional(DistAndPoints{diff.norm(), f1.get_point(), f2.get_point()}); - result.distance_xyz = diff; - + result.distance_xyz = diff.cwiseAbs(); + /////////////////////////////////////////////////////////////////////////// } else if (f2.get_type() == SurfaceFeatureType::Edge) { const auto [s,e] = f2.get_edge(); diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 6d6dca14fe..ede8c634ee 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -156,10 +156,10 @@ struct MeasurementResult { angle->transform(trafo); if (distance_infinite.has_value()) distance_infinite->transform(trafo); - if (distance_strict.has_value()) + if (distance_strict.has_value()) { distance_strict->transform(trafo); - if (distance_xyz.has_value()) - distance_xyz = trafo * *distance_xyz; + distance_xyz = (distance_strict->to - distance_strict->from).cwiseAbs(); + } } };