diff --git a/lib/Slic3r/Fill/Concentric.pm b/lib/Slic3r/Fill/Concentric.pm index 75dce8d23..5649a8aa7 100644 --- a/lib/Slic3r/Fill/Concentric.pm +++ b/lib/Slic3r/Fill/Concentric.pm @@ -4,7 +4,7 @@ use Moo; extends 'Slic3r::Fill::Base'; use Slic3r::Geometry qw(scale unscale X); -use Slic3r::Geometry::Clipper qw(offset offset2 union_pt traverse_pt); +use Slic3r::Geometry::Clipper qw(offset offset2 union_pt_chained); sub fill_surface { my $self = shift; @@ -37,7 +37,7 @@ sub fill_surface { # generate paths from the outermost to the innermost, to avoid # adhesion problems of the first central tiny loops @loops = map Slic3r::Polygon->new(@$_), - reverse traverse_pt( union_pt(\@loops) ); + reverse @{union_pt_chained(\@loops)}; # order paths using a nearest neighbor search my @paths = (); diff --git a/lib/Slic3r/Geometry/Clipper.pm b/lib/Slic3r/Geometry/Clipper.pm index 565ae5e66..f91f9f06c 100644 --- a/lib/Slic3r/Geometry/Clipper.pm +++ b/lib/Slic3r/Geometry/Clipper.pm @@ -6,27 +6,8 @@ require Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw(offset offset_ex diff_ex diff union_ex intersection_ex xor_ex JT_ROUND JT_MITER - JT_SQUARE is_counter_clockwise union_pt offset2 offset2_ex traverse_pt - intersection intersection_pl diff_pl union CLIPPER_OFFSET_SCALE); - -use Slic3r::Geometry qw(scale); -use Slic3r::Geometry qw(chained_path); - -sub traverse_pt { - my ($polynodes) = @_; - - # use a nearest neighbor search to order these children - # TODO: supply second argument to chained_path() too? - my @ordering_points = map { ($_->{outer} // $_->{hole})->first_point } @$polynodes; - my @nodes = @$polynodes[ @{chained_path(\@ordering_points)} ]; - - my @polygons = (); - foreach my $polynode (@$polynodes) { - # traverse the next depth - push @polygons, traverse_pt($polynode->{children}); - push @polygons, $polynode->{outer} // [ reverse @{$polynode->{hole}} ]; - } - return @polygons; -} + JT_SQUARE is_counter_clockwise union_pt offset2 offset2_ex + intersection intersection_pl diff_pl union CLIPPER_OFFSET_SCALE + union_pt_chained); 1; diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm index f02108c3c..b37f73f38 100644 --- a/lib/Slic3r/Layer/Region.pm +++ b/lib/Slic3r/Layer/Region.pm @@ -5,7 +5,7 @@ use List::Util qw(sum first); use Slic3r::ExtrusionPath ':roles'; use Slic3r::Geometry qw(PI A B scale unscale chained_path points_coincide); use Slic3r::Geometry::Clipper qw(union_ex diff_ex intersection_ex - offset offset2 offset2_ex union_pt traverse_pt diff intersection + offset offset2 offset2_ex union_pt diff intersection union diff intersection_pl); use Slic3r::Surface ':types'; diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index e8b6a4419..8e7b5d56a 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -8,7 +8,7 @@ use Slic3r::ExtrusionPath ':roles'; use Slic3r::Geometry qw(X Y Z X1 Y1 X2 Y2 MIN MAX PI scale unscale move_points chained_path convex_hull); use Slic3r::Geometry::Clipper qw(diff_ex union_ex union_pt intersection_ex intersection offset - offset2 traverse_pt JT_ROUND JT_SQUARE); + offset2 union_pt_chained JT_ROUND JT_SQUARE); use Time::HiRes qw(gettimeofday tv_interval); has 'config' => (is => 'rw', default => sub { Slic3r::Config->new_from_defaults }, trigger => 1); @@ -678,7 +678,7 @@ sub make_brim { polygon => Slic3r::Polygon->new(@$_), role => EXTR_ROLE_SKIRT, flow_spacing => $flow->spacing, - ), reverse traverse_pt( union_pt(\@loops) )); + ), reverse @{union_pt_chained(\@loops)}); } sub write_gcode { diff --git a/xs/src/ClipperUtils.cpp b/xs/src/ClipperUtils.cpp index 069822fc9..3ba65924d 100644 --- a/xs/src/ClipperUtils.cpp +++ b/xs/src/ClipperUtils.cpp @@ -1,4 +1,5 @@ #include "ClipperUtils.hpp" +#include "Geometry.hpp" namespace Slic3r { @@ -385,6 +386,42 @@ void union_pt(const Slic3r::Polygons &subject, ClipperLib::PolyTree &retval, boo _clipper_do(ClipperLib::ctUnion, subject, clip, retval, ClipperLib::pftEvenOdd, safety_offset_); } +void union_pt_chained(const Slic3r::Polygons &subject, Slic3r::Polygons &retval, bool safety_offset_) +{ + ClipperLib::PolyTree pt; + union_pt(subject, pt, safety_offset_); + traverse_pt(pt.Childs, retval); +} + +static void traverse_pt(ClipperLib::PolyNodes &nodes, Slic3r::Polygons &retval) +{ + /* use a nearest neighbor search to order these children + TODO: supply start_near to chained_path() too? */ + + // collect ordering points + Points ordering_points; + ordering_points.reserve(nodes.size()); + for (ClipperLib::PolyNodes::const_iterator it = nodes.begin(); it != nodes.end(); ++it) { + Point p((*it)->Contour.front().X, (*it)->Contour.front().Y); + ordering_points.push_back(p); + } + + // perform the ordering + ClipperLib::PolyNodes ordered_nodes; + Slic3r::Geometry::chained_path_items(ordering_points, nodes, ordered_nodes); + + // push results recursively + for (ClipperLib::PolyNodes::iterator it = ordered_nodes.begin(); it != ordered_nodes.end(); ++it) { + // traverse the next depth + traverse_pt((*it)->Childs, retval); + + Polygon p; + ClipperPath_to_Slic3rMultiPoint((*it)->Contour, p); + retval.push_back(p); + if ((*it)->IsHole()) retval.back().reverse(); // ccw + } +} + void simplify_polygons(const Slic3r::Polygons &subject, Slic3r::Polygons &retval) { // convert into Clipper polygons diff --git a/xs/src/ClipperUtils.hpp b/xs/src/ClipperUtils.hpp index 6b090d08e..e5e80c942 100644 --- a/xs/src/ClipperUtils.hpp +++ b/xs/src/ClipperUtils.hpp @@ -95,6 +95,8 @@ template void union_(const Slic3r::Polygons &subject, T &retval, bool safety_offset_ = false); void union_pt(const Slic3r::Polygons &subject, ClipperLib::PolyTree &retval, bool safety_offset_ = false); +void union_pt_chained(const Slic3r::Polygons &subject, Slic3r::Polygons &retval, bool safety_offset_ = false); +static void traverse_pt(ClipperLib::PolyNodes &nodes, Slic3r::Polygons &retval); void simplify_polygons(const Slic3r::Polygons &subject, Slic3r::Polygons &retval); diff --git a/xs/src/Geometry.cpp b/xs/src/Geometry.cpp index 1b7cda080..748340542 100644 --- a/xs/src/Geometry.cpp +++ b/xs/src/Geometry.cpp @@ -1,4 +1,5 @@ #include "Geometry.hpp" +#include "clipper.hpp" #include #include @@ -80,4 +81,16 @@ chained_path(Points &points, std::vector &retval) chained_path(points, retval, points.front()); } +/* retval and items must be different containers */ +template +void +chained_path_items(Points &points, T &items, T &retval) +{ + std::vector indices; + chained_path(points, indices); + for (std::vector::const_iterator it = indices.begin(); it != indices.end(); ++it) + retval.push_back(items[*it]); +} +template void chained_path_items(Points &points, ClipperLib::PolyNodes &items, ClipperLib::PolyNodes &retval); + } } diff --git a/xs/src/Geometry.hpp b/xs/src/Geometry.hpp index 1a0aaced2..d998b7aba 100644 --- a/xs/src/Geometry.hpp +++ b/xs/src/Geometry.hpp @@ -8,6 +8,7 @@ namespace Slic3r { namespace Geometry { void convex_hull(Points points, Polygon &hull); void chained_path(Points &points, std::vector &retval, Point start_near); void chained_path(Points &points, std::vector &retval); +template void chained_path_items(Points &points, T &items, T &retval); } } diff --git a/xs/xsp/Clipper.xsp b/xs/xsp/Clipper.xsp index 129f83517..55026948d 100644 --- a/xs/xsp/Clipper.xsp +++ b/xs/xsp/Clipper.xsp @@ -170,6 +170,16 @@ union_pt(subject, safety_offset = false) OUTPUT: RETVAL +Polygons +union_pt_chained(subject, safety_offset = false) + Polygons subject + bool safety_offset + CODE: + // perform operation + union_pt_chained(subject, RETVAL, safety_offset); + OUTPUT: + RETVAL + Polygons simplify_polygons(subject) Polygons subject