Fixed polygons_simplify() to correctly handle holes.

This fixes some missing tree / organic supports in the middle
of an object surrounded by walls all around.
This commit is contained in:
Vojtech Bubnik 2022-11-18 17:16:47 +01:00
parent a98467f661
commit da00cedc84
3 changed files with 42 additions and 29 deletions

View File

@ -931,7 +931,7 @@ ExPolygons simplify_polygons_ex(const Polygons &subject, bool preserve_collinear
if (! preserve_collinear)
return union_ex(simplify_polygons(subject, false));
ClipperLib::PolyTree polytree;
ClipperLib::PolyTree polytree;
ClipperLib::Clipper c;
c.PreserveCollinear(true);
c.StrictlySimple(true);

View File

@ -99,9 +99,11 @@ void Polygon::douglas_peucker(double tolerance)
this->points = std::move(p);
}
// this only works on CCW polygons as CW will be ripped out by Clipper's simplify_polygons()
Polygons Polygon::simplify(double tolerance) const
{
// Works on CCW polygons only, CW contour will be reoriented to CCW by Clipper's simplify_polygons()!
assert(this->is_counter_clockwise());
// repeat first point at the end in order to apply Douglas-Peucker
// on the whole polygon
Points points = this->points;
@ -114,13 +116,6 @@ Polygons Polygon::simplify(double tolerance) const
return simplify_polygons(pp);
}
void Polygon::simplify(double tolerance, Polygons &polygons) const
{
Polygons pp = this->simplify(tolerance);
polygons.reserve(polygons.size() + pp.size());
polygons.insert(polygons.end(), pp.begin(), pp.end());
}
// Only call this on convex polygons or it will return invalid results
void Polygon::triangulate_convex(Polygons* polygons) const
{
@ -562,6 +557,27 @@ void remove_collinear(Polygons &polys)
remove_collinear(poly);
}
Polygons polygons_simplify(const Polygons &source_polygons, double tolerance)
{
Polygons out;
out.reserve(source_polygons.size());
for (const Polygon &source_polygon : source_polygons) {
// Run Douglas / Peucker simplification algorithm on an open polyline (by repeating the first point at the end of the polyline),
Points simplified = MultiPoint::_douglas_peucker(to_polyline(source_polygon).points, tolerance);
// then remove the last (repeated) point.
simplified.pop_back();
// Simplify the decimated contour by ClipperLib.
bool ccw = ClipperLib::Area(simplified) > 0.;
for (Points &path : ClipperLib::SimplifyPolygons(ClipperUtils::SinglePathProvider(simplified), ClipperLib::pftNonZero)) {
if (! ccw)
// ClipperLib likely reoriented negative area contours to become positive. Reverse holes back to CW.
std::reverse(path.begin(), path.end());
out.emplace_back(std::move(path));
}
}
return out;
}
// Do polygons match? If they match, they must have the same topology,
// however their contours may be rotated.
bool polygons_match(const Polygon &l, const Polygon &r)

View File

@ -67,8 +67,8 @@ public:
bool on_boundary(const Point &point, double eps) const
{ return (this->point_projection(point) - point).cast<double>().squaredNorm() < eps * eps; }
// Works on CCW polygons only, CW contour will be reoriented to CCW by Clipper's simplify_polygons()!
Polygons simplify(double tolerance) const;
void simplify(double tolerance, Polygons &polygons) const;
void densify(float min_length, std::vector<float>* lengths = nullptr);
void triangulate_convex(Polygons* polygons) const;
Point centroid() const;
@ -148,14 +148,7 @@ inline void polygons_append(Polygons &dst, Polygons &&src)
}
}
inline Polygons polygons_simplify(const Polygons &polys, double tolerance)
{
Polygons out;
out.reserve(polys.size());
for (const Polygon &p : polys)
polygons_append(out, p.simplify(tolerance));
return out;
}
Polygons polygons_simplify(const Polygons &polys, double tolerance);
inline void polygons_rotate(Polygons &polys, double angle)
{
@ -216,18 +209,22 @@ inline Lines to_lines(const Polygons &polys)
return lines;
}
inline Polylines to_polylines(const Polygons &polys)
inline Polyline to_polyline(const Polygon &polygon)
{
Polylines polylines;
polylines.assign(polys.size(), Polyline());
size_t idx = 0;
for (Polygons::const_iterator it = polys.begin(); it != polys.end(); ++ it) {
Polyline &pl = polylines[idx ++];
pl.points = it->points;
pl.points.push_back(it->points.front());
}
assert(idx == polylines.size());
return polylines;
Polyline out;
out.points.reserve(polygon.size() + 1);
out.points.assign(polygon.points.begin(), polygon.points.end());
out.points.push_back(polygon.points.front());
return out;
}
inline Polylines to_polylines(const Polygons &polygons)
{
Polylines out;
out.reserve(polygons.size());
for (const Polygon &polygon : polygons)
out.emplace_back(to_polyline(polygon));
return out;
}
inline Polylines to_polylines(Polygons &&polys)