mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-12 03:21:47 +08:00
Measurement: tweaking of the tolerances, ransacing the whole border
This commit is contained in:
parent
220104dbe2
commit
eeea803be5
@ -18,7 +18,7 @@ static std::pair<Vec3d, double> get_center_and_radius(const std::vector<Vec3d>&
|
|||||||
{
|
{
|
||||||
Vec2ds out;
|
Vec2ds out;
|
||||||
double z = 0.;
|
double z = 0.;
|
||||||
for (const Vec3d pt : points) {
|
for (const Vec3d& pt : points) {
|
||||||
Vec3d pt_transformed = trafo * pt;
|
Vec3d pt_transformed = trafo * pt;
|
||||||
z = pt_transformed.z();
|
z = pt_transformed.z();
|
||||||
out.emplace_back(pt_transformed.x(), pt_transformed.y());
|
out.emplace_back(pt_transformed.x(), pt_transformed.y());
|
||||||
@ -29,6 +29,14 @@ static std::pair<Vec3d, double> get_center_and_radius(const std::vector<Vec3d>&
|
|||||||
return std::make_pair(trafo.inverse() * Vec3d(circle.center.x(), circle.center.y(), z), circle.radius);
|
return std::make_pair(trafo.inverse() * Vec3d(circle.center.x(), circle.center.y(), z), circle.radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool circle_fit_is_ok(const std::vector<Vec3d>& pts, const Vec3d& center, double radius)
|
||||||
|
{
|
||||||
|
for (const Vec3d& pt : pts)
|
||||||
|
if (std::abs((pt - center).norm() - radius) > 0.05)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static std::array<Vec3d, 3> orthonormal_basis(const Vec3d& v)
|
static std::array<Vec3d, 3> orthonormal_basis(const Vec3d& v)
|
||||||
{
|
{
|
||||||
std::array<Vec3d, 3> ret;
|
std::array<Vec3d, 3> ret;
|
||||||
@ -246,10 +254,7 @@ void MeasuringImpl::update_planes()
|
|||||||
|
|
||||||
void MeasuringImpl::extract_features()
|
void MeasuringImpl::extract_features()
|
||||||
{
|
{
|
||||||
auto are_angles_same = [](double a, double b) { return Slic3r::is_approx(a,b); };
|
std::vector<double> angles; // placed in outer scope to prevent reallocations
|
||||||
auto are_lengths_same = [](double a, double b) { return Slic3r::is_approx(a,b); };
|
|
||||||
|
|
||||||
std::vector<double> angles;
|
|
||||||
std::vector<double> lengths;
|
std::vector<double> lengths;
|
||||||
|
|
||||||
|
|
||||||
@ -267,8 +272,43 @@ void MeasuringImpl::extract_features()
|
|||||||
if (border.size() <= 1)
|
if (border.size() <= 1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
bool done = false;
|
||||||
|
|
||||||
|
if (const auto& [center, radius] = get_center_and_radius(border, trafo);
|
||||||
|
(border.size()>4) && circle_fit_is_ok(border, center, radius)) {
|
||||||
|
// The whole border is one circle. Just add it into the list of features
|
||||||
|
// and we are done.
|
||||||
|
|
||||||
|
bool is_polygon = border.size()>4 && border.size()<=8;
|
||||||
|
bool lengths_match = std::all_of(border.begin()+2, border.end(), [is_polygon](const Vec3d& pt) {
|
||||||
|
return Slic3r::is_approx((pt - *((&pt)-1)).squaredNorm(), (*((&pt)-1) - *((&pt)-2)).squaredNorm(), is_polygon ? 0.01 : 0.01);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (lengths_match && (is_polygon || border.size() > 8)) {
|
||||||
|
if (is_polygon) {
|
||||||
|
// This is a polygon, add the separate edges with the center.
|
||||||
|
for (int j=0; j<int(border.size()); ++j)
|
||||||
|
plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge,
|
||||||
|
border[j==0 ? border.size()-1 : j-1], border[j],
|
||||||
|
std::make_optional(center)));
|
||||||
|
} else {
|
||||||
|
// The fit went well and it has more than 8 points - let's consider this a circle.
|
||||||
|
plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius));
|
||||||
|
}
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! done) {
|
||||||
|
// In this case, the border is not a circle and may contain circular
|
||||||
|
// segments. Try to find them and then add all remaining edges as edges.
|
||||||
|
|
||||||
|
auto are_angles_same = [](double a, double b) { return Slic3r::is_approx(a,b,0.01); };
|
||||||
|
auto are_lengths_same = [](double a, double b) { return Slic3r::is_approx(a,b,0.01); };
|
||||||
|
|
||||||
|
|
||||||
// Given an idx into border, return the index that is idx+offset position,
|
// Given an idx into border, return the index that is idx+offset position,
|
||||||
// while taking into account the need for warp-around and the fact that
|
// while taking into account the need for wrap-around and the fact that
|
||||||
// the first and last point are the same.
|
// the first and last point are the same.
|
||||||
auto offset_to_index = [border_size = int(border.size())](int idx, int offset) -> int {
|
auto offset_to_index = [border_size = int(border.size())](int idx, int offset) -> int {
|
||||||
assert(std::abs(offset) < border_size);
|
assert(std::abs(offset) < border_size);
|
||||||
@ -354,29 +394,14 @@ void MeasuringImpl::extract_features()
|
|||||||
|
|
||||||
// Check that the fit went well. The tolerance is high, only to
|
// Check that the fit went well. The tolerance is high, only to
|
||||||
// reject complete failures.
|
// reject complete failures.
|
||||||
for (const Vec3d& pt : single_circle) {
|
accept_circle &= circle_fit_is_ok(single_circle, center, radius);
|
||||||
if (std::abs((pt - center).norm() - radius) > 0.5) {
|
|
||||||
accept_circle = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the segment subtends less than 90 degrees, throw it away.
|
// If the segment subtends less than 90 degrees, throw it away.
|
||||||
accept_circle &= single_circle_length / radius > 0.9*M_PI/2.;
|
accept_circle &= single_circle_length / radius > 0.9*M_PI/2.;
|
||||||
|
|
||||||
// If this is all-around and 5 to 8 vertices, consider it a polygon.
|
|
||||||
bool is_polygon = start_idx == i && single_circle.size() <= 9 && single_circle.size() >= 6;
|
|
||||||
|
|
||||||
if (accept_circle) {
|
if (accept_circle) {
|
||||||
// Add the circle and remember indices into borders.
|
// Add the circle and remember indices into borders.
|
||||||
circles_idxs.emplace_back(start_idx, i);
|
circles_idxs.emplace_back(start_idx, i);
|
||||||
if (is_polygon) {
|
|
||||||
for (int j=0; j<=i; ++j) // No wrap-around handling needed here.
|
|
||||||
edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge,
|
|
||||||
border[j==0 ? border.size()-1 : j-1], border[j],
|
|
||||||
std::make_optional(center)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius));
|
circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -394,7 +419,7 @@ void MeasuringImpl::extract_features()
|
|||||||
for (int i=1; i<int(border.size()); ++i)
|
for (int i=1; i<int(border.size()); ++i)
|
||||||
edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[i-1], border[i]));
|
edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[i-1], border[i]));
|
||||||
edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[0], border[border.size()-1]));
|
edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[0], border[border.size()-1]));
|
||||||
} else {
|
} else if (circles_idxs.size() > 1 || circles_idxs.front().first != circles_idxs.front().second) {
|
||||||
// There is at least one circular segment. Start at its end and add edges until the start of the next one.
|
// There is at least one circular segment. Start at its end and add edges until the start of the next one.
|
||||||
int i = circles_idxs.front().second;
|
int i = circles_idxs.front().second;
|
||||||
int circle_idx = 1;
|
int circle_idx = 1;
|
||||||
@ -437,6 +462,7 @@ void MeasuringImpl::extract_features()
|
|||||||
plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(edges.begin()),
|
plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(edges.begin()),
|
||||||
std::make_move_iterator(edges.end()));
|
std::make_move_iterator(edges.end()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The last surface feature is the plane itself.
|
// The last surface feature is the plane itself.
|
||||||
Vec3d cog = Vec3d::Zero();
|
Vec3d cog = Vec3d::Zero();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user