diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index d5cb9c24b..a8ee3d326 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 bbc7d9e1e..1360b47ff 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 043adba97..a8b257a93 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 2781d2b35..f74b82fa4 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);