mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-07-25 06:44:26 +08:00
Fix clipper::union adding extremely small holes even with safety_offset
It check that all polygons are all thicker than scaled_epsilon
This commit is contained in:
parent
b6a98377ae
commit
42a0c31cb2
@ -162,6 +162,25 @@ double Area(const Path &poly)
|
||||
return -a * 0.5;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
IntPoint Centroid(const Path& poly, double area)
|
||||
{
|
||||
double x_temp = 0;
|
||||
double y_temp = 0;
|
||||
|
||||
const int max = poly.size() - 1;
|
||||
size_t i = 0;
|
||||
for (; i < max; ++i)
|
||||
{
|
||||
size_t j = i + 1;
|
||||
x_temp += (double)(poly[i].X + poly[j].X) * ((double)poly[i].X * poly[j].Y - (double)poly[j].X * poly[i].Y);
|
||||
y_temp += (double)(poly[i].Y + poly[j].Y) * ((double)poly[i].X * poly[j].Y - (double)poly[j].X * poly[i].Y);
|
||||
}
|
||||
x_temp += (double)(poly[i].X + poly[0].X) * ((double)poly[i].X * poly[0].Y - (double)poly[0].X * poly[i].Y);
|
||||
y_temp += (double)(poly[i].Y + poly[0].Y) * ((double)poly[i].X * poly[0].Y - (double)poly[0].X * poly[i].Y);
|
||||
|
||||
return IntPoint(x_temp / (6 * area), y_temp / (6 * area));
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
double Area(const OutRec &outRec)
|
||||
{
|
||||
@ -3895,10 +3914,10 @@ double DistanceFromLineSqrd(
|
||||
const IntPoint& pt, const IntPoint& ln1, const IntPoint& ln2)
|
||||
{
|
||||
//The equation of a line in general form (Ax + By + C = 0)
|
||||
//given 2 points (x¹,y¹) & (x²,y²) is ...
|
||||
//(y¹ - y²)x + (x² - x¹)y + (y² - y¹)x¹ - (x² - x¹)y¹ = 0
|
||||
//A = (y¹ - y²); B = (x² - x¹); C = (y² - y¹)x¹ - (x² - x¹)y¹
|
||||
//perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²)
|
||||
//given 2 points (x<EFBFBD>,y<>) & (x<>,y<>) is ...
|
||||
//(y<EFBFBD> - y<>)x + (x<> - x<>)y + (y<> - y<>)x<> - (x<> - x<>)y<> = 0
|
||||
//A = (y<EFBFBD> - y<>); B = (x<> - x<>); C = (y<> - y<>)x<> - (x<> - x<>)y<>
|
||||
//perpendicular distance of point (x<EFBFBD>,y<>) = (Ax<41> + By<42> + C)/Sqrt(A<> + B<>)
|
||||
//see http://en.wikipedia.org/wiki/Perpendicular_distance
|
||||
double A = double(ln1.Y - ln2.Y);
|
||||
double B = double(ln2.X - ln1.X);
|
||||
|
@ -184,6 +184,7 @@ private:
|
||||
};
|
||||
|
||||
double Area(const Path &poly);
|
||||
IntPoint Centroid(const Path& poly, double area);
|
||||
inline bool Orientation(const Path &poly) { return Area(poly) >= 0; }
|
||||
int PointInPolygon(const IntPoint &pt, const Path &path);
|
||||
|
||||
|
@ -524,6 +524,22 @@ T _clipper_do(const ClipperLib::ClipType clipType,
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool test_path(const ClipperLib::Path &path) {
|
||||
|
||||
double area = std::abs(ClipperLib::Area(path));
|
||||
// get highest dist, but as it's n² in complexity, i use 2*dist to center wich is 2n in complexity
|
||||
ClipperLib::cInt max_dist_sqrd = 0;
|
||||
ClipperLib::IntPoint centroid = ClipperLib::Centroid(path, area);
|
||||
for (const ClipperLib::IntPoint& pt : path) {
|
||||
// &0x3FFFFFFF to let (dx * dx + dy * dy) be storable into a int64
|
||||
ClipperLib::cInt dx = (pt.X - centroid.X) & 0x3FFFFFFF;
|
||||
ClipperLib::cInt dy = (pt.Y - centroid.Y) & 0x3FFFFFFF;
|
||||
ClipperLib::cInt dist_sqrd = (dx * dx + dy * dy);
|
||||
max_dist_sqrd = std::max(max_dist_sqrd, dist_sqrd);
|
||||
}
|
||||
return (area < (SCALED_EPSILON + SCALED_EPSILON) * std::sqrt(max_dist_sqrd));
|
||||
}
|
||||
|
||||
// Fix of #117: A large fractal pyramid takes ages to slice
|
||||
// The Clipper library has difficulties processing overlapping polygons.
|
||||
// Namely, the function ClipperLib::JoinCommonEdges() has potentially a terrible time complexity if the output
|
||||
@ -554,6 +570,24 @@ inline ClipperLib::PolyTree _clipper_do_polytree2(const ClipperLib::ClipType cli
|
||||
clipper.AddPaths(input_subject, ClipperLib::ptSubject, true);
|
||||
ClipperLib::PolyTree retval;
|
||||
clipper.Execute(ClipperLib::ctUnion, retval, fillType, fillType);
|
||||
|
||||
// if safety_offset_, remove too small polygons & holes
|
||||
if (safety_offset_)
|
||||
for (int idx_poly = 0; idx_poly < retval.ChildCount(); ++idx_poly) {
|
||||
ClipperLib::PolyNode* ex_polygon = retval.Childs[idx_poly];
|
||||
if (test_path(ex_polygon->Contour)) {
|
||||
retval.Childs.erase(retval.Childs.begin() + idx_poly);
|
||||
--idx_poly;
|
||||
} else {
|
||||
for (int i = 0; i < ex_polygon->ChildCount(); ++i)
|
||||
{
|
||||
if (test_path(ex_polygon->Childs[i]->Contour)) {
|
||||
ex_polygon->Childs.erase(ex_polygon->Childs.begin() + i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user