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; }