From e64d381fa966fb6a05557a600a3183600b64d85b Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 16 Jan 2024 13:43:46 +0100 Subject: [PATCH] Fix convex hull in the case where the convex hull consist of islands CURA-11395 --- src/utils/polygon.cpp | 73 ++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/src/utils/polygon.cpp b/src/utils/polygon.cpp index 1c698598db..3966b581a7 100644 --- a/src/utils/polygon.cpp +++ b/src/utils/polygon.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "utils/ListPolyIt.h" #include "utils/PolylineStitcher.h" @@ -111,56 +112,50 @@ void Polygons::makeConvex() return; } - // convex hulls cannot have holes, so remove all paths except the outerpath - this->paths.resize(1); - // Andrew’s Monotone Chain Convex Hull Algorithm - for (PolygonRef poly : *this) + std::vector points; + + for (const auto& poly : this->paths) { - if (poly.size() <= 3) - { - // Already convex. - continue; - } + points.insert(points.end(), poly.begin(), poly.end()); + } + + ClipperLib::Path convexified; + auto make_sorted_poly_convex = [&convexified](std::vector& poly) + { + convexified.push_back(poly[0]); - Polygon convexified; - auto makeSortedPolyConvex = [&convexified](PolygonRef& poly) + for (const auto window : poly | ranges::views::sliding(2)) { - convexified.path->push_back(poly[0]); + const Point2LL& current = window[0]; + const Point2LL& after = window[1]; - for (const auto window : poly | ranges::views::sliding(2)) + if (LinearAlg2D::pointIsLeftOfLine(current, convexified.back(), after) < 0) { - const Point2LL& current = window[0]; - const Point2LL& after = window[1]; - - if (LinearAlg2D::pointIsLeftOfLine(current, convexified.path->back(), after) < 0) + // Track backwards to make sure we haven't been in a concave pocket for multiple vertices already. + while (convexified.size() >= 2 + && (LinearAlg2D::pointIsLeftOfLine(convexified.back(), convexified[convexified.size() - 2], current) >= 0 + || LinearAlg2D::pointIsLeftOfLine(convexified.back(), convexified[convexified.size() - 2], convexified.front()) > 0)) { - // Track backwards to make sure we haven't been in a concave pocket for multiple vertices already. - while (convexified.size() >= 2 - && (LinearAlg2D::pointIsLeftOfLine(convexified.path->back(), (*convexified.path)[convexified.size() - 2], current) >= 0 - || LinearAlg2D::pointIsLeftOfLine(convexified.path->back(), (*convexified.path)[convexified.size() - 2], convexified.path->front()) > 0)) - { - convexified.path->pop_back(); - } - convexified.path->push_back(current); + convexified.pop_back(); } + convexified.push_back(current); } - }; + } + }; - std::sort( - poly.begin(), - poly.end(), - [](Point2LL a, Point2LL b) - { - return a.X == b.X ? a.Y < b.Y : a.X < b.X; - }); - makeSortedPolyConvex(poly); - std::reverse(poly.begin(), poly.end()); - makeSortedPolyConvex(poly); + std::sort( + points.begin(), + points.end(), + [](Point2LL a, Point2LL b) + { + return a.X == b.X ? a.Y < b.Y : a.X < b.X; + }); + make_sorted_poly_convex(points); + std::reverse(points.begin(), points.end()); + make_sorted_poly_convex(points); - // Due to vector's implementation, this is constant time - poly.path->swap(*convexified.path); - } + this->paths = { convexified }; } size_t Polygons::pointCount() const