Improve performance by migrating to Clipper2 2.0.1 (#15969)

Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
This commit is contained in:
Ian BassiandRodrigo Faselli authored and GitHub committed 2026-10-02 17:33:41 -03:00
1 parent 70bc02467b
commit 222c6a2df5
78 files changed
+3028 -7038

No files matched your search

+77 -6
View File
@@ -404,18 +404,89 @@ bool Emboss::divide_segments_for_close_point(ExPolygons &expolygons, double dist
return true;
}
// Clipper1's CleanPolygon(): removes vertices closer than `distance` to a neighbour or to the line through their neighbours.
static void clean_polygon(Points &points, double distance)
{
auto points_are_close = [](const Point &a, const Point &b, double dist2) {
const double dx = double(a.x() - b.x()), dy = double(a.y() - b.y());
return dx * dx + dy * dy <= dist2;
};
auto distance_from_line2 = [](const Point &pt, const Point &ln1, const Point &ln2) {
const double A = double(ln1.y() - ln2.y());
const double B = double(ln2.x() - ln1.x());
const double C = A * pt.x() + B * pt.y() - (A * ln1.x() + B * ln1.y());
return (C * C) / (A * A + B * B);
};
auto slopes_near_collinear = [&distance_from_line2](const Point &pt1, const Point &pt2, const Point &pt3, double dist2) {
if (std::abs(pt1.x() - pt2.x()) > std::abs(pt1.y() - pt2.y())) {
if ((pt1.x() > pt2.x()) == (pt1.x() < pt3.x()))
return distance_from_line2(pt1, pt2, pt3) < dist2;
if ((pt2.x() > pt1.x()) == (pt2.x() < pt3.x()))
return distance_from_line2(pt2, pt1, pt3) < dist2;
return distance_from_line2(pt3, pt1, pt2) < dist2;
}
if ((pt1.y() > pt2.y()) == (pt1.y() < pt3.y()))
return distance_from_line2(pt1, pt2, pt3) < dist2;
if ((pt2.y() > pt1.y()) == (pt2.y() < pt3.y()))
return distance_from_line2(pt2, pt1, pt3) < dist2;
return distance_from_line2(pt3, pt1, pt2) < dist2;
};
size_t size = points.size();
if (size == 0)
return;
std::vector<size_t> next(size), prev(size);
std::vector<char> done(size, 0);
for (size_t i = 0; i < size; ++i) {
next[i] = (i + 1) % size;
prev[next[i]] = i;
}
auto exclude = [&next, &prev, &done](size_t op) {
const size_t result = prev[op];
next[result] = next[op];
prev[next[op]] = result;
done[result] = 0;
return result;
};
const double dist2 = distance * distance;
size_t op = 0;
while (! done[op] && next[op] != prev[op]) {
if (points_are_close(points[op], points[prev[op]], dist2)) {
op = exclude(op);
-- size;
} else if (points_are_close(points[prev[op]], points[next[op]], dist2)) {
exclude(next[op]);
op = exclude(op);
size -= 2;
} else if (slopes_near_collinear(points[prev[op]], points[op], points[next[op]], dist2)) {
op = exclude(op);
-- size;
} else {
done[op] = 1;
op = next[op];
}
}
if (size < 3)
size = 0;
Points out;
out.reserve(size);
for (size_t i = 0; i < size; ++i) {
out.emplace_back(points[op]);
op = next[op];
}
points = std::move(out);
}
HealedExPolygons Emboss::heal_polygons(const Polygons &shape, bool is_non_zero, unsigned int max_iteration)
{
const double clean_distance = 1.415; // little grater than sqrt(2)
ClipperLib::PolyFillType fill_type = is_non_zero ?
ClipperLib::pftNonZero : ClipperLib::pftEvenOdd;
PolyFillType fill_type = is_non_zero ? pftNonZero : pftEvenOdd;
// When edit this code check that font 'ALIENATE.TTF' and glyph 'i' still work
// fix of self intersections
// http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Functions/SimplifyPolygon.htm
ClipperLib::Paths paths = ClipperLib::SimplifyPolygons(ClipperUtils::PolygonsProvider(shape), fill_type);
ClipperLib::CleanPolygons(paths, clean_distance);
Polygons polygons = to_polygons(paths);
Polygons polygons = union_(shape, fill_type);
for (Polygon &polygon : polygons)
clean_polygon(polygon.points, clean_distance);
polygons.erase(std::remove_if(polygons.begin(), polygons.end(),
[](const Polygon &p) { return p.size() < 3; }), polygons.end());