mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-10 09:11:08 +00:00
Improve performance by migrating to Clipper2 2.0.1 (#15969)
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
This commit is contained in:
co-authored by
Rodrigo Faselli
parent
70bc02467b
commit
222c6a2df5
@@ -2,6 +2,7 @@
|
||||
#include "AABBTreeLines.hpp"
|
||||
#include "BridgeDetector.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "ClipperZUtils.hpp"
|
||||
#include "ExtrusionEntity.hpp"
|
||||
#include "ExtrusionEntityCollection.hpp"
|
||||
#include "Feature/FuzzySkin/FuzzySkin.hpp"
|
||||
@@ -296,13 +297,12 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
|
||||
return out;
|
||||
}
|
||||
|
||||
static ClipperLib_Z::Paths clip_extrusion(const ClipperLib_Z::Path& subject, const ClipperLib_Z::Paths& clip, ClipperLib_Z::ClipType clipType)
|
||||
static ClipperZUtils::ZPaths clip_extrusion(const ClipperZUtils::ZPath& subject, const ClipperZUtils::ZPaths& clip, ClipType clipType)
|
||||
{
|
||||
ClipperLib_Z::Clipper clipper;
|
||||
clipper.ZFillFunction([](const ClipperLib_Z::IntPoint& e1bot, const ClipperLib_Z::IntPoint& e1top, const ClipperLib_Z::IntPoint& e2bot,
|
||||
const ClipperLib_Z::IntPoint& e2top, ClipperLib_Z::IntPoint& pt) {
|
||||
ClipperLib_Z::IntPoint start = e1bot;
|
||||
ClipperLib_Z::IntPoint end = e1top;
|
||||
auto zfill = [](const ClipperZUtils::ZPoint& e1bot, const ClipperZUtils::ZPoint& e1top, const ClipperZUtils::ZPoint& e2bot,
|
||||
const ClipperZUtils::ZPoint& e2top, ClipperZUtils::ZPoint& pt) {
|
||||
ClipperZUtils::ZPoint start = e1bot;
|
||||
ClipperZUtils::ZPoint end = e1top;
|
||||
|
||||
if (start.z() <= 0 && end.z() <= 0) {
|
||||
start = e2bot;
|
||||
@@ -317,23 +317,15 @@ static ClipperLib_Z::Paths clip_extrusion(const ClipperLib_Z::Path& subject, con
|
||||
double t = std::sqrt(dist_sqr / length_sqr);
|
||||
|
||||
pt.z() = start.z() + coord_t((end.z() - start.z()) * t);
|
||||
});
|
||||
};
|
||||
|
||||
clipper.AddPath(subject, ClipperLib_Z::ptSubject, false);
|
||||
clipper.AddPaths(clip, ClipperLib_Z::ptClip, true);
|
||||
|
||||
ClipperLib_Z::Paths clipped_paths;
|
||||
{
|
||||
ClipperLib_Z::PolyTree clipped_polytree;
|
||||
clipper.Execute(clipType, clipped_polytree, ClipperLib_Z::pftNonZero, ClipperLib_Z::pftNonZero);
|
||||
ClipperLib_Z::PolyTreeToPaths(std::move(clipped_polytree), clipped_paths);
|
||||
}
|
||||
ClipperZUtils::ZPaths clipped_paths = ClipperZUtils::clip_zpaths(clipType, ClipperZUtils::ZPaths{ subject }, true, clip, zfill);
|
||||
|
||||
// Clipped path could contain vertices from the clip with a Z coordinate equal to zero.
|
||||
// For those vertices, we must assign value based on the subject.
|
||||
// This happens only in sporadic cases.
|
||||
for (ClipperLib_Z::Path& path : clipped_paths)
|
||||
for (ClipperLib_Z::IntPoint& c_pt : path)
|
||||
for (ClipperZUtils::ZPath& path : clipped_paths)
|
||||
for (ClipperZUtils::ZPoint& c_pt : path)
|
||||
if (c_pt.z() == 0) {
|
||||
// Now we must find the corresponding line on with this point is located and compute line width (Z coordinate).
|
||||
if (subject.size() <= 2)
|
||||
@@ -366,8 +358,8 @@ static ClipperLib_Z::Paths clip_extrusion(const ClipperLib_Z::Path& subject, con
|
||||
}
|
||||
|
||||
assert([&clipped_paths = std::as_const(clipped_paths)]() -> bool {
|
||||
for (const ClipperLib_Z::Path& path : clipped_paths)
|
||||
for (const ClipperLib_Z::IntPoint& pt : path)
|
||||
for (const ClipperZUtils::ZPath& path : clipped_paths)
|
||||
for (const ClipperZUtils::ZPoint& pt : path)
|
||||
if (pt.z() <= 0)
|
||||
return false;
|
||||
return true;
|
||||
@@ -376,7 +368,7 @@ static ClipperLib_Z::Paths clip_extrusion(const ClipperLib_Z::Path& subject, con
|
||||
return clipped_paths;
|
||||
}
|
||||
|
||||
static double clipper_z_path_length(const ClipperLib_Z::Path &path)
|
||||
static double clipper_z_path_length(const ClipperZUtils::ZPath &path)
|
||||
{
|
||||
double len = 0.;
|
||||
for (size_t i = 1; i < path.size(); ++ i)
|
||||
@@ -413,7 +405,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p
|
||||
ExtrusionPaths paths;
|
||||
// detect overhanging/bridging perimeters
|
||||
if (perimeter_generator.config->detect_overhang_wall && perimeter_generator.layer_id > perimeter_generator.object_config->raft_layers) {
|
||||
ClipperLib_Z::Path extrusion_path;
|
||||
ClipperZUtils::ZPath extrusion_path;
|
||||
extrusion_path.reserve(extrusion->size());
|
||||
BoundingBox extrusion_path_bbox;
|
||||
for (const Arachne::ExtrusionJunction &ej : extrusion->junctions) {
|
||||
@@ -421,7 +413,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p
|
||||
extrusion_path_bbox.merge(Point(ej.p.x(), ej.p.y()));
|
||||
}
|
||||
|
||||
ClipperLib_Z::Paths lower_slices_paths;
|
||||
ClipperZUtils::ZPaths lower_slices_paths;
|
||||
{
|
||||
lower_slices_paths.reserve(perimeter_generator.lower_slices_polygons().size());
|
||||
Points clipped;
|
||||
@@ -431,7 +423,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p
|
||||
ClipperUtils::clip_clipper_polygon_with_subject_bbox(poly.points, extrusion_path_bbox, clipped);
|
||||
if (!clipped.empty()) {
|
||||
lower_slices_paths.emplace_back();
|
||||
ClipperLib_Z::Path &out = lower_slices_paths.back();
|
||||
ClipperZUtils::ZPath &out = lower_slices_paths.back();
|
||||
out.reserve(clipped.size());
|
||||
for (const Point &pt : clipped)
|
||||
out.emplace_back(pt.x(), pt.y(), 0);
|
||||
@@ -440,7 +432,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p
|
||||
}
|
||||
|
||||
// get non-overhang paths by intersecting this loop with the grown lower slices
|
||||
extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ClipperLib_Z::ctIntersection), role,
|
||||
extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ctIntersection), role,
|
||||
is_external ? perimeter_generator.ext_perimeter_flow : perimeter_generator.perimeter_flow);
|
||||
|
||||
// Always reverse extrusion if use fuzzy skin: https://github.com/OrcaSlicer/OrcaSlicer/pull/2413#issuecomment-1769735357
|
||||
@@ -481,7 +473,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p
|
||||
// get overhang paths by checking what parts of this loop fall
|
||||
// outside the grown lower slices (thus where the distance between
|
||||
// the loop centerline and original lower slices is >= half nozzle diameter
|
||||
extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ClipperLib_Z::ctDifference), erOverhangPerimeter,
|
||||
extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ctDifference), erOverhangPerimeter,
|
||||
perimeter_generator.overhang_flow);
|
||||
|
||||
// Reapply the nearest point search for starting point.
|
||||
@@ -674,10 +666,10 @@ static void clip_inner_walls_over_top(std::vector<Arachne::VariableWidthLines> &
|
||||
};
|
||||
// Pull the cut back by half a wall width: the clip severs the centerline, but the bead's rounded end
|
||||
// extends half a width past its endpoint and would otherwise overlap the top fill.
|
||||
ClipperLib_Z::Paths top_paths_z;
|
||||
ClipperZUtils::ZPaths top_paths_z;
|
||||
for (const Polygon &poly : to_polygons(offset_ex(top_region, float(perimeter_width) / 2.f))) {
|
||||
top_paths_z.emplace_back();
|
||||
ClipperLib_Z::Path &out = top_paths_z.back();
|
||||
ClipperZUtils::ZPath &out = top_paths_z.back();
|
||||
out.reserve(poly.points.size());
|
||||
for (const Point &pt : poly.points)
|
||||
out.emplace_back(pt.x(), pt.y(), 0);
|
||||
@@ -695,21 +687,21 @@ static void clip_inner_walls_over_top(std::vector<Arachne::VariableWidthLines> &
|
||||
}
|
||||
if (overlap == TopOverlap::Full)
|
||||
continue; // the clip below would return nothing anyway
|
||||
ClipperLib_Z::Path subject;
|
||||
ClipperZUtils::ZPath subject;
|
||||
subject.reserve(el.size());
|
||||
for (const Arachne::ExtrusionJunction &j : el.junctions)
|
||||
subject.emplace_back(j.p.x(), j.p.y(), j.w);
|
||||
ClipperLib_Z::Paths pieces = clip_extrusion(subject, top_paths_z, ClipperLib_Z::ctDifference);
|
||||
ClipperZUtils::ZPaths pieces = clip_extrusion(subject, top_paths_z, ctDifference);
|
||||
|
||||
// Clipper treats the subject as an open polyline, so it also cuts a closed loop at its (arbitrary)
|
||||
// start vertex and may reverse pieces. Stitch pieces sharing an endpoint back together.
|
||||
auto same_pt = [](const ClipperLib_Z::IntPoint &p, const ClipperLib_Z::IntPoint &q) {
|
||||
auto same_pt = [](const ClipperZUtils::ZPoint &p, const ClipperZUtils::ZPoint &q) {
|
||||
return std::abs(p.x() - q.x()) <= SCALED_EPSILON && std::abs(p.y() - q.y()) <= SCALED_EPSILON;
|
||||
};
|
||||
for (size_t i = 0; i < pieces.size(); ++ i) {
|
||||
for (size_t j = i + 1; j < pieces.size();) {
|
||||
ClipperLib_Z::Path &a = pieces[i];
|
||||
ClipperLib_Z::Path &b = pieces[j];
|
||||
ClipperZUtils::ZPath &a = pieces[i];
|
||||
ClipperZUtils::ZPath &b = pieces[j];
|
||||
if (same_pt(a.front(), b.front()) || same_pt(a.front(), b.back()))
|
||||
std::reverse(a.begin(), a.end());
|
||||
if (same_pt(a.back(), b.back()))
|
||||
@@ -726,7 +718,7 @@ static void clip_inner_walls_over_top(std::vector<Arachne::VariableWidthLines> &
|
||||
// If the clip removed next to nothing, keep the loop untouched instead of slitting it open. The
|
||||
// half-width pull-back above already costs about one width per crossing, hence two widths.
|
||||
double kept_length = 0.;
|
||||
for (const ClipperLib_Z::Path &path : pieces)
|
||||
for (const ClipperZUtils::ZPath &path : pieces)
|
||||
kept_length += clipper_z_path_length(path);
|
||||
if (clipper_z_path_length(subject) - kept_length < 2. * double(perimeter_width)) {
|
||||
append(kept_over_top, covered_by(el));
|
||||
@@ -734,10 +726,10 @@ static void clip_inner_walls_over_top(std::vector<Arachne::VariableWidthLines> &
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const ClipperLib_Z::Path &path : pieces) {
|
||||
for (const ClipperZUtils::ZPath &path : pieces) {
|
||||
Arachne::ExtrusionLine clipped(el.inset_idx, el.is_odd);
|
||||
clipped.junctions.reserve(path.size());
|
||||
for (const ClipperLib_Z::IntPoint &pt : path)
|
||||
for (const ClipperZUtils::ZPoint &pt : path)
|
||||
clipped.junctions.emplace_back(Point(pt.x(), pt.y()), coord_t(pt.z()), el.inset_idx);
|
||||
// Discard tiny leftovers that would print as zits.
|
||||
if (clipped.size() >= 2 && clipped.getLength() >= perimeter_width)
|
||||
@@ -1056,7 +1048,7 @@ ExtrusionPaths sort_extra_perimeters(const ExtrusionPaths& extra_perims, int ind
|
||||
return filtered;
|
||||
}
|
||||
|
||||
#define EXTRA_PERIMETER_OFFSET_PARAMETERS ClipperLib::jtSquare, 0.
|
||||
#define EXTRA_PERIMETER_OFFSET_PARAMETERS jtSquare, 0.
|
||||
// #define EXTRA_PERIM_DEBUG_FILES
|
||||
// Function will generate extra perimeters clipped over nonbridgeable areas of the provided surface and returns both the new perimeters and
|
||||
// Polygons filled by those clipped perimeters
|
||||
|
||||
Reference in New Issue
Block a user