From 9fbba855ef42a4b870ce402930d6e6772564c7cb Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Fri, 30 Apr 2021 11:49:57 +0200 Subject: [PATCH 1/6] Clipper optimization: 1) Removed the already commented-out scaling / unscaling when doing "safe offsetting" 2) Removed some of the "safe offsetting" at calls where it never was used. 3) Reworked Clipper & ClipperUtils to pass Polygons / ExPolygons / Surfaces as input parameters without conversion to ClipperLib::Paths. This should save a lot of memory allocation and copying. 4) Reworked conversions from ClipperLib::Paths & PolyTree to Polygons / ExPolygons to use the move operator to avoid many unnecessary allocations. 5) Reworked some "union with safe ofsetting" to "offset_ex", which should be cheaper. --- src/clipper/clipper.cpp | 71 +-- src/clipper/clipper.hpp | 72 ++- src/libslic3r/Brim.cpp | 10 +- src/libslic3r/ClipperUtils.cpp | 698 +++++++++----------------- src/libslic3r/ClipperUtils.hpp | 404 +++++++++------ src/libslic3r/ExPolygon.hpp | 4 +- src/libslic3r/Fill/FillConcentric.cpp | 2 +- src/libslic3r/Layer.cpp | 2 +- src/libslic3r/Polygon.cpp | 2 +- src/libslic3r/Polygon.hpp | 18 + src/libslic3r/Polyline.hpp | 18 + src/libslic3r/SLA/ConcaveHull.cpp | 17 +- src/libslic3r/SLA/Pad.cpp | 14 +- src/libslic3r/TriangleMesh.cpp | 4 +- src/slic3r/GUI/3DBed.cpp | 2 +- 15 files changed, 616 insertions(+), 722 deletions(-) diff --git a/src/clipper/clipper.cpp b/src/clipper/clipper.cpp index 06c91bf3a..0285d9167 100644 --- a/src/clipper/clipper.cpp +++ b/src/clipper/clipper.cpp @@ -759,48 +759,6 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed) return result; } -bool ClipperBase::AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed) -{ - CLIPPERLIB_PROFILE_FUNC(); - std::vector num_edges(ppg.size(), 0); - int num_edges_total = 0; - for (size_t i = 0; i < ppg.size(); ++ i) { - const Path &pg = ppg[i]; - // Remove duplicate end point from a closed input path. - // Remove duplicate points from the end of the input path. - int highI = (int)pg.size() -1; - if (Closed) - while (highI > 0 && (pg[highI] == pg[0])) - --highI; - while (highI > 0 && (pg[highI] == pg[highI -1])) - --highI; - if ((Closed && highI < 2) || (!Closed && highI < 1)) - highI = -1; - num_edges[i] = highI + 1; - num_edges_total += highI + 1; - } - if (num_edges_total == 0) - return false; - - // Allocate a new edge array. - std::vector edges(num_edges_total); - // Fill in the edge array. - bool result = false; - TEdge *p_edge = edges.data(); - for (Paths::size_type i = 0; i < ppg.size(); ++i) - if (num_edges[i]) { - bool res = AddPathInternal(ppg[i], num_edges[i] - 1, PolyTyp, Closed, p_edge); - if (res) { - p_edge += num_edges[i]; - result = true; - } - } - if (result) - // At least some edges were generated. Remember the edge array. - m_edges.emplace_back(std::move(edges)); - return result; -} - bool ClipperBase::AddPathInternal(const Path &pg, int highI, PolyType PolyTyp, bool Closed, TEdge* edges) { CLIPPERLIB_PROFILE_FUNC(); @@ -1103,7 +1061,7 @@ bool Clipper::Execute(ClipType clipType, Paths &solution, CLIPPERLIB_PROFILE_FUNC(); if (m_HasOpenPaths) throw clipperException("Error: PolyTree struct is needed for open path clipping."); - solution.resize(0); + solution.clear(); m_SubjFillType = subjFillType; m_ClipFillType = clipFillType; m_ClipType = clipType; @@ -3426,13 +3384,6 @@ void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType } //------------------------------------------------------------------------------ -void ClipperOffset::AddPaths(const Paths& paths, JoinType joinType, EndType endType) -{ - for (const Path &path : paths) - AddPath(path, joinType, endType); -} -//------------------------------------------------------------------------------ - void ClipperOffset::FixOrientations() { //fixup orientations of all closed paths if the orientation of the @@ -3875,28 +3826,16 @@ void ReversePaths(Paths& p) } //------------------------------------------------------------------------------ -void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType) +Paths SimplifyPolygon(const Path &in_poly, PolyFillType fillType) { Clipper c; c.StrictlySimple(true); c.AddPath(in_poly, ptSubject, true); - c.Execute(ctUnion, out_polys, fillType, fillType); + Paths out; + c.Execute(ctUnion, out, fillType, fillType); + return out; } -//------------------------------------------------------------------------------ -void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType) -{ - Clipper c; - c.StrictlySimple(true); - c.AddPaths(in_polys, ptSubject, true); - c.Execute(ctUnion, out_polys, fillType, fillType); -} -//------------------------------------------------------------------------------ - -void SimplifyPolygons(Paths &polys, PolyFillType fillType) -{ - SimplifyPolygons(polys, polys, fillType); -} //------------------------------------------------------------------------------ inline double DistanceSqrd(const IntPoint& pt1, const IntPoint& pt2) diff --git a/src/clipper/clipper.hpp b/src/clipper/clipper.hpp index c32bcf87b..36b9beee5 100644 --- a/src/clipper/clipper.hpp +++ b/src/clipper/clipper.hpp @@ -191,9 +191,16 @@ double Area(const Path &poly); inline bool Orientation(const Path &poly) { return Area(poly) >= 0; } int PointInPolygon(const IntPoint &pt, const Path &path); -void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd); -void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd); -void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd); +Paths SimplifyPolygon(const Path &in_poly, PolyFillType fillType = pftEvenOdd); +template +inline Paths SimplifyPolygons(PathsProvider &&in_polys, PolyFillType fillType = pftEvenOdd) { + Clipper c; + c.StrictlySimple(true); + c.AddPaths(std::forward(in_polys), ptSubject, true); + Paths out; + c.Execute(ctUnion, out, fillType, fillType); + return out; +} void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415); void CleanPolygon(Path& poly, double distance = 1.415); @@ -300,7 +307,58 @@ public: m_HasOpenPaths(false) {} ~ClipperBase() { Clear(); } bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed); - bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed); + + template + bool AddPaths(PathsProvider &&paths_provider, PolyType PolyTyp, bool Closed) + { + size_t num_paths = paths_provider.size(); + if (num_paths == 0) + return false; + if (num_paths == 1) + return AddPath(*paths_provider.begin(), PolyTyp, Closed); + + std::vector num_edges(num_paths, 0); + int num_edges_total = 0; + size_t i = 0; + for (const Path &pg : paths_provider) { + // Remove duplicate end point from a closed input path. + // Remove duplicate points from the end of the input path. + int highI = (int)pg.size() -1; + if (Closed) + while (highI > 0 && (pg[highI] == pg[0])) + --highI; + while (highI > 0 && (pg[highI] == pg[highI -1])) + --highI; + if ((Closed && highI < 2) || (!Closed && highI < 1)) + highI = -1; + num_edges[i ++] = highI + 1; + num_edges_total += highI + 1; + } + if (num_edges_total == 0) + return false; + + // Allocate a new edge array. + std::vector edges(num_edges_total); + // Fill in the edge array. + bool result = false; + TEdge *p_edge = edges.data(); + i = 0; + for (const Path &pg : paths_provider) { + if (num_edges[i]) { + bool res = AddPathInternal(pg, num_edges[i] - 1, PolyTyp, Closed, p_edge); + if (res) { + p_edge += num_edges[i]; + result = true; + } + } + ++ i; + } + if (result) + // At least some edges were generated. Remember the edge array. + m_edges.emplace_back(std::move(edges)); + return result; + } + void Clear(); IntRect GetBounds(); // By default, when three or more vertices are collinear in input polygons (subject or clip), the Clipper object removes the 'inner' vertices before clipping. @@ -461,7 +519,11 @@ public: MiterLimit(miterLimit), ArcTolerance(roundPrecision), ShortestEdgeLength(shortestEdgeLength), m_lowest(-1, 0) {} ~ClipperOffset() { Clear(); } void AddPath(const Path& path, JoinType joinType, EndType endType); - void AddPaths(const Paths& paths, JoinType joinType, EndType endType); + template + void AddPaths(PathsProvider &&paths, JoinType joinType, EndType endType) { + for (const Path &path : paths) + AddPath(path, joinType, endType); + } void Execute(Paths& solution, double delta); void Execute(PolyTree& solution, double delta); void Clear(); diff --git a/src/libslic3r/Brim.cpp b/src/libslic3r/Brim.cpp index 19f5ae82e..16b81e488 100644 --- a/src/libslic3r/Brim.cpp +++ b/src/libslic3r/Brim.cpp @@ -139,7 +139,7 @@ static ExPolygons top_level_outer_brim_area(const Print &print, const ConstPrint Polygons no_brim_area_object; for (const ExPolygon &ex_poly : object->layers().front()->lslices) { if ((brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner) && is_top_outer_brim) - append(brim_area_object, diff_ex(offset_ex(ex_poly.contour, brim_width + brim_offset), offset_ex(ex_poly.contour, brim_offset))); + append(brim_area_object, diff_ex(offset(ex_poly.contour, brim_width + brim_offset), offset(ex_poly.contour, brim_offset))); if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btNoBrim) append(no_brim_area_object, offset(ex_poly.holes, -no_brim_offset)); @@ -183,14 +183,14 @@ static ExPolygons inner_brim_area(const Print &print, const ConstPrintObjectPtrs if (top_outer_brim) no_brim_area_object.emplace_back(ex_poly); else - append(brim_area_object, diff_ex(offset_ex(ex_poly.contour, brim_width + brim_offset), offset_ex(ex_poly.contour, brim_offset))); + append(brim_area_object, diff_ex(offset(ex_poly.contour, brim_width + brim_offset), offset(ex_poly.contour, brim_offset))); } if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btOuterAndInner) append(brim_area_object, diff_ex(offset_ex(ex_poly.holes, -brim_offset), offset_ex(ex_poly.holes, -brim_width - brim_offset))); if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btNoBrim) - append(no_brim_area_object, offset_ex(ex_poly.contour, no_brim_offset)); + append(no_brim_area_object, to_expolygons(offset(ex_poly.contour, no_brim_offset))); if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btNoBrim) append(no_brim_area_object, offset_ex(ex_poly.holes, -no_brim_offset)); @@ -317,7 +317,7 @@ static void make_inner_brim(const Print &print, const ConstPrintObjectPtrs &top_ islands_ex = offset_ex(islands_ex, -float(flow.scaled_spacing()), jtSquare); } - loops = union_pt_chained_outside_in(loops, false); + loops = union_pt_chained_outside_in(loops); std::reverse(loops.begin(), loops.end()); extrusion_entities_append_loops(brim.entities, std::move(loops), erSkirt, float(flow.mm3_per_mm()), float(flow.width()), float(print.skirt_first_layer_height())); @@ -342,7 +342,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance poly.douglas_peucker(SCALED_RESOLUTION); polygons_append(loops, offset(islands, -0.5f * float(flow.scaled_spacing()))); } - loops = union_pt_chained_outside_in(loops, false); + loops = union_pt_chained_outside_in(loops); std::vector loops_pl_by_levels; { diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index 477dbf6f1..1cd4a7c2f 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -24,7 +24,6 @@ namespace Slic3r { #ifdef CLIPPER_UTILS_DEBUG -bool clipper_export_enabled = false; // For debugging the Clipper library, for providing bug reports to the Clipper author. bool export_clipper_input_polygons_bin(const char *path, const ClipperLib::Paths &input_subject, const ClipperLib::Paths &input_clip) { @@ -57,207 +56,137 @@ err: } #endif /* CLIPPER_UTILS_DEBUG */ -#ifdef CLIPPERUTILS_OFFSET_SCALE -void scaleClipperPolygon(ClipperLib::Path &polygon) -{ - CLIPPERUTILS_PROFILE_FUNC(); - for (ClipperLib::Path::iterator pit = polygon.begin(); pit != polygon.end(); ++pit) { - pit->X <<= CLIPPER_OFFSET_POWER_OF_2; - pit->Y <<= CLIPPER_OFFSET_POWER_OF_2; - } +namespace ClipperUtils { + Points SinglePathProvider::s_end; } -void scaleClipperPolygons(ClipperLib::Paths &polygons) +static ExPolygons PolyTreeToExPolygons(ClipperLib::PolyTree &&polytree) { - CLIPPERUTILS_PROFILE_FUNC(); - for (ClipperLib::Paths::iterator it = polygons.begin(); it != polygons.end(); ++it) - for (ClipperLib::Path::iterator pit = (*it).begin(); pit != (*it).end(); ++pit) { - pit->X <<= CLIPPER_OFFSET_POWER_OF_2; - pit->Y <<= CLIPPER_OFFSET_POWER_OF_2; + struct Inner { + static void PolyTreeToExPolygonsRecursive(ClipperLib::PolyNode &polynode, ExPolygons *expolygons) + { + size_t cnt = expolygons->size(); + expolygons->resize(cnt + 1); + (*expolygons)[cnt].contour.points = std::move(polynode.Contour); + (*expolygons)[cnt].holes.resize(polynode.ChildCount()); + for (int i = 0; i < polynode.ChildCount(); ++ i) { + (*expolygons)[cnt].holes[i].points = std::move(polynode.Childs[i]->Contour); + // Add outer polygons contained by (nested within) holes. + for (int j = 0; j < polynode.Childs[i]->ChildCount(); ++ j) + PolyTreeToExPolygonsRecursive(*polynode.Childs[i]->Childs[j], expolygons); + } } -} -void unscaleClipperPolygon(ClipperLib::Path &polygon) -{ - CLIPPERUTILS_PROFILE_FUNC(); - for (ClipperLib::Path::iterator pit = polygon.begin(); pit != polygon.end(); ++pit) { - pit->X += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA; - pit->Y += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA; - pit->X >>= CLIPPER_OFFSET_POWER_OF_2; - pit->Y >>= CLIPPER_OFFSET_POWER_OF_2; - } -} - -void unscaleClipperPolygons(ClipperLib::Paths &polygons) -{ - CLIPPERUTILS_PROFILE_FUNC(); - for (ClipperLib::Paths::iterator it = polygons.begin(); it != polygons.end(); ++it) - for (ClipperLib::Path::iterator pit = (*it).begin(); pit != (*it).end(); ++pit) { - pit->X += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA; - pit->Y += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA; - pit->X >>= CLIPPER_OFFSET_POWER_OF_2; - pit->Y >>= CLIPPER_OFFSET_POWER_OF_2; + static size_t PolyTreeCountExPolygons(const ClipperLib::PolyNode &polynode) + { + size_t cnt = 1; + for (int i = 0; i < polynode.ChildCount(); ++ i) { + for (int j = 0; j < polynode.Childs[i]->ChildCount(); ++ j) + cnt += PolyTreeCountExPolygons(*polynode.Childs[i]->Childs[j]); + } + return cnt; } -} -#endif // CLIPPERUTILS_OFFSET_SCALE + }; -//----------------------------------------------------------- -// legacy code from Clipper documentation -void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, ExPolygons* expolygons) -{ - size_t cnt = expolygons->size(); - expolygons->resize(cnt + 1); - (*expolygons)[cnt].contour = ClipperPath_to_Slic3rPolygon(polynode.Contour); - (*expolygons)[cnt].holes.resize(polynode.ChildCount()); - for (int i = 0; i < polynode.ChildCount(); ++i) - { - (*expolygons)[cnt].holes[i] = ClipperPath_to_Slic3rPolygon(polynode.Childs[i]->Contour); - //Add outer polygons contained by (nested within) holes ... - for (int j = 0; j < polynode.Childs[i]->ChildCount(); ++j) - AddOuterPolyNodeToExPolygons(*polynode.Childs[i]->Childs[j], expolygons); - } -} - -ExPolygons PolyTreeToExPolygons(ClipperLib::PolyTree& polytree) -{ ExPolygons retval; - for (int i = 0; i < polytree.ChildCount(); ++i) - AddOuterPolyNodeToExPolygons(*polytree.Childs[i], &retval); - return retval; -} -//----------------------------------------------------------- - -Slic3r::Polygon ClipperPath_to_Slic3rPolygon(const ClipperLib::Path &input) -{ - Polygon retval; - for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit) - retval.points.emplace_back(pit->x(), pit->y()); + size_t cnt = 0; + for (int i = 0; i < polytree.ChildCount(); ++ i) + cnt += Inner::PolyTreeCountExPolygons(*polytree.Childs[i]); + retval.reserve(cnt); + for (int i = 0; i < polytree.ChildCount(); ++ i) + Inner::PolyTreeToExPolygonsRecursive(std::move(*polytree.Childs[i]), &retval); return retval; } -Slic3r::Polyline ClipperPath_to_Slic3rPolyline(const ClipperLib::Path &input) +Polylines PolyTreeToPolylines(ClipperLib::PolyTree &&polytree) { - Polyline retval; - for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit) - retval.points.emplace_back(pit->x(), pit->y()); - return retval; -} + struct Inner { + static void AddPolyNodeToPaths(ClipperLib::PolyNode &polynode, Polylines &out) + { + if (! polynode.Contour.empty()) + out.emplace_back(std::move(polynode.Contour)); + for (ClipperLib::PolyNode *child : polynode.Childs) + AddPolyNodeToPaths(*child, out); + } + }; -Slic3r::Polygons ClipperPaths_to_Slic3rPolygons(const ClipperLib::Paths &input) -{ - Slic3r::Polygons retval; - retval.reserve(input.size()); - for (ClipperLib::Paths::const_iterator it = input.begin(); it != input.end(); ++it) - retval.emplace_back(ClipperPath_to_Slic3rPolygon(*it)); - return retval; -} - -Slic3r::Polylines ClipperPaths_to_Slic3rPolylines(const ClipperLib::Paths &input) -{ - Slic3r::Polylines retval; - retval.reserve(input.size()); - for (ClipperLib::Paths::const_iterator it = input.begin(); it != input.end(); ++it) - retval.emplace_back(ClipperPath_to_Slic3rPolyline(*it)); - return retval; + Polylines out; + out.reserve(polytree.Total()); + Inner::AddPolyNodeToPaths(polytree, out); + return out; } ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input) { - // init Clipper ClipperLib::Clipper clipper; - clipper.Clear(); - - // perform union clipper.AddPaths(input, ClipperLib::ptSubject, true); ClipperLib::PolyTree polytree; clipper.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); // offset results work with both EvenOdd and NonZero - - // write to ExPolygons object - return PolyTreeToExPolygons(polytree); + return PolyTreeToExPolygons(std::move(polytree)); } -ClipperLib::Path Slic3rMultiPoint_to_ClipperPath(const MultiPoint &input) +// Offset outside by 10um, one by one. +template +static ClipperLib::Paths safety_offset(PathsProvider &&paths) { - ClipperLib::Path retval; - for (Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit) - retval.emplace_back((*pit)(0), (*pit)(1)); - return retval; -} - -ClipperLib::Path Slic3rMultiPoint_to_ClipperPath_reversed(const Slic3r::MultiPoint &input) -{ - ClipperLib::Path output; - output.reserve(input.points.size()); - for (Slic3r::Points::const_reverse_iterator pit = input.points.rbegin(); pit != input.points.rend(); ++pit) - output.emplace_back((*pit)(0), (*pit)(1)); - return output; -} - -ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const Polygons &input) -{ - ClipperLib::Paths retval; - for (Polygons::const_iterator it = input.begin(); it != input.end(); ++it) - retval.emplace_back(Slic3rMultiPoint_to_ClipperPath(*it)); - return retval; -} - -ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const ExPolygons &input) -{ - ClipperLib::Paths retval; - for (auto &ep : input) { - retval.emplace_back(Slic3rMultiPoint_to_ClipperPath(ep.contour)); - - for (auto &h : ep.holes) - retval.emplace_back(Slic3rMultiPoint_to_ClipperPath(h)); + ClipperLib::ClipperOffset co; + ClipperLib::Paths out; + out.reserve(paths.size()); + ClipperLib::Paths out_this; + for (const ClipperLib::Path &path : paths) { + co.Clear(); + co.MiterLimit = 2.; + co.AddPath(path, ClipperLib::jtMiter, ClipperLib::etClosedPolygon); + co.Execute(out_this, ClipperSafetyOffset); + append(out, std::move(out_this)); } - - return retval; + return out; } -ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const Polylines &input) +static ClipperLib::Paths safety_offset(const ClipperLib::Paths &paths) { - ClipperLib::Paths retval; - for (Polylines::const_iterator it = input.begin(); it != input.end(); ++it) - retval.emplace_back(Slic3rMultiPoint_to_ClipperPath(*it)); - return retval; + return safety_offset(paths); } -ClipperLib::Paths _offset(ClipperLib::Paths &&input, ClipperLib::EndType endType, const float delta, ClipperLib::JoinType joinType, double miterLimit) +static void safety_offset(ClipperLib::Paths *paths) +{ + *paths = safety_offset(*paths); +} + +template +ClipperLib::Paths _offset(PathsProvider &&input, ClipperLib::EndType endType, const float delta, ClipperLib::JoinType joinType, double miterLimit) { -#ifdef CLIPPERUTILS_OFFSET_SCALE - // scale input - scaleClipperPolygons(input); -#endif // CLIPPERUTILS_OFFSET_SCALE - // perform offset ClipperLib::ClipperOffset co; if (joinType == jtRound) co.ArcTolerance = miterLimit; else co.MiterLimit = miterLimit; -#ifdef CLIPPERUTILS_OFFSET_SCALE - float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE); -#else // CLIPPERUTILS_OFFSET_SCALE float delta_scaled = delta; -#endif // CLIPPERUTILS_OFFSET_SCALE co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); - co.AddPaths(input, joinType, endType); + co.AddPaths(std::forward(input), joinType, endType); ClipperLib::Paths retval; co.Execute(retval, delta_scaled); - -#ifdef CLIPPERUTILS_OFFSET_SCALE - // unscale output - unscaleClipperPolygons(retval); -#endif // CLIPPERUTILS_OFFSET_SCALE return retval; } -ClipperLib::Paths _offset(ClipperLib::Path &&input, ClipperLib::EndType endType, const float delta, ClipperLib::JoinType joinType, double miterLimit) -{ - ClipperLib::Paths paths; - paths.emplace_back(std::move(input)); - return _offset(std::move(paths), endType, delta, joinType, miterLimit); -} +Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType, double miterLimit) + { return to_polygons(_offset(ClipperUtils::SinglePathProvider(polygon.points), ClipperLib::etClosedPolygon, delta, joinType, miterLimit)); } + +#ifdef CLIPPERUTILS_UNSAFE_OFFSET +Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType, double miterLimit) + { return to_polygons(_offset(ClipperUtils::PolygonsProvider(polygons), ClipperLib::etClosedPolygon, delta, joinType, miterLimit)); } +#endif // CLIPPERUTILS_UNSAFE_OFFSET + +Slic3r::Polygons offset(const Slic3r::Polyline &polyline, const float delta, ClipperLib::JoinType joinType, double miterLimit) + { return to_polygons(_offset(ClipperUtils::SinglePathProvider(polyline.points), ClipperLib::etOpenButt, delta, joinType, miterLimit)); } +Slic3r::Polygons offset(const Slic3r::Polylines &polylines, const float delta, ClipperLib::JoinType joinType, double miterLimit) + { return to_polygons(_offset(ClipperUtils::PolylinesProvider(polylines), ClipperLib::etOpenButt, delta, joinType, miterLimit)); } + +#ifdef CLIPPERUTILS_UNSAFE_OFFSET +Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType, double miterLimit) + { return ClipperPaths_to_Slic3rExPolygons(_offset(ClipperUtils::PolygonsProvider(polygons), ClipperLib::etClosedPolygon, delta, joinType, miterLimit)); } +#endif // CLIPPERUTILS_UNSAFE_OFFSET // This is a safe variant of the polygon offset, tailored for a single ExPolygon: // a single polygon with multiple non-overlapping holes. @@ -267,28 +196,16 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta, { // printf("new ExPolygon offset\n"); // 1) Offset the outer contour. -#ifdef CLIPPERUTILS_OFFSET_SCALE - float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE); -#else // CLIPPERUTILS_OFFSET_SCALE float delta_scaled = delta; -#endif // CLIPPERUTILS_OFFSET_SCALE ClipperLib::Paths contours; { - ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath(expolygon.contour); -#ifdef CLIPPERUTILS_OFFSET_SCALE - scaleClipperPolygon(input); -#endif // CLIPPERUTILS_OFFSET_SCALE ClipperLib::ClipperOffset co; if (joinType == jtRound) -#ifdef CLIPPERUTILS_OFFSET_SCALE - co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); -#else // CLIPPERUTILS_OFFSET_SCALE co.ArcTolerance = miterLimit; -#endif // CLIPPERUTILS_OFFSET_SCALE else co.MiterLimit = miterLimit; co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); - co.AddPath(input, joinType, ClipperLib::etClosedPolygon); + co.AddPath(expolygon.contour.points, joinType, ClipperLib::etClosedPolygon); co.Execute(contours, delta_scaled); } @@ -297,22 +214,17 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta, { holes.reserve(expolygon.holes.size()); for (Polygons::const_iterator it_hole = expolygon.holes.begin(); it_hole != expolygon.holes.end(); ++ it_hole) { - ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole); -#ifdef CLIPPERUTILS_OFFSET_SCALE - scaleClipperPolygon(input); -#endif // CLIPPERUTILS_OFFSET_SCALE ClipperLib::ClipperOffset co; if (joinType == jtRound) -#ifdef CLIPPERUTILS_OFFSET_SCALE - co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); -#else // CLIPPERUTILS_OFFSET_SCALE co.ArcTolerance = miterLimit; -#endif // CLIPPERUTILS_OFFSET_SCALE else co.MiterLimit = miterLimit; co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); - co.AddPath(input, joinType, ClipperLib::etClosedPolygon); + co.AddPath(it_hole->points, joinType, ClipperLib::etClosedPolygon); ClipperLib::Paths out; + // Execute reorients the contours so that the outer most contour has a positive area. Thus the output + // contours will be CCW oriented even though the input paths are CW oriented. + // Offset is applied after contour reorientation, thus the signum of the offset value is reversed. co.Execute(out, - delta_scaled); append(holes, std::move(out)); } @@ -330,10 +242,6 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta, clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); } - // 4) Unscale the output. -#ifdef CLIPPERUTILS_OFFSET_SCALE - unscaleClipperPolygons(output); -#endif // CLIPPERUTILS_OFFSET_SCALE return output; } @@ -343,76 +251,59 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit) { -#ifdef CLIPPERUTILS_OFFSET_SCALE - float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE); -#else // CLIPPERUTILS_OFFSET_SCALE float delta_scaled = delta; -#endif // CLIPPERUTILS_OFFSET_SCALE // Offsetted ExPolygons before they are united. ClipperLib::Paths contours_cummulative; contours_cummulative.reserve(expolygons.size()); // How many non-empty offsetted expolygons were actually collected into contours_cummulative? // If only one, then there is no need to do a final union. size_t expolygons_collected = 0; - for (Slic3r::ExPolygons::const_iterator it_expoly = expolygons.begin(); it_expoly != expolygons.end(); ++ it_expoly) { + for (const Slic3r::ExPolygon &expoly : expolygons) { // 1) Offset the outer contour. ClipperLib::Paths contours; { - ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath(it_expoly->contour); -#ifdef CLIPPERUTILS_OFFSET_SCALE - scaleClipperPolygon(input); -#endif // CLIPPERUTILS_OFFSET_SCALE ClipperLib::ClipperOffset co; if (joinType == jtRound) -#ifdef CLIPPERUTILS_OFFSET_SCALE - co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); -#else // CLIPPERUTILS_OFFSET_SCALE co.ArcTolerance = miterLimit; -#endif // CLIPPERUTILS_OFFSET_SCALE else co.MiterLimit = miterLimit; co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); - co.AddPath(input, joinType, ClipperLib::etClosedPolygon); + co.AddPath(expoly.contour.points, joinType, ClipperLib::etClosedPolygon); co.Execute(contours, delta_scaled); } if (contours.empty()) // No need to try to offset the holes. continue; - if (it_expoly->holes.empty()) { + if (expoly.holes.empty()) { // No need to subtract holes from the offsetted expolygon, we are done. - contours_cummulative.insert(contours_cummulative.end(), contours.begin(), contours.end()); + append(contours_cummulative, std::move(contours)); ++ expolygons_collected; } else { // 2) Offset the holes one by one, collect the offsetted holes. ClipperLib::Paths holes; { - for (Polygons::const_iterator it_hole = it_expoly->holes.begin(); it_hole != it_expoly->holes.end(); ++ it_hole) { - ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole); -#ifdef CLIPPERUTILS_OFFSET_SCALE - scaleClipperPolygon(input); -#endif // CLIPPERUTILS_OFFSET_SCALE + for (const Polygon &hole : expoly.holes) { ClipperLib::ClipperOffset co; if (joinType == jtRound) -#ifdef CLIPPERUTILS_OFFSET_SCALE - co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); -#else // CLIPPERUTILS_OFFSET_SCALE co.ArcTolerance = miterLimit; -#endif // CLIPPERUTILS_OFFSET_SCALE else co.MiterLimit = miterLimit; co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); - co.AddPath(input, joinType, ClipperLib::etClosedPolygon); + co.AddPath(hole.points, joinType, ClipperLib::etClosedPolygon); ClipperLib::Paths out; + // Execute reorients the contours so that the outer most contour has a positive area. Thus the output + // contours will be CCW oriented even though the input paths are CW oriented. + // Offset is applied after contour reorientation, thus the signum of the offset value is reversed. co.Execute(out, - delta_scaled); - holes.insert(holes.end(), out.begin(), out.end()); + append(holes, std::move(out)); } } // 3) Subtract holes from the contours. if (holes.empty()) { // No hole remaining after an offset. Just copy the outer contour. - contours_cummulative.insert(contours_cummulative.end(), contours.begin(), contours.end()); + append(contours_cummulative, std::move(contours)); ++ expolygons_collected; } else if (delta < 0) { // Negative offset. There is a chance, that the offsetted hole intersects the outer contour. @@ -424,7 +315,7 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delt ClipperLib::Paths output; clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); if (! output.empty()) { - contours_cummulative.insert(contours_cummulative.end(), output.begin(), output.end()); + append(contours_cummulative, std::move(output)); ++ expolygons_collected; } else { // The offsetted holes have eaten up the offsetted outer contour. @@ -434,11 +325,11 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delt // area than the original hole or even disappear, therefore there will be no new intersections. // Just collect the reversed holes. contours_cummulative.reserve(contours.size() + holes.size()); - contours_cummulative.insert(contours_cummulative.end(), contours.begin(), contours.end()); + append(contours_cummulative, std::move(contours)); // Reverse the holes in place. for (size_t i = 0; i < holes.size(); ++ i) std::reverse(holes[i].begin(), holes[i].end()); - contours_cummulative.insert(contours_cummulative.end(), holes.begin(), holes.end()); + append(contours_cummulative, std::move(holes)); ++ expolygons_collected; } } @@ -457,25 +348,11 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delt output = std::move(contours_cummulative); } -#ifdef CLIPPERUTILS_OFFSET_SCALE - // 4) Unscale the output. - unscaleClipperPolygons(output); -#endif // CLIPPERUTILS_OFFSET_SCALE return output; } -ClipperLib::Paths -_offset2(const Polygons &polygons, const float delta1, const float delta2, - const ClipperLib::JoinType joinType, const double miterLimit) +ClipperLib::Paths _offset2(const Polygons &polygons, const float delta1, const float delta2, const ClipperLib::JoinType joinType, const double miterLimit) { - // read input - ClipperLib::Paths input = Slic3rMultiPoints_to_ClipperPaths(polygons); - -#ifdef CLIPPERUTILS_OFFSET_SCALE - // scale input - scaleClipperPolygons(input); -#endif // CLIPPERUTILS_OFFSET_SCALE - // prepare ClipperOffset object ClipperLib::ClipperOffset co; if (joinType == jtRound) { @@ -483,18 +360,13 @@ _offset2(const Polygons &polygons, const float delta1, const float delta2, } else { co.MiterLimit = miterLimit; } -#ifdef CLIPPERUTILS_OFFSET_SCALE - float delta_scaled1 = delta1 * float(CLIPPER_OFFSET_SCALE); - float delta_scaled2 = delta2 * float(CLIPPER_OFFSET_SCALE); -#else // CLIPPERUTILS_OFFSET_SCALE float delta_scaled1 = delta1; float delta_scaled2 = delta2; -#endif // CLIPPERUTILS_OFFSET_SCALE co.ShortestEdgeLength = double(std::max(std::abs(delta_scaled1), std::abs(delta_scaled2)) * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR); // perform first offset ClipperLib::Paths output1; - co.AddPaths(input, joinType, ClipperLib::etClosedPolygon); + co.AddPaths(ClipperUtils::PolygonsProvider(polygons), joinType, ClipperLib::etClosedPolygon); co.Execute(output1, delta_scaled1); // perform second offset @@ -503,33 +375,17 @@ _offset2(const Polygons &polygons, const float delta1, const float delta2, ClipperLib::Paths retval; co.Execute(retval, delta_scaled2); -#ifdef CLIPPERUTILS_OFFSET_SCALE - // unscale output - unscaleClipperPolygons(retval); -#endif // CLIPPERUTILS_OFFSET_SCALE return retval; } -Polygons -offset2(const Polygons &polygons, const float delta1, const float delta2, - const ClipperLib::JoinType joinType, const double miterLimit) +Polygons offset2(const Polygons &polygons, const float delta1, const float delta2, const ClipperLib::JoinType joinType, const double miterLimit) { - // perform offset - ClipperLib::Paths output = _offset2(polygons, delta1, delta2, joinType, miterLimit); - - // convert into ExPolygons - return ClipperPaths_to_Slic3rPolygons(output); + return to_polygons(_offset2(polygons, delta1, delta2, joinType, miterLimit)); } -ExPolygons -offset2_ex(const Polygons &polygons, const float delta1, const float delta2, - const ClipperLib::JoinType joinType, const double miterLimit) +ExPolygons offset2_ex(const Polygons &polygons, const float delta1, const float delta2, const ClipperLib::JoinType joinType, const double miterLimit) { - // perform offset - ClipperLib::Paths output = _offset2(polygons, delta1, delta2, joinType, miterLimit); - - // convert into ExPolygons - return ClipperPaths_to_Slic3rExPolygons(output); + return ClipperPaths_to_Slic3rExPolygons(_offset2(polygons, delta1, delta2, joinType, miterLimit)); } //FIXME Vojtech: This functon may likely be optimized to avoid some of the Slic3r to Clipper @@ -545,64 +401,57 @@ ExPolygons offset2_ex(const ExPolygons &expolygons, const float delta1, return union_ex(polys); } -template -T _clipper_do(const ClipperLib::ClipType clipType, - TSubj && subject, - TClip && clip, - const ClipperLib::PolyFillType fillType, - const bool safety_offset_) +template +TResult _clipper_do( + const ClipperLib::ClipType clipType, + TSubj && subject, + TClip && clip, + const ClipperLib::PolyFillType fillType) { - // read input - ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(std::forward(subject)); - ClipperLib::Paths input_clip = Slic3rMultiPoints_to_ClipperPaths(std::forward(clip)); - - // perform safety offset - if (safety_offset_) { - if (clipType == ClipperLib::ctUnion) { - safety_offset(&input_subject); - } else { - safety_offset(&input_clip); - } - } - - // init Clipper ClipperLib::Clipper clipper; - clipper.Clear(); - - // add polygons - clipper.AddPaths(input_subject, ClipperLib::ptSubject, true); - clipper.AddPaths(input_clip, ClipperLib::ptClip, true); - - // perform operation - T retval; + clipper.AddPaths(std::forward(subject), ClipperLib::ptSubject, true); + clipper.AddPaths(std::forward(clip), ClipperLib::ptClip, true); + TResult retval; clipper.Execute(clipType, retval, fillType, fillType); return retval; } +template +TResult _clipper_do( + const ClipperLib::ClipType clipType, + TSubj && subject, + TClip && clip, + const ClipperLib::PolyFillType fillType, + const bool do_safety_offset) +{ + return do_safety_offset ? + (clipType == ClipperLib::ctUnion ? + _clipper_do(clipType, safety_offset(std::forward(subject)), std::forward(clip), fillType) : + _clipper_do(clipType, std::forward(subject), safety_offset(std::forward(clip)), fillType)) : + _clipper_do(clipType, std::forward(subject), std::forward(clip), fillType); +} + // 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 // of the operation is of the PolyTree type. -// This function implmenets a following workaround: +// This function implemenets a following workaround: // 1) Peform the Clipper operation with the output to Paths. This method handles overlaps in a reasonable time. // 2) Run Clipper Union once again to extract the PolyTree from the result of 1). -inline ClipperLib::PolyTree _clipper_do_polytree2(const ClipperLib::ClipType clipType, const Polygons &subject, - const Polygons &clip, const ClipperLib::PolyFillType fillType, const bool safety_offset_) +template +inline ClipperLib::PolyTree _clipper_do_polytree2( + const ClipperLib::ClipType clipType, + PathProvider1 &&subject, + PathProvider2 &&clip, + const ClipperLib::PolyFillType fillType) { - // read input - ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(subject); - ClipperLib::Paths input_clip = Slic3rMultiPoints_to_ClipperPaths(clip); - - // perform safety offset - if (safety_offset_) - safety_offset((clipType == ClipperLib::ctUnion) ? &input_subject : &input_clip); - ClipperLib::Clipper clipper; - clipper.AddPaths(input_subject, ClipperLib::ptSubject, true); - clipper.AddPaths(input_clip, ClipperLib::ptClip, true); + clipper.AddPaths(std::forward(subject), ClipperLib::ptSubject, true); + clipper.AddPaths(std::forward(clip), ClipperLib::ptClip, true); // Perform the operation with the output to input_subject. // This pass does not generate a PolyTree, which is a very expensive operation with the current Clipper library // if there are overapping edges. + ClipperLib::Paths input_subject; clipper.Execute(clipType, input_subject, fillType, fillType); // Perform an additional Union operation to generate the PolyTree ordering. clipper.Clear(); @@ -611,51 +460,75 @@ inline ClipperLib::PolyTree _clipper_do_polytree2(const ClipperLib::ClipType cli clipper.Execute(ClipperLib::ctUnion, retval, fillType, fillType); return retval; } - -ClipperLib::PolyTree _clipper_do_pl(const ClipperLib::ClipType clipType, const Polylines &subject, - const Polygons &clip, const ClipperLib::PolyFillType fillType, - const bool safety_offset_) +template +inline ClipperLib::PolyTree _clipper_do_polytree2( + const ClipperLib::ClipType clipType, + PathProvider1 &&subject, + PathProvider2 &&clip, + const ClipperLib::PolyFillType fillType, + const bool do_safety_offset) +{ + return do_safety_offset ? + (clipType == ClipperLib::ctUnion ? + _clipper_do_polytree2(clipType, safety_offset(std::forward(subject)), std::forward(clip), fillType) : + _clipper_do_polytree2(clipType, std::forward(subject), safety_offset(std::forward(clip)), fillType)) : + _clipper_do_polytree2(clipType, std::forward(subject), std::forward(clip), fillType); +} + +template +static inline Polygons _clipper(ClipperLib::ClipType clipType, TSubj &&subject, TClip &&clip, bool do_safety_offset) +{ + return to_polygons(_clipper_do(clipType, std::forward(subject), std::forward(clip), ClipperLib::pftNonZero, do_safety_offset)); +} + +Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset) + { return _clipper(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } +Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset) + { return _clipper(ClipperLib::ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } +Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset) + { return _clipper(ClipperLib::ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } +Slic3r::Polygons intersection(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset) + { return _clipper(ClipperLib::ctIntersection, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } +Slic3r::Polygons union_(const Slic3r::Polygons &subject, bool do_safety_offset) + { return _clipper(ClipperLib::ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), do_safety_offset); } +Slic3r::Polygons union_(const Slic3r::ExPolygons &subject, bool do_safety_offset) + { return _clipper(ClipperLib::ctUnion, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), do_safety_offset); } +Slic3r::Polygons union_(const Slic3r::Polygons &subject, const Slic3r::Polygons &subject2, bool do_safety_offset) + { return _clipper(ClipperLib::ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(subject2), do_safety_offset); } + +template +static ExPolygons _clipper_ex(ClipperLib::ClipType clipType, TSubject &&subject, TClip &&clip, bool do_safety_offset) + { return PolyTreeToExPolygons(_clipper_do_polytree2(clipType, std::forward(subject), std::forward(clip), ClipperLib::pftNonZero, do_safety_offset)); } + +Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } +Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } +Slic3r::ExPolygons intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } +Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } +Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), do_safety_offset); } +Slic3r::ExPolygons union_ex(const Slic3r::ExPolygons& subject) + { return PolyTreeToExPolygons(_clipper_do_polytree2(ClipperLib::ctUnion, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), ClipperLib::pftNonZero)); } +Slic3r::ExPolygons union_ex(const Slic3r::Surfaces& subject) + { return PolyTreeToExPolygons(_clipper_do_polytree2(ClipperLib::ctUnion, ClipperUtils::SurfacesProvider(subject), ClipperUtils::EmptyPathsProvider(), ClipperLib::pftNonZero)); } + +Polylines _clipper_pl(ClipperLib::ClipType clipType, const Polylines &subject, const Polygons &clip, bool do_safety_offset) { - // read input - ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(subject); - ClipperLib::Paths input_clip = Slic3rMultiPoints_to_ClipperPaths(clip); - - // perform safety offset - if (safety_offset_) safety_offset(&input_clip); - - // init Clipper ClipperLib::Clipper clipper; - clipper.Clear(); - - // add polygons - clipper.AddPaths(input_subject, ClipperLib::ptSubject, false); - clipper.AddPaths(input_clip, ClipperLib::ptClip, true); - - // perform operation + clipper.AddPaths(ClipperUtils::PolylinesProvider(subject), ClipperLib::ptSubject, false); + if (do_safety_offset) + clipper.AddPaths(safety_offset(ClipperUtils::PolygonsProvider(clip)), ClipperLib::ptClip, true); + else + clipper.AddPaths(ClipperUtils::PolygonsProvider(clip), ClipperLib::ptClip, true); ClipperLib::PolyTree retval; - clipper.Execute(clipType, retval, fillType, fillType); - return retval; + clipper.Execute(clipType, retval, ClipperLib::pftNonZero, ClipperLib::pftNonZero); + return PolyTreeToPolylines(std::move(retval)); } -Polygons _clipper(ClipperLib::ClipType clipType, const Polygons &subject, const Polygons &clip, bool safety_offset_) -{ - return ClipperPaths_to_Slic3rPolygons(_clipper_do(clipType, subject, clip, ClipperLib::pftNonZero, safety_offset_)); -} - -ExPolygons _clipper_ex(ClipperLib::ClipType clipType, const Polygons &subject, const Polygons &clip, bool safety_offset_) -{ - ClipperLib::PolyTree polytree = _clipper_do_polytree2(clipType, subject, clip, ClipperLib::pftNonZero, safety_offset_); - return PolyTreeToExPolygons(polytree); -} - -Polylines _clipper_pl(ClipperLib::ClipType clipType, const Polylines &subject, const Polygons &clip, bool safety_offset_) -{ - ClipperLib::Paths output; - ClipperLib::PolyTreeToPaths(_clipper_do_pl(clipType, subject, clip, ClipperLib::pftNonZero, safety_offset_), output); - return ClipperPaths_to_Slic3rPolylines(output); -} - -Polylines _clipper_pl(ClipperLib::ClipType clipType, const Polygons &subject, const Polygons &clip, bool safety_offset_) +Polylines _clipper_pl(ClipperLib::ClipType clipType, const Polygons &subject, const Polygons &clip, bool do_safety_offset) { // transform input polygons into polylines Polylines polylines; @@ -664,7 +537,7 @@ Polylines _clipper_pl(ClipperLib::ClipType clipType, const Polygons &subject, co polylines.emplace_back(polygon->operator Polyline()); // implicit call to split_at_first_point() // perform clipping - Polylines retval = _clipper_pl(clipType, polylines, clip, safety_offset_); + Polylines retval = _clipper_pl(clipType, polylines, clip, do_safety_offset); /* If the split_at_first_point() call above happens to split the polygon inside the clipping area we would get two consecutive polylines instead of a single one, so we go through them in order @@ -703,9 +576,7 @@ Polylines _clipper_pl(ClipperLib::ClipType clipType, const Polygons &subject, co return retval; } -Lines -_clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Polygons &clip, - bool safety_offset_) +Lines _clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Polygons &clip, bool do_safety_offset) { // convert Lines to Polylines Polylines polylines; @@ -714,7 +585,7 @@ _clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Polygons polylines.emplace_back(Polyline(line.a, line.b)); // perform operation - polylines = _clipper_pl(clipType, polylines, clip, safety_offset_); + polylines = _clipper_pl(clipType, polylines, clip, do_safety_offset); // convert Polylines to Lines Lines retval; @@ -723,24 +594,14 @@ _clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Polygons return retval; } -ClipperLib::PolyTree union_pt(const Polygons &subject, bool safety_offset_) +ClipperLib::PolyTree union_pt(const Polygons &subject) { - return _clipper_do(ClipperLib::ctUnion, subject, Polygons(), ClipperLib::pftEvenOdd, safety_offset_); + return _clipper_do(ClipperLib::ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), ClipperLib::pftEvenOdd); } -ClipperLib::PolyTree union_pt(const ExPolygons &subject, bool safety_offset_) +ClipperLib::PolyTree union_pt(const ExPolygons &subject) { - return _clipper_do(ClipperLib::ctUnion, subject, Polygons(), ClipperLib::pftEvenOdd, safety_offset_); -} - -ClipperLib::PolyTree union_pt(Polygons &&subject, bool safety_offset_) -{ - return _clipper_do(ClipperLib::ctUnion, std::move(subject), Polygons(), ClipperLib::pftEvenOdd, safety_offset_); -} - -ClipperLib::PolyTree union_pt(ExPolygons &&subject, bool safety_offset_) -{ - return _clipper_do(ClipperLib::ctUnion, std::move(subject), Polygons(), ClipperLib::pftEvenOdd, safety_offset_); + return _clipper_do(ClipperLib::ctUnion, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), ClipperLib::pftEvenOdd); } // Simple spatial ordering of Polynodes @@ -766,7 +627,7 @@ static void traverse_pt_noholes(const ClipperLib::PolyNodes &nodes, Polygons *ou foreach_node(nodes, [&out](const ClipperLib::PolyNode *node) { traverse_pt_noholes(node->Childs, out); - out->emplace_back(ClipperPath_to_Slic3rPolygon(node->Contour)); + out->emplace_back(node->Contour); if (node->IsHole()) out->back().reverse(); // ccw }); } @@ -782,7 +643,7 @@ static void traverse_pt_outside_in(const ClipperLib::PolyNodes &nodes, Polygons // Perform the ordering, push results recursively. //FIXME pass the last point to chain_clipper_polynodes? for (const ClipperLib::PolyNode *node : chain_clipper_polynodes(ordering_points, nodes)) { - retval->emplace_back(ClipperPath_to_Slic3rPolygon(node->Contour)); + retval->emplace_back(node->Contour); if (node->IsHole()) // Orient a hole, which is clockwise oriented, to CCW. retval->back().reverse(); @@ -791,9 +652,9 @@ static void traverse_pt_outside_in(const ClipperLib::PolyNodes &nodes, Polygons } } -Polygons union_pt_chained_outside_in(const Polygons &subject, bool safety_offset_) +Polygons union_pt_chained_outside_in(const Polygons &subject) { - ClipperLib::PolyTree polytree = union_pt(subject, safety_offset_); + ClipperLib::PolyTree polytree = union_pt(subject); Polygons retval; traverse_pt_outside_in(polytree.Childs, &retval); @@ -802,22 +663,19 @@ Polygons union_pt_chained_outside_in(const Polygons &subject, bool safety_offset Polygons simplify_polygons(const Polygons &subject, bool preserve_collinear) { - // convert into Clipper polygons - ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(subject); - ClipperLib::Paths output; if (preserve_collinear) { ClipperLib::Clipper c; c.PreserveCollinear(true); c.StrictlySimple(true); - c.AddPaths(input_subject, ClipperLib::ptSubject, true); + c.AddPaths(ClipperUtils::PolygonsProvider(subject), ClipperLib::ptSubject, true); c.Execute(ClipperLib::ctUnion, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); } else { - ClipperLib::SimplifyPolygons(input_subject, output, ClipperLib::pftNonZero); + output = ClipperLib::SimplifyPolygons(ClipperUtils::PolygonsProvider(subject), ClipperLib::pftNonZero); } // convert into Slic3r polygons - return ClipperPaths_to_Slic3rPolygons(output); + return to_polygons(std::move(output)); } ExPolygons simplify_polygons_ex(const Polygons &subject, bool preserve_collinear) @@ -825,76 +683,15 @@ ExPolygons simplify_polygons_ex(const Polygons &subject, bool preserve_collinear if (! preserve_collinear) return union_ex(simplify_polygons(subject, false)); - // convert into Clipper polygons - ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(subject); - - ClipperLib::PolyTree polytree; - + ClipperLib::PolyTree polytree; ClipperLib::Clipper c; c.PreserveCollinear(true); c.StrictlySimple(true); - c.AddPaths(input_subject, ClipperLib::ptSubject, true); + c.AddPaths(ClipperUtils::PolygonsProvider(subject), ClipperLib::ptSubject, true); c.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); // convert into ExPolygons - return PolyTreeToExPolygons(polytree); -} - -void safety_offset(ClipperLib::Paths* paths) -{ - CLIPPERUTILS_PROFILE_FUNC(); - -#ifdef CLIPPERUTILS_OFFSET_SCALE - // scale input - scaleClipperPolygons(*paths); -#endif // CLIPPERUTILS_OFFSET_SCALE - - // perform offset (delta = scale 1e-05) - ClipperLib::ClipperOffset co; -#ifdef CLIPPER_UTILS_DEBUG - if (clipper_export_enabled) { - static int iRun = 0; - export_clipper_input_polygons_bin(debug_out_path("safety_offset-polygons-%d", ++iRun).c_str(), *paths, ClipperLib::Paths()); - } -#endif /* CLIPPER_UTILS_DEBUG */ - ClipperLib::Paths out; - for (size_t i = 0; i < paths->size(); ++ i) { - ClipperLib::Path &path = (*paths)[i]; - co.Clear(); - co.MiterLimit = 2; - bool ccw = ClipperLib::Orientation(path); - if (! ccw) - std::reverse(path.begin(), path.end()); - { - CLIPPERUTILS_PROFILE_BLOCK(safety_offset_AddPaths); - co.AddPath((*paths)[i], ClipperLib::jtMiter, ClipperLib::etClosedPolygon); - } - { - CLIPPERUTILS_PROFILE_BLOCK(safety_offset_Execute); - // offset outside by 10um - ClipperLib::Paths out_this; -#ifdef CLIPPERUTILS_OFFSET_SCALE - co.Execute(out_this, ccw ? 10.f * float(CLIPPER_OFFSET_SCALE) : -10.f * float(CLIPPER_OFFSET_SCALE)); -#else // CLIPPERUTILS_OFFSET_SCALE - co.Execute(out_this, ccw ? 10.f : -10.f); -#endif // CLIPPERUTILS_OFFSET_SCALE - if (! ccw) { - // Reverse the resulting contours once again. - for (ClipperLib::Paths::iterator it = out_this.begin(); it != out_this.end(); ++ it) - std::reverse(it->begin(), it->end()); - } - if (out.empty()) - out = std::move(out_this); - else - std::move(std::begin(out_this), std::end(out_this), std::back_inserter(out)); - } - } - *paths = std::move(out); - -#ifdef CLIPPERUTILS_OFFSET_SCALE - // unscale output - unscaleClipperPolygons(*paths); -#endif // CLIPPERUTILS_OFFSET_SCALE + return PolyTreeToExPolygons(std::move(polytree)); } Polygons top_level_islands(const Slic3r::Polygons &polygons) @@ -903,14 +700,14 @@ Polygons top_level_islands(const Slic3r::Polygons &polygons) ClipperLib::Clipper clipper; clipper.Clear(); // perform union - clipper.AddPaths(Slic3rMultiPoints_to_ClipperPaths(polygons), ClipperLib::ptSubject, true); + clipper.AddPaths(ClipperUtils::PolygonsProvider(polygons), ClipperLib::ptSubject, true); ClipperLib::PolyTree polytree; clipper.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); // Convert only the top level islands to the output. Polygons out; out.reserve(polytree.ChildCount()); for (int i = 0; i < polytree.ChildCount(); ++i) - out.emplace_back(ClipperPath_to_Slic3rPolygon(polytree.Childs[i]->Contour)); + out.emplace_back(std::move(polytree.Childs[i]->Contour)); return out; } @@ -988,9 +785,6 @@ ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::v // Add a new point to the output, scale by CLIPPER_OFFSET_SCALE and round to ClipperLib::cInt. auto add_offset_point = [&out](Vec2d pt) { -#ifdef CLIPPERUTILS_OFFSET_SCALE - pt *= double(CLIPPER_OFFSET_SCALE); -#endif // CLIPPERUTILS_OFFSET_SCALE pt += Vec2d(0.5 - (pt.x() < 0), 0.5 - (pt.y() < 0)); out.emplace_back(ClipperLib::cInt(pt.x()), ClipperLib::cInt(pt.y())); }; @@ -1086,7 +880,7 @@ ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::v { ClipperLib::Path polytmp(out); unscaleClipperPolygon(polytmp); - Slic3r::Polygon offsetted = ClipperPath_to_Slic3rPolygon(polytmp); + Slic3r::Polygon offsetted(std::move(polytmp)); BoundingBox bbox = get_extents(contour); bbox.merge(get_extents(offsetted)); static int iRun = 0; @@ -1140,11 +934,7 @@ Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector> &deltas, double miter_limit) @@ -1186,11 +976,7 @@ for (const std::vector& ds : deltas) clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); } -#ifdef CLIPPERUTILS_OFFSET_SCALE - // 4) Unscale the output. - unscaleClipperPolygons(output); -#endif // CLIPPERUTILS_OFFSET_SCALE - return ClipperPaths_to_Slic3rPolygons(output); + return to_polygons(std::move(output)); } ExPolygons variable_offset_outer_ex(const ExPolygon &expoly, const std::vector> &deltas, double miter_limit) @@ -1221,24 +1007,18 @@ for (const std::vector& ds : deltas) #endif /* NDEBUG */ // 3) Subtract holes from the contours. -#ifdef CLIPPERUTILS_OFFSET_SCALE - unscaleClipperPolygons(contours); -#endif // CLIPPERUTILS_OFFSET_SCALE ExPolygons output; if (holes.empty()) { output.reserve(contours.size()); for (ClipperLib::Path &path : contours) - output.emplace_back(ClipperPath_to_Slic3rPolygon(path)); + output.emplace_back(std::move(path)); } else { ClipperLib::Clipper clipper; -#ifdef CLIPPERUTILS_OFFSET_SCALE - unscaleClipperPolygons(holes); -#endif // CLIPPERUTILS_OFFSET_SCALE clipper.AddPaths(contours, ClipperLib::ptSubject, true); clipper.AddPaths(holes, ClipperLib::ptClip, true); ClipperLib::PolyTree polytree; clipper.Execute(ClipperLib::ctDifference, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); - output = PolyTreeToExPolygons(polytree); + output = PolyTreeToExPolygons(std::move(polytree)); } return output; @@ -1273,24 +1053,18 @@ ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector(nullptr); } + // all iterators point to end. + constexpr bool operator==(const iterator &rhs) const { return true; } + constexpr bool operator!=(const iterator &rhs) const { return false; } + constexpr const Points& operator++(int) { assert(false); return *static_cast(nullptr); } + constexpr iterator& operator++() { assert(false); return *this; } + }; + + constexpr EmptyPathsProvider() {} + static constexpr iterator cend() throw() { return iterator{}; } + static constexpr iterator end() throw() { return cend(); } + static constexpr iterator cbegin() throw() { return cend(); } + static constexpr iterator begin() throw() { return cend(); } + static constexpr size_t size() throw() { return 0; } + }; + + class SinglePathProvider { + public: + SinglePathProvider(const Points &points) : m_points(points) {} + + struct iterator : public PathsProviderIteratorBase { + public: + explicit iterator(const Points &points) : m_ptr(&points) {} + const Points& operator*() const { return *m_ptr; } + bool operator==(const iterator &rhs) const { return m_ptr == rhs.m_ptr; } + bool operator!=(const iterator &rhs) const { return !(*this == rhs); } + const Points& operator++(int) { auto out = m_ptr; m_ptr = &s_end; return *out; } + iterator& operator++() { m_ptr = &s_end; return *this; } + private: + const Points *m_ptr; + }; + + iterator cbegin() const { return iterator(m_points); } + iterator begin() const { return this->cbegin(); } + iterator cend() const { return iterator(s_end); } + iterator end() const { return this->cend(); } + size_t size() const { return 1; } + + private: + const Points &m_points; + static Points s_end; + }; + + template + class MultiPointsProvider { + public: + MultiPointsProvider(const std::vector &multipoints) : m_multipoints(multipoints) {} + + struct iterator : public PathsProviderIteratorBase { + public: + explicit iterator(typename std::vector::const_iterator it) : m_it(it) {} + const Points& operator*() const { return m_it->points; } + bool operator==(const iterator &rhs) const { return m_it == rhs.m_it; } + bool operator!=(const iterator &rhs) const { return !(*this == rhs); } + const Points& operator++(int) { return (m_it ++)->points; } + iterator& operator++() { ++ m_it; return *this; } + private: + typename std::vector::const_iterator m_it; + }; + + iterator cbegin() const { return iterator(m_multipoints.begin()); } + iterator begin() const { return this->cbegin(); } + iterator cend() const { return iterator(m_multipoints.end()); } + iterator end() const { return this->cend(); } + size_t size() const { return m_multipoints.size(); } + + private: + const std::vector &m_multipoints; + }; + + using PolygonsProvider = MultiPointsProvider; + using PolylinesProvider = MultiPointsProvider; + + struct ExPolygonProvider { + ExPolygonProvider(const ExPolygon &expoly) : m_expoly(expoly) {} + + struct iterator : public PathsProviderIteratorBase { + public: + explicit iterator(const ExPolygon &expoly, int idx) : m_expoly(expoly), m_idx(idx) {} + const Points& operator*() const { return (m_idx == 0) ? m_expoly.contour.points : m_expoly.holes[m_idx - 1].points; } + bool operator==(const iterator &rhs) const { assert(m_expoly == rhs.m_expoly); return m_idx == rhs.m_idx; } + bool operator!=(const iterator &rhs) const { return !(*this == rhs); } + const Points& operator++(int) { const Points &out = **this; ++ m_idx; return out; } + iterator& operator++() { ++ m_idx; return *this; } + private: + const ExPolygon &m_expoly; + int m_idx; + }; + + iterator cbegin() const { return iterator(m_expoly, 0); } + iterator begin() const { return this->cbegin(); } + iterator cend() const { return iterator(m_expoly, m_expoly.holes.size() + 1); } + iterator end() const { return this->cend(); } + size_t size() const { return m_expoly.holes.size() + 1; } + + private: + const ExPolygon &m_expoly; + }; + + struct ExPolygonsProvider { + ExPolygonsProvider(const ExPolygons &expolygons) : m_expolygons(expolygons) { + m_size = 0; + for (const ExPolygon &expoly : expolygons) + m_size += expoly.holes.size() + 1; + } + + struct iterator : public PathsProviderIteratorBase { + public: + explicit iterator(ExPolygons::const_iterator it) : m_it_expolygon(it), m_idx_contour(0) {} + const Points& operator*() const { return (m_idx_contour == 0) ? m_it_expolygon->contour.points : m_it_expolygon->holes[m_idx_contour - 1].points; } + bool operator==(const iterator &rhs) const { return m_it_expolygon == rhs.m_it_expolygon && m_idx_contour == rhs.m_idx_contour; } + bool operator!=(const iterator &rhs) const { return !(*this == rhs); } + iterator& operator++() { + if (++ m_idx_contour == m_it_expolygon->holes.size() + 1) { + ++ m_it_expolygon; + m_idx_contour = 0; + } + return *this; + } + const Points& operator++(int) { + const Points &out = **this; + ++ (*this); + return out; + } + private: + ExPolygons::const_iterator m_it_expolygon; + int m_idx_contour; + }; + + iterator cbegin() const { return iterator(m_expolygons.cbegin()); } + iterator begin() const { return this->cbegin(); } + iterator cend() const { return iterator(m_expolygons.cend()); } + iterator end() const { return this->cend(); } + size_t size() const { return m_size; } + + private: + const ExPolygons &m_expolygons; + size_t m_size; + }; + + struct SurfacesProvider { + SurfacesProvider(const Surfaces &surfaces) : m_surfaces(surfaces) { + m_size = 0; + for (const Surface &surface : surfaces) + m_size += surface.expolygon.holes.size() + 1; + } + + struct iterator : public PathsProviderIteratorBase { + public: + explicit iterator(Surfaces::const_iterator it) : m_it_surface(it), m_idx_contour(0) {} + const Points& operator*() const { return (m_idx_contour == 0) ? m_it_surface->expolygon.contour.points : m_it_surface->expolygon.holes[m_idx_contour - 1].points; } + bool operator==(const iterator &rhs) const { return m_it_surface == rhs.m_it_surface && m_idx_contour == rhs.m_idx_contour; } + bool operator!=(const iterator &rhs) const { return !(*this == rhs); } + iterator& operator++() { + if (++ m_idx_contour == m_it_surface->expolygon.holes.size() + 1) { + ++ m_it_surface; + m_idx_contour = 0; + } + return *this; + } + const Points& operator++(int) { + const Points &out = **this; + ++ (*this); + return out; + } + private: + Surfaces::const_iterator m_it_surface; + int m_idx_contour; + }; + + iterator cbegin() const { return iterator(m_surfaces.cbegin()); } + iterator begin() const { return this->cbegin(); } + iterator cend() const { return iterator(m_surfaces.cend()); } + iterator end() const { return this->cend(); } + size_t size() const { return m_size; } + + private: + const Surfaces &m_surfaces; + size_t m_size; + }; +} + +ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input); // offset Polygons -ClipperLib::Paths _offset(ClipperLib::Path &&input, ClipperLib::EndType endType, const float delta, ClipperLib::JoinType joinType, double miterLimit); -ClipperLib::Paths _offset(ClipperLib::Paths &&input, ClipperLib::EndType endType, const float delta, ClipperLib::JoinType joinType, double miterLimit); -inline Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3) - { return ClipperPaths_to_Slic3rPolygons(_offset(Slic3rMultiPoint_to_ClipperPath(polygon), ClipperLib::etClosedPolygon, delta, joinType, miterLimit)); } +Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3); #ifdef CLIPPERUTILS_UNSAFE_OFFSET -inline Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3) - { return ClipperPaths_to_Slic3rPolygons(_offset(Slic3rMultiPoints_to_ClipperPaths(polygons), ClipperLib::etClosedPolygon, delta, joinType, miterLimit)); } +Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3); #endif // CLIPPERUTILS_UNSAFE_OFFSET // offset Polylines -inline Slic3r::Polygons offset(const Slic3r::Polyline &polyline, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtSquare, double miterLimit = 3) - { return ClipperPaths_to_Slic3rPolygons(_offset(Slic3rMultiPoint_to_ClipperPath(polyline), ClipperLib::etOpenButt, delta, joinType, miterLimit)); } -inline Slic3r::Polygons offset(const Slic3r::Polylines &polylines, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtSquare, double miterLimit = 3) - { return ClipperPaths_to_Slic3rPolygons(_offset(Slic3rMultiPoints_to_ClipperPaths(polylines), ClipperLib::etOpenButt, delta, joinType, miterLimit)); } +Slic3r::Polygons offset(const Slic3r::Polyline &polyline, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtSquare, double miterLimit = 3); +Slic3r::Polygons offset(const Slic3r::Polylines &polylines, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtSquare, double miterLimit = 3); // offset expolygons and surfaces ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType, double miterLimit); ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit); inline Slic3r::Polygons offset(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3) - { return ClipperPaths_to_Slic3rPolygons(_offset(expolygon, delta, joinType, miterLimit)); } + { return to_polygons(_offset(expolygon, delta, joinType, miterLimit)); } inline Slic3r::Polygons offset(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3) - { return ClipperPaths_to_Slic3rPolygons(_offset(expolygons, delta, joinType, miterLimit)); } -inline Slic3r::ExPolygons offset_ex(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3) - { return ClipperPaths_to_Slic3rExPolygons(_offset(Slic3rMultiPoint_to_ClipperPath(polygon), ClipperLib::etClosedPolygon, delta, joinType, miterLimit)); } + { return to_polygons(_offset(expolygons, delta, joinType, miterLimit)); } #ifdef CLIPPERUTILS_UNSAFE_OFFSET -inline Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3) - { return ClipperPaths_to_Slic3rExPolygons(_offset(Slic3rMultiPoints_to_ClipperPaths(polygons), ClipperLib::etClosedPolygon, delta, joinType, miterLimit)); } +Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3); #endif // CLIPPERUTILS_UNSAFE_OFFSET inline Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3) @@ -101,141 +260,68 @@ Slic3r::ExPolygons offset2_ex(const Slic3r::ExPolygons &expolygons, const float const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3); -Slic3r::Polygons _clipper(ClipperLib::ClipType clipType, - const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false); -Slic3r::ExPolygons _clipper_ex(ClipperLib::ClipType clipType, - const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false); -Slic3r::Polylines _clipper_pl(ClipperLib::ClipType clipType, - const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false); -Slic3r::Polylines _clipper_pl(ClipperLib::ClipType clipType, - const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false); -Slic3r::Lines _clipper_ln(ClipperLib::ClipType clipType, - const Slic3r::Lines &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false); +Slic3r::Polylines _clipper_pl(ClipperLib::ClipType clipType, const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::Polylines _clipper_pl(ClipperLib::ClipType clipType, const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::Lines _clipper_ln(ClipperLib::ClipType clipType, const Slic3r::Lines &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); -// diff -inline Slic3r::Polygons -diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false) +Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset = false); +Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset = false); + +inline Slic3r::Polylines diff_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false) { - return _clipper(ClipperLib::ctDifference, subject, clip, safety_offset_); + return _clipper_pl(ClipperLib::ctDifference, subject, clip, do_safety_offset); } -inline Slic3r::ExPolygons -diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false) +inline Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false) { - return _clipper_ex(ClipperLib::ctDifference, subject, clip, safety_offset_); + return _clipper_pl(ClipperLib::ctDifference, subject, clip, do_safety_offset); } -inline Slic3r::ExPolygons -diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool safety_offset_ = false) +inline Slic3r::Lines diff_ln(const Slic3r::Lines &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false) { - return _clipper_ex(ClipperLib::ctDifference, to_polygons(subject), to_polygons(clip), safety_offset_); + return _clipper_ln(ClipperLib::ctDifference, subject, clip, do_safety_offset); } -inline Slic3r::Polygons -diff(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool safety_offset_ = false) +Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::Polygons intersection(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset = false); +Slic3r::ExPolygons intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset = false); + +inline Slic3r::Polylines intersection_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false) { - return _clipper(ClipperLib::ctDifference, to_polygons(subject), to_polygons(clip), safety_offset_); + return _clipper_pl(ClipperLib::ctIntersection, subject, clip, do_safety_offset); } -inline Slic3r::Polylines -diff_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false) +inline Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false) { - return _clipper_pl(ClipperLib::ctDifference, subject, clip, safety_offset_); + return _clipper_pl(ClipperLib::ctIntersection, subject, clip, do_safety_offset); } -inline Slic3r::Polylines -diff_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false) +inline Slic3r::Lines intersection_ln(const Slic3r::Lines &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false) { - return _clipper_pl(ClipperLib::ctDifference, subject, clip, safety_offset_); + return _clipper_ln(ClipperLib::ctIntersection, subject, clip, do_safety_offset); } -inline Slic3r::Lines -diff_ln(const Slic3r::Lines &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false) -{ - return _clipper_ln(ClipperLib::ctDifference, subject, clip, safety_offset_); -} - -// intersection -inline Slic3r::Polygons -intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false) -{ - return _clipper(ClipperLib::ctIntersection, subject, clip, safety_offset_); -} - -inline Slic3r::ExPolygons -intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false) -{ - return _clipper_ex(ClipperLib::ctIntersection, subject, clip, safety_offset_); -} - -inline Slic3r::ExPolygons -intersection_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool safety_offset_ = false) -{ - return _clipper_ex(ClipperLib::ctIntersection, to_polygons(subject), to_polygons(clip), safety_offset_); -} - -inline Slic3r::Polygons -intersection(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool safety_offset_ = false) -{ - return _clipper(ClipperLib::ctIntersection, to_polygons(subject), to_polygons(clip), safety_offset_); -} - -inline Slic3r::Polylines -intersection_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false) -{ - return _clipper_pl(ClipperLib::ctIntersection, subject, clip, safety_offset_); -} - -inline Slic3r::Polylines -intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false) -{ - return _clipper_pl(ClipperLib::ctIntersection, subject, clip, safety_offset_); -} - -inline Slic3r::Lines intersection_ln(const Slic3r::Lines &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false) -{ - return _clipper_ln(ClipperLib::ctIntersection, subject, clip, safety_offset_); -} - -inline Slic3r::Lines intersection_ln(const Slic3r::Line &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false) +inline Slic3r::Lines intersection_ln(const Slic3r::Line &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false) { Slic3r::Lines lines; lines.emplace_back(subject); - return _clipper_ln(ClipperLib::ctIntersection, lines, clip, safety_offset_); + return _clipper_ln(ClipperLib::ctIntersection, lines, clip, do_safety_offset); } -// union -inline Slic3r::Polygons union_(const Slic3r::Polygons &subject, bool safety_offset_ = false) -{ - return _clipper(ClipperLib::ctUnion, subject, Slic3r::Polygons(), safety_offset_); -} +Slic3r::Polygons union_(const Slic3r::Polygons &subject, bool do_safety_offset = false); +Slic3r::Polygons union_(const Slic3r::ExPolygons &subject, bool do_safety_offset = false); +Slic3r::Polygons union_(const Slic3r::Polygons &subject, const Slic3r::Polygons &subject2, bool do_safety_offset = false); +Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, bool do_safety_offset = false); +Slic3r::ExPolygons union_ex(const Slic3r::ExPolygons &subject); +Slic3r::ExPolygons union_ex(const Slic3r::Surfaces &subject); -inline Slic3r::Polygons union_(const Slic3r::Polygons &subject, const Slic3r::Polygons &subject2, bool safety_offset_ = false) -{ - return _clipper(ClipperLib::ctUnion, subject, subject2, safety_offset_); -} +ClipperLib::PolyTree union_pt(const Slic3r::Polygons &subject); +ClipperLib::PolyTree union_pt(const Slic3r::ExPolygons &subject); -inline Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, bool safety_offset_ = false) -{ - return _clipper_ex(ClipperLib::ctUnion, subject, Slic3r::Polygons(), safety_offset_); -} - -inline Slic3r::ExPolygons union_ex(const Slic3r::ExPolygons &subject, bool safety_offset_ = false) -{ - return _clipper_ex(ClipperLib::ctUnion, to_polygons(subject), Slic3r::Polygons(), safety_offset_); -} - -inline Slic3r::ExPolygons union_ex(const Slic3r::Surfaces &subject, bool safety_offset_ = false) -{ - return _clipper_ex(ClipperLib::ctUnion, to_polygons(subject), Slic3r::Polygons(), safety_offset_); -} - -ClipperLib::PolyTree union_pt(const Slic3r::Polygons &subject, bool safety_offset_ = false); -ClipperLib::PolyTree union_pt(const Slic3r::ExPolygons &subject, bool safety_offset_ = false); -ClipperLib::PolyTree union_pt(Slic3r::Polygons &&subject, bool safety_offset_ = false); -ClipperLib::PolyTree union_pt(Slic3r::ExPolygons &&subject, bool safety_offset_ = false); - -Slic3r::Polygons union_pt_chained_outside_in(const Slic3r::Polygons &subject, bool safety_offset_ = false); +Slic3r::Polygons union_pt_chained_outside_in(const Slic3r::Polygons &subject); ClipperLib::PolyNodes order_nodes(const ClipperLib::PolyNodes &nodes); @@ -283,7 +369,7 @@ void traverse_pt(const ClipperLib::PolyNode *tree, Polygons *out) if (!tree) return; // terminates recursion // Push the contour of the current level - out->emplace_back(ClipperPath_to_Slic3rPolygon(tree->Contour)); + out->emplace_back(tree->Contour); // Do the recursion for all the children. traverse_pt(tree->Childs, out); @@ -302,13 +388,13 @@ void traverse_pt(const ClipperLib::PolyNode *tree, ExPolygons *out) } ExPolygon level; - level.contour = ClipperPath_to_Slic3rPolygon(tree->Contour); + level.contour.points = tree->Contour; foreach_node(tree->Childs, [out, &level] (const ClipperLib::PolyNode *node) { // Holes are collected here. - level.holes.emplace_back(ClipperPath_to_Slic3rPolygon(node->Contour)); + level.holes.emplace_back(node->Contour); // By doing a recursion, a new level expoly is created with the contour // and holes of the lower level. Doing this for all the childs. @@ -331,8 +417,6 @@ void traverse_pt(const ClipperLib::PolyNodes &nodes, ExOrJustPolygons *retval) Slic3r::Polygons simplify_polygons(const Slic3r::Polygons &subject, bool preserve_collinear = false); Slic3r::ExPolygons simplify_polygons_ex(const Slic3r::Polygons &subject, bool preserve_collinear = false); -void safety_offset(ClipperLib::Paths* paths); - Polygons top_level_islands(const Slic3r::Polygons &polygons); ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::vector &deltas, double miter_limit); diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp index fcf3c159e..04b84f767 100644 --- a/src/libslic3r/ExPolygon.hpp +++ b/src/libslic3r/ExPolygon.hpp @@ -83,8 +83,8 @@ inline bool operator!=(const ExPolygon &lhs, const ExPolygon &rhs) { return lhs. inline size_t number_polygons(const ExPolygons &expolys) { size_t n_polygons = 0; - for (ExPolygons::const_iterator it = expolys.begin(); it != expolys.end(); ++ it) - n_polygons += it->holes.size() + 1; + for (const ExPolygon &ex : expolys) + n_polygons += ex.holes.size() + 1; return n_polygons; } diff --git a/src/libslic3r/Fill/FillConcentric.cpp b/src/libslic3r/Fill/FillConcentric.cpp index 785c93be3..d5997552b 100644 --- a/src/libslic3r/Fill/FillConcentric.cpp +++ b/src/libslic3r/Fill/FillConcentric.cpp @@ -33,7 +33,7 @@ void FillConcentric::_fill_surface_single( // generate paths from the outermost to the innermost, to avoid // adhesion problems of the first central tiny loops - loops = union_pt_chained_outside_in(loops, false); + loops = union_pt_chained_outside_in(loops); // split paths using a nearest neighbor search size_t iPathFirst = polylines_out.size(); diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index e86a67b6f..857c98f52 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -185,7 +185,7 @@ void Layer::make_perimeters() } // merge the surfaces assigned to each group for (std::pair &surfaces_with_extra_perimeters : slices) - new_slices.append(offset_ex(to_expolygons(surfaces_with_extra_perimeters.second), 10.f), surfaces_with_extra_perimeters.second.front()); + new_slices.append(offset_ex(to_expolygons(surfaces_with_extra_perimeters.second), ClipperSafetyOffset), surfaces_with_extra_perimeters.second.front()); } // make perimeters diff --git a/src/libslic3r/Polygon.cpp b/src/libslic3r/Polygon.cpp index 7c588c67c..e744272ac 100644 --- a/src/libslic3r/Polygon.cpp +++ b/src/libslic3r/Polygon.cpp @@ -70,7 +70,7 @@ double Polygon::area() const bool Polygon::is_counter_clockwise() const { - return ClipperLib::Orientation(Slic3rMultiPoint_to_ClipperPath(*this)); + return ClipperLib::Orientation(this->points); } bool Polygon::is_clockwise() const diff --git a/src/libslic3r/Polygon.hpp b/src/libslic3r/Polygon.hpp index 93cd70121..333f1e6b1 100644 --- a/src/libslic3r/Polygon.hpp +++ b/src/libslic3r/Polygon.hpp @@ -222,6 +222,24 @@ inline Polylines to_polylines(Polygons &&polys) return polylines; } +inline Polygons to_polygons(const std::vector &paths) +{ + Polygons out; + out.reserve(paths.size()); + for (const Points &path : paths) + out.emplace_back(path); + return out; +} + +inline Polygons to_polygons(std::vector &&paths) +{ + Polygons out; + out.reserve(paths.size()); + for (const Points &path : paths) + out.emplace_back(std::move(path)); + return out; +} + } // Slic3r // start Boost diff --git a/src/libslic3r/Polyline.hpp b/src/libslic3r/Polyline.hpp index 9c70522bf..88f910590 100644 --- a/src/libslic3r/Polyline.hpp +++ b/src/libslic3r/Polyline.hpp @@ -124,6 +124,24 @@ inline Lines to_lines(const Polylines &polys) return lines; } +inline Polylines to_polylines(const std::vector &paths) +{ + Polylines out; + out.reserve(paths.size()); + for (const Points &path : paths) + out.emplace_back(path); + return out; +} + +inline Polylines to_polylines(std::vector &&paths) +{ + Polylines out; + out.reserve(paths.size()); + for (const Points &path : paths) + out.emplace_back(std::move(path)); + return out; +} + inline void polylines_append(Polylines &dst, const Polylines &src) { dst.insert(dst.end(), src.begin(), src.end()); diff --git a/src/libslic3r/SLA/ConcaveHull.cpp b/src/libslic3r/SLA/ConcaveHull.cpp index d3c0d1022..172408989 100644 --- a/src/libslic3r/SLA/ConcaveHull.cpp +++ b/src/libslic3r/SLA/ConcaveHull.cpp @@ -42,9 +42,10 @@ Point ConcaveHull::centroid(const Points &pp) // As it shows, the current offset_ex in ClipperUtils hangs if used in jtRound // mode -static ClipperLib::Paths fast_offset(const ClipperLib::Paths &paths, - coord_t delta, - ClipperLib::JoinType jointype) +template +static ClipperLib::Paths fast_offset(PolygonsProvider &&paths, + coord_t delta, + ClipperLib::JoinType jointype) { using ClipperLib::ClipperOffset; using ClipperLib::etClosedPolygon; @@ -61,7 +62,7 @@ static ClipperLib::Paths fast_offset(const ClipperLib::Paths &paths, return {}; } - offs.AddPaths(paths, jointype, etClosedPolygon); + offs.AddPaths(std::forward(paths), jointype, etClosedPolygon); Paths result; offs.Execute(result, static_cast(delta)); @@ -157,11 +158,9 @@ ExPolygons ConcaveHull::to_expolygons() const ExPolygons offset_waffle_style_ex(const ConcaveHull &hull, coord_t delta) { - ClipperLib::Paths paths = Slic3rMultiPoints_to_ClipperPaths(hull.polygons()); - paths = fast_offset(paths, 2 * delta, ClipperLib::jtRound); - paths = fast_offset(paths, -delta, ClipperLib::jtRound); - ExPolygons ret = ClipperPaths_to_Slic3rExPolygons(paths); - for (ExPolygon &p : ret) p.holes = {}; + ExPolygons ret = ClipperPaths_to_Slic3rExPolygons( + fast_offset(fast_offset(ClipperUtils::PolygonsProvider(hull.polygons()), 2 * delta, ClipperLib::jtRound), -delta, ClipperLib::jtRound)); + for (ExPolygon &p : ret) p.holes.clear(); return ret; } diff --git a/src/libslic3r/SLA/Pad.cpp b/src/libslic3r/SLA/Pad.cpp index 927c32589..e11914a1c 100644 --- a/src/libslic3r/SLA/Pad.cpp +++ b/src/libslic3r/SLA/Pad.cpp @@ -179,10 +179,10 @@ PadSkeleton divide_blueprint(const ExPolygons &bp) ret.outer.reserve(size_t(ptree.Total())); for (ClipperLib::PolyTree::PolyNode *node : ptree.Childs) { - ExPolygon poly(ClipperPath_to_Slic3rPolygon(node->Contour)); + ExPolygon poly; + poly.contour.points = std::move(node->Contour); for (ClipperLib::PolyTree::PolyNode *child : node->Childs) { - poly.holes.emplace_back( - ClipperPath_to_Slic3rPolygon(child->Contour)); + poly.holes.emplace_back(std::move(child->Contour)); traverse_pt(child->Childs, &ret.inner); } @@ -342,18 +342,18 @@ public: template ExPolygon offset_contour_only(const ExPolygon &poly, coord_t delta, Args...args) { - ExPolygons tmp = offset_ex(poly.contour, float(delta), args...); + Polygons tmp = offset(poly.contour, float(delta), args...); if (tmp.empty()) return {}; Polygons holes = poly.holes; for (auto &h : holes) h.reverse(); - tmp = diff_ex(to_polygons(tmp), holes); + ExPolygons tmp2 = diff_ex(tmp, holes); - if (tmp.empty()) return {}; + if (tmp2.empty()) return {}; - return tmp.front(); + return std::move(tmp2.front()); } bool add_cavity(Contour3D &pad, ExPolygon &top_poly, const PadConfig3D &cfg, diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index f8fa1ca17..da0583310 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -1799,9 +1799,9 @@ void TriangleMeshSlicer::make_expolygons(const Polygons &loops, const float clos // append to the supplied collection if (safety_offset > 0) - expolygons_append(*slices, offset2_ex(union_ex(loops, false), +safety_offset, -safety_offset)); + expolygons_append(*slices, offset2_ex(union_ex(loops), +safety_offset, -safety_offset)); else - expolygons_append(*slices, union_ex(loops, false)); + expolygons_append(*slices, union_ex(loops)); } void TriangleMeshSlicer::make_expolygons(std::vector &lines, const float closing_radius, ExPolygons* slices) const diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 1c43e7eb0..29551ac15 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -194,7 +194,7 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c const BoundingBox& bed_bbox = poly.contour.bounding_box(); calc_gridlines(poly, bed_bbox); - m_polygon = offset_ex(poly.contour, (float)bed_bbox.radius() * 1.7f, jtRound, scale_(0.5))[0].contour; + m_polygon = offset(poly.contour, (float)bed_bbox.radius() * 1.7f, jtRound, scale_(0.5))[0]; reset(); m_texture.reset(); From 09a80d954cc066c1f752a8a2762907ad0b46cd56 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Mon, 3 May 2021 11:39:53 +0200 Subject: [PATCH 2/6] Further rework of ClipperUtils: Replaced many to_polygons() / to_expolygons() calls with templated ClipperUtils variants to avoid memory allocation and copying. --- src/libslic3r/BridgeDetector.cpp | 20 +- src/libslic3r/Brim.cpp | 2 +- src/libslic3r/ClipperUtils.cpp | 376 +++++++++++--------- src/libslic3r/ClipperUtils.hpp | 144 +++++--- src/libslic3r/ExtrusionEntity.cpp | 4 +- src/libslic3r/Fill/Fill3DHoneycomb.cpp | 2 +- src/libslic3r/Fill/FillAdaptive.cpp | 2 +- src/libslic3r/Fill/FillGyroid.cpp | 2 +- src/libslic3r/Fill/FillHoneycomb.cpp | 2 +- src/libslic3r/Fill/FillPlanePath.cpp | 2 +- src/libslic3r/Layer.cpp | 10 +- src/libslic3r/Layer.hpp | 2 +- src/libslic3r/LayerRegion.cpp | 33 +- src/libslic3r/PerimeterGenerator.cpp | 6 +- src/libslic3r/PrintObject.cpp | 97 +++-- src/libslic3r/SLA/SupportPointGenerator.cpp | 9 +- src/libslic3r/SLA/SupportPointGenerator.hpp | 2 +- src/libslic3r/SupportMaterial.cpp | 53 ++- src/libslic3r/Surface.hpp | 11 +- src/libslic3r/SurfaceCollection.cpp | 37 +- src/libslic3r/SurfaceCollection.hpp | 7 +- tests/libslic3r/test_clipper_utils.cpp | 12 +- 22 files changed, 437 insertions(+), 398 deletions(-) diff --git a/src/libslic3r/BridgeDetector.cpp b/src/libslic3r/BridgeDetector.cpp index 671ebbdaa..cd90a1f03 100644 --- a/src/libslic3r/BridgeDetector.cpp +++ b/src/libslic3r/BridgeDetector.cpp @@ -227,29 +227,33 @@ void ExPolygon::get_trapezoids(ExPolygon clone, Polygons* polygons, double angle // This algorithm may return more trapezoids than necessary // (i.e. it may break a single trapezoid in several because // other parts of the object have x coordinates in the middle) -static void get_trapezoids2(const ExPolygon &expoly, Polygons* polygons) +static void get_trapezoids2(const ExPolygon& expoly, Polygons* polygons) { Polygons src_polygons = to_polygons(expoly); // get all points of this ExPolygon - const Points pp = to_points(src_polygons); - + const Points pp = to_points(src_polygons); + // build our bounding box BoundingBox bb(pp); - + // get all x coordinates std::vector xx; xx.reserve(pp.size()); for (Points::const_iterator p = pp.begin(); p != pp.end(); ++p) xx.push_back(p->x()); std::sort(xx.begin(), xx.end()); - + // find trapezoids by looping from first to next-to-last coordinate + Polygons rectangle; + rectangle.emplace_back(Polygon()); for (std::vector::const_iterator x = xx.begin(); x != xx.end()-1; ++x) { coord_t next_x = *(x + 1); - if (*x != next_x) + if (*x != next_x) { // intersect with rectangle // append results to return value - polygons_append(*polygons, intersection({ { { *x, bb.min.y() }, { next_x, bb.min.y() }, { next_x, bb.max.y() }, { *x, bb.max.y() } } }, src_polygons)); + rectangle.front() = { { *x, bb.min.y() }, { next_x, bb.min.y() }, { next_x, bb.max.y() }, { *x, bb.max.y() } }; + polygons_append(*polygons, intersection(rectangle, src_polygons)); + } } } @@ -302,7 +306,7 @@ Polygons BridgeDetector::coverage(double angle) const covered = union_(covered); // Intersect trapezoids with actual bridge area to remove extra margins and append it to result. polygons_rotate(covered, -(PI/2.0 - angle)); - covered = intersection(covered, to_polygons(this->expolygons)); + covered = intersection(this->expolygons, covered); #if 0 { my @lines = map @{$_->lines}, @$trapezoids; diff --git a/src/libslic3r/Brim.cpp b/src/libslic3r/Brim.cpp index 16b81e488..68851e051 100644 --- a/src/libslic3r/Brim.cpp +++ b/src/libslic3r/Brim.cpp @@ -156,7 +156,7 @@ static ExPolygons top_level_outer_brim_area(const Print &print, const ConstPrint } } - return diff_ex(to_polygons(std::move(brim_area)), no_brim_area); + return diff_ex(brim_area, no_brim_area); } static ExPolygons inner_brim_area(const Print &print, const ConstPrintObjectPtrs &top_level_objects_with_brim, const float no_brim_offset) diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index 1cd4a7c2f..49a244089 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -188,15 +188,10 @@ Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta { return ClipperPaths_to_Slic3rExPolygons(_offset(ClipperUtils::PolygonsProvider(polygons), ClipperLib::etClosedPolygon, delta, joinType, miterLimit)); } #endif // CLIPPERUTILS_UNSAFE_OFFSET -// This is a safe variant of the polygon offset, tailored for a single ExPolygon: -// a single polygon with multiple non-overlapping holes. -// Each contour and hole is offsetted separately, then the holes are subtracted from the outer contours. -ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta, - ClipperLib::JoinType joinType, double miterLimit) +// returns number of expolygons collected (0 or 1). +static int offset_expolygon_inner(const Slic3r::ExPolygon &expoly, const float delta, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::Paths &out) { -// printf("new ExPolygon offset\n"); // 1) Offset the outer contour. - float delta_scaled = delta; ClipperLib::Paths contours; { ClipperLib::ClipperOffset co; @@ -204,153 +199,129 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta, co.ArcTolerance = miterLimit; else co.MiterLimit = miterLimit; - co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); - co.AddPath(expolygon.contour.points, joinType, ClipperLib::etClosedPolygon); - co.Execute(contours, delta_scaled); + co.ShortestEdgeLength = double(std::abs(delta * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); + co.AddPath(expoly.contour.points, joinType, ClipperLib::etClosedPolygon); + co.Execute(contours, delta); } + if (contours.empty()) + // No need to try to offset the holes. + return 0; - // 2) Offset the holes one by one, collect the results. - ClipperLib::Paths holes; - { - holes.reserve(expolygon.holes.size()); - for (Polygons::const_iterator it_hole = expolygon.holes.begin(); it_hole != expolygon.holes.end(); ++ it_hole) { - ClipperLib::ClipperOffset co; - if (joinType == jtRound) - co.ArcTolerance = miterLimit; - else - co.MiterLimit = miterLimit; - co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); - co.AddPath(it_hole->points, joinType, ClipperLib::etClosedPolygon); - ClipperLib::Paths out; - // Execute reorients the contours so that the outer most contour has a positive area. Thus the output - // contours will be CCW oriented even though the input paths are CW oriented. - // Offset is applied after contour reorientation, thus the signum of the offset value is reversed. - co.Execute(out, - delta_scaled); - append(holes, std::move(out)); + if (expoly.holes.empty()) { + // No need to subtract holes from the offsetted expolygon, we are done. + append(out, std::move(contours)); + } else { + // 2) Offset the holes one by one, collect the offsetted holes. + ClipperLib::Paths holes; + { + for (const Polygon &hole : expoly.holes) { + ClipperLib::ClipperOffset co; + if (joinType == jtRound) + co.ArcTolerance = miterLimit; + else + co.MiterLimit = miterLimit; + co.ShortestEdgeLength = double(std::abs(delta * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); + co.AddPath(hole.points, joinType, ClipperLib::etClosedPolygon); + ClipperLib::Paths out2; + // Execute reorients the contours so that the outer most contour has a positive area. Thus the output + // contours will be CCW oriented even though the input paths are CW oriented. + // Offset is applied after contour reorientation, thus the signum of the offset value is reversed. + co.Execute(out2, - delta); + append(holes, std::move(out2)); + } + } + + // 3) Subtract holes from the contours. + if (holes.empty()) { + // No hole remaining after an offset. Just copy the outer contour. + append(out, std::move(contours)); + } else if (delta < 0) { + // Negative offset. There is a chance, that the offsetted hole intersects the outer contour. + // Subtract the offsetted holes from the offsetted contours. + ClipperLib::Clipper clipper; + clipper.Clear(); + clipper.AddPaths(contours, ClipperLib::ptSubject, true); + clipper.AddPaths(holes, ClipperLib::ptClip, true); + ClipperLib::Paths output; + clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); + if (! output.empty()) { + append(out, std::move(output)); + } else { + // The offsetted holes have eaten up the offsetted outer contour. + return 0; + } + } else { + // Positive offset. As long as the Clipper offset does what one expects it to do, the offsetted hole will have a smaller + // area than the original hole or even disappear, therefore there will be no new intersections. + // Just collect the reversed holes. + out.reserve(contours.size() + holes.size()); + append(out, std::move(contours)); + // Reverse the holes in place. + for (size_t i = 0; i < holes.size(); ++ i) + std::reverse(holes[i].begin(), holes[i].end()); + append(out, std::move(holes)); } } - // 3) Subtract holes from the contours. - ClipperLib::Paths output; - if (holes.empty()) { - output = std::move(contours); - } else { - ClipperLib::Clipper clipper; - clipper.Clear(); - clipper.AddPaths(contours, ClipperLib::ptSubject, true); - clipper.AddPaths(holes, ClipperLib::ptClip, true); - clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); - } - - return output; + return 1; +} + +static int offset_expolygon_inner(const Slic3r::Surface &surface, const float delta, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::Paths &out) + { return offset_expolygon_inner(surface.expolygon, delta, joinType, miterLimit, out); } +static int offset_expolygon_inner(const Slic3r::Surface *surface, const float delta, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::Paths &out) + { return offset_expolygon_inner(surface->expolygon, delta, joinType, miterLimit, out); } + +ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType, double miterLimit) +{ + ClipperLib::Paths out; + offset_expolygon_inner(expolygon, delta, joinType, miterLimit, out); + return out; } // This is a safe variant of the polygons offset, tailored for multiple ExPolygons. // It is required, that the input expolygons do not overlap and that the holes of each ExPolygon don't intersect with their respective outer contours. // Each ExPolygon is offsetted separately, then the offsetted ExPolygons are united. -ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delta, - ClipperLib::JoinType joinType, double miterLimit) +template +ClipperLib::Paths _offset(const ExPolygonVector &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit) { - float delta_scaled = delta; // Offsetted ExPolygons before they are united. - ClipperLib::Paths contours_cummulative; - contours_cummulative.reserve(expolygons.size()); - // How many non-empty offsetted expolygons were actually collected into contours_cummulative? + ClipperLib::Paths output; + output.reserve(expolygons.size()); + // How many non-empty offsetted expolygons were actually collected into output? // If only one, then there is no need to do a final union. size_t expolygons_collected = 0; - for (const Slic3r::ExPolygon &expoly : expolygons) { - // 1) Offset the outer contour. - ClipperLib::Paths contours; - { - ClipperLib::ClipperOffset co; - if (joinType == jtRound) - co.ArcTolerance = miterLimit; - else - co.MiterLimit = miterLimit; - co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); - co.AddPath(expoly.contour.points, joinType, ClipperLib::etClosedPolygon); - co.Execute(contours, delta_scaled); - } - if (contours.empty()) - // No need to try to offset the holes. - continue; - - if (expoly.holes.empty()) { - // No need to subtract holes from the offsetted expolygon, we are done. - append(contours_cummulative, std::move(contours)); - ++ expolygons_collected; - } else { - // 2) Offset the holes one by one, collect the offsetted holes. - ClipperLib::Paths holes; - { - for (const Polygon &hole : expoly.holes) { - ClipperLib::ClipperOffset co; - if (joinType == jtRound) - co.ArcTolerance = miterLimit; - else - co.MiterLimit = miterLimit; - co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); - co.AddPath(hole.points, joinType, ClipperLib::etClosedPolygon); - ClipperLib::Paths out; - // Execute reorients the contours so that the outer most contour has a positive area. Thus the output - // contours will be CCW oriented even though the input paths are CW oriented. - // Offset is applied after contour reorientation, thus the signum of the offset value is reversed. - co.Execute(out, - delta_scaled); - append(holes, std::move(out)); - } - } - - // 3) Subtract holes from the contours. - if (holes.empty()) { - // No hole remaining after an offset. Just copy the outer contour. - append(contours_cummulative, std::move(contours)); - ++ expolygons_collected; - } else if (delta < 0) { - // Negative offset. There is a chance, that the offsetted hole intersects the outer contour. - // Subtract the offsetted holes from the offsetted contours. - ClipperLib::Clipper clipper; - clipper.Clear(); - clipper.AddPaths(contours, ClipperLib::ptSubject, true); - clipper.AddPaths(holes, ClipperLib::ptClip, true); - ClipperLib::Paths output; - clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); - if (! output.empty()) { - append(contours_cummulative, std::move(output)); - ++ expolygons_collected; - } else { - // The offsetted holes have eaten up the offsetted outer contour. - } - } else { - // Positive offset. As long as the Clipper offset does what one expects it to do, the offsetted hole will have a smaller - // area than the original hole or even disappear, therefore there will be no new intersections. - // Just collect the reversed holes. - contours_cummulative.reserve(contours.size() + holes.size()); - append(contours_cummulative, std::move(contours)); - // Reverse the holes in place. - for (size_t i = 0; i < holes.size(); ++ i) - std::reverse(holes[i].begin(), holes[i].end()); - append(contours_cummulative, std::move(holes)); - ++ expolygons_collected; - } - } - } + for (const auto &expoly : expolygons) + expolygons_collected += offset_expolygon_inner(expoly, delta, joinType, miterLimit, output); // 4) Unite the offsetted expolygons. - ClipperLib::Paths output; if (expolygons_collected > 1 && delta > 0) { // There is a chance that the outwards offsetted expolygons may intersect. Perform a union. ClipperLib::Clipper clipper; clipper.Clear(); - clipper.AddPaths(contours_cummulative, ClipperLib::ptSubject, true); + clipper.AddPaths(output, ClipperLib::ptSubject, true); clipper.Execute(ClipperLib::ctUnion, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); } else { // Negative offset. The shrunk expolygons shall not mutually intersect. Just copy the output. - output = std::move(contours_cummulative); } return output; } +Slic3r::Polygons offset(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType, double miterLimit) + { return to_polygons(_offset(expolygon, delta, joinType, miterLimit)); } +Slic3r::Polygons offset(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit) + { return to_polygons(_offset(expolygons, delta, joinType, miterLimit)); } +Slic3r::Polygons offset(const Slic3r::Surfaces &surfaces, const float delta, ClipperLib::JoinType joinType, double miterLimit) + { return to_polygons(_offset(surfaces, delta, joinType, miterLimit)); } +Slic3r::Polygons offset(const Slic3r::SurfacesPtr &surfaces, const float delta, ClipperLib::JoinType joinType, double miterLimit) + { return to_polygons(_offset(surfaces, delta, joinType, miterLimit)); } +Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType, double miterLimit) + { return ClipperPaths_to_Slic3rExPolygons(_offset(expolygon, delta, joinType, miterLimit)); } +Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit) + { return ClipperPaths_to_Slic3rExPolygons(_offset(expolygons, delta, joinType, miterLimit)); } +Slic3r::ExPolygons offset_ex(const Slic3r::Surfaces &surfaces, const float delta, ClipperLib::JoinType joinType, double miterLimit) + { return ClipperPaths_to_Slic3rExPolygons(_offset(surfaces, delta, joinType, miterLimit)); } + ClipperLib::Paths _offset2(const Polygons &polygons, const float delta1, const float delta2, const ClipperLib::JoinType joinType, const double miterLimit) { // prepare ClipperOffset object @@ -389,16 +360,14 @@ ExPolygons offset2_ex(const Polygons &polygons, const float delta1, const float } //FIXME Vojtech: This functon may likely be optimized to avoid some of the Slic3r to Clipper -// conversions and unnecessary Clipper calls. -ExPolygons offset2_ex(const ExPolygons &expolygons, const float delta1, - const float delta2, ClipperLib::JoinType joinType, double miterLimit) +// conversions and unnecessary Clipper calls. It is not that bad now as Clipper uses Slic3r's own Point / Polygon types directly. +Polygons offset2(const ExPolygons &expolygons, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit) { - Polygons polys; - for (const ExPolygon &expoly : expolygons) - append(polys, - offset(offset_ex(expoly, delta1, joinType, miterLimit), - delta2, joinType, miterLimit)); - return union_ex(polys); + return offset(offset_ex(expolygons, delta1, joinType, miterLimit), delta2, joinType, miterLimit); +} +ExPolygons offset2_ex(const ExPolygons &expolygons, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit) +{ + return offset_ex(offset_ex(expolygons, delta1, joinType, miterLimit), delta2, joinType, miterLimit); } template @@ -483,12 +452,22 @@ static inline Polygons _clipper(ClipperLib::ClipType clipType, TSubj &&subject, Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset) { return _clipper(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } +Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset) + { return _clipper(ClipperLib::ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset) { return _clipper(ClipperLib::ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset) { return _clipper(ClipperLib::ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } +Slic3r::Polygons intersection(const Slic3r::ExPolygon &subject, const Slic3r::ExPolygon &clip, bool do_safety_offset) + { return _clipper(ClipperLib::ctIntersection, ClipperUtils::ExPolygonProvider(subject), ClipperUtils::ExPolygonProvider(clip), do_safety_offset); } +Slic3r::Polygons intersection(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset) + { return _clipper(ClipperLib::ctIntersection, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } Slic3r::Polygons intersection(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset) { return _clipper(ClipperLib::ctIntersection, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } +Slic3r::Polygons intersection(const Slic3r::Surfaces &subject, const Slic3r::Polygons &clip, bool do_safety_offset) + { return _clipper(ClipperLib::ctIntersection, ClipperUtils::SurfacesProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } +Slic3r::Polygons intersection(const Slic3r::Surfaces &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset) + { return _clipper(ClipperLib::ctIntersection, ClipperUtils::SurfacesProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } Slic3r::Polygons union_(const Slic3r::Polygons &subject, bool do_safety_offset) { return _clipper(ClipperLib::ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), do_safety_offset); } Slic3r::Polygons union_(const Slic3r::ExPolygons &subject, bool do_safety_offset) @@ -502,12 +481,45 @@ static ExPolygons _clipper_ex(ClipperLib::ClipType clipType, TSubject &&subject, Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset) { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } +Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Surfaces &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::SurfacesProvider(clip), do_safety_offset); } +Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } +Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygon &subject, const Slic3r::Polygons &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::ExPolygonProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } +Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset) { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } +Slic3r::ExPolygons diff_ex(const Slic3r::Surfaces &subject, const Slic3r::Polygons &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::SurfacesProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } +Slic3r::ExPolygons diff_ex(const Slic3r::Surfaces &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::SurfacesProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } +Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::Surfaces &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::SurfacesProvider(clip), do_safety_offset); } +Slic3r::ExPolygons diff_ex(const Slic3r::Surfaces &subject, const Slic3r::Surfaces &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::SurfacesProvider(subject), ClipperUtils::SurfacesProvider(clip), do_safety_offset); } +Slic3r::ExPolygons diff_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::Polygons &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::SurfacesPtrProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } + Slic3r::ExPolygons intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset) { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } +Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygon &subject, const Slic3r::Polygons &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::ExPolygonProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } +Slic3r::ExPolygons intersection_ex(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } +Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset) { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } +Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::Polygons &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::SurfacesProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } +Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::SurfacesProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } +Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::Surfaces &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::SurfacesProvider(subject), ClipperUtils::SurfacesProvider(clip), do_safety_offset); } +Slic3r::ExPolygons intersection_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset) + { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::SurfacesPtrProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, bool do_safety_offset) { return _clipper_ex(ClipperLib::ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), do_safety_offset); } Slic3r::ExPolygons union_ex(const Slic3r::ExPolygons& subject) @@ -515,67 +527,93 @@ Slic3r::ExPolygons union_ex(const Slic3r::ExPolygons& subject) Slic3r::ExPolygons union_ex(const Slic3r::Surfaces& subject) { return PolyTreeToExPolygons(_clipper_do_polytree2(ClipperLib::ctUnion, ClipperUtils::SurfacesProvider(subject), ClipperUtils::EmptyPathsProvider(), ClipperLib::pftNonZero)); } -Polylines _clipper_pl(ClipperLib::ClipType clipType, const Polylines &subject, const Polygons &clip, bool do_safety_offset) +template +Polylines _clipper_pl_open(ClipperLib::ClipType clipType, PathsProvider1 &&subject, PathsProvider2 &&clip, bool do_safety_offset) { ClipperLib::Clipper clipper; - clipper.AddPaths(ClipperUtils::PolylinesProvider(subject), ClipperLib::ptSubject, false); + clipper.AddPaths(std::forward(subject), ClipperLib::ptSubject, false); if (do_safety_offset) - clipper.AddPaths(safety_offset(ClipperUtils::PolygonsProvider(clip)), ClipperLib::ptClip, true); + clipper.AddPaths(safety_offset(std::forward(clip)), ClipperLib::ptClip, true); else - clipper.AddPaths(ClipperUtils::PolygonsProvider(clip), ClipperLib::ptClip, true); + clipper.AddPaths(std::forward(clip), ClipperLib::ptClip, true); ClipperLib::PolyTree retval; clipper.Execute(clipType, retval, ClipperLib::pftNonZero, ClipperLib::pftNonZero); return PolyTreeToPolylines(std::move(retval)); } -Polylines _clipper_pl(ClipperLib::ClipType clipType, const Polygons &subject, const Polygons &clip, bool do_safety_offset) +// If the split_at_first_point() call above happens to split the polygon inside the clipping area +// we would get two consecutive polylines instead of a single one, so we go through them in order +// to recombine continuous polylines. +static void _clipper_pl_recombine(Polylines &polylines) { - // transform input polygons into polylines - Polylines polylines; - polylines.reserve(subject.size()); - for (Polygons::const_iterator polygon = subject.begin(); polygon != subject.end(); ++polygon) - polylines.emplace_back(polygon->operator Polyline()); // implicit call to split_at_first_point() - - // perform clipping - Polylines retval = _clipper_pl(clipType, polylines, clip, do_safety_offset); - - /* If the split_at_first_point() call above happens to split the polygon inside the clipping area - we would get two consecutive polylines instead of a single one, so we go through them in order - to recombine continuous polylines. */ - for (size_t i = 0; i < retval.size(); ++i) { - for (size_t j = i+1; j < retval.size(); ++j) { - if (retval[i].points.back() == retval[j].points.front()) { + for (size_t i = 0; i < polylines.size(); ++i) { + for (size_t j = i+1; j < polylines.size(); ++j) { + if (polylines[i].points.back() == polylines[j].points.front()) { /* If last point of i coincides with first point of j, append points of j to i and delete j */ - retval[i].points.insert(retval[i].points.end(), retval[j].points.begin()+1, retval[j].points.end()); - retval.erase(retval.begin() + j); + polylines[i].points.insert(polylines[i].points.end(), polylines[j].points.begin()+1, polylines[j].points.end()); + polylines.erase(polylines.begin() + j); --j; - } else if (retval[i].points.front() == retval[j].points.back()) { + } else if (polylines[i].points.front() == polylines[j].points.back()) { /* If first point of i coincides with last point of j, prepend points of j to i and delete j */ - retval[i].points.insert(retval[i].points.begin(), retval[j].points.begin(), retval[j].points.end()-1); - retval.erase(retval.begin() + j); + polylines[i].points.insert(polylines[i].points.begin(), polylines[j].points.begin(), polylines[j].points.end()-1); + polylines.erase(polylines.begin() + j); --j; - } else if (retval[i].points.front() == retval[j].points.front()) { + } else if (polylines[i].points.front() == polylines[j].points.front()) { /* Since Clipper does not preserve orientation of polylines, also check the case when first point of i coincides with first point of j. */ - retval[j].reverse(); - retval[i].points.insert(retval[i].points.begin(), retval[j].points.begin(), retval[j].points.end()-1); - retval.erase(retval.begin() + j); + polylines[j].reverse(); + polylines[i].points.insert(polylines[i].points.begin(), polylines[j].points.begin(), polylines[j].points.end()-1); + polylines.erase(polylines.begin() + j); --j; - } else if (retval[i].points.back() == retval[j].points.back()) { + } else if (polylines[i].points.back() == polylines[j].points.back()) { /* Since Clipper does not preserve orientation of polylines, also check the case when last point of i coincides with last point of j. */ - retval[j].reverse(); - retval[i].points.insert(retval[i].points.end(), retval[j].points.begin()+1, retval[j].points.end()); - retval.erase(retval.begin() + j); + polylines[j].reverse(); + polylines[i].points.insert(polylines[i].points.end(), polylines[j].points.begin()+1, polylines[j].points.end()); + polylines.erase(polylines.begin() + j); --j; } } } +} + +template +Polylines _clipper_pl_closed(ClipperLib::ClipType clipType, PathProvider1 &&subject, PathProvider2 &&clip, bool do_safety_offset) +{ + // Transform input polygons into open paths. + ClipperLib::Paths paths; + paths.reserve(subject.size()); + for (const Points &poly : subject) { + // Emplace polygon, duplicate the 1st point. + paths.push_back({}); + ClipperLib::Path &path = paths.back(); + path.reserve(poly.size() + 1); + path = poly; + path.emplace_back(poly.front()); + } + // perform clipping + Polylines retval = _clipper_pl_open(clipType, paths, std::forward(clip), do_safety_offset); + _clipper_pl_recombine(retval); return retval; } +Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool do_safety_offset) + { return _clipper_pl_open(ClipperLib::ctDifference, ClipperUtils::PolylinesProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } +Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygon &clip, bool do_safety_offset) + { return _clipper_pl_open(ClipperLib::ctDifference, ClipperUtils::PolylinesProvider(subject), ClipperUtils::ExPolygonProvider(clip), do_safety_offset); } +Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset) + { return _clipper_pl_open(ClipperLib::ctDifference, ClipperUtils::PolylinesProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } +Slic3r::Polylines diff_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset) + { return _clipper_pl_closed(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } +Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool do_safety_offset) + { return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } +Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset) + { return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } +Slic3r::Polylines intersection_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset) + { return _clipper_pl_closed(ClipperLib::ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } + Lines _clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Polygons &clip, bool do_safety_offset) { // convert Lines to Polylines @@ -585,7 +623,7 @@ Lines _clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Pol polylines.emplace_back(Polyline(line.a, line.b)); // perform operation - polylines = _clipper_pl(clipType, polylines, clip, do_safety_offset); + polylines = _clipper_pl_open(clipType, ClipperUtils::PolylinesProvider(polylines), ClipperUtils::PolygonsProvider(clip), do_safety_offset); // convert Polylines to Lines Lines retval; diff --git a/src/libslic3r/ClipperUtils.hpp b/src/libslic3r/ClipperUtils.hpp index d7eb37127..0d3b986c0 100644 --- a/src/libslic3r/ClipperUtils.hpp +++ b/src/libslic3r/ClipperUtils.hpp @@ -212,6 +212,47 @@ namespace ClipperUtils { const Surfaces &m_surfaces; size_t m_size; }; + + struct SurfacesPtrProvider { + SurfacesPtrProvider(const SurfacesPtr &surfaces) : m_surfaces(surfaces) { + m_size = 0; + for (const Surface *surface : surfaces) + m_size += surface->expolygon.holes.size() + 1; + } + + struct iterator : public PathsProviderIteratorBase { + public: + explicit iterator(SurfacesPtr::const_iterator it) : m_it_surface(it), m_idx_contour(0) {} + const Points& operator*() const { return (m_idx_contour == 0) ? (*m_it_surface)->expolygon.contour.points : (*m_it_surface)->expolygon.holes[m_idx_contour - 1].points; } + bool operator==(const iterator &rhs) const { return m_it_surface == rhs.m_it_surface && m_idx_contour == rhs.m_idx_contour; } + bool operator!=(const iterator &rhs) const { return !(*this == rhs); } + iterator& operator++() { + if (++ m_idx_contour == (*m_it_surface)->expolygon.holes.size() + 1) { + ++ m_it_surface; + m_idx_contour = 0; + } + return *this; + } + const Points& operator++(int) { + const Points &out = **this; + ++ (*this); + return out; + } + private: + SurfacesPtr::const_iterator m_it_surface; + int m_idx_contour; + }; + + iterator cbegin() const { return iterator(m_surfaces.cbegin()); } + iterator begin() const { return this->cbegin(); } + iterator cend() const { return iterator(m_surfaces.cend()); } + iterator end() const { return this->cend(); } + size_t size() const { return m_size; } + + private: + const SurfacesPtr &m_surfaces; + size_t m_size; + }; } ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input); @@ -224,80 +265,71 @@ Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta, Cli #endif // CLIPPERUTILS_UNSAFE_OFFSET // offset Polylines -Slic3r::Polygons offset(const Slic3r::Polyline &polyline, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtSquare, double miterLimit = 3); -Slic3r::Polygons offset(const Slic3r::Polylines &polylines, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtSquare, double miterLimit = 3); +Slic3r::Polygons offset(const Slic3r::Polyline &polyline, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtSquare, double miterLimit = 3); +Slic3r::Polygons offset(const Slic3r::Polylines &polylines, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtSquare, double miterLimit = 3); +Slic3r::Polygons offset(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3); +Slic3r::Polygons offset(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3); +Slic3r::Polygons offset(const Slic3r::Surfaces &surfaces, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3); +Slic3r::Polygons offset(const Slic3r::SurfacesPtr &surfaces, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3); +Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3); +Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3); +Slic3r::ExPolygons offset_ex(const Slic3r::Surfaces &surfaces, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3); -// offset expolygons and surfaces -ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType, double miterLimit); -ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit); -inline Slic3r::Polygons offset(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3) - { return to_polygons(_offset(expolygon, delta, joinType, miterLimit)); } -inline Slic3r::Polygons offset(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3) - { return to_polygons(_offset(expolygons, delta, joinType, miterLimit)); } +Slic3r::Polygons offset2(const Slic3r::ExPolygons &expolygons, const float delta1, const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3); +Slic3r::ExPolygons offset2_ex(const Slic3r::ExPolygons &expolygons, const float delta1, const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3); #ifdef CLIPPERUTILS_UNSAFE_OFFSET Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3); +ClipperLib::Paths _offset2(const Slic3r::Polygons &polygons, const float delta1, const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3); +Slic3r::Polygons offset2(const Slic3r::Polygons &polygons, const float delta1, const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3); +Slic3r::ExPolygons offset2_ex(const Slic3r::Polygons &polygons, const float delta1, const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3); #endif // CLIPPERUTILS_UNSAFE_OFFSET -inline Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3) - { return ClipperPaths_to_Slic3rExPolygons(_offset(expolygon, delta, joinType, miterLimit)); } -inline Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3) - { return ClipperPaths_to_Slic3rExPolygons(_offset(expolygons, delta, joinType, miterLimit)); } - -#ifdef CLIPPERUTILS_UNSAFE_OFFSET -ClipperLib::Paths _offset2(const Slic3r::Polygons &polygons, const float delta1, - const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter, - double miterLimit = 3); -Slic3r::Polygons offset2(const Slic3r::Polygons &polygons, const float delta1, - const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter, - double miterLimit = 3); -Slic3r::ExPolygons offset2_ex(const Slic3r::Polygons &polygons, const float delta1, - const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter, - double miterLimit = 3); -#endif // CLIPPERUTILS_UNSAFE_OFFSET - -Slic3r::ExPolygons offset2_ex(const Slic3r::ExPolygons &expolygons, const float delta1, - const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter, - double miterLimit = 3); - -Slic3r::Polylines _clipper_pl(ClipperLib::ClipType clipType, const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); -Slic3r::Polylines _clipper_pl(ClipperLib::ClipType clipType, const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); Slic3r::Lines _clipper_ln(ClipperLib::ClipType clipType, const Slic3r::Lines &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); -Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); -Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset = false); +Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset = false); Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset = false); +Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Surfaces &clip, bool do_safety_offset = false); +Slic3r::ExPolygons diff_ex(const Slic3r::Polygon &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset = false); +Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygon &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset = false); - -inline Slic3r::Polylines diff_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false) -{ - return _clipper_pl(ClipperLib::ctDifference, subject, clip, do_safety_offset); -} - -inline Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false) -{ - return _clipper_pl(ClipperLib::ctDifference, subject, clip, do_safety_offset); -} +Slic3r::ExPolygons diff_ex(const Slic3r::Surfaces &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::ExPolygons diff_ex(const Slic3r::Surfaces &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset = false); +Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::Surfaces &clip, bool do_safety_offset = false); +Slic3r::ExPolygons diff_ex(const Slic3r::Surfaces &subject, const Slic3r::Surfaces &clip, bool do_safety_offset = false); +Slic3r::ExPolygons diff_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygon &clip, bool do_safety_offset = false); +Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset = false); +Slic3r::Polylines diff_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); inline Slic3r::Lines diff_ln(const Slic3r::Lines &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false) { return _clipper_ln(ClipperLib::ctDifference, subject, clip, do_safety_offset); } -Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); -Slic3r::Polygons intersection(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset = false); +Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::Polygons intersection(const Slic3r::ExPolygon &subject, const Slic3r::ExPolygon &clip, bool do_safety_offset = false); +Slic3r::Polygons intersection(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::Polygons intersection(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset = false); +Slic3r::Polygons intersection(const Slic3r::Surfaces &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::Polygons intersection(const Slic3r::Surfaces &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset = false); Slic3r::ExPolygons intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygon &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::ExPolygons intersection_ex(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset = false); +Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset = false); - -inline Slic3r::Polylines intersection_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false) -{ - return _clipper_pl(ClipperLib::ctIntersection, subject, clip, do_safety_offset); -} - -inline Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false) -{ - return _clipper_pl(ClipperLib::ctIntersection, subject, clip, do_safety_offset); -} +Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset = false); +Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::Surfaces &clip, bool do_safety_offset = false); +Slic3r::ExPolygons intersection_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset = false); +Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); +Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip, bool do_safety_offset = false); +Slic3r::Polylines intersection_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false); inline Slic3r::Lines intersection_ln(const Slic3r::Lines &subject, const Slic3r::Polygons &clip, bool do_safety_offset = false) { diff --git a/src/libslic3r/ExtrusionEntity.cpp b/src/libslic3r/ExtrusionEntity.cpp index 3284bc39e..714a122a0 100644 --- a/src/libslic3r/ExtrusionEntity.cpp +++ b/src/libslic3r/ExtrusionEntity.cpp @@ -14,12 +14,12 @@ namespace Slic3r { void ExtrusionPath::intersect_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const { - this->_inflate_collection(intersection_pl((Polylines)polyline, to_polygons(collection.expolygons)), retval); + this->_inflate_collection(intersection_pl(Polylines{ polyline }, collection.expolygons), retval); } void ExtrusionPath::subtract_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const { - this->_inflate_collection(diff_pl((Polylines)this->polyline, to_polygons(collection.expolygons)), retval); + this->_inflate_collection(diff_pl(Polylines{ this->polyline }, collection.expolygons), retval); } void ExtrusionPath::clip_end(double distance) diff --git a/src/libslic3r/Fill/Fill3DHoneycomb.cpp b/src/libslic3r/Fill/Fill3DHoneycomb.cpp index 95c26fbad..0dec8004b 100644 --- a/src/libslic3r/Fill/Fill3DHoneycomb.cpp +++ b/src/libslic3r/Fill/Fill3DHoneycomb.cpp @@ -162,7 +162,7 @@ void Fill3DHoneycomb::_fill_surface_single( pl.translate(bb.min); // clip pattern to boundaries, chain the clipped polylines - polylines = intersection_pl(polylines, to_polygons(expolygon)); + polylines = intersection_pl(polylines, expolygon); // connect lines if needed if (params.dont_connect() || polylines.size() <= 1) diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index d8c05887e..6b303e636 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -1368,7 +1368,7 @@ void Filler::_fill_surface_single( all_polylines.reserve(lines.size()); std::transform(lines.begin(), lines.end(), std::back_inserter(all_polylines), [](const Line& l) { return Polyline{ l.a, l.b }; }); // Crop all polylines - all_polylines = intersection_pl(std::move(all_polylines), to_polygons(expolygon)); + all_polylines = intersection_pl(std::move(all_polylines), expolygon); #endif } diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp index ff2d049cf..c6510daa2 100644 --- a/src/libslic3r/Fill/FillGyroid.cpp +++ b/src/libslic3r/Fill/FillGyroid.cpp @@ -180,7 +180,7 @@ void FillGyroid::_fill_surface_single( for (Polyline &pl : polylines) pl.translate(bb.min); - polylines = intersection_pl(polylines, to_polygons(expolygon)); + polylines = intersection_pl(polylines, expolygon); if (! polylines.empty()) { // Remove very small bits, but be careful to not remove infill lines connecting thin walls! diff --git a/src/libslic3r/Fill/FillHoneycomb.cpp b/src/libslic3r/Fill/FillHoneycomb.cpp index f7f79ae83..5dc2ed501 100644 --- a/src/libslic3r/Fill/FillHoneycomb.cpp +++ b/src/libslic3r/Fill/FillHoneycomb.cpp @@ -73,7 +73,7 @@ void FillHoneycomb::_fill_surface_single( } } - all_polylines = intersection_pl(std::move(all_polylines), to_polygons(expolygon)); + all_polylines = intersection_pl(std::move(all_polylines), expolygon); if (params.dont_connect() || all_polylines.size() <= 1) append(polylines_out, chain_polylines(std::move(all_polylines))); else diff --git a/src/libslic3r/Fill/FillPlanePath.cpp b/src/libslic3r/Fill/FillPlanePath.cpp index 7beaf2f08..6385a880e 100644 --- a/src/libslic3r/Fill/FillPlanePath.cpp +++ b/src/libslic3r/Fill/FillPlanePath.cpp @@ -44,7 +44,7 @@ void FillPlanePath::_fill_surface_single( coord_t(floor(pt.x() * distance_between_lines + 0.5)), coord_t(floor(pt.y() * distance_between_lines + 0.5)))); // intersection(polylines_src, offset((Polygons)expolygon, scale_(0.02)), &polylines); - polylines = intersection_pl(std::move(polylines), to_polygons(expolygon)); + polylines = intersection_pl(std::move(polylines), expolygon); Polylines chained; if (params.dont_connect() || params.density > 0.5 || polylines.size() <= 1) chained = chain_polylines(std::move(polylines)); diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 857c98f52..e8e3c4275 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -39,11 +39,11 @@ void Layer::make_slices() ExPolygons slices; if (m_regions.size() == 1) { // optimization: if we only have one region, take its slices - slices = m_regions.front()->slices; + slices = to_expolygons(m_regions.front()->slices.surfaces); } else { Polygons slices_p; for (LayerRegion *layerm : m_regions) - polygons_append(slices_p, to_polygons(layerm->slices)); + polygons_append(slices_p, to_polygons(layerm->slices.surfaces)); slices = union_ex(slices_p); } @@ -105,7 +105,7 @@ ExPolygons Layer::merged(float offset_scaled) const const PrintRegionConfig &config = layerm->region()->config(); // Our users learned to bend Slic3r to produce empty volumes to act as subtracters. Only add the region if it is non-empty. if (config.bottom_solid_layers > 0 || config.top_solid_layers > 0 || config.fill_density > 0. || config.perimeters > 0) - append(polygons, offset(to_expolygons(layerm->slices.surfaces), offset_scaled)); + append(polygons, offset(layerm->slices.surfaces, offset_scaled)); } ExPolygons out = union_ex(polygons); if (offset_scaled2 != 0.f) @@ -185,7 +185,7 @@ void Layer::make_perimeters() } // merge the surfaces assigned to each group for (std::pair &surfaces_with_extra_perimeters : slices) - new_slices.append(offset_ex(to_expolygons(surfaces_with_extra_perimeters.second), ClipperSafetyOffset), surfaces_with_extra_perimeters.second.front()); + new_slices.append(offset_ex(surfaces_with_extra_perimeters.second, ClipperSafetyOffset), surfaces_with_extra_perimeters.second.front()); } // make perimeters @@ -196,7 +196,7 @@ void Layer::make_perimeters() if (!fill_surfaces.surfaces.empty()) { for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) { // Separate the fill surfaces. - ExPolygons expp = intersection_ex(to_polygons(fill_surfaces), (*l)->slices); + ExPolygons expp = intersection_ex(fill_surfaces.surfaces, (*l)->slices.surfaces); (*l)->fill_expolygons = expp; (*l)->fill_surfaces.set(std::move(expp), fill_surfaces.surfaces.front()); } diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index 87296f8f1..2e3e29eab 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -196,7 +196,7 @@ protected: // between the raft and the object first layer. SupportLayer(size_t id, PrintObject *object, coordf_t height, coordf_t print_z, coordf_t slice_z) : Layer(id, object, height, print_z, slice_z) {} - virtual ~SupportLayer() {} + virtual ~SupportLayer() = default; }; } diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index 059d94e25..5b4a021b0 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -49,19 +49,17 @@ void LayerRegion::slices_to_fill_surfaces_clipped() // in place. However we're now only using its boundaries (which are invariant) // so we're safe. This guarantees idempotence of prepare_infill() also in case // that combine_infill() turns some fill_surface into VOID surfaces. -// Polygons fill_boundaries = to_polygons(std::move(this->fill_surfaces)); - Polygons fill_boundaries = to_polygons(this->fill_expolygons); // Collect polygons per surface type. - std::vector polygons_by_surface; - polygons_by_surface.assign(size_t(stCount), Polygons()); + std::vector by_surface; + by_surface.assign(size_t(stCount), SurfacesPtr()); for (Surface &surface : this->slices.surfaces) - polygons_append(polygons_by_surface[(size_t)surface.surface_type], surface.expolygon); + by_surface[size_t(surface.surface_type)].emplace_back(&surface); // Trim surfaces by the fill_boundaries. this->fill_surfaces.surfaces.clear(); for (size_t surface_type = 0; surface_type < size_t(stCount); ++ surface_type) { - const Polygons &polygons = polygons_by_surface[surface_type]; - if (! polygons.empty()) - this->fill_surfaces.append(intersection_ex(polygons, fill_boundaries), SurfaceType(surface_type)); + const SurfacesPtr &this_surfaces = by_surface[surface_type]; + if (! this_surfaces.empty()) + this->fill_surfaces.append(intersection_ex(this_surfaces, this->fill_expolygons), SurfaceType(surface_type)); } } @@ -221,7 +219,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly BOOST_LOG_TRIVIAL(trace) << "Bridge did not fall into the source region!"; } else { // Found an island, to which this bridge region belongs. Trim it, - polys = intersection(polys, to_polygons(fill_boundaries_ex[idx_island])); + polys = intersection(polys, fill_boundaries_ex[idx_island]); } bridge_bboxes.push_back(get_extents(polys)); bridges_grown.push_back(std::move(polys)); @@ -325,11 +323,11 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly if (s1.empty()) continue; Polygons polys; - polygons_append(polys, std::move(s1)); + polygons_append(polys, to_polygons(std::move(s1))); for (size_t j = i + 1; j < top.size(); ++ j) { Surface &s2 = top[j]; if (! s2.empty() && surfaces_could_merge(s1, s2)) { - polygons_append(polys, std::move(s2)); + polygons_append(polys, to_polygons(std::move(s2))); s2.clear(); } } @@ -351,11 +349,11 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly if (s1.empty()) continue; Polygons polys; - polygons_append(polys, std::move(s1)); + polygons_append(polys, to_polygons(std::move(s1))); for (size_t j = i + 1; j < internal.size(); ++ j) { Surface &s2 = internal[j]; if (! s2.empty() && surfaces_could_merge(s1, s2)) { - polygons_append(polys, std::move(s2)); + polygons_append(polys, to_polygons(std::move(s2))); s2.clear(); } } @@ -423,7 +421,7 @@ void LayerRegion::trim_surfaces(const Polygons &trimming_polygons) for (const Surface &surface : this->slices.surfaces) assert(surface.surface_type == stInternal); #endif /* NDEBUG */ - this->slices.set(intersection_ex(to_polygons(std::move(this->slices.surfaces)), trimming_polygons, false), stInternal); + this->slices.set(intersection_ex(this->slices.surfaces, trimming_polygons), stInternal); } void LayerRegion::elephant_foot_compensation_step(const float elephant_foot_compensation_perimeter_step, const Polygons &trimming_polygons) @@ -432,10 +430,9 @@ void LayerRegion::elephant_foot_compensation_step(const float elephant_foot_comp for (const Surface &surface : this->slices.surfaces) assert(surface.surface_type == stInternal); #endif /* NDEBUG */ - ExPolygons slices_expolygons = to_expolygons(std::move(this->slices.surfaces)); - Polygons slices_polygons = to_polygons(slices_expolygons); - Polygons tmp = intersection(slices_polygons, trimming_polygons, false); - append(tmp, diff(slices_polygons, offset(offset_ex(slices_expolygons, -elephant_foot_compensation_perimeter_step), elephant_foot_compensation_perimeter_step))); + ExPolygons surfaces = to_expolygons(std::move(this->slices.surfaces)); + Polygons tmp = intersection(surfaces, trimming_polygons); + append(tmp, diff(surfaces, offset(offset_ex(surfaces, -elephant_foot_compensation_perimeter_step), elephant_foot_compensation_perimeter_step))); this->slices.set(union_ex(tmp), stInternal); } diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 6ec4dbf6b..a459b90fa 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -349,9 +349,7 @@ void PerimeterGenerator::process() coord_t min_width = coord_t(scale_(this->ext_perimeter_flow.nozzle_diameter() / 3)); ExPolygons expp = offset2_ex( // medial axis requires non-overlapping geometry - diff_ex(to_polygons(last), - offset(offsets, float(ext_perimeter_width / 2.)), - true), + diff_ex(last, offset(offsets, float(ext_perimeter_width / 2.)), true), - float(min_width / 2.), float(min_width / 2.)); // the maximum thickness of our thin wall area is equal to the minimum thickness of a single loop for (ExPolygon &ex : expp) @@ -514,7 +512,7 @@ void PerimeterGenerator::process() and use zigzag). */ //FIXME Vojtech: This grows by a rounded extrusion width, not by line spacing, // therefore it may cover the area, but no the volume. - last = diff_ex(to_polygons(last), gap_fill.polygons_covered_by_width(10.f)); + last = diff_ex(last, gap_fill.polygons_covered_by_width(10.f)); this->gap_fill->append(std::move(gap_fill.entities)); } } diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index cbf3e71ab..d0a6a871f 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -186,7 +186,7 @@ void PrintObject::make_perimeters() m_print->throw_if_canceled(); LayerRegion &layerm = *m_layers[layer_idx]->m_regions[region_id]; const LayerRegion &upper_layerm = *m_layers[layer_idx+1]->m_regions[region_id]; - const Polygons upper_layerm_polygons = upper_layerm.slices; + const Polygons upper_layerm_polygons = to_polygons(upper_layerm.slices.surfaces); // Filter upper layer polygons in intersection_ppl by their bounding boxes? // my $upper_layerm_poly_bboxes= [ map $_->bounding_box, @{$upper_layerm_polygons} ]; const double total_loop_length = total_length(upper_layerm_polygons); @@ -809,19 +809,14 @@ void PrintObject::detect_surfaces_type() // collapse very narrow parts (using the safety offset in the diff is not enough) float offset = layerm->flow(frExternalPerimeter).scaled_width() / 10.f; - Polygons layerm_slices_surfaces = to_polygons(layerm->slices.surfaces); - // find top surfaces (difference between current surfaces // of current layer and upper one) Surfaces top; if (upper_layer) { - Polygons upper_slices = interface_shells ? - to_polygons(upper_layer->m_regions[idx_region]->slices.surfaces) : - to_polygons(upper_layer->lslices); - surfaces_append(top, - //FIXME implement offset2_ex working over ExPolygons, that should be a bit more efficient than calling offset_ex twice. - offset_ex(offset_ex(diff_ex(layerm_slices_surfaces, upper_slices, true), -offset), offset), - stTop); + ExPolygons upper_slices = interface_shells ? + diff_ex(layerm->slices.surfaces, upper_layer->m_regions[idx_region]->slices.surfaces, true) : + diff_ex(layerm->slices.surfaces, upper_layer->lslices, true); + surfaces_append(top, offset2_ex(upper_slices, -offset, offset), stTop); } else { // if no upper layer, all surfaces of this one are solid // we clone surfaces because we're going to clear the slices collection @@ -839,14 +834,14 @@ void PrintObject::detect_surfaces_type() to_polygons(lower_layer->get_region(idx_region)->slices.surfaces) : to_polygons(lower_layer->slices); surfaces_append(bottom, - offset2_ex(diff(layerm_slices_surfaces, lower_slices, true), -offset, offset), + offset2_ex(diff(layerm->slices.surfaces, lower_slices, true), -offset, offset), surface_type_bottom_other); #else // Any surface lying on the void is a true bottom bridge (an overhang) surfaces_append( bottom, offset2_ex( - diff(layerm_slices_surfaces, to_polygons(lower_layer->lslices), true), + diff_ex(layerm->slices.surfaces, lower_layer->lslices, true), -offset, offset), surface_type_bottom_other); // if user requested internal shells, we need to identify surfaces @@ -857,10 +852,10 @@ void PrintObject::detect_surfaces_type() surfaces_append( bottom, offset2_ex( - diff( - intersection(layerm_slices_surfaces, to_polygons(lower_layer->lslices)), // supported - to_polygons(lower_layer->m_regions[idx_region]->slices.surfaces), - true), + diff_ex( + intersection(layerm->slices.surfaces, lower_layer->lslices), // supported + lower_layer->m_regions[idx_region]->slices.surfaces, + true), -offset, offset), stBottom); } @@ -883,7 +878,7 @@ void PrintObject::detect_surfaces_type() Polygons top_polygons = to_polygons(std::move(top)); top.clear(); surfaces_append(top, - diff_ex(top_polygons, to_polygons(bottom), false), + diff_ex(top_polygons, bottom, false), stTop); } @@ -900,15 +895,18 @@ void PrintObject::detect_surfaces_type() // save surfaces to layer Surfaces &surfaces_out = interface_shells ? surfaces_new[idx_layer] : layerm->slices.surfaces; - surfaces_out.clear(); + Surfaces surfaces_backup; + if (! interface_shells) { + surfaces_backup = std::move(surfaces_out); + surfaces_out.clear(); + } + const Surfaces &surfaces_prev = interface_shells ? layerm->slices.surfaces : surfaces_backup; // find internal surfaces (difference between top/bottom surfaces and others) { Polygons topbottom = to_polygons(top); polygons_append(topbottom, to_polygons(bottom)); - surfaces_append(surfaces_out, - diff_ex(layerm_slices_surfaces, topbottom, false), - stInternal); + surfaces_append(surfaces_out, diff_ex(surfaces_prev, topbottom, false), stInternal); } surfaces_append(surfaces_out, std::move(top)); @@ -1012,7 +1010,7 @@ void PrintObject::process_external_surfaces() // Shrink the holes, let the layer above expand slightly inside the unsupported areas. polygons_append(voids, offset(surface.expolygon, unsupported_width)); } - surfaces_covered[layer_idx] = diff(to_polygons(this->m_layers[layer_idx]->lslices), voids); + surfaces_covered[layer_idx] = diff(this->m_layers[layer_idx]->lslices, voids); } } ); @@ -1107,11 +1105,11 @@ void PrintObject::discover_vertical_shells() LayerRegion &layerm = *layer.m_regions[idx_region]; float min_perimeter_infill_spacing = float(layerm.flow(frSolidInfill).scaled_spacing()) * 1.05f; // Top surfaces. - append(cache.top_surfaces, offset(to_expolygons(layerm.slices.filter_by_type(stTop)), min_perimeter_infill_spacing)); - append(cache.top_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_type(stTop)), min_perimeter_infill_spacing)); + append(cache.top_surfaces, offset(layerm.slices.filter_by_type(stTop), min_perimeter_infill_spacing)); + append(cache.top_surfaces, offset(layerm.fill_surfaces.filter_by_type(stTop), min_perimeter_infill_spacing)); // Bottom surfaces. - append(cache.bottom_surfaces, offset(to_expolygons(layerm.slices.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing)); - append(cache.bottom_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing)); + append(cache.bottom_surfaces, offset(layerm.slices.filter_by_types(surfaces_bottom, 2), min_perimeter_infill_spacing)); + append(cache.bottom_surfaces, offset(layerm.fill_surfaces.filter_by_types(surfaces_bottom, 2), min_perimeter_infill_spacing)); // Calculate the maximum perimeter offset as if the slice was extruded with a single extruder only. // First find the maxium number of perimeters per region slice. unsigned int perimeters = 0; @@ -1181,11 +1179,11 @@ void PrintObject::discover_vertical_shells() float min_perimeter_infill_spacing = float(layerm.flow(frSolidInfill).scaled_spacing()) * 1.05f; // Top surfaces. auto &cache = cache_top_botom_regions[idx_layer]; - cache.top_surfaces = offset(to_expolygons(layerm.slices.filter_by_type(stTop)), min_perimeter_infill_spacing); - append(cache.top_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_type(stTop)), min_perimeter_infill_spacing)); + cache.top_surfaces = offset(layerm.slices.filter_by_type(stTop), min_perimeter_infill_spacing); + append(cache.top_surfaces, offset(layerm.fill_surfaces.filter_by_type(stTop), min_perimeter_infill_spacing)); // Bottom surfaces. - cache.bottom_surfaces = offset(to_expolygons(layerm.slices.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing); - append(cache.bottom_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing)); + cache.bottom_surfaces = offset(layerm.slices.filter_by_types(surfaces_bottom, 2), min_perimeter_infill_spacing); + append(cache.bottom_surfaces, offset(layerm.fill_surfaces.filter_by_types(surfaces_bottom, 2), min_perimeter_infill_spacing)); // Holes over all regions. Only collect them once, they are valid for all idx_region iterations. if (cache.holes.empty()) { for (size_t idx_region = 0; idx_region < layer.regions().size(); ++ idx_region) @@ -1407,16 +1405,8 @@ void PrintObject::discover_vertical_shells() #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ // Trim the internal & internalvoid by the shell. - Slic3r::ExPolygons new_internal = diff_ex( - to_polygons(layerm->fill_surfaces.filter_by_type(stInternal)), - shell, - false - ); - Slic3r::ExPolygons new_internal_void = diff_ex( - to_polygons(layerm->fill_surfaces.filter_by_type(stInternalVoid)), - shell, - false - ); + Slic3r::ExPolygons new_internal = diff_ex(layerm->fill_surfaces.filter_by_type(stInternal), shell); + Slic3r::ExPolygons new_internal_void = diff_ex(layerm->fill_surfaces.filter_by_type(stInternalVoid), shell); #ifdef SLIC3R_DEBUG_SLICE_PROCESSING { @@ -1521,8 +1511,8 @@ void PrintObject::bridge_over_infill() #endif // compute the remaning internal solid surfaces as difference - ExPolygons not_to_bridge = diff_ex(internal_solid, to_polygons(to_bridge), true); - to_bridge = intersection_ex(to_polygons(to_bridge), internal_solid, true); + ExPolygons not_to_bridge = diff_ex(internal_solid, to_bridge, true); + to_bridge = intersection_ex(to_bridge, internal_solid, true); // build the new collection of fill_surfaces layerm->fill_surfaces.remove_type(stInternalSolid); for (ExPolygon &ex : to_bridge) @@ -1875,7 +1865,7 @@ void PrintObject::_slice(const std::vector &layer_height_profile) slices = offset_ex(std::move(slices), delta); if (! processed.empty()) // Trim by the slices of already processed regions. - slices = diff_ex(to_polygons(std::move(slices)), processed); + slices = diff_ex(slices, processed); if (size_t(&sliced_volume - &sliced_volumes.front()) + 1 < sliced_volumes.size()) // Collect the already processed regions to trim the to be processed regions. polygons_append(processed, slices); @@ -1926,12 +1916,11 @@ void PrintObject::_slice(const std::vector &layer_height_profile) LayerRegion *other_layerm = layer->m_regions[other_region_id]; if (layerm == nullptr || other_layerm == nullptr || other_layerm->slices.empty() || expolygons_by_layer[layer_id].empty()) continue; - Polygons other_slices = to_polygons(other_layerm->slices); - ExPolygons my_parts = intersection_ex(other_slices, to_polygons(expolygons_by_layer[layer_id])); + ExPolygons my_parts = intersection_ex(other_layerm->slices.surfaces, expolygons_by_layer[layer_id]); if (my_parts.empty()) continue; // Remove such parts from original region. - other_layerm->slices.set(diff_ex(other_slices, to_polygons(my_parts)), stInternal); + other_layerm->slices.set(diff_ex(other_layerm->slices.surfaces, my_parts), stInternal); // Append new parts to our region. layerm->slices.append(std::move(my_parts), stInternal); } @@ -2018,7 +2007,7 @@ end: slices = offset_ex(std::move(slices), xy_compensation_scaled); if (region_id > 0 && clip) // Trim by the slices of already processed regions. - slices = diff_ex(to_polygons(std::move(slices)), processed); + slices = diff_ex(slices, processed); if (clip && (region_id + 1 < layer->m_regions.size())) // Collect the already processed regions to trim the to be processed regions. polygons_append(processed, slices); @@ -2649,10 +2638,7 @@ void PrintObject::discover_horizontal_shells() neighbor_layerm->fill_surfaces.set(internal_solid, stInternalSolid); // subtract intersections from layer surfaces to get resulting internal surfaces Polygons polygons_internal = to_polygons(std::move(internal_solid)); - ExPolygons internal = diff_ex( - to_polygons(backup.filter_by_type(stInternal)), - polygons_internal, - true); + ExPolygons internal = diff_ex(backup.filter_by_type(stInternal), polygons_internal, true); // assign resulting internal surfaces to layer neighbor_layerm->fill_surfaces.append(internal, stInternal); polygons_append(polygons_internal, to_polygons(std::move(internal))); @@ -2663,7 +2649,7 @@ void PrintObject::discover_horizontal_shells() backup.group(&top_bottom_groups); for (SurfacesPtr &group : top_bottom_groups) neighbor_layerm->fill_surfaces.append( - diff_ex(to_polygons(group), polygons_internal), + diff_ex(group, polygons_internal), // Use an existing surface as a template, it carries the bridge angle etc. *group.front()); } @@ -2742,10 +2728,7 @@ void PrintObject::combine_infill() ExPolygons intersection = to_expolygons(layerms.front()->fill_surfaces.filter_by_type(stInternal)); // Start looping from the second layer and intersect the current intersection with it. for (size_t i = 1; i < layerms.size(); ++ i) - intersection = intersection_ex( - to_polygons(intersection), - to_polygons(layerms[i]->fill_surfaces.filter_by_type(stInternal)), - false); + intersection = intersection_ex(layerms[i]->fill_surfaces.filter_by_type(stInternal), intersection); double area_threshold = layerms.front()->infill_area_threshold(); if (! intersection.empty() && area_threshold > 0.) intersection.erase(std::remove_if(intersection.begin(), intersection.end(), @@ -2774,7 +2757,7 @@ void PrintObject::combine_infill() for (ExPolygon &expoly : intersection) polygons_append(intersection_with_clearance, offset(expoly, clearance_offset)); for (LayerRegion *layerm : layerms) { - Polygons internal = to_polygons(layerm->fill_surfaces.filter_by_type(stInternal)); + Polygons internal = to_polygons(std::move(layerm->fill_surfaces.filter_by_type(stInternal))); layerm->fill_surfaces.remove_type(stInternal); layerm->fill_surfaces.append(diff_ex(internal, intersection_with_clearance, false), stInternal); if (layerm == layerms.back()) { diff --git a/src/libslic3r/SLA/SupportPointGenerator.cpp b/src/libslic3r/SLA/SupportPointGenerator.cpp index 5ef4eb001..bbc6b03fa 100644 --- a/src/libslic3r/SLA/SupportPointGenerator.cpp +++ b/src/libslic3r/SLA/SupportPointGenerator.cpp @@ -179,9 +179,8 @@ static std::vector make_layers( } } if (! top.islands_below.empty()) { - Polygons top_polygons = to_polygons(*top.polygon); Polygons bottom_polygons = top.polygons_below(); - top.overhangs = diff_ex(top_polygons, bottom_polygons); + top.overhangs = diff_ex(*top.polygon, bottom_polygons); if (! top.overhangs.empty()) { // Produce 2 bands around the island, a safe band for dangling overhangs @@ -191,7 +190,7 @@ static std::vector make_layers( auto overh_mask = offset(bottom_polygons, slope_offset, ClipperLib::jtSquare); // Absolutely hopeless overhangs are those outside the unsafe band - top.overhangs = diff_ex(top_polygons, overh_mask); + top.overhangs = diff_ex(*top.polygon, overh_mask); // Now cut out the supported core from the safe band // and cut the safe band from the unsafe band to get distinct @@ -199,8 +198,8 @@ static std::vector make_layers( overh_mask = diff(overh_mask, dangl_mask); dangl_mask = diff(dangl_mask, bottom_polygons); - top.dangling_areas = intersection_ex(top_polygons, dangl_mask); - top.overhangs_slopes = intersection_ex(top_polygons, overh_mask); + top.dangling_areas = intersection_ex(*top.polygon, dangl_mask); + top.overhangs_slopes = intersection_ex(*top.polygon, overh_mask); top.overhangs_area = 0.f; std::vector> expolys_with_areas; diff --git a/src/libslic3r/SLA/SupportPointGenerator.hpp b/src/libslic3r/SLA/SupportPointGenerator.hpp index d7588e3ba..9ceda7896 100644 --- a/src/libslic3r/SLA/SupportPointGenerator.hpp +++ b/src/libslic3r/SLA/SupportPointGenerator.hpp @@ -90,7 +90,7 @@ public: float overlap_area(const Structure &rhs) const { double out = 0.; if (this->bbox.overlap(rhs.bbox)) { - Polygons polys = intersection(to_polygons(*this->polygon), to_polygons(*rhs.polygon), false); + Polygons polys = intersection(*this->polygon, *rhs.polygon, false); for (const Polygon &poly : polys) out += poly.area(); } diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 08cd04b90..b4f5fefae 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -815,7 +815,7 @@ public: // Expanding, thus m_support_polygons are all inside islands. union_ex(*m_support_polygons) : // Shrinking, thus m_support_polygons may be trimmed a tiny bit by islands. - intersection_ex(*m_support_polygons, to_polygons(islands))); + intersection_ex(*m_support_polygons, islands)); std::vector> samples_inside; for (ExPolygon &island : islands) { @@ -932,7 +932,7 @@ public: } // Deserialization constructor - bool deserialize_(const std::string &path, int which = -1) + bool deserialize_(const std::string &path, int which = -1) { FILE *file = ::fopen(path.c_str(), "rb"); if (file == nullptr) @@ -961,7 +961,7 @@ public: poly.points.emplace_back(Point(x * scale, y * scale)); } if (which == -1 || which == i) - m_support_polygons_deserialized.emplace_back(std::move(poly)); + m_support_polygons_deserialized.emplace_back(std::move(poly)); printf("Polygon %d, area: %lf\n", i, area(poly.points)); } ::fread(&n_polygons, 4, 1, file); @@ -984,14 +984,14 @@ public: m_support_polygons_deserialized = simplify_polygons(m_support_polygons_deserialized, false); //m_support_polygons_deserialized = to_polygons(union_ex(m_support_polygons_deserialized, false)); - // Create an EdgeGrid, initialize it with projection, initialize signed distance field. - coord_t grid_resolution = coord_t(scale_(m_support_spacing)); - BoundingBox bbox = get_extents(*m_support_polygons); + // Create an EdgeGrid, initialize it with projection, initialize signed distance field. + coord_t grid_resolution = coord_t(scale_(m_support_spacing)); + BoundingBox bbox = get_extents(*m_support_polygons); bbox.offset(20); - bbox.align_to_grid(grid_resolution); - m_grid.set_bbox(bbox); - m_grid.create(*m_support_polygons, grid_resolution); - m_grid.calculate_sdf(); + bbox.align_to_grid(grid_resolution); + m_grid.set_bbox(bbox); + m_grid.create(*m_support_polygons, grid_resolution); + m_grid.calculate_sdf(); return true; } @@ -1285,7 +1285,7 @@ namespace SupportMaterialInternal { // Is the straight perimeter segment supported at both sides? Point pts[2] = { polyline.first_point(), polyline.last_point() }; bool supported[2] = { false, false }; - for (size_t i = 0; i < lower_layer.lslices.size() && ! (supported[0] && supported[1]); ++ i) + for (size_t i = 0; i < lower_layer.lslices.size() && ! (supported[0] && supported[1]); ++ i) for (int j = 0; j < 2; ++ j) if (! supported[j] && lower_layer.lslices_bboxes[i].contains(pts[j]) && lower_layer.lslices[i].contains(pts[j])) supported[j] = true; @@ -1437,7 +1437,7 @@ static inline std::tuple detect_overhangs( 0.5f * fw); // Overhang polygons for this layer and region. Polygons diff_polygons; - Polygons layerm_polygons = to_polygons(layerm->slices); + Polygons layerm_polygons = to_polygons(layerm->slices.surfaces); if (lower_layer_offset == 0.f) { // Support everything. diff_polygons = diff(layerm_polygons, lower_layer_polygons); @@ -1469,13 +1469,13 @@ static inline std::tuple detect_overhangs( diff_polygons = diff(diff_polygons, annotations.buildplate_covered[layer_id]); } if (! diff_polygons.empty()) { - // Offset the support regions back to a full overhang, restrict them to the full overhang. - // This is done to increase size of the supporting columns below, as they are calculated by - // propagating these contact surfaces downwards. - diff_polygons = diff( - intersection(offset(diff_polygons, lower_layer_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS), layerm_polygons), - lower_layer_polygons); - } + // Offset the support regions back to a full overhang, restrict them to the full overhang. + // This is done to increase size of the supporting columns below, as they are calculated by + // propagating these contact surfaces downwards. + diff_polygons = diff( + intersection(offset(diff_polygons, lower_layer_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS), layerm_polygons), + lower_layer_polygons); + } } } @@ -1489,7 +1489,7 @@ static inline std::tuple detect_overhangs( // Subtracting them as they are may leave unwanted narrow // residues of diff_polygons that would then be supported. diff_polygons = diff(diff_polygons, - offset(union_(to_polygons(std::move(annotations.blockers_layers[layer_id]))), float(1000.*SCALED_EPSILON))); + offset(union_(annotations.blockers_layers[layer_id]), float(1000.*SCALED_EPSILON))); } #ifdef SLIC3R_DEBUG @@ -1538,7 +1538,7 @@ static inline std::tuple detect_overhangs( slices_margin.offset = slices_margin_offset; slices_margin.polygons = (slices_margin_offset == 0.f) ? lower_layer_polygons : - offset2(to_polygons(lower_layer.lslices), - no_interface_offset * 0.5f, slices_margin_offset + no_interface_offset * 0.5f, SUPPORT_SURFACES_OFFSET_PARAMETERS); + offset2(lower_layer.lslices, - no_interface_offset * 0.5f, slices_margin_offset + no_interface_offset * 0.5f, SUPPORT_SURFACES_OFFSET_PARAMETERS); if (buildplate_only && ! annotations.buildplate_covered[layer_id].empty()) { if (has_enforcer) // Make a backup of trimming polygons before enforcing "on build plate only". @@ -1569,9 +1569,9 @@ static inline std::tuple detect_overhangs( if (has_enforcer) { // Enforce supports (as if with 90 degrees of slope) for the regions covered by the enforcer meshes. #ifdef SLIC3R_DEBUG - ExPolygons enforcers_united = union_ex(to_polygons(annotations.enforcers_layers[layer_id]), false); + ExPolygons enforcers_united = union_ex(annotations.enforcers_layers[layer_id]); #endif // SLIC3R_DEBUG - enforcer_polygons = diff(intersection(to_polygons(layer.lslices), to_polygons(std::move(annotations.enforcers_layers[layer_id]))), + enforcer_polygons = diff(intersection(layer.lslices, annotations.enforcers_layers[layer_id]), // Inflate just a tiny bit to avoid intersection of the overhang areas with the object. offset(lower_layer_polygons, 0.05f * fw, SUPPORT_SURFACES_OFFSET_PARAMETERS)); #ifdef SLIC3R_DEBUG @@ -2772,8 +2772,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object( break; some_region_overlaps = true; polygons_append(polygons_trimming, - offset(to_expolygons(region->fill_surfaces.filter_by_type(stBottomBridge)), - gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS)); + offset(region->fill_surfaces.filter_by_type(stBottomBridge), gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS)); if (region->region()->config().overhangs.value) // Add bridging perimeters. SupportMaterialInternal::collect_bridging_perimeter_areas(region->perimeters, gap_xy_scaled, polygons_trimming); @@ -3093,8 +3092,8 @@ static inline void fill_expolygon_generate_paths( Polylines polylines; try { polylines = filler->fill_surface(&surface, fill_params); - } catch (InfillFailedException &) { - } + } catch (InfillFailedException &) { + } extrusion_entities_append_paths( dst, std::move(polylines), diff --git a/src/libslic3r/Surface.hpp b/src/libslic3r/Surface.hpp index fbebe5610..4920efbbf 100644 --- a/src/libslic3r/Surface.hpp +++ b/src/libslic3r/Surface.hpp @@ -90,7 +90,6 @@ public: return *this; } - operator Polygons() const { return this->expolygon; } double area() const { return this->expolygon.area(); } bool empty() const { return expolygon.empty(); } void clear() { expolygon.clear(); } @@ -107,6 +106,16 @@ public: typedef std::vector Surfaces; typedef std::vector SurfacesPtr; +inline Polygons to_polygons(const Surface &surface) +{ + return to_polygons(surface.expolygon); +} + +inline Polygons to_polygons(Surface &&surface) +{ + return to_polygons(std::move(surface.expolygon)); +} + inline Polygons to_polygons(const Surfaces &src) { size_t num = 0; diff --git a/src/libslic3r/SurfaceCollection.cpp b/src/libslic3r/SurfaceCollection.cpp index 6db599306..ec847d2a3 100644 --- a/src/libslic3r/SurfaceCollection.cpp +++ b/src/libslic3r/SurfaceCollection.cpp @@ -6,18 +6,7 @@ namespace Slic3r { -SurfaceCollection::operator Polygons() const -{ - return to_polygons(surfaces); -} - -SurfaceCollection::operator ExPolygons() const -{ - return to_expolygons(surfaces); -} - -void -SurfaceCollection::simplify(double tolerance) +void SurfaceCollection::simplify(double tolerance) { Surfaces ss; for (Surfaces::const_iterator it_s = this->surfaces.begin(); it_s != this->surfaces.end(); ++it_s) { @@ -33,8 +22,7 @@ SurfaceCollection::simplify(double tolerance) } /* group surfaces by common properties */ -void -SurfaceCollection::group(std::vector *retval) +void SurfaceCollection::group(std::vector *retval) { for (Surfaces::iterator it = this->surfaces.begin(); it != this->surfaces.end(); ++it) { // find a group with the same properties @@ -54,8 +42,7 @@ SurfaceCollection::group(std::vector *retval) } } -SurfacesPtr -SurfaceCollection::filter_by_type(const SurfaceType type) +SurfacesPtr SurfaceCollection::filter_by_type(const SurfaceType type) { SurfacesPtr ss; for (Surfaces::iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) { @@ -64,8 +51,7 @@ SurfaceCollection::filter_by_type(const SurfaceType type) return ss; } -SurfacesPtr -SurfaceCollection::filter_by_types(const SurfaceType *types, int ntypes) +SurfacesPtr SurfaceCollection::filter_by_types(const SurfaceType *types, int ntypes) { SurfacesPtr ss; for (Surfaces::iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) { @@ -79,8 +65,7 @@ SurfaceCollection::filter_by_types(const SurfaceType *types, int ntypes) return ss; } -void -SurfaceCollection::filter_by_type(SurfaceType type, Polygons* polygons) +void SurfaceCollection::filter_by_type(SurfaceType type, Polygons* polygons) { for (Surfaces::iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) { if (surface->surface_type == type) { @@ -90,8 +75,7 @@ SurfaceCollection::filter_by_type(SurfaceType type, Polygons* polygons) } } -void -SurfaceCollection::keep_type(const SurfaceType type) +void SurfaceCollection::keep_type(const SurfaceType type) { size_t j = 0; for (size_t i = 0; i < surfaces.size(); ++ i) { @@ -105,8 +89,7 @@ SurfaceCollection::keep_type(const SurfaceType type) surfaces.erase(surfaces.begin() + j, surfaces.end()); } -void -SurfaceCollection::keep_types(const SurfaceType *types, int ntypes) +void SurfaceCollection::keep_types(const SurfaceType *types, int ntypes) { size_t j = 0; for (size_t i = 0; i < surfaces.size(); ++ i) { @@ -127,8 +110,7 @@ SurfaceCollection::keep_types(const SurfaceType *types, int ntypes) surfaces.erase(surfaces.begin() + j, surfaces.end()); } -void -SurfaceCollection::remove_type(const SurfaceType type) +void SurfaceCollection::remove_type(const SurfaceType type) { size_t j = 0; for (size_t i = 0; i < surfaces.size(); ++ i) { @@ -142,8 +124,7 @@ SurfaceCollection::remove_type(const SurfaceType type) surfaces.erase(surfaces.begin() + j, surfaces.end()); } -void -SurfaceCollection::remove_types(const SurfaceType *types, int ntypes) +void SurfaceCollection::remove_types(const SurfaceType *types, int ntypes) { size_t j = 0; for (size_t i = 0; i < surfaces.size(); ++ i) { diff --git a/src/libslic3r/SurfaceCollection.hpp b/src/libslic3r/SurfaceCollection.hpp index 9f0324d20..7e01a68df 100644 --- a/src/libslic3r/SurfaceCollection.hpp +++ b/src/libslic3r/SurfaceCollection.hpp @@ -12,11 +12,10 @@ class SurfaceCollection public: Surfaces surfaces; - SurfaceCollection() {}; - SurfaceCollection(const Surfaces &surfaces) : surfaces(surfaces) {}; + SurfaceCollection() = default; + SurfaceCollection(const Surfaces& surfaces) : surfaces(surfaces) {}; SurfaceCollection(Surfaces &&surfaces) : surfaces(std::move(surfaces)) {}; - operator Polygons() const; - operator ExPolygons() const; + void simplify(double tolerance); void group(std::vector *retval); template bool any_internal_contains(const T &item) const { diff --git a/tests/libslic3r/test_clipper_utils.cpp b/tests/libslic3r/test_clipper_utils.cpp index a660b29cb..bbf76ea18 100644 --- a/tests/libslic3r/test_clipper_utils.cpp +++ b/tests/libslic3r/test_clipper_utils.cpp @@ -22,7 +22,7 @@ SCENARIO("Various Clipper operations - xs/t/11_clipper.t", "[ClipperUtils]") { THEN("offset matches") { REQUIRE(result == Polygons { { { 205, 205 }, { 95, 205 }, { 95, 95 }, { 205, 95 }, }, - { { 145, 145 }, { 145, 155 }, { 155, 155 }, { 155, 145 } } }); + { { 155, 145 }, { 145, 145 }, { 145, 155 }, { 155, 155 } } }); } } WHEN("offset_ex") { @@ -56,7 +56,7 @@ SCENARIO("Various Clipper operations - xs/t/11_clipper.t", "[ClipperUtils]") { } GIVEN("square and hole") { WHEN("diff_ex") { - ExPolygons result = Slic3r::diff_ex({ square }, { hole_in_square }); + ExPolygons result = Slic3r::diff_ex(Polygons{ square }, Polygons{ hole_in_square }); THEN("hole is created") { REQUIRE(result.size() == 1); REQUIRE(square_with_hole.area() == result.front().area()); @@ -77,7 +77,7 @@ SCENARIO("Various Clipper operations - xs/t/11_clipper.t", "[ClipperUtils]") { } } WHEN("diff_pl") { - Polylines result = Slic3r::diff_pl({ polyline }, { square, hole_in_square }); + Polylines result = Slic3r::diff_pl({ polyline }, Polygons{ square, hole_in_square }); THEN("correct number of result lines") { REQUIRE(result.size() == 3); } @@ -180,7 +180,7 @@ SCENARIO("Various Clipper operations - t/clipper.t", "[ClipperUtils]") { // CW oriented contour Slic3r::Polygon hole_in_square { { 14, 14 }, { 14, 16 }, { 16, 16 }, { 16, 14 } }; WHEN("intersection_ex with another square") { - ExPolygons intersection = Slic3r::intersection_ex({ square, hole_in_square }, { square2 }); + ExPolygons intersection = Slic3r::intersection_ex(Polygons{ square, hole_in_square }, Polygons{ square2 }); THEN("intersection area matches (hole is preserved)") { ExPolygon match({ { 20, 18 }, { 10, 18 }, { 10, 12 }, { 20, 12 } }, { { 14, 16 }, { 16, 16 }, { 16, 14 }, { 14, 14 } }); @@ -203,7 +203,7 @@ SCENARIO("Various Clipper operations - t/clipper.t", "[ClipperUtils]") { } } WHEN("diff_ex with another square") { - ExPolygons diff = Slic3r::diff_ex({ square, square2 }, { hole }); + ExPolygons diff = Slic3r::diff_ex(Polygons{ square, square2 }, Polygons{ hole }); THEN("difference of a cw from two ccw is a contour with one hole") { REQUIRE(diff.size() == 1); REQUIRE(diff.front().area() == Approx(ExPolygon({ {40, 40}, {0, 40}, {0, 0}, {40, 0} }, { {15, 25}, {25, 25}, {25, 15}, {15, 15} }).area())); @@ -214,7 +214,7 @@ SCENARIO("Various Clipper operations - t/clipper.t", "[ClipperUtils]") { Slic3r::Polygon square { { 10, 10 }, { 20, 10 }, { 20, 20 }, { 10, 20 } }; Slic3r::Polyline square_pl = square.split_at_first_point(); WHEN("no-op diff_pl") { - Slic3r::Polylines res = Slic3r::diff_pl({ square_pl }, {}); + Slic3r::Polylines res = Slic3r::diff_pl({ square_pl }, Polygons{}); THEN("returns the right number of polylines") { REQUIRE(res.size() == 1); } From c7c7983e77e42b5c5209a384fc2afabd5b08974f Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Mon, 3 May 2021 11:50:05 +0200 Subject: [PATCH 3/6] Fixing compilation on C++ conforming compilers --- src/clipper/clipper.hpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/clipper/clipper.hpp b/src/clipper/clipper.hpp index 36b9beee5..74e6601f9 100644 --- a/src/clipper/clipper.hpp +++ b/src/clipper/clipper.hpp @@ -192,15 +192,6 @@ inline bool Orientation(const Path &poly) { return Area(poly) >= 0; } int PointInPolygon(const IntPoint &pt, const Path &path); Paths SimplifyPolygon(const Path &in_poly, PolyFillType fillType = pftEvenOdd); -template -inline Paths SimplifyPolygons(PathsProvider &&in_polys, PolyFillType fillType = pftEvenOdd) { - Clipper c; - c.StrictlySimple(true); - c.AddPaths(std::forward(in_polys), ptSubject, true); - Paths out; - c.Execute(ctUnion, out, fillType, fillType); - return out; -} void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415); void CleanPolygon(Path& poly, double distance = 1.415); @@ -560,6 +551,16 @@ class clipperException : public std::exception }; //------------------------------------------------------------------------------ +template +inline Paths SimplifyPolygons(PathsProvider &&in_polys, PolyFillType fillType = pftEvenOdd) { + Clipper c; + c.StrictlySimple(true); + c.AddPaths(std::forward(in_polys), ptSubject, true); + Paths out; + c.Execute(ctUnion, out, fillType, fillType); + return out; +} + } //ClipperLib namespace #ifdef CLIPPERLIB_NAMESPACE_PREFIX From 96f8744e05bc97e99f7c7db811a5ac17fe9858d5 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Mon, 3 May 2021 11:55:23 +0200 Subject: [PATCH 4/6] Another fix for C++ conformant compilers --- src/libslic3r/ClipperUtils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index 49a244089..f8a94ed69 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -63,7 +63,7 @@ namespace ClipperUtils { static ExPolygons PolyTreeToExPolygons(ClipperLib::PolyTree &&polytree) { struct Inner { - static void PolyTreeToExPolygonsRecursive(ClipperLib::PolyNode &polynode, ExPolygons *expolygons) + static void PolyTreeToExPolygonsRecursive(ClipperLib::PolyNode &&polynode, ExPolygons *expolygons) { size_t cnt = expolygons->size(); expolygons->resize(cnt + 1); @@ -73,7 +73,7 @@ static ExPolygons PolyTreeToExPolygons(ClipperLib::PolyTree &&polytree) (*expolygons)[cnt].holes[i].points = std::move(polynode.Childs[i]->Contour); // Add outer polygons contained by (nested within) holes. for (int j = 0; j < polynode.Childs[i]->ChildCount(); ++ j) - PolyTreeToExPolygonsRecursive(*polynode.Childs[i]->Childs[j], expolygons); + PolyTreeToExPolygonsRecursive(std::move(*polynode.Childs[i]->Childs[j]), expolygons); } } From 0e6e60705ddec3d1d67d983c720b665d65380aaf Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Mon, 3 May 2021 14:12:08 +0200 Subject: [PATCH 5/6] Fixing one unit test, which seems to indicate that the refactoring fixed one issue (hopefully it was not that a newly introduced bug hides an old one). --- t/perimeters.t | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/perimeters.t b/t/perimeters.t index d0657cb23..3d3fd3819 100644 --- a/t/perimeters.t +++ b/t/perimeters.t @@ -394,9 +394,9 @@ use Slic3r::Test; }); return scalar keys %z_with_bridges; }; - ok $test->(Slic3r::Test::init_print('V', config => $config)) == 1, - 'no overhangs printed with bridge speed'; # except for the first internal solid layers above void - ok $test->(Slic3r::Test::init_print('V', config => $config, scale_xyz => [3,1,1])) > 1, + ok $test->(Slic3r::Test::init_print('V', config => $config)) == 2, + 'no overhangs printed with bridge speed'; # except for the two internal solid layers above void + ok $test->(Slic3r::Test::init_print('V', config => $config, scale_xyz => [3,1,1])) > 2, 'overhangs printed with bridge speed'; } From 7563c885a19dac14d599bff4e08bcbf4de017064 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Mon, 3 May 2021 15:00:23 +0200 Subject: [PATCH 6/6] Fixing compiler warnings --- src/libslic3r/ClipperUtils.cpp | 11 +---------- src/libslic3r/ClipperUtils.hpp | 12 +++++++----- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index f8a94ed69..8bca3b25a 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -57,6 +57,7 @@ err: #endif /* CLIPPER_UTILS_DEBUG */ namespace ClipperUtils { + Points EmptyPathsProvider::s_empty_points; Points SinglePathProvider::s_end; } @@ -143,16 +144,6 @@ static ClipperLib::Paths safety_offset(PathsProvider &&paths) return out; } -static ClipperLib::Paths safety_offset(const ClipperLib::Paths &paths) -{ - return safety_offset(paths); -} - -static void safety_offset(ClipperLib::Paths *paths) -{ - *paths = safety_offset(*paths); -} - template ClipperLib::Paths _offset(PathsProvider &&input, ClipperLib::EndType endType, const float delta, ClipperLib::JoinType joinType, double miterLimit) { diff --git a/src/libslic3r/ClipperUtils.hpp b/src/libslic3r/ClipperUtils.hpp index 0d3b986c0..f3adba94e 100644 --- a/src/libslic3r/ClipperUtils.hpp +++ b/src/libslic3r/ClipperUtils.hpp @@ -32,11 +32,11 @@ namespace ClipperUtils { public: struct iterator : public PathsProviderIteratorBase { public: - constexpr const Points& operator*() { assert(false); return *static_cast(nullptr); } + constexpr const Points& operator*() { assert(false); return s_empty_points; } // all iterators point to end. constexpr bool operator==(const iterator &rhs) const { return true; } constexpr bool operator!=(const iterator &rhs) const { return false; } - constexpr const Points& operator++(int) { assert(false); return *static_cast(nullptr); } + constexpr const Points& operator++(int) { assert(false); return s_empty_points; } constexpr iterator& operator++() { assert(false); return *this; } }; @@ -46,6 +46,8 @@ namespace ClipperUtils { static constexpr iterator cbegin() throw() { return cend(); } static constexpr iterator begin() throw() { return cend(); } static constexpr size_t size() throw() { return 0; } + + static Points &s_empty_points; }; class SinglePathProvider { @@ -158,7 +160,7 @@ namespace ClipperUtils { } private: ExPolygons::const_iterator m_it_expolygon; - int m_idx_contour; + size_t m_idx_contour; }; iterator cbegin() const { return iterator(m_expolygons.cbegin()); } @@ -199,7 +201,7 @@ namespace ClipperUtils { } private: Surfaces::const_iterator m_it_surface; - int m_idx_contour; + size_t m_idx_contour; }; iterator cbegin() const { return iterator(m_surfaces.cbegin()); } @@ -240,7 +242,7 @@ namespace ClipperUtils { } private: SurfacesPtr::const_iterator m_it_surface; - int m_idx_contour; + size_t m_idx_contour; }; iterator cbegin() const { return iterator(m_surfaces.cbegin()); }