diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index e59e3c04d..8c7254f85 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 87bed1cf1..fe0b1687a 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 7eaf7b2e0..07c920120 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);