diff --git a/src/clipper/clipper.cpp b/src/clipper/clipper.cpp index be4cb4a6a..bc9b2d89b 100644 --- a/src/clipper/clipper.cpp +++ b/src/clipper/clipper.cpp @@ -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�,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�) //see http://en.wikipedia.org/wiki/Perpendicular_distance double A = double(ln1.Y - ln2.Y); double B = double(ln2.X - ln1.X); diff --git a/src/clipper/clipper.hpp b/src/clipper/clipper.hpp index 8b34779e3..d47bced55 100644 --- a/src/clipper/clipper.hpp +++ b/src/clipper/clipper.hpp @@ -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); diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index b02da5fd6..1502834c3 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -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; }