Measurement: moving arrow-drawing functions from frontend to the backend (3/4)
This commit is contained in:
parent
8af3e5823a
commit
79ab1ab1b5
4 changed files with 156 additions and 278 deletions
|
@ -431,6 +431,67 @@ std::vector<std::vector<int>> Measuring::get_planes_triangle_indices() const
|
|||
|
||||
|
||||
|
||||
static AngleAndPoints angle_edge_edge(const std::pair<Vec3d, Vec3d>& e1, const std::pair<Vec3d, Vec3d>& 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<double, 3> 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<double>::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<double, 2> e1_rot_2d_line = Eigen::Hyperplane<double, 2>::Through(e11_rot_2d, e12_rot_2d);
|
||||
const Eigen::Hyperplane<double, 2> e2_rot_2d_line = Eigen::Hyperplane<double, 2>::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<DistAndPoints> distances;
|
||||
|
||||
auto add_point_edge_distance = [&distances](const Vec3d& v, const std::pair<Vec3d, Vec3d>& 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<Vec3d>(), 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<Vec3d, Vec3d> 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<DistAndPoints> 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<double, 3> plane(e1e2_unit, center);
|
||||
const Eigen::ParametrizedLine<double, 3> line = Eigen::ParametrizedLine<double, 3>::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
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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<double> angle;
|
||||
std::optional<AngleAndPoints> angle;
|
||||
std::optional<DistAndPoints> distance_infinite;
|
||||
std::optional<DistAndPoints> distance_strict;
|
||||
std::optional<Vec3d> distance_xyz;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define slic3r_SurfaceMesh_hpp_
|
||||
|
||||
#include <admesh/stl.h>
|
||||
#include <libslic3r/TriangleMesh.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue