Skip to content

Commit fc57adb

Browse files
authored
Simplify polygons after offset operations (openscad#5581)
* Added failing testcase for openscad#5554 * Perform simplification of Clipper paths after applying offset, per recommendation from the Clipper docs
1 parent 9eed1da commit fc57adb

File tree

5 files changed

+28
-7
lines changed

5 files changed

+28
-7
lines changed

src/geometry/ClipperUtils.cc

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "geometry/ClipperUtils.h"
2+
#include "clipper2/clipper.h"
23
#include "utils/printutils.h"
34

45
#include <algorithm>
@@ -94,6 +95,13 @@ void fill_minkowski_insides(const Clipper2Lib::Paths64& a,
9495
}
9596
}
9697

98+
void SimplifyPolyTree(const Clipper2Lib::PolyPath64& polytree, double epsilon, Clipper2Lib::PolyPath64& result) {
99+
for (const auto& child : polytree) {
100+
Clipper2Lib::PolyPath64 *newchild = result.AddChild(Clipper2Lib::SimplifyPath(child->Polygon(), epsilon));
101+
SimplifyPolyTree(*child, epsilon, *newchild);
102+
}
103+
}
104+
97105
} // namespace
98106

99107
// Using 1 bit less precision than the maximum possible, to limit the chance
@@ -178,15 +186,14 @@ std::unique_ptr<Polygon2d> toPolygon2d(const Clipper2Lib::PolyTree64& polytree,
178186
const double scale = std::ldexp(1.0, -scale_bits);
179187
auto processChildren = [scale, &result](auto&& processChildren, const Clipper2Lib::PolyPath64& node) -> void {
180188
Outline2d outline;
181-
// Apparently, when using offset(), clipper gets the hole status wrong
182-
//outline.positive = !node->IsHole();
183-
189+
// When using offset, clipper can get the hole status wrong.
190+
// IsPositive() calculates the area of the polygon, and if it's negative, it's a hole.
184191
outline.positive = IsPositive(node.Polygon());
185-
// TODO: Should we replace the missing CleanPolygons in Clipper2 and call it here?
186192

187-
// CleanPolygon can in some cases reduce the polygon down to no vertices
188-
const auto &cleaned_path = node.Polygon();
193+
constexpr double epsilon = 1.1415; // Epsilon taken from Clipper1's default epsilon.
194+
const auto cleaned_path = Clipper2Lib::SimplifyPath(node.Polygon(), epsilon);
189195

196+
// SimplifyPath can potentially reduce the polygon down to no vertices
190197
if (cleaned_path.size() >= 3) {
191198
for (const auto& ip : cleaned_path) {
192199
outline.vertices.emplace_back(scale * ip.x, scale * ip.y);
@@ -335,7 +342,7 @@ std::unique_ptr<Polygon2d> applyOffset(const Polygon2d& poly, double offset, Cli
335342
isMiter ? miter_limit : 2.0,
336343
isRound ? std::ldexp(arc_tolerance, scale_bits) : 1.0
337344
);
338-
auto p = ClipperUtils::fromPolygon2d(poly, scale_bits);
345+
auto p = ClipperUtils::fromPolygon2d(poly, scale_bits);
339346
co.AddPaths(p, joinType, Clipper2Lib::EndType::Polygon);
340347
Clipper2Lib::PolyTree64 result;
341348
co.Execute(std::ldexp(offset, scale_bits), result);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
offset(delta=1)
2+
offset(+27)
3+
offset(delta=-1)
4+
polygon([
5+
[111.775,6.286],
6+
[92,5],
7+
[73,3],
8+
[21,3],
9+
[2.5,5],
10+
[2.5,76],
11+
[78.2932,76.776],
12+
[110.629,95.4452],
13+
[124.94,103.708],
14+
]);
7.24 KB
Loading
7.07 KB
Loading
7.24 KB
Loading

0 commit comments

Comments
 (0)