diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index 86653598b0..0c36cc3f11 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -20,6 +20,9 @@ #include "libslic3r/Surface.hpp" #include "libslic3r/libslic3r.h" +#include +#include + // #define CLIPPER_UTILS_TIMING #ifdef CLIPPER_UTILS_TIMING @@ -745,6 +748,8 @@ Slic3r::Polygons union_(const Slic3r::Polygons &subject, const ClipperLib::PolyF { return to_polygons(clipper_do(ClipperLib::ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), fillType, ApplySafetyOffset::No)); } Slic3r::Polygons union_(const Slic3r::ExPolygons &subject) { return _clipper(ClipperLib::ctUnion, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), ApplySafetyOffset::No); } +Slic3r::Polygons union_(const Slic3r::Polygons &subject, const Slic3r::Polygon &subject2) + { return _clipper(ClipperLib::ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::SinglePathProvider(subject2.points), ApplySafetyOffset::No); } Slic3r::Polygons union_(const Slic3r::Polygons &subject, const Slic3r::Polygons &subject2) { return _clipper(ClipperLib::ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(subject2), ApplySafetyOffset::No); } Slic3r::Polygons union_(Slic3r::Polygons &&subject, const Slic3r::Polygons &subject2) { @@ -1012,6 +1017,21 @@ Polygons union_pt_chained_outside_in(const Polygons &subject) return retval; } +Polygons union_parallel_reduce(const Polygons &subject) +{ + return tbb::parallel_reduce( + tbb::blocked_range(0, subject.size()), Polygons(), + [&subject](tbb::blocked_range range, Polygons partial_union) { + for (size_t subject_idx = range.begin(); subject_idx < range.end(); ++subject_idx) { + partial_union = union_(partial_union, subject[subject_idx]); + } + return partial_union; + }, + [](const Polygons &a, const Polygons &b) { + return union_(a, b); + }); +} + Polygons simplify_polygons(const Polygons &subject) { CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT); diff --git a/src/libslic3r/ClipperUtils.hpp b/src/libslic3r/ClipperUtils.hpp index 00931e5268..6a01adef1f 100644 --- a/src/libslic3r/ClipperUtils.hpp +++ b/src/libslic3r/ClipperUtils.hpp @@ -520,6 +520,7 @@ inline Slic3r::Lines intersection_ln(const Slic3r::Line &subject, const Slic3r:: Slic3r::Polygons union_(const Slic3r::Polygons &subject); Slic3r::Polygons union_(const Slic3r::ExPolygons &subject); Slic3r::Polygons union_(const Slic3r::Polygons &subject, const ClipperLib::PolyFillType fillType); +Slic3r::Polygons union_(const Slic3r::Polygons &subject, const Slic3r::Polygon &subject2); Slic3r::Polygons union_(const Slic3r::Polygons &subject, const Slic3r::Polygons &subject2); Slic3r::Polygons union_(const Slic3r::Polygons &subject, const Slic3r::ExPolygon &subject2); // May be used to "heal" unusual models (3DLabPrints etc.) by providing fill_type (pftEvenOdd, pftNonZero, pftPositive, pftNegative). @@ -538,6 +539,11 @@ ClipperLib::PolyTree union_pt(const Slic3r::ExPolygons &subject); Slic3r::Polygons union_pt_chained_outside_in(const Slic3r::Polygons &subject); +// Perform union operation on Polygons using parallel reduction to merge Polygons one by one. +// When many detailed Polygons overlap, performing union over all Polygons at once can be quite slow. +// However, performing the union operation incrementally can be significantly faster in such cases. +Slic3r::Polygons union_parallel_reduce(const Slic3r::Polygons &subject); + ClipperLib::PolyNodes order_nodes(const ClipperLib::PolyNodes &nodes); // Implementing generalized loop (foreach) over a list of nodes which can be diff --git a/src/libslic3r/TriangleMeshSlicer.cpp b/src/libslic3r/TriangleMeshSlicer.cpp index 81d555aba6..d52d126e7f 100644 --- a/src/libslic3r/TriangleMeshSlicer.cpp +++ b/src/libslic3r/TriangleMeshSlicer.cpp @@ -2434,7 +2434,10 @@ Polygons project_mesh( std::vector top, bottom; std::vector zs { -1e10, 1e10 }; slice_mesh_slabs(mesh, zs, trafo, &top, &bottom, throw_on_cancel); - return union_(top.front(), bottom.back()); + + // We typically perform a union operation on a lot of overlapping polygons, which can be slow in some cases. + // To address this, we use parallel reduction, which can be significantly faster in such cases. + return union_(union_parallel_reduce(top.front()), union_parallel_reduce(bottom.back())); } void cut_mesh(const indexed_triangle_set &mesh, float z, indexed_triangle_set *upper, indexed_triangle_set *lower, bool triangulate_caps)