diff --git a/lib/Slic3r/Fill/Concentric.pm b/lib/Slic3r/Fill/Concentric.pm index 3c47de489..311bfa1f5 100644 --- a/lib/Slic3r/Fill/Concentric.pm +++ b/lib/Slic3r/Fill/Concentric.pm @@ -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, PFT_EVENODD) ); + reverse traverse_pt( union_pt(\@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 40f1c7d35..362569ff7 100644 --- a/lib/Slic3r/Geometry/Clipper.pm +++ b/lib/Slic3r/Geometry/Clipper.pm @@ -13,20 +13,6 @@ use Math::Clipper 1.22 qw(:cliptypes :polyfilltypes :jointypes is_counter_clockw use Slic3r::Geometry qw(scale); our $clipper = Math::Clipper->new; -sub _safety_offset { - my ($polygons, $factor) = @_; - return [ map Slic3r::Polygon->new(@$_), - @{Math::Clipper::int_offset(_convert($polygons), $factor // (scale 1e-05), 100000, JT_MITER, 2)} ]; -} - -sub union_pt { - my ($polygons, $jointype, $safety_offset) = @_; - $jointype = PFT_NONZERO unless defined $jointype; - $clipper->clear; - $clipper->add_subject_polygons($safety_offset ? _convert(_safety_offset($polygons)) : _convert($polygons)); - return $clipper->pt_execute(CT_UNION, $jointype, $jointype); -} - sub traverse_pt { my ($polynodes) = @_; @@ -45,10 +31,4 @@ sub traverse_pt { return @polygons; } -sub _convert { - my $p = shift; - $p = $p->pp if ref($p) ne 'ARRAY' && $p->can('pp'); - return [ map { (ref($_) ne 'ARRAY' && $_->can('pp')) ? $_->pp : $_ } @$p ]; -} - 1; diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm index b642f30c1..2c896bc07 100644 --- a/lib/Slic3r/Layer/Region.pm +++ b/lib/Slic3r/Layer/Region.pm @@ -239,8 +239,8 @@ sub make_perimeters { $self->_fill_gaps(\@gaps); # find nesting hierarchies separately for contours and holes - my $contours_pt = union_pt(\@contours, PFT_EVENODD); - my $holes_pt = union_pt(\@holes, PFT_EVENODD); + my $contours_pt = union_pt(\@contours); + my $holes_pt = union_pt(\@holes); # prepare a coderef for traversing the PolyTree object # external contours are root items of $contours_pt diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 30e57b251..e40b1eb84 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -681,7 +681,7 @@ sub make_brim { polygon => Slic3r::Polygon->new(@$_), role => EXTR_ROLE_SKIRT, flow_spacing => $flow->spacing, - ), reverse traverse_pt( union_pt(\@loops, PFT_EVENODD) ); + ), reverse traverse_pt( union_pt(\@loops) ); } sub write_gcode { diff --git a/xs/src/ClipperUtils.cpp b/xs/src/ClipperUtils.cpp index c398d3154..4327406bb 100644 --- a/xs/src/ClipperUtils.cpp +++ b/xs/src/ClipperUtils.cpp @@ -28,19 +28,19 @@ void PolyTreeToExPolygons(ClipperLib::PolyTree& polytree, Slic3r::ExPolygons& ex //----------------------------------------------------------- void -ClipperPolygon_to_Slic3rPolygon(ClipperLib::Polygon &input, Slic3r::Polygon &output) +ClipperPolygon_to_Slic3rPolygon(const ClipperLib::Polygon &input, Slic3r::Polygon &output) { output.points.clear(); - for (ClipperLib::Polygon::iterator pit = input.begin(); pit != input.end(); ++pit) { + for (ClipperLib::Polygon::const_iterator pit = input.begin(); pit != input.end(); ++pit) { output.points.push_back(Slic3r::Point( (*pit).X, (*pit).Y )); } } void -ClipperPolygons_to_Slic3rPolygons(ClipperLib::Polygons &input, Slic3r::Polygons &output) +ClipperPolygons_to_Slic3rPolygons(const ClipperLib::Polygons &input, Slic3r::Polygons &output) { output.clear(); - for (ClipperLib::Polygons::iterator it = input.begin(); it != input.end(); ++it) { + for (ClipperLib::Polygons::const_iterator it = input.begin(); it != input.end(); ++it) { Slic3r::Polygon p; ClipperPolygon_to_Slic3rPolygon(*it, p); output.push_back(p); @@ -48,7 +48,7 @@ ClipperPolygons_to_Slic3rPolygons(ClipperLib::Polygons &input, Slic3r::Polygons } void -ClipperPolygons_to_Slic3rExPolygons(ClipperLib::Polygons &input, Slic3r::ExPolygons &output) +ClipperPolygons_to_Slic3rExPolygons(const ClipperLib::Polygons &input, Slic3r::ExPolygons &output) { // init Clipper ClipperLib::Clipper clipper; @@ -67,19 +67,19 @@ ClipperPolygons_to_Slic3rExPolygons(ClipperLib::Polygons &input, Slic3r::ExPolyg } void -Slic3rPolygon_to_ClipperPolygon(Slic3r::Polygon &input, ClipperLib::Polygon &output) +Slic3rPolygon_to_ClipperPolygon(const Slic3r::Polygon &input, ClipperLib::Polygon &output) { output.clear(); - for (Slic3r::Points::iterator pit = input.points.begin(); pit != input.points.end(); ++pit) { + for (Slic3r::Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit) { output.push_back(ClipperLib::IntPoint( (*pit).x, (*pit).y )); } } void -Slic3rPolygons_to_ClipperPolygons(Slic3r::Polygons &input, ClipperLib::Polygons &output) +Slic3rPolygons_to_ClipperPolygons(const Slic3r::Polygons &input, ClipperLib::Polygons &output) { output.clear(); - for (Slic3r::Polygons::iterator it = input.begin(); it != input.end(); ++it) { + for (Slic3r::Polygons::const_iterator it = input.begin(); it != input.end(); ++it) { ClipperLib::Polygon p; Slic3rPolygon_to_ClipperPolygon(*it, p); output.push_back(p); @@ -194,7 +194,7 @@ offset2_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float d template void _clipper_do(const ClipperLib::ClipType clipType, Slic3r::Polygons &subject, - Slic3r::Polygons &clip, T &retval, const bool safety_offset_) + Slic3r::Polygons &clip, T &retval, const ClipperLib::PolyFillType fillType, const bool safety_offset_) { // read input ClipperLib::Polygons* input_subject = new ClipperLib::Polygons(); @@ -222,7 +222,7 @@ void _clipper_do(const ClipperLib::ClipType clipType, Slic3r::Polygons &subject, delete input_clip; // perform operation - clipper.Execute(clipType, retval, ClipperLib::pftNonZero, ClipperLib::pftNonZero); + clipper.Execute(clipType, retval, fillType, fillType); } void _clipper(ClipperLib::ClipType clipType, Slic3r::Polygons &subject, @@ -230,7 +230,7 @@ void _clipper(ClipperLib::ClipType clipType, Slic3r::Polygons &subject, { // perform operation ClipperLib::Polygons* output = new ClipperLib::Polygons(); - _clipper_do(clipType, subject, clip, *output, safety_offset_); + _clipper_do(clipType, subject, clip, *output, ClipperLib::pftNonZero, safety_offset_); // convert into Polygons ClipperPolygons_to_Slic3rPolygons(*output, retval); @@ -242,7 +242,7 @@ void _clipper(ClipperLib::ClipType clipType, Slic3r::Polygons &subject, { // perform operation ClipperLib::PolyTree* polytree = new ClipperLib::PolyTree(); - _clipper_do(clipType, subject, clip, *polytree, safety_offset_); + _clipper_do(clipType, subject, clip, *polytree, ClipperLib::pftNonZero, safety_offset_); // convert into ExPolygons PolyTreeToExPolygons(*polytree, retval); @@ -280,6 +280,12 @@ void union_(Slic3r::Polygons &subject, T &retval, bool safety_offset_) template void union_(Slic3r::Polygons &subject, Slic3r::ExPolygons &retval, bool safety_offset_); template void union_(Slic3r::Polygons &subject, Slic3r::Polygons &retval, bool safety_offset_); +void union_pt(Slic3r::Polygons &subject, ClipperLib::PolyTree &retval, bool safety_offset_) +{ + Slic3r::Polygons clip; + _clipper_do(ClipperLib::ctUnion, subject, clip, retval, ClipperLib::pftEvenOdd, safety_offset_); +} + void simplify_polygons(Slic3r::Polygons &subject, Slic3r::Polygons &retval) { // convert into Clipper polygons @@ -312,4 +318,33 @@ void safety_offset(ClipperLib::Polygons* &subject) subject = retval; } +/////////////////////// + +SV* +polynode_children_2_perl(const ClipperLib::PolyNode& node) +{ + AV* av = newAV(); + const unsigned int len = node.ChildCount(); + av_extend(av, len-1); + for (int i = 0; i < len; ++i) { + av_store(av, i, polynode2perl(*node.Childs[i])); + } + return (SV*)newRV_noinc((SV*)av); +} + +SV* +polynode2perl(const ClipperLib::PolyNode& node) +{ + HV* hv = newHV(); + Slic3r::Polygon p; + ClipperPolygon_to_Slic3rPolygon(node.Contour, p); + if (node.IsHole()) { + (void)hv_stores( hv, "hole", p.to_SV() ); + } else { + (void)hv_stores( hv, "outer", p.to_SV() ); + } + (void)hv_stores( hv, "children", polynode_children_2_perl(node) ); + return (SV*)newRV_noinc((SV*)hv); +} + } diff --git a/xs/src/ClipperUtils.hpp b/xs/src/ClipperUtils.hpp index 77214bd2c..c907bbcd7 100644 --- a/xs/src/ClipperUtils.hpp +++ b/xs/src/ClipperUtils.hpp @@ -16,11 +16,11 @@ void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, Slic3r::ExPoly void PolyTreeToExPolygons(ClipperLib::PolyTree& polytree, Slic3r::ExPolygons& expolygons); //----------------------------------------------------------- -void Slic3rPolygon_to_ClipperPolygon(Slic3r::Polygon &input, ClipperLib::Polygon &output); -void Slic3rPolygons_to_ClipperPolygons(Slic3r::Polygons &input, ClipperLib::Polygons &output); -void ClipperPolygon_to_Slic3rPolygon(ClipperLib::Polygon &input, Slic3r::Polygon &output); -void ClipperPolygons_to_Slic3rPolygons(ClipperLib::Polygons &input, Slic3r::Polygons &output); -void ClipperPolygons_to_Slic3rExPolygons(ClipperLib::Polygons &input, Slic3r::ExPolygons &output); +void Slic3rPolygon_to_ClipperPolygon(const Slic3r::Polygon &input, ClipperLib::Polygon &output); +void Slic3rPolygons_to_ClipperPolygons(const Slic3r::Polygons &input, ClipperLib::Polygons &output); +void ClipperPolygon_to_Slic3rPolygon(const ClipperLib::Polygon &input, Slic3r::Polygon &output); +void ClipperPolygons_to_Slic3rPolygons(const ClipperLib::Polygons &input, Slic3r::Polygons &output); +void ClipperPolygons_to_Slic3rExPolygons(const ClipperLib::Polygons &input, Slic3r::ExPolygons &output); void scaleClipperPolygons(ClipperLib::Polygons &polygons, const double scale); @@ -64,10 +64,18 @@ void xor_ex(Slic3r::Polygons &subject, Slic3r::Polygons &clip, Slic3r::ExPolygon template void union_(Slic3r::Polygons &subject, T &retval, bool safety_offset_ = false); +void union_pt(Slic3r::Polygons &subject, ClipperLib::PolyTree &retval, bool safety_offset_ = false); + void simplify_polygons(Slic3r::Polygons &subject, Slic3r::Polygons &retval); void safety_offset(ClipperLib::Polygons* &subject); +///////////////// + +SV* polynode_children_2_perl(const ClipperLib::PolyNode& node); +SV* polynode2perl(const ClipperLib::PolyNode& node); + + } #endif diff --git a/xs/xsp/Clipper.xsp b/xs/xsp/Clipper.xsp index 150a31166..e69873e07 100644 --- a/xs/xsp/Clipper.xsp +++ b/xs/xsp/Clipper.xsp @@ -128,6 +128,19 @@ union_ex(subject, safety_offset = false) OUTPUT: RETVAL +SV* +union_pt(subject, safety_offset = false) + Polygons subject + bool safety_offset + CODE: + // perform operation + ClipperLib::PolyTree polytree; + union_pt(subject, polytree, safety_offset); + + RETVAL = polynode_children_2_perl(polytree); + OUTPUT: + RETVAL + Polygons simplify_polygons(subject) Polygons subject