Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
Slic3r::Measure Namespace Reference

Classes

struct  AngleAndEdges
 
struct  DistAndPoints
 
struct  MeasurementResult
 
class  Measuring
 
class  MeasuringImpl
 
class  Polynomial1
 
class  RootsPolynomial
 
class  SurfaceFeature
 

Enumerations

enum class  SurfaceFeatureType : int {
  Undef = 0 , Point = 1 << 0 , Edge = 1 << 1 , Circle = 1 << 2 ,
  Plane = 1 << 3
}
 

Functions

static std::tuple< Vec3d, double, double > get_center_and_radius (const std::vector< Vec3d > &points, const Transform3d &trafo, const Transform3d &trafo_inv)
 
static std::array< Vec3d, 3 > orthonormal_basis (const Vec3d &v)
 
static AngleAndEdges angle_edge_edge (const std::pair< Vec3d, Vec3d > &e1, const std::pair< Vec3d, Vec3d > &e2)
 
static AngleAndEdges angle_edge_plane (const std::pair< Vec3d, Vec3d > &e, const std::tuple< int, Vec3d, Vec3d > &p)
 
static AngleAndEdges angle_plane_plane (const std::tuple< int, Vec3d, Vec3d > &p1, const std::tuple< int, Vec3d, Vec3d > &p2)
 
MeasurementResult get_measurement (const SurfaceFeature &a, const SurfaceFeature &b, const Measuring *measuring)
 
Vec3d edge_direction (const Vec3d &from, const Vec3d &to)
 
Vec3d edge_direction (const std::pair< Vec3d, Vec3d > &e)
 
Vec3d edge_direction (const SurfaceFeature &edge)
 
Vec3d plane_normal (const SurfaceFeature &plane)
 
bool are_parallel (const Vec3d &v1, const Vec3d &v2)
 
bool are_perpendicular (const Vec3d &v1, const Vec3d &v2)
 
bool are_parallel (const std::pair< Vec3d, Vec3d > &e1, const std::pair< Vec3d, Vec3d > &e2)
 
bool are_parallel (const SurfaceFeature &f1, const SurfaceFeature &f2)
 
bool are_perpendicular (const SurfaceFeature &f1, const SurfaceFeature &f2)
 
Polynomial1 operator* (const Polynomial1 &p0, const Polynomial1 &p1)
 
Polynomial1 operator+ (const Polynomial1 &p0, const Polynomial1 &p1)
 
Polynomial1 operator- (const Polynomial1 &p0, const Polynomial1 &p1)
 
Polynomial1 operator* (double scalar, const Polynomial1 &p)
 
Vec3d get_orthogonal (const Vec3d &v, bool unitLength)
 

Variables

constexpr double feature_hover_limit = 0.5
 

Enumeration Type Documentation

◆ SurfaceFeatureType

enum class Slic3r::Measure::SurfaceFeatureType : int
strong
Enumerator
Undef 
Point 
Edge 
Circle 
Plane 
21 : int {
22 Undef = 0,
23 Point = 1 << 0,
24 Edge = 1 << 1,
25 Circle = 1 << 2,
26 Plane = 1 << 3
27};
Definition Point.hpp:158
@ Undef
Definition CustomGCode.hpp:49

Function Documentation

◆ angle_edge_edge()

static AngleAndEdges Slic3r::Measure::angle_edge_edge ( const std::pair< Vec3d, Vec3d > &  e1,
const std::pair< Vec3d, Vec3d > &  e2 
)
static
637{
638 if (are_parallel(e1, e2))
639 return AngleAndEdges::Dummy;
640
641 Vec3d e1_unit = edge_direction(e1.first, e1.second);
642 Vec3d e2_unit = edge_direction(e2.first, e2.second);
643
644 // project edges on the plane defined by them
645 Vec3d normal = e1_unit.cross(e2_unit).normalized();
646 const Eigen::Hyperplane<double, 3> plane(normal, e1.first);
647 Vec3d e11_proj = plane.projection(e1.first);
648 Vec3d e12_proj = plane.projection(e1.second);
649 Vec3d e21_proj = plane.projection(e2.first);
650 Vec3d e22_proj = plane.projection(e2.second);
651
652 const bool coplanar = (e2.first - e21_proj).norm() < EPSILON && (e2.second - e22_proj).norm() < EPSILON;
653
654 // rotate the plane to become the XY plane
655 auto qp = Eigen::Quaternion<double>::FromTwoVectors(normal, Vec3d::UnitZ());
656 auto qp_inverse = qp.inverse();
657 const Vec3d e11_rot = qp * e11_proj;
658 const Vec3d e12_rot = qp * e12_proj;
659 const Vec3d e21_rot = qp * e21_proj;
660 const Vec3d e22_rot = qp * e22_proj;
661
662 // discard Z
663 const Vec2d e11_rot_2d = Vec2d(e11_rot.x(), e11_rot.y());
664 const Vec2d e12_rot_2d = Vec2d(e12_rot.x(), e12_rot.y());
665 const Vec2d e21_rot_2d = Vec2d(e21_rot.x(), e21_rot.y());
666 const Vec2d e22_rot_2d = Vec2d(e22_rot.x(), e22_rot.y());
667
668 // find intersection (arc center) of edges in XY plane
669 const Eigen::Hyperplane<double, 2> e1_rot_2d_line = Eigen::Hyperplane<double, 2>::Through(e11_rot_2d, e12_rot_2d);
670 const Eigen::Hyperplane<double, 2> e2_rot_2d_line = Eigen::Hyperplane<double, 2>::Through(e21_rot_2d, e22_rot_2d);
671 const Vec2d center_rot_2d = e1_rot_2d_line.intersection(e2_rot_2d_line);
672
673 // arc center in original coordinate
674 const Vec3d center = qp_inverse * Vec3d(center_rot_2d.x(), center_rot_2d.y(), e11_rot.z());
675
676 // ensure the edges are pointing away from the center
677 std::pair<Vec3d, Vec3d> out_e1 = e1;
678 std::pair<Vec3d, Vec3d> out_e2 = e2;
679 if ((center_rot_2d - e11_rot_2d).squaredNorm() > (center_rot_2d - e12_rot_2d).squaredNorm()) {
680 std::swap(e11_proj, e12_proj);
681 std::swap(out_e1.first, out_e1.second);
682 e1_unit = -e1_unit;
683 }
684 if ((center_rot_2d - e21_rot_2d).squaredNorm() > (center_rot_2d - e22_rot_2d).squaredNorm()) {
685 std::swap(e21_proj, e22_proj);
686 std::swap(out_e2.first, out_e2.second);
687 e2_unit = -e2_unit;
688 }
689
690 // arc angle
691 const double angle = std::acos(std::clamp(e1_unit.dot(e2_unit), -1.0, 1.0));
692 // arc radius
693 const Vec3d e1_proj_mid = 0.5 * (e11_proj + e12_proj);
694 const Vec3d e2_proj_mid = 0.5 * (e21_proj + e22_proj);
695 const double radius = std::min((center - e1_proj_mid).norm(), (center - e2_proj_mid).norm());
696
697 return { angle, center, out_e1, out_e2, radius, coplanar };
698}
static EIGEN_DEVICE_FUNC Quaternion FromTwoVectors(const MatrixBase< Derived1 > &a, const MatrixBase< Derived2 > &b)
EIGEN_DEVICE_FUNC VectorType intersection(const Hyperplane &other) const
Definition Hyperplane.h:189
static EIGEN_DEVICE_FUNC Hyperplane Through(const VectorType &p0, const VectorType &p1)
Definition Hyperplane.h:88
A hyperplane.
Definition Hyperplane.h:35
static constexpr double EPSILON
Definition libslic3r.h:51
bool are_parallel(const Vec3d &v1, const Vec3d &v2)
Definition Measure.hpp:169
Vec3d edge_direction(const Vec3d &from, const Vec3d &to)
Definition Measure.hpp:157

References Slic3r::angle(), are_parallel(), Slic3r::Measure::AngleAndEdges::Dummy, edge_direction(), EPSILON, Eigen::Quaternion< _Scalar, _Options >::FromTwoVectors(), Eigen::Hyperplane< _Scalar, _AmbientDim, _Options >::intersection(), Eigen::Hyperplane< _Scalar, _AmbientDim, _Options >::projection(), and Eigen::Hyperplane< _Scalar, _AmbientDim, _Options >::Through().

Referenced by angle_edge_plane(), angle_plane_plane(), and get_measurement().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ angle_edge_plane()

static AngleAndEdges Slic3r::Measure::angle_edge_plane ( const std::pair< Vec3d, Vec3d > &  e,
const std::tuple< int, Vec3d, Vec3d > &  p 
)
static
701{
702 const auto& [idx, normal, origin] = p;
703 Vec3d e1e2_unit = edge_direction(e);
704 if (are_perpendicular(e1e2_unit, normal))
705 return AngleAndEdges::Dummy;
706
707 // ensure the edge is pointing away from the intersection
708 // 1st calculate instersection between edge and plane
709 const Eigen::Hyperplane<double, 3> plane(normal, origin);
711 const Vec3d inters = line.intersectionPoint(plane);
712
713 // then verify edge direction and revert it, if needed
714 Vec3d e1 = e.first;
715 Vec3d e2 = e.second;
716 if ((e1 - inters).squaredNorm() > (e2 - inters).squaredNorm()) {
717 std::swap(e1, e2);
718 e1e2_unit = -e1e2_unit;
719 }
720
721 if (are_parallel(e1e2_unit, normal)) {
722 const std::array<Vec3d, 3> basis = orthonormal_basis(e1e2_unit);
723 const double radius = (0.5 * (e1 + e2) - inters).norm();
724 const Vec3d edge_on_plane_dir = (basis[1].dot(origin - inters) >= 0.0) ? basis[1] : -basis[1];
725 std::pair<Vec3d, Vec3d> edge_on_plane = std::make_pair(inters, inters + radius * edge_on_plane_dir);
726 if (!inters.isApprox(e1)) {
727 edge_on_plane.first += radius * edge_on_plane_dir;
728 edge_on_plane.second += radius * edge_on_plane_dir;
729 }
730 return AngleAndEdges(0.5 * double(PI), inters, std::make_pair(e1, e2), edge_on_plane, radius, inters.isApprox(e1));
731 }
732
733 const Vec3d e1e2 = e2 - e1;
734 const double e1e2_len = e1e2.norm();
735
736 // calculate 2nd edge (on the plane)
737 const Vec3d temp = normal.cross(e1e2);
738 const Vec3d edge_on_plane_unit = normal.cross(temp).normalized();
739 std::pair<Vec3d, Vec3d> edge_on_plane = { origin, origin + e1e2_len * edge_on_plane_unit };
740
741 // ensure the 2nd edge is pointing in the correct direction
742 const Vec3d test_edge = (edge_on_plane.second - edge_on_plane.first).cross(e1e2);
743 if (test_edge.dot(temp) < 0.0)
744 edge_on_plane = { origin, origin - e1e2_len * edge_on_plane_unit };
745
746 AngleAndEdges ret = angle_edge_edge({ e1, e2 }, edge_on_plane);
747 ret.radius = (inters - 0.5 * (e1 + e2)).norm();
748 return ret;
749}
static EIGEN_DEVICE_FUNC ParametrizedLine Through(const VectorType &p0, const VectorType &p1)
Definition ParametrizedLine.h:65
EIGEN_DEVICE_FUNC VectorType intersectionPoint(const Hyperplane< _Scalar, _AmbientDim, OtherOptions > &hyperplane) const
Definition ParametrizedLine.h:188
A parametrized line.
Definition ParametrizedLine.h:31
static constexpr double PI
Definition libslic3r.h:58
static AngleAndEdges angle_edge_edge(const std::pair< Vec3d, Vec3d > &e1, const std::pair< Vec3d, Vec3d > &e2)
Definition Measure.cpp:636
bool are_perpendicular(const Vec3d &v1, const Vec3d &v2)
Definition Measure.hpp:170
Vec< 3, T > normal(const std::array< Vec< 3, T >, 3 > &tri)
Definition Rotfinder.cpp:43
Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vec3d
Definition Point.hpp:52
IGL_INLINE void cross(const double *a, const double *b, double *out)
Definition cross.cpp:11
double radius
Definition Measure.hpp:133

References angle_edge_edge(), are_parallel(), are_perpendicular(), Slic3r::cross(), Slic3r::Measure::AngleAndEdges::Dummy, edge_direction(), Eigen::ParametrizedLine< _Scalar, _AmbientDim, _Options >::intersectionPoint(), orthonormal_basis(), PI, Slic3r::Measure::AngleAndEdges::radius, and Eigen::ParametrizedLine< _Scalar, _AmbientDim, _Options >::Through().

Referenced by get_measurement().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ angle_plane_plane()

static AngleAndEdges Slic3r::Measure::angle_plane_plane ( const std::tuple< int, Vec3d, Vec3d > &  p1,
const std::tuple< int, Vec3d, Vec3d > &  p2 
)
static
752{
753 const auto& [idx1, normal1, origin1] = p1;
754 const auto& [idx2, normal2, origin2] = p2;
755
756 // are planes parallel ?
757 if (are_parallel(normal1, normal2))
758 return AngleAndEdges::Dummy;
759
760 auto intersection_plane_plane = [](const Vec3d& n1, const Vec3d& o1, const Vec3d& n2, const Vec3d& o2) {
761 Eigen::MatrixXd m(2, 3);
762 m << n1.x(), n1.y(), n1.z(), n2.x(), n2.y(), n2.z();
763 Eigen::VectorXd b(2);
764 b << o1.dot(n1), o2.dot(n2);
765 Eigen::VectorXd x = m.colPivHouseholderQr().solve(b);
766 return std::make_pair(n1.cross(n2).normalized(), Vec3d(x(0), x(1), x(2)));
767 };
768
769 // Calculate intersection line between planes
770 const auto [intersection_line_direction, intersection_line_origin] = intersection_plane_plane(normal1, origin1, normal2, origin2);
771
772 // Project planes' origin on intersection line
773 const Eigen::ParametrizedLine<double, 3> intersection_line = Eigen::ParametrizedLine<double, 3>(intersection_line_origin, intersection_line_direction);
774 const Vec3d origin1_proj = intersection_line.projection(origin1);
775 const Vec3d origin2_proj = intersection_line.projection(origin2);
776
777 // Calculate edges on planes
778 const Vec3d edge_on_plane1_unit = (origin1 - origin1_proj).normalized();
779 const Vec3d edge_on_plane2_unit = (origin2 - origin2_proj).normalized();
780 const double radius = std::max(10.0, std::max((origin1 - origin1_proj).norm(), (origin2 - origin2_proj).norm()));
781 const std::pair<Vec3d, Vec3d> edge_on_plane1 = { origin1_proj + radius * edge_on_plane1_unit, origin1_proj + 2.0 * radius * edge_on_plane1_unit };
782 const std::pair<Vec3d, Vec3d> edge_on_plane2 = { origin2_proj + radius * edge_on_plane2_unit, origin2_proj + 2.0 * radius * edge_on_plane2_unit };
783
784 AngleAndEdges ret = angle_edge_edge(edge_on_plane1, edge_on_plane2);
785 ret.radius = radius;
786 return ret;
787}
EIGEN_DEVICE_FUNC VectorType projection(const VectorType &p) const
Definition ParametrizedLine.h:93

References angle_edge_edge(), are_parallel(), Slic3r::Measure::AngleAndEdges::Dummy, Eigen::ParametrizedLine< _Scalar, _AmbientDim, _Options >::projection(), and Slic3r::Measure::AngleAndEdges::radius.

Referenced by get_measurement().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ are_parallel() [1/3]

bool Slic3r::Measure::are_parallel ( const std::pair< Vec3d, Vec3d > &  e1,
const std::pair< Vec3d, Vec3d > &  e2 
)
inline
172 {
173 return are_parallel(e1.second - e1.first, e2.second - e2.first);
174}

References are_parallel().

+ Here is the call graph for this function:

◆ are_parallel() [2/3]

bool Slic3r::Measure::are_parallel ( const SurfaceFeature f1,
const SurfaceFeature f2 
)
inline
175 {
176 if (f1.get_type() == SurfaceFeatureType::Edge && f2.get_type() == SurfaceFeatureType::Edge)
178 else if (f1.get_type() == SurfaceFeatureType::Edge && f2.get_type() == SurfaceFeatureType::Plane)
180 else
181 return false;
182}
SurfaceFeatureType get_type() const
Definition Measure.hpp:38
Vec3d plane_normal(const SurfaceFeature &plane)
Definition Measure.hpp:164

References are_parallel(), are_perpendicular(), Edge, edge_direction(), Slic3r::Measure::SurfaceFeature::get_type(), Plane, and plane_normal().

+ Here is the call graph for this function:

◆ are_parallel() [3/3]

bool Slic3r::Measure::are_parallel ( const Vec3d v1,
const Vec3d v2 
)
inline
169{ return std::abs(std::abs(v1.dot(v2)) - 1.0) < EPSILON; }

References EPSILON.

Referenced by angle_edge_edge(), angle_edge_plane(), angle_plane_plane(), are_parallel(), are_parallel(), are_perpendicular(), and get_measurement().

+ Here is the caller graph for this function:

◆ are_perpendicular() [1/2]

bool Slic3r::Measure::are_perpendicular ( const SurfaceFeature f1,
const SurfaceFeature f2 
)
inline
184 {
185 if (f1.get_type() == SurfaceFeatureType::Edge && f2.get_type() == SurfaceFeatureType::Edge)
187 else if (f1.get_type() == SurfaceFeatureType::Edge && f2.get_type() == SurfaceFeatureType::Plane)
189 else
190 return false;
191}

References are_parallel(), are_perpendicular(), Edge, edge_direction(), Slic3r::Measure::SurfaceFeature::get_type(), Plane, and plane_normal().

+ Here is the call graph for this function:

◆ are_perpendicular() [2/2]

bool Slic3r::Measure::are_perpendicular ( const Vec3d v1,
const Vec3d v2 
)
inline
170{ return std::abs(v1.dot(v2)) < EPSILON; }

References EPSILON.

Referenced by angle_edge_plane(), are_parallel(), are_perpendicular(), and get_measurement().

+ Here is the caller graph for this function:

◆ edge_direction() [1/3]

Vec3d Slic3r::Measure::edge_direction ( const std::pair< Vec3d, Vec3d > &  e)
inline
158{ return edge_direction(e.first, e.second); }

References edge_direction().

+ Here is the call graph for this function:

◆ edge_direction() [2/3]

Vec3d Slic3r::Measure::edge_direction ( const SurfaceFeature edge)
inline
159 {
160 assert(edge.get_type() == SurfaceFeatureType::Edge);
161 return edge_direction(edge.get_edge());
162}
std::pair< Vec3d, Vec3d > get_edge() const
Definition Measure.hpp:44

References Edge, edge_direction(), Slic3r::Measure::SurfaceFeature::get_edge(), and Slic3r::Measure::SurfaceFeature::get_type().

+ Here is the call graph for this function:

◆ edge_direction() [3/3]

Vec3d Slic3r::Measure::edge_direction ( const Vec3d from,
const Vec3d to 
)
inline
157{ return (to - from).normalized(); }

Referenced by angle_edge_edge(), angle_edge_plane(), are_parallel(), are_perpendicular(), edge_direction(), edge_direction(), and Slic3r::GUI::GLGizmoMeasure::render_dimensioning().

+ Here is the caller graph for this function:

◆ get_center_and_radius()

static std::tuple< Vec3d, double, double > Slic3r::Measure::get_center_and_radius ( const std::vector< Vec3d > &  points,
const Transform3d trafo,
const Transform3d trafo_inv 
)
static
20{
21 Vec2ds out;
22 double z = 0.;
23 for (const Vec3d& pt : points) {
24 Vec3d pt_transformed = trafo * pt;
25 z = pt_transformed.z();
26 out.emplace_back(pt_transformed.x(), pt_transformed.y());
27 }
28
29 const int iter = points.size() < 10 ? 2 :
30 points.size() < 100 ? 4 :
31 6;
32
33 double error = std::numeric_limits<double>::max();
34 auto circle = Geometry::circle_ransac(out, iter, &error);
35
36 return std::make_tuple(trafo.inverse() * Vec3d(circle.center.x(), circle.center.y(), z), circle.radius, error);
37}
EIGEN_DEVICE_FUNC Transform inverse(TransformTraits traits=(TransformTraits) Mode) const
Definition Transform.h:1202
std::vector< Vec2d > Vec2ds
Definition Point.hpp:63
static char error[256]
Definition tga.cpp:50

References Slic3r::Geometry::circle_ransac(), error, and Eigen::Transform< _Scalar, _Dim, _Mode, _Options >::inverse().

Referenced by Slic3r::Measure::MeasuringImpl::extract_features().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_measurement()

MeasurementResult Slic3r::Measure::get_measurement ( const SurfaceFeature a,
const SurfaceFeature b,
const Measuring measuring 
)
796{
797 assert(a.get_type() != SurfaceFeatureType::Undef && b.get_type() != SurfaceFeatureType::Undef);
798
799 const bool swap = int(a.get_type()) > int(b.get_type());
800 const SurfaceFeature& f1 = swap ? b : a;
801 const SurfaceFeature& f2 = swap ? a : b;
802
803 MeasurementResult result;
804
808 if (f1.get_type() == SurfaceFeatureType::Point) {
809 if (f2.get_type() == SurfaceFeatureType::Point) {
810 Vec3d diff = (f2.get_point() - f1.get_point());
811 result.distance_strict = std::make_optional(DistAndPoints{diff.norm(), f1.get_point(), f2.get_point()});
812 result.distance_xyz = diff.cwiseAbs();
813
815 } else if (f2.get_type() == SurfaceFeatureType::Edge) {
816 const auto [s,e] = f2.get_edge();
817 const Eigen::ParametrizedLine<double, 3> line(s, (e-s).normalized());
818 const double dist_inf = line.distance(f1.get_point());
819 const Vec3d proj = line.projection(f1.get_point());
820 const double len_sq = (e-s).squaredNorm();
821 const double dist_start_sq = (proj-s).squaredNorm();
822 const double dist_end_sq = (proj-e).squaredNorm();
823 if (dist_start_sq < len_sq && dist_end_sq < len_sq) {
824 // projection falls on the line - the strict distance is the same as infinite
825 result.distance_strict = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj});
826 } else { // the result is the closer of the endpoints
827 const bool s_is_closer = dist_start_sq < dist_end_sq;
828 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});
829 }
830 result.distance_infinite = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj});
832 } else if (f2.get_type() == SurfaceFeatureType::Circle) {
833 // Find a plane containing normal, center and the point.
834 const auto [c, radius, n] = f2.get_circle();
835 const Eigen::Hyperplane<double, 3> circle_plane(n, c);
836 const Vec3d proj = circle_plane.projection(f1.get_point());
837 if (proj.isApprox(c)) {
838 const Vec3d p_on_circle = c + radius * get_orthogonal(n, true);
839 result.distance_strict = std::make_optional(DistAndPoints{ radius, c, p_on_circle });
840 }
841 else {
842 const Eigen::Hyperplane<double, 3> circle_plane(n, c);
843 const Vec3d proj = circle_plane.projection(f1.get_point());
844 const double dist = std::sqrt(std::pow((proj - c).norm() - radius, 2.) +
845 (f1.get_point() - proj).squaredNorm());
846
847 const Vec3d p_on_circle = c + radius * (proj - c).normalized();
848 result.distance_strict = std::make_optional(DistAndPoints{ dist, f1.get_point(), p_on_circle }); // TODO
849 }
851 } else if (f2.get_type() == SurfaceFeatureType::Plane) {
852 const auto [idx, normal, pt] = f2.get_plane();
853 Eigen::Hyperplane<double, 3> plane(normal, pt);
854 result.distance_infinite = std::make_optional(DistAndPoints{plane.absDistance(f1.get_point()), f1.get_point(), plane.projection(f1.get_point())}); // TODO
855 // TODO: result.distance_strict =
856 }
860 }
861 else if (f1.get_type() == SurfaceFeatureType::Edge) {
862 if (f2.get_type() == SurfaceFeatureType::Edge) {
863 std::vector<DistAndPoints> distances;
864
865 auto add_point_edge_distance = [&distances](const Vec3d& v, const std::pair<Vec3d, Vec3d>& e) {
866 const MeasurementResult res = get_measurement(SurfaceFeature(v), SurfaceFeature(SurfaceFeatureType::Edge, e.first, e.second));
867 double distance = res.distance_strict->dist;
868 Vec3d v2 = res.distance_strict->to;
869
870 const Vec3d e1e2 = e.second - e.first;
871 const Vec3d e1v2 = v2 - e.first;
872 if (e1v2.dot(e1e2) >= 0.0 && e1v2.norm() < e1e2.norm())
873 distances.emplace_back(distance, v, v2);
874 };
875
876 std::pair<Vec3d, Vec3d> e1 = f1.get_edge();
877 std::pair<Vec3d, Vec3d> e2 = f2.get_edge();
878
879 distances.emplace_back((e2.first - e1.first).norm(), e1.first, e2.first);
880 distances.emplace_back((e2.second - e1.first).norm(), e1.first, e2.second);
881 distances.emplace_back((e2.first - e1.second).norm(), e1.second, e2.first);
882 distances.emplace_back((e2.second - e1.second).norm(), e1.second, e2.second);
883 add_point_edge_distance(e1.first, e2);
884 add_point_edge_distance(e1.second, e2);
885 add_point_edge_distance(e2.first, e1);
886 add_point_edge_distance(e2.second, e1);
887 auto it = std::min_element(distances.begin(), distances.end(),
888 [](const DistAndPoints& item1, const DistAndPoints& item2) {
889 return item1.dist < item2.dist;
890 });
891 result.distance_infinite = std::make_optional(*it);
892
893 result.angle = angle_edge_edge(f1.get_edge(), f2.get_edge());
895 } else if (f2.get_type() == SurfaceFeatureType::Circle) {
896 const std::pair<Vec3d, Vec3d> e = f1.get_edge();
897 const auto& [center, radius, normal] = f2.get_circle();
898 const Vec3d e1e2 = (e.second - e.first);
899 const Vec3d e1e2_unit = e1e2.normalized();
900
901 std::vector<DistAndPoints> distances;
902 distances.emplace_back(*get_measurement(SurfaceFeature(e.first), f2).distance_strict);
903 distances.emplace_back(*get_measurement(SurfaceFeature(e.second), f2).distance_strict);
904
905 const Eigen::Hyperplane<double, 3> plane(e1e2_unit, center);
907 const Vec3d inter = line.intersectionPoint(plane);
908 const Vec3d e1inter = inter - e.first;
909 if (e1inter.dot(e1e2) >= 0.0 && e1inter.norm() < e1e2.norm())
910 distances.emplace_back(*get_measurement(SurfaceFeature(inter), f2).distance_strict);
911
912 auto it = std::min_element(distances.begin(), distances.end(),
913 [](const DistAndPoints& item1, const DistAndPoints& item2) {
914 return item1.dist < item2.dist;
915 });
916 result.distance_infinite = std::make_optional(DistAndPoints{it->dist, it->from, it->to});
918 } else if (f2.get_type() == SurfaceFeatureType::Plane) {
919 assert(measuring != nullptr);
920
921 const auto [from, to] = f1.get_edge();
922 const auto [idx, normal, origin] = f2.get_plane();
923
924 const Vec3d edge_unit = (to - from).normalized();
925 if (are_perpendicular(edge_unit, normal)) {
926 std::vector<DistAndPoints> distances;
927 const Eigen::Hyperplane<double, 3> plane(normal, origin);
928 distances.push_back(DistAndPoints{ plane.absDistance(from), from, plane.projection(from) });
929 distances.push_back(DistAndPoints{ plane.absDistance(to), to, plane.projection(to) });
930 auto it = std::min_element(distances.begin(), distances.end(),
931 [](const DistAndPoints& item1, const DistAndPoints& item2) {
932 return item1.dist < item2.dist;
933 });
934 result.distance_infinite = std::make_optional(DistAndPoints{ it->dist, it->from, it->to });
935 }
936 else {
937 const std::vector<SurfaceFeature>& plane_features = measuring->get_plane_features(idx);
938 std::vector<DistAndPoints> distances;
939 for (const SurfaceFeature& sf : plane_features) {
940 if (sf.get_type() == SurfaceFeatureType::Edge) {
941 const auto m = get_measurement(sf, f1);
942 if (!m.distance_infinite.has_value()) {
943 distances.clear();
944 break;
945 }
946 else
947 distances.push_back(*m.distance_infinite);
948 }
949 }
950 if (!distances.empty()) {
951 auto it = std::min_element(distances.begin(), distances.end(),
952 [](const DistAndPoints& item1, const DistAndPoints& item2) {
953 return item1.dist < item2.dist;
954 });
955 result.distance_infinite = std::make_optional(DistAndPoints{ it->dist, it->from, it->to });
956 }
957 }
958 result.angle = angle_edge_plane(f1.get_edge(), f2.get_plane());
959 }
963 } else if (f1.get_type() == SurfaceFeatureType::Circle) {
964 if (f2.get_type() == SurfaceFeatureType::Circle) {
965 const auto [c0, r0, n0] = f1.get_circle();
966 const auto [c1, r1, n1] = f2.get_circle();
967
968 // The following code is an adaptation of the algorithm found in:
969 // https://github.com/davideberly/GeometricTools/blob/master/GTE/Mathematics/DistCircle3Circle3.h
970 // and described in:
971 // https://www.geometrictools.com/Documentation/DistanceToCircle3.pdf
972
973 struct ClosestInfo
974 {
975 double sqrDistance{ 0.0 };
976 Vec3d circle0Closest{ Vec3d::Zero() };
977 Vec3d circle1Closest{ Vec3d::Zero() };
978
979 inline bool operator < (const ClosestInfo& other) const { return sqrDistance < other.sqrDistance; }
980 };
981 std::array<ClosestInfo, 16> candidates{};
982
983 const double zero = 0.0;
984
985 const Vec3d D = c1 - c0;
986
987 if (!are_parallel(n0, n1)) {
988 // Get parameters for constructing the degree-8 polynomial phi.
989 const double one = 1.0;
990 const double two = 2.0;
991 const double r0sqr = sqr(r0);
992 const double r1sqr = sqr(r1);
993
994 // Compute U1 and V1 for the plane of circle1.
995 const std::array<Vec3d, 3> basis = orthonormal_basis(n1);
996 const Vec3d U1 = basis[0];
997 const Vec3d V1 = basis[1];
998
999 // Construct the polynomial phi(cos(theta)).
1000 const Vec3d N0xD = n0.cross(D);
1001 const Vec3d N0xU1 = n0.cross(U1);
1002 const Vec3d N0xV1 = n0.cross(V1);
1003 const double a0 = r1 * D.dot(U1);
1004 const double a1 = r1 * D.dot(V1);
1005 const double a2 = N0xD.dot(N0xD);
1006 const double a3 = r1 * N0xD.dot(N0xU1);
1007 const double a4 = r1 * N0xD.dot(N0xV1);
1008 const double a5 = r1sqr * N0xU1.dot(N0xU1);
1009 const double a6 = r1sqr * N0xU1.dot(N0xV1);
1010 const double a7 = r1sqr * N0xV1.dot(N0xV1);
1011 Polynomial1 p0{ a2 + a7, two * a3, a5 - a7 };
1012 Polynomial1 p1{ two * a4, two * a6 };
1013 Polynomial1 p2{ zero, a1 };
1014 Polynomial1 p3{ -a0 };
1015 Polynomial1 p4{ -a6, a4, two * a6 };
1016 Polynomial1 p5{ -a3, a7 - a5 };
1017 Polynomial1 tmp0{ one, zero, -one };
1018 Polynomial1 tmp1 = p2 * p2 + tmp0 * p3 * p3;
1019 Polynomial1 tmp2 = two * p2 * p3;
1020 Polynomial1 tmp3 = p4 * p4 + tmp0 * p5 * p5;
1021 Polynomial1 tmp4 = two * p4 * p5;
1022 Polynomial1 p6 = p0 * tmp1 + tmp0 * p1 * tmp2 - r0sqr * tmp3;
1023 Polynomial1 p7 = p0 * tmp2 + p1 * tmp1 - r0sqr * tmp4;
1024
1025 // Parameters for polynomial root finding. The roots[] array
1026 // stores the roots. We need only the unique ones, which is
1027 // the responsibility of the set uniqueRoots. The pairs[]
1028 // array stores the (cosine,sine) information mentioned in the
1029 // PDF. TODO: Choose the maximum number of iterations for root
1030 // finding based on specific polynomial data?
1031 const uint32_t maxIterations = 128;
1032 int32_t degree = 0;
1033 size_t numRoots = 0;
1034 std::array<double, 8> roots{};
1035 std::set<double> uniqueRoots{};
1036 size_t numPairs = 0;
1037 std::array<std::pair<double, double>, 16> pairs{};
1038 double temp = zero;
1039 double sn = zero;
1040
1041 if (p7.GetDegree() > 0 || p7[0] != zero) {
1042 // H(cs,sn) = p6(cs) + sn * p7(cs)
1043 Polynomial1 phi = p6 * p6 - tmp0 * p7 * p7;
1044 degree = static_cast<int32_t>(phi.GetDegree());
1045 assert(degree > 0);
1046 numRoots = RootsPolynomial::Find(degree, &phi[0], maxIterations, roots.data());
1047 for (size_t i = 0; i < numRoots; ++i) {
1048 uniqueRoots.insert(roots[i]);
1049 }
1050
1051 for (auto const& cs : uniqueRoots) {
1052 if (std::fabs(cs) <= one) {
1053 temp = p7(cs);
1054 if (temp != zero) {
1055 sn = -p6(cs) / temp;
1056 pairs[numPairs++] = std::make_pair(cs, sn);
1057 }
1058 else {
1059 temp = std::max(one - sqr(cs), zero);
1060 sn = std::sqrt(temp);
1061 pairs[numPairs++] = std::make_pair(cs, sn);
1062 if (sn != zero)
1063 pairs[numPairs++] = std::make_pair(cs, -sn);
1064 }
1065 }
1066 }
1067 }
1068 else {
1069 // H(cs,sn) = p6(cs)
1070 degree = static_cast<int32_t>(p6.GetDegree());
1071 assert(degree > 0);
1072 numRoots = RootsPolynomial::Find(degree, &p6[0], maxIterations, roots.data());
1073 for (size_t i = 0; i < numRoots; ++i) {
1074 uniqueRoots.insert(roots[i]);
1075 }
1076
1077 for (auto const& cs : uniqueRoots) {
1078 if (std::fabs(cs) <= one) {
1079 temp = std::max(one - sqr(cs), zero);
1080 sn = std::sqrt(temp);
1081 pairs[numPairs++] = std::make_pair(cs, sn);
1082 if (sn != zero)
1083 pairs[numPairs++] = std::make_pair(cs, -sn);
1084 }
1085 }
1086 }
1087
1088 for (size_t i = 0; i < numPairs; ++i) {
1089 ClosestInfo& info = candidates[i];
1090 Vec3d delta = D + r1 * (pairs[i].first * U1 + pairs[i].second * V1);
1091 info.circle1Closest = c0 + delta;
1092 const double N0dDelta = n0.dot(delta);
1093 const double lenN0xDelta = n0.cross(delta).norm();
1094 if (lenN0xDelta > 0.0) {
1095 const double diff = lenN0xDelta - r0;
1096 info.sqrDistance = sqr(N0dDelta) + sqr(diff);
1097 delta -= N0dDelta * n0;
1098 delta.normalize();
1099 info.circle0Closest = c0 + r0 * delta;
1100 }
1101 else {
1102 const Vec3d r0U0 = r0 * get_orthogonal(n0, true);
1103 const Vec3d diff = delta - r0U0;
1104 info.sqrDistance = diff.dot(diff);
1105 info.circle0Closest = c0 + r0U0;
1106 }
1107 }
1108
1109 std::sort(candidates.begin(), candidates.begin() + numPairs);
1110 }
1111 else {
1112 ClosestInfo& info = candidates[0];
1113
1114 const double N0dD = n0.dot(D);
1115 const Vec3d normProj = N0dD * n0;
1116 const Vec3d compProj = D - normProj;
1117 Vec3d U = compProj;
1118 const double d = U.norm();
1119 U.normalize();
1120
1121 // The configuration is determined by the relative location of the
1122 // intervals of projection of the circles on to the D-line.
1123 // Circle0 projects to [-r0,r0] and circle1 projects to
1124 // [d-r1,d+r1].
1125 const double dmr1 = d - r1;
1126 double distance;
1127 if (dmr1 >= r0) {
1128 // d >= r0 + r1
1129 // The circles are separated (d > r0 + r1) or tangent with one
1130 // outside the other (d = r0 + r1).
1131 distance = dmr1 - r0;
1132 info.circle0Closest = c0 + r0 * U;
1133 info.circle1Closest = c1 - r1 * U;
1134 }
1135 else {
1136 // d < r0 + r1
1137 // The cases implicitly use the knowledge that d >= 0.
1138 const double dpr1 = d + r1;
1139 if (dpr1 <= r0) {
1140 // Circle1 is inside circle0.
1141 distance = r0 - dpr1;
1142 if (d > 0.0) {
1143 info.circle0Closest = c0 + r0 * U;
1144 info.circle1Closest = c1 + r1 * U;
1145 }
1146 else {
1147 // The circles are concentric, so U = (0,0,0).
1148 // Construct a vector perpendicular to N0 to use for
1149 // closest points.
1150 U = get_orthogonal(n0, true);
1151 info.circle0Closest = c0 + r0 * U;
1152 info.circle1Closest = c1 + r1 * U;
1153 }
1154 }
1155 else if (dmr1 <= -r0) {
1156 // Circle0 is inside circle1.
1157 distance = -r0 - dmr1;
1158 if (d > 0.0) {
1159 info.circle0Closest = c0 - r0 * U;
1160 info.circle1Closest = c1 - r1 * U;
1161 }
1162 else {
1163 // The circles are concentric, so U = (0,0,0).
1164 // Construct a vector perpendicular to N0 to use for
1165 // closest points.
1166 U = get_orthogonal(n0, true);
1167 info.circle0Closest = c0 + r0 * U;
1168 info.circle1Closest = c1 + r1 * U;
1169 }
1170 }
1171 else {
1172 distance = (c1 - c0).norm();
1173 info.circle0Closest = c0;
1174 info.circle1Closest = c1;
1175 }
1176 }
1177
1178 info.sqrDistance = distance * distance + N0dD * N0dD;
1179 }
1180
1181 result.distance_infinite = std::make_optional(DistAndPoints{ std::sqrt(candidates[0].sqrDistance), candidates[0].circle0Closest, candidates[0].circle1Closest }); // TODO
1183 } else if (f2.get_type() == SurfaceFeatureType::Plane) {
1184 assert(measuring != nullptr);
1185
1186 const auto [center, radius, normal1] = f1.get_circle();
1187 const auto [idx2, normal2, origin2] = f2.get_plane();
1188
1189 const bool coplanar = are_parallel(normal1, normal2) && Eigen::Hyperplane<double, 3>(normal1, center).absDistance(origin2) < EPSILON;
1190 if (!coplanar) {
1191 const std::vector<SurfaceFeature>& plane_features = measuring->get_plane_features(idx2);
1192 std::vector<DistAndPoints> distances;
1193 for (const SurfaceFeature& sf : plane_features) {
1194 if (sf.get_type() == SurfaceFeatureType::Edge) {
1195 const auto m = get_measurement(sf, f1);
1196 if (!m.distance_infinite.has_value()) {
1197 distances.clear();
1198 break;
1199 }
1200 else
1201 distances.push_back(*m.distance_infinite);
1202 }
1203 }
1204 if (!distances.empty()) {
1205 auto it = std::min_element(distances.begin(), distances.end(),
1206 [](const DistAndPoints& item1, const DistAndPoints& item2) {
1207 return item1.dist < item2.dist;
1208 });
1209 result.distance_infinite = std::make_optional(DistAndPoints{ it->dist, it->from, it->to });
1210 }
1211 }
1212 }
1216 } else if (f1.get_type() == SurfaceFeatureType::Plane) {
1217 const auto [idx1, normal1, pt1] = f1.get_plane();
1218 const auto [idx2, normal2, pt2] = f2.get_plane();
1219
1220 if (are_parallel(normal1, normal2)) {
1221 // The planes are parallel, calculate distance.
1222 const Eigen::Hyperplane<double, 3> plane(normal1, pt1);
1223 result.distance_infinite = std::make_optional(DistAndPoints{ plane.absDistance(pt2), pt2, plane.projection(pt2) }); // TODO
1224 }
1225 else
1226 result.angle = angle_plane_plane(f1.get_plane(), f2.get_plane());
1227 }
1228
1229 return result;
1230}
const std::vector< SurfaceFeature > & get_plane_features(unsigned int plane_id) const
Definition Measure.cpp:624
Definition Measure.hpp:29
std::tuple< Vec3d, double, Vec3d > get_circle() const
Definition Measure.hpp:47
Vec3d get_point() const
Definition Measure.hpp:41
std::tuple< int, Vec3d, Vec3d > get_plane() const
Definition Measure.hpp:50
EIGEN_DEVICE_FUNC Scalar absDistance(const VectorType &p) const
Definition Hyperplane.h:148
T dist(const boost::polygon::point_data< T > &p1, const boost::polygon::point_data< T > &p2)
Definition Geometry.cpp:280
static AngleAndEdges angle_plane_plane(const std::tuple< int, Vec3d, Vec3d > &p1, const std::tuple< int, Vec3d, Vec3d > &p2)
Definition Measure.cpp:751
static AngleAndEdges angle_edge_plane(const std::pair< Vec3d, Vec3d > &e, const std::tuple< int, Vec3d, Vec3d > &p)
Definition Measure.cpp:700
Vec3d get_orthogonal(const Vec3d &v, bool unitLength)
Definition MeasureUtils.hpp:355
static std::array< Vec3d, 3 > orthonormal_basis(const Vec3d &v)
Definition Measure.cpp:41
MeasurementResult get_measurement(const SurfaceFeature &a, const SurfaceFeature &b, const Measuring *measuring)
Definition Measure.cpp:795
constexpr T sqr(T x)
Definition libslic3r.h:258
Slic3r::Polygons diff(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:672
double distance(const P &p1, const P &p2)
Definition geometry_traits.hpp:329
Definition Measure.hpp:119
Definition Measure.hpp:139
std::optional< DistAndPoints > distance_infinite
Definition Measure.hpp:141
std::optional< AngleAndEdges > angle
Definition Measure.hpp:140
std::optional< Vec3d > distance_xyz
Definition Measure.hpp:143
std::optional< DistAndPoints > distance_strict
Definition Measure.hpp:142
__int32 int32_t
Definition unistd.h:75
unsigned __int32 uint32_t
Definition unistd.h:79

References Eigen::Hyperplane< _Scalar, _AmbientDim, _Options >::absDistance(), Slic3r::Measure::MeasurementResult::angle, angle_edge_edge(), angle_edge_plane(), angle_plane_plane(), are_parallel(), are_perpendicular(), Circle, Slic3r::diff(), Slic3r::Measure::DistAndPoints::dist, Eigen::ParametrizedLine< _Scalar, _AmbientDim, _Options >::distance(), Slic3r::Measure::MeasurementResult::distance_infinite, Slic3r::Measure::MeasurementResult::distance_strict, Slic3r::Measure::MeasurementResult::distance_xyz, Edge, EPSILON, Slic3r::Measure::RootsPolynomial::Find(), Slic3r::Measure::SurfaceFeature::get_circle(), Slic3r::Measure::SurfaceFeature::get_edge(), get_measurement(), get_orthogonal(), Slic3r::Measure::SurfaceFeature::get_plane(), Slic3r::Measure::Measuring::get_plane_features(), Slic3r::Measure::SurfaceFeature::get_point(), Slic3r::Measure::SurfaceFeature::get_type(), Slic3r::Measure::Polynomial1::GetDegree(), Eigen::ParametrizedLine< _Scalar, _AmbientDim, _Options >::intersectionPoint(), orthonormal_basis(), Plane, Point, Eigen::Hyperplane< _Scalar, _AmbientDim, _Options >::projection(), Eigen::ParametrizedLine< _Scalar, _AmbientDim, _Options >::projection(), Slic3r::sqr(), Eigen::ParametrizedLine< _Scalar, _AmbientDim, _Options >::Through(), and Undef.

Referenced by Slic3r::Measure::MeasuringImpl::get_feature(), get_measurement(), and Slic3r::GUI::GLGizmoMeasure::update_measurement_result().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_orthogonal()

Vec3d Slic3r::Measure::get_orthogonal ( const Vec3d v,
bool  unitLength 
)
inline
356{
357 double cmax = std::fabs(v[0]);
358 int32_t imax = 0;
359 for (int32_t i = 1; i < 3; ++i) {
360 double c = std::fabs(v[i]);
361 if (c > cmax) {
362 cmax = c;
363 imax = i;
364 }
365 }
366
367 Vec3d result = Vec3d::Zero();
368 int32_t inext = imax + 1;
369 if (inext == 3)
370 inext = 0;
371
372 result[imax] = v[inext];
373 result[inext] = -v[imax];
374 if (unitLength) {
375 const double sqrDistance = result[imax] * result[imax] + result[inext] * result[inext];
376 const double invLength = 1.0 / std::sqrt(sqrDistance);
377 result[imax] *= invLength;
378 result[inext] *= invLength;
379 }
380 return result;
381}

Referenced by get_measurement(), and Slic3r::GUI::GLGizmoMeasure::on_render_input_window().

+ Here is the caller graph for this function:

◆ operator*() [1/2]

Polynomial1 Slic3r::Measure::operator* ( const Polynomial1 p0,
const Polynomial1 p1 
)
inline
95{
96 const uint32_t p0Degree = p0.GetDegree();
97 const uint32_t p1Degree = p1.GetDegree();
98 Polynomial1 result(p0Degree + p1Degree);
99 result.SetCoefficients(0.0);
100 for (uint32_t i0 = 0; i0 <= p0Degree; ++i0) {
101 for (uint32_t i1 = 0; i1 <= p1Degree; ++i1) {
102 result[i0 + i1] += p0[i0] * p1[i1];
103 }
104 }
105 return result;
106}
Definition MeasureUtils.hpp:14
uint32_t GetDegree() const
Definition MeasureUtils.hpp:67

References Slic3r::Measure::Polynomial1::GetDegree(), and Slic3r::Measure::Polynomial1::SetCoefficients().

+ Here is the call graph for this function:

◆ operator*() [2/2]

Polynomial1 Slic3r::Measure::operator* ( double  scalar,
const Polynomial1 p 
)
inline
167{
168 const uint32_t degree = p.GetDegree();
169 Polynomial1 result(degree);
170 for (uint32_t i = 0; i <= degree; ++i) {
171 result[i] = scalar * p[i];
172 }
173 return result;
174}

References Slic3r::Measure::Polynomial1::GetDegree().

+ Here is the call graph for this function:

◆ operator+()

Polynomial1 Slic3r::Measure::operator+ ( const Polynomial1 p0,
const Polynomial1 p1 
)
inline
109{
110 const uint32_t p0Degree = p0.GetDegree();
111 const uint32_t p1Degree = p1.GetDegree();
112 uint32_t i;
113 if (p0Degree >= p1Degree) {
114 Polynomial1 result(p0Degree);
115 for (i = 0; i <= p1Degree; ++i) {
116 result[i] = p0[i] + p1[i];
117 }
118 for (; i <= p0Degree; ++i) {
119 result[i] = p0[i];
120 }
121 result.EliminateLeadingZeros();
122 return result;
123 }
124 else {
125 Polynomial1 result(p1Degree);
126 for (i = 0; i <= p0Degree; ++i) {
127 result[i] = p0[i] + p1[i];
128 }
129 for (; i <= p1Degree; ++i) {
130 result[i] = p1[i];
131 }
132 result.EliminateLeadingZeros();
133 return result;
134 }
135}
void EliminateLeadingZeros()
Definition MeasureUtils.hpp:46

References Slic3r::Measure::Polynomial1::EliminateLeadingZeros(), and Slic3r::Measure::Polynomial1::GetDegree().

+ Here is the call graph for this function:

◆ operator-()

Polynomial1 Slic3r::Measure::operator- ( const Polynomial1 p0,
const Polynomial1 p1 
)
inline
138{
139 const uint32_t p0Degree = p0.GetDegree();
140 const uint32_t p1Degree = p1.GetDegree();
141 uint32_t i;
142 if (p0Degree >= p1Degree) {
143 Polynomial1 result(p0Degree);
144 for (i = 0; i <= p1Degree; ++i) {
145 result[i] = p0[i] - p1[i];
146 }
147 for (; i <= p0Degree; ++i) {
148 result[i] = p0[i];
149 }
150 result.EliminateLeadingZeros();
151 return result;
152 }
153 else {
154 Polynomial1 result(p1Degree);
155 for (i = 0; i <= p0Degree; ++i) {
156 result[i] = p0[i] - p1[i];
157 }
158 for (; i <= p1Degree; ++i) {
159 result[i] = -p1[i];
160 }
161 result.EliminateLeadingZeros();
162 return result;
163 }
164}

References Slic3r::Measure::Polynomial1::EliminateLeadingZeros(), and Slic3r::Measure::Polynomial1::GetDegree().

+ Here is the call graph for this function:

◆ orthonormal_basis()

static std::array< Vec3d, 3 > Slic3r::Measure::orthonormal_basis ( const Vec3d v)
static
42{
43 std::array<Vec3d, 3> ret;
44 ret[2] = v.normalized();
45 int index;
46 ret[2].cwiseAbs().maxCoeff(&index);
47 switch (index)
48 {
49 case 0: { ret[0] = Vec3d(ret[2].y(), -ret[2].x(), 0.0).normalized(); break; }
50 case 1: { ret[0] = Vec3d(0.0, ret[2].z(), -ret[2].y()).normalized(); break; }
51 case 2: { ret[0] = Vec3d(-ret[2].z(), 0.0, ret[2].x()).normalized(); break; }
52 }
53 ret[1] = ret[2].cross(ret[0]).normalized();
54 return ret;
55}

Referenced by angle_edge_plane(), and get_measurement().

+ Here is the caller graph for this function:

◆ plane_normal()

Vec3d Slic3r::Measure::plane_normal ( const SurfaceFeature plane)
inline
164 {
165 assert(plane.get_type() == SurfaceFeatureType::Plane);
166 return std::get<1>(plane.get_plane());
167}

References Slic3r::Measure::SurfaceFeature::get_plane(), Slic3r::Measure::SurfaceFeature::get_type(), and Plane.

Referenced by are_parallel(), and are_perpendicular().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ feature_hover_limit

constexpr double Slic3r::Measure::feature_hover_limit = 0.5
constexpr