Browse Source

Use Clipper for line clipping

Alessandro Ranellucci 11 years ago
parent
commit
3025c77675

+ 4 - 4
lib/Slic3r/ExPolygon.pm

@@ -8,7 +8,7 @@ use Boost::Geometry::Utils;
 use List::Util qw(first);
 use Math::Geometry::Voronoi;
 use Slic3r::Geometry qw(X Y A B point_in_polygon epsilon scaled_epsilon);
-use Slic3r::Geometry::Clipper qw(union_ex);
+use Slic3r::Geometry::Clipper qw(union_ex diff_pl);
 
 sub wkt {
     my $self = shift;
@@ -77,7 +77,7 @@ sub clip_line {
     
     return [
         map Slic3r::Line->new(@$_),
-            @{Boost::Geometry::Utils::polygon_multi_linestring_intersection($self->pp, [$line->pp])}
+            @{Slic3r::Geometry::Clipper::intersection_pl([ Slic3r::Polyline->new(@$line) ], \@$self)}
     ];
 }
 
@@ -138,10 +138,10 @@ sub _medial_axis_clip {
         my @polylines = ();
         foreach my $line (@{$polygon->lines}) {
             # remove the areas that are already covered from this line
-            my $clipped = Boost::Geometry::Utils::multi_linestring_multi_polygon_difference([$line->pp], [ map $_->pp, @{union_ex($covered)} ]);
+            my $clipped = diff_pl([$line->as_polyline], $covered);
             
             # skip very short segments/dots
-            @$clipped = grep $_->length > $width/10, map Slic3r::Polyline->new(@$_), @$clipped;
+            @$clipped = grep $_->length > $width/10, @$clipped;
             
             # grow the remaining lines and add them to the covered areas
             push @$covered, map $grow->($_, $width*1.1), @$clipped;

+ 10 - 12
lib/Slic3r/Fill/Honeycomb.pm

@@ -6,7 +6,7 @@ extends 'Slic3r::Fill::Base';
 has 'cache'         => (is => 'rw', default => sub {{}});
 
 use Slic3r::Geometry qw(PI X Y MIN MAX scale scaled_epsilon);
-use Slic3r::Geometry::Clipper qw(intersection);
+use Slic3r::Geometry::Clipper qw(intersection intersection_pl);
 
 sub angles () { [0, PI/3, PI/3*2] }
 
@@ -88,17 +88,16 @@ sub fill_surface {
         # consider polygons as polylines without re-appending the initial point:
         # this cuts the last segment on purpose, so that the jump to the next 
         # path is more straight
-        @paths = map Slic3r::Polyline->new(@$_),
-            @{ Boost::Geometry::Utils::polygon_multi_linestring_intersection(
-                $surface->expolygon->pp,
-                [ map $_->pp, @polygons ],
-            ) };
+        @paths = @{intersection_pl(
+            [ map Slic3r::Polyline->new(@$_), @polygons ],
+            [ @{$surface->expolygon} ],
+        )};
         
         # connect paths
         {
             my $collection = Slic3r::Polyline::Collection->new(@paths);
             @paths = ();
-            foreach my $path (@{$collection->chained_path(0)}) {
+            foreach my $path (@{$collection->chained_path_from($collection->leftmost_point, 0)}) {
                 if (@paths) {
                     # distance between first point of this path and last point of last path
                     my $distance = $paths[-1]->last_point->distance_to($path->first_point);
@@ -115,11 +114,10 @@ sub fill_surface {
         }
         
         # clip paths again to prevent connection segments from crossing the expolygon boundaries
-        @paths = map Slic3r::Polyline->new(@$_),
-            @{ Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection(
-                [ map $_->pp, @{$surface->expolygon->offset_ex(scaled_epsilon)} ],
-                [ map $_->pp, @paths ],
-            ) } if @paths;  # this temporary check is a workaround for the multilinestring bug in B::G::U
+        @paths = @{intersection_pl(
+            \@paths,
+            [ @{$surface->expolygon->offset_ex(scaled_epsilon)} ],
+        )};
     }
     
     return { flow_spacing => $params{flow_spacing} }, @paths;

+ 4 - 7
lib/Slic3r/Fill/Rectilinear.pm

@@ -6,6 +6,7 @@ extends 'Slic3r::Fill::Base';
 has 'cache'         => (is => 'rw', default => sub {{}});
 
 use Slic3r::Geometry qw(A B X Y MIN scale unscale scaled_epsilon);
+use Slic3r::Geometry::Clipper qw(intersection_pl offset);
 
 sub fill_surface {
     my $self = shift;
@@ -47,7 +48,7 @@ sub fill_surface {
             $vertical_line->[A][X] += $line_oscillation;
             $vertical_line->[B][X] -= $line_oscillation;
         }
-        push @vertical_lines, $vertical_line;
+        push @vertical_lines, Slic3r::Polyline->new(@$vertical_line);
         $i++;
         $x += $line_spacing;
     }
@@ -57,11 +58,7 @@ sub fill_surface {
     # the minimum offset for preventing edge lines from being clipped is scaled_epsilon;
     # however we use a larger offset to support expolygons with slightly skewed sides and 
     # not perfectly straight
-    my @polylines = map Slic3r::Polyline->new(@$_),
-        @{ Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection(
-            [ map $_->pp, @{$expolygon->offset_ex($line_spacing*0.05)} ],
-            [ @vertical_lines ],
-        ) };
+    my @polylines = @{intersection_pl(\@vertical_lines, $expolygon->offset($line_spacing*0.05))};
     
     # connect lines
     unless ($params{dont_connect}) {
@@ -78,7 +75,7 @@ sub fill_surface {
             }
             : sub { $_[X] <= $diagonal_distance && $_[Y] <= $diagonal_distance };
         
-        foreach my $polyline (@{$collection->chained_path(0)}) {
+        foreach my $polyline (@{$collection->chained_path_from($collection->leftmost_point, 0)}) {
             if (@polylines) {
                 my $first_point = $polyline->first_point;
                 my $last_point = $polylines[-1]->last_point;

+ 3 - 3
lib/Slic3r/GCode/MotionPlanner.pm

@@ -14,7 +14,7 @@ has '_tolerance'    => (is => 'lazy');
 
 use List::Util qw(first);
 use Slic3r::Geometry qw(A B scale epsilon);
-use Slic3r::Geometry::Clipper qw(diff_ex offset);
+use Slic3r::Geometry::Clipper qw(diff_ex offset intersection_pl);
 
 # clearance (in mm) from the perimeters
 has '_inner_margin' => (is => 'ro', default => sub { scale 0.5 });
@@ -91,7 +91,7 @@ sub BUILD {
                 for my $m (0 .. $#{$outer[$i]}) {
                     for my $n (0 .. $#{$outer[$j]}) {
                         my $line = Slic3r::Line->new($outer[$i][$m], $outer[$j][$n]);
-                        if (!@{Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection([ map $_->pp, @outer_ex ], [$line->pp])}) {
+                        if (!@{intersection_pl([$line->as_polyline], [ map @$_, @outer_ex ])}) {
                             # this line does not cross any polygon
                             my $dist = $line->length;
                             $edges->{$outer[$i][$m]}{$outer[$j][$n]} = $dist;
@@ -112,7 +112,7 @@ sub BUILD {
                 for my $m (0 .. $#{$inner[$i]}) {
                     for my $n (0 .. $#{$inner[$j]}) {
                         my $line = Slic3r::Line->new($inner[$i][$m], $inner[$j][$n]);
-                        if (!@{Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection([ map $_->pp, @inner_ex ], [$line->pp])}) {
+                        if (!@{intersection_pl([$line->as_polyline], [ map @$_, @inner_ex ])}) {
                             # this line does not cross any polygon
                             my $dist = $line->length * CROSSING_FACTOR;
                             $edges->{$inner[$i][$m]}{$inner[$j][$n]} = $dist;

+ 3 - 93
lib/Slic3r/Geometry.pm

@@ -11,9 +11,9 @@ our @EXPORT_OK = qw(
     point_in_polygon point_in_segment segment_in_segment
     point_is_on_left_of_segment polyline_lines polygon_lines
     point_along_segment polygon_segment_having_point polygon_has_subsegment
-    polygon_has_vertex can_connect_points deg2rad rad2deg
-    rotate_points move_points clip_segment_polygon
-    sum_vectors multiply_vector subtract_vectors dot perp polygon_points_visibility
+    deg2rad rad2deg
+    rotate_points move_points
+    dot perp polygon_points_visibility
     line_intersection bounding_box bounding_box_intersect
     angle3points three_points_aligned line_direction
     polyline_remove_parallel_continuous_edges polyline_remove_acute_vertices
@@ -229,14 +229,6 @@ sub polygon_has_subsegment {
     return 0;
 }
 
-sub polygon_has_vertex {
-    my ($polygon, $point) = @_;
-    foreach my $p (@$polygon) {
-        return 1 if points_coincide($p, $point);
-    }
-    return 0;
-}
-
 # polygon must be simple (non complex) and ccw
 sub polygon_is_convex {
     my ($points) = @_;
@@ -247,29 +239,6 @@ sub polygon_is_convex {
     return 1;
 }
 
-sub can_connect_points {
-    my ($p1, $p2, $polygons) = @_;
-    
-    # check that the two points are visible from each other
-    return 0 if grep !polygon_points_visibility($_, $p1, $p2), @$polygons;
-    
-    # get segment where $p1 lies
-    my $p1_segment;
-    for (@$polygons) {
-        $p1_segment = polygon_segment_having_point($_, $p1);
-        last if $p1_segment;
-    }
-    
-    # defensive programming, this shouldn't happen
-    if (!$p1_segment) {
-        die sprintf "Point %f,%f wasn't found in polygon contour or holes!", @$p1;
-    }
-    
-    # check whether $p2 is internal or external  (internal = on the left)
-    return point_is_on_left_of_segment($p2, $p1_segment)
-        || point_in_segment($p2, $p1_segment);
-}
-
 sub deg2rad {
     my ($degrees) = @_;
     return PI() * $degrees / 180;
@@ -315,65 +284,6 @@ sub move_points_3D {
     ], @points;
 }
 
-# implementation of Liang-Barsky algorithm
-# polygon must be convex and ccw
-sub clip_segment_polygon {
-    my ($line, $polygon) = @_;
-    
-    if (@$line == 1) {
-        # the segment is a point, check for inclusion
-        return point_in_polygon($line, $polygon);
-    }
-    
-    my @V = (@$polygon, $polygon->[0]);
-    my $tE = 0; # the maximum entering segment parameter
-    my $tL = 1; # the minimum entering segment parameter
-    my $dS = subtract_vectors($line->[B], $line->[A]); # the segment direction vector
-    
-    for (my $i = 0; $i < $#V; $i++) {   # process polygon edge V[i]V[Vi+1]
-        my $e = subtract_vectors($V[$i+1], $V[$i]);
-        my $N = perp($e, subtract_vectors($line->[A], $V[$i]));
-        my $D = -perp($e, $dS);
-        if (abs($D) < epsilon) {          # $line is nearly parallel to this edge
-            ($N < 0) ? return : next;     # P0 outside this edge ? $line is outside : $line cannot cross edge, thus ignoring
-        }
-        
-        my $t = $N / $D;
-        if ($D < 0) { # $line is entering across this edge
-            if ($t > $tE) {  # new max $tE
-                $tE = $t;
-                return if $tE > $tL;  # $line enters after leaving polygon?
-            }
-        } else { # $line is leaving across this edge
-            if ($t < $tL) {  # new min $tL
-                $tL = $t;
-                return if $tL < $tE;  # $line leaves before entering polygon?
-            }
-        }
-    }
-    
-    # $tE <= $tL implies that there is a valid intersection subsegment
-    return [
-        sum_vectors($line->[A], multiply_vector($dS, $tE)),  # = P(tE) = point where S enters polygon
-        sum_vectors($line->[A], multiply_vector($dS, $tL)),  # = P(tE) = point where S enters polygon
-    ];
-}
-
-sub sum_vectors {
-    my ($v1, $v2) = @_;
-    return [ $v1->[X] + $v2->[X], $v1->[Y] + $v2->[Y] ];
-}
-
-sub multiply_vector {
-    my ($line, $scalar) = @_;
-    return [ $line->[X] * $scalar, $line->[Y] * $scalar ];
-}
-
-sub subtract_vectors {
-    my ($line2, $line1) = @_;
-    return [ $line2->[X] - $line1->[X], $line2->[Y] - $line1->[Y] ];
-}
-
 sub normal {
     my ($line1, $line2) = @_;
     

+ 1 - 1
lib/Slic3r/Geometry/Clipper.pm

@@ -7,7 +7,7 @@ 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 union CLIPPER_OFFSET_SCALE);
+    intersection intersection_pl diff_pl union CLIPPER_OFFSET_SCALE);
 
 use Slic3r::Geometry qw(scale);
 

+ 2 - 4
lib/Slic3r/Layer/Region.pm

@@ -562,12 +562,10 @@ sub _detect_bridge_direction {
             
             my @lines = ();
             for (my $x = $bounding_box->x_min; $x <= $bounding_box->x_max; $x += $line_increment) {
-                push @lines, [ [$x, $bounding_box->y_min], [$x, $bounding_box->y_max] ];
+                push @lines, Slic3r::Polyline->new([$x, $bounding_box->y_min], [$x, $bounding_box->y_max]);
             }
             
-            # TODO: use a multi_polygon_multi_linestring_intersection() call
-            my @clipped_lines = map Slic3r::Line->new(@$_),
-                map @{ Boost::Geometry::Utils::polygon_multi_linestring_intersection($_->pp, \@lines) }, @$inset;
+            my @clipped_lines = map Slic3r::Line->new(@$_), @{ intersection_pl(\@lines, [ map @$_, @$inset ]) };
             
             # remove any line not having both endpoints within anchors
             @clipped_lines = grep {

+ 28 - 50
t/polyclip.t

@@ -2,7 +2,7 @@ use Test::More;
 use strict;
 use warnings;
 
-plan tests => 24;
+plan tests => 23;
 
 BEGIN {
     use FindBin;
@@ -31,24 +31,6 @@ my $square = Slic3r::Polygon->new(  # ccw
 
 my $line = Slic3r::Line->new([50, 150], [300, 150]);
 
-my $intersection = Slic3r::Geometry::clip_segment_polygon($line, $square);
-is_deeply $intersection, [ [100, 150], [200, 150] ], 'line is clipped to square';
-
-#==========================================================
-
-$intersection = Slic3r::Geometry::clip_segment_polygon(Slic3r::Line->new([0, 150], [80, 150]), $square);
-is $intersection, undef, 'external lines are ignored 1';
-
-#==========================================================
-
-$intersection = Slic3r::Geometry::clip_segment_polygon(Slic3r::Line->new([300, 150], [400, 150]), $square);
-is $intersection, undef, 'external lines are ignored 2';
-
-#==========================================================
-
-$intersection = Slic3r::Geometry::clip_segment_polygon(Slic3r::Line->new([120, 120], [180, 160]), $square);
-is_deeply $intersection, [ [120, 120], [180, 160] ], 'internal lines are preserved';
-
 #==========================================================
 
 {
@@ -64,42 +46,38 @@ is_deeply $intersection, [ [120, 120], [180, 160] ], 'internal lines are preserv
     is $expolygon->encloses_point(Slic3r::Point->new(140, 150)), 1, 'point on hole contour is recognized';
     is $expolygon->encloses_point(Slic3r::Point->new(140, 140)), 1, 'point on hole corner is recognized';
     {
-        my $intersections = $expolygon->clip_line(Slic3r::Line->new([150,180], [150,150]));
-        is_deeply [ map $_->pp, @$intersections ], [
-            [ [150, 180], [150, 160] ],
-        ], 'line is clipped to square with hole';
+        my $intersection = $expolygon->clip_line(Slic3r::Line->new([150,180], [150,150]));
+        is $intersection->[0]->length, Slic3r::Line->new([150, 180], [150, 160])->length,
+            'line is clipped to square with hole';
     }
     {
-        my $intersections = $expolygon->clip_line(Slic3r::Line->new([150,150], [150,120]));
-        is_deeply [ map $_->pp, @$intersections ], [
-            [ [150, 140], [150, 120] ],
-        ], 'line is clipped to square with hole';
+        my $intersection = $expolygon->clip_line(Slic3r::Line->new([150,150], [150,120]));
+        is $intersection->[0]->length, Slic3r::Line->new([150, 140], [150, 120])->length,
+            'line is clipped to square with hole';
     }
     {
-        my $intersections = $expolygon->clip_line(Slic3r::Line->new([120,180], [180,180]));
-        is_deeply [ map $_->pp, @$intersections ], [
-            [ [120,180], [180,180] ],
-        ], 'line is clipped to square with hole';
+        my $intersection = $expolygon->clip_line(Slic3r::Line->new([120,180], [180,180]));
+        is $intersection->[0]->length, Slic3r::Line->new([120,180], [180,180])->length,
+            'line is clipped to square with hole';
     }
     {
-        my $intersections = $expolygon->clip_line($line);
-        is_deeply [ map $_->pp, @$intersections ], [
-            [ [100, 150], [140, 150] ],
-            [ [160, 150], [200, 150] ],
-        ], 'line is clipped to square with hole';
+        my $intersection = $expolygon->clip_line($line);
+        is $intersection->[0]->length, Slic3r::Line->new([100, 150], [140, 150])->length,
+            'line is clipped to square with hole';
+        is $intersection->[1]->length, Slic3r::Line->new([160, 150], [200, 150])->length,
+            'line is clipped to square with hole';
     }
     {
-        my $intersections = $expolygon->clip_line(Slic3r::Line->new(reverse @$line));
-        is_deeply [ map $_->pp, @$intersections ], [
-            [ [200, 150], [160, 150] ],
-            [ [140, 150], [100, 150] ],
-        ], 'reverse line is clipped to square with hole';
+        my $intersection = $expolygon->clip_line(Slic3r::Line->new(reverse @$line));
+        is $intersection->[0]->length, Slic3r::Line->new([200, 150], [160, 150])->length,
+            'reverse line is clipped to square with hole';
+        is $intersection->[1]->length, Slic3r::Line->new([140, 150], [100, 150])->length,
+            'reverse line is clipped to square with hole';
     }
     {
-        my $intersections = $expolygon->clip_line(Slic3r::Line->new([100,180], [200,180]));
-        is_deeply [ map $_->pp, @$intersections ], [
-            [ [100, 180], [200, 180] ],
-        ], 'tangent line is clipped to square with hole';
+        my $intersection = $expolygon->clip_line(Slic3r::Line->new([100,180], [200,180]));
+        is $intersection->[0]->length, Slic3r::Line->new([100,180], [200,180])->length,
+            'tangent line is clipped to square with hole';
     }
     {
         my $polyline = Slic3r::Polyline->new([50, 180], [250, 180], [250, 150], [150, 150], [150, 120], [120, 120], [120, 50]);
@@ -141,11 +119,11 @@ is_deeply $intersection, [ [120, 120], [180, 160] ], 'internal lines are preserv
     my $expolygon = Slic3r::ExPolygon->new($large_circle, $small_circle);
     $line = Slic3r::Line->new_scale([152.742,288.086671142818], [152.742,34.166466971035]);
     
-    my $intersections = $expolygon->clip_line($line);
-    is_deeply [ map $_->pp, @$intersections ], [
-        [ [152742000, 288086661], [152742000, 215178843],  ],
-        [ [152742000, 108087507], [152742000, 35166477] ],
-    ], 'line is clipped to square with hole';
+    my $intersection = $expolygon->clip_line($line);
+    is $intersection->[0]->length, Slic3r::Line->new([152742000, 288086661], [152742000, 215178843])->length,
+        'line is clipped to square with hole';
+    is $intersection->[1]->length, Slic3r::Line->new([152742000, 108087507], [152742000, 35166477])->length,
+        'line is clipped to square with hole';
 }
 
 #==========================================================

+ 72 - 24
xs/src/ClipperUtils.cpp

@@ -8,11 +8,11 @@ void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, Slic3r::ExPoly
 {  
   size_t cnt = expolygons.size();
   expolygons.resize(cnt + 1);
-  ClipperPolygon_to_Slic3rPolygon(polynode.Contour, expolygons[cnt].contour);
+  ClipperPath_to_Slic3rMultiPoint(polynode.Contour, expolygons[cnt].contour);
   expolygons[cnt].holes.resize(polynode.ChildCount());
   for (int i = 0; i < polynode.ChildCount(); ++i)
   {
-    ClipperPolygon_to_Slic3rPolygon(polynode.Childs[i]->Contour, expolygons[cnt].holes[i]);
+    ClipperPath_to_Slic3rMultiPoint(polynode.Childs[i]->Contour, expolygons[cnt].holes[i]);
     //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);
@@ -27,8 +27,9 @@ void PolyTreeToExPolygons(ClipperLib::PolyTree& polytree, Slic3r::ExPolygons& ex
 }
 //-----------------------------------------------------------
 
+template <class T>
 void
-ClipperPolygon_to_Slic3rPolygon(const ClipperLib::Path &input, Slic3r::Polygon &output)
+ClipperPath_to_Slic3rMultiPoint(const ClipperLib::Path &input, T &output)
 {
     output.points.clear();
     for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit) {
@@ -36,19 +37,20 @@ ClipperPolygon_to_Slic3rPolygon(const ClipperLib::Path &input, Slic3r::Polygon &
     }
 }
 
+template <class T>
 void
-ClipperPolygons_to_Slic3rPolygons(const ClipperLib::Paths &input, Slic3r::Polygons &output)
+ClipperPaths_to_Slic3rMultiPoints(const ClipperLib::Paths &input, T &output)
 {
     output.clear();
     for (ClipperLib::Paths::const_iterator it = input.begin(); it != input.end(); ++it) {
-        Slic3r::Polygon p;
-        ClipperPolygon_to_Slic3rPolygon(*it, p);
+        typename T::value_type p;
+        ClipperPath_to_Slic3rMultiPoint(*it, p);
         output.push_back(p);
     }
 }
 
 void
-ClipperPolygons_to_Slic3rExPolygons(const ClipperLib::Paths &input, Slic3r::ExPolygons &output)
+ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, Slic3r::ExPolygons &output)
 {
     // init Clipper
     ClipperLib::Clipper clipper;
@@ -67,7 +69,7 @@ ClipperPolygons_to_Slic3rExPolygons(const ClipperLib::Paths &input, Slic3r::ExPo
 }
 
 void
-Slic3rPolygon_to_ClipperPolygon(const Slic3r::MultiPoint &input, ClipperLib::Path &output)
+Slic3rMultiPoint_to_ClipperPath(const Slic3r::MultiPoint &input, ClipperLib::Path &output)
 {
     output.clear();
     for (Slic3r::Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit) {
@@ -77,12 +79,12 @@ Slic3rPolygon_to_ClipperPolygon(const Slic3r::MultiPoint &input, ClipperLib::Pat
 
 template <class T>
 void
-Slic3rPolygons_to_ClipperPolygons(const T &input, ClipperLib::Paths &output)
+Slic3rMultiPoints_to_ClipperPaths(const T &input, ClipperLib::Paths &output)
 {
     output.clear();
     for (typename T::const_iterator it = input.begin(); it != input.end(); ++it) {
         ClipperLib::Path p;
-        Slic3rPolygon_to_ClipperPolygon(*it, p);
+        Slic3rMultiPoint_to_ClipperPath(*it, p);
         output.push_back(p);
     }
 }
@@ -104,7 +106,7 @@ offset(Slic3r::Polygons &polygons, ClipperLib::Paths &retval, const float delta,
 {
     // read input
     ClipperLib::Paths* input = new ClipperLib::Paths();
-    Slic3rPolygons_to_ClipperPolygons(polygons, *input);
+    Slic3rMultiPoints_to_ClipperPaths(polygons, *input);
     
     // scale input
     scaleClipperPolygons(*input, scale);
@@ -126,7 +128,7 @@ offset(Slic3r::Polygons &polygons, Slic3r::Polygons &retval, const float delta,
     offset(polygons, *output, delta, scale, joinType, miterLimit);
     
     // convert into ExPolygons
-    ClipperPolygons_to_Slic3rPolygons(*output, retval);
+    ClipperPaths_to_Slic3rMultiPoints(*output, retval);
     delete output;
 }
 
@@ -136,7 +138,7 @@ offset(Slic3r::Polylines &polylines, ClipperLib::Paths &retval, const float delt
 {
     // read input
     ClipperLib::Paths* input = new ClipperLib::Paths();
-    Slic3rPolygons_to_ClipperPolygons(polylines, *input);
+    Slic3rMultiPoints_to_ClipperPaths(polylines, *input);
     
     // scale input
     scaleClipperPolygons(*input, scale);
@@ -158,7 +160,7 @@ offset(Slic3r::Polylines &polylines, Slic3r::Polygons &retval, const float delta
     offset(polylines, *output, delta, scale, joinType, miterLimit);
     
     // convert into ExPolygons
-    ClipperPolygons_to_Slic3rPolygons(*output, retval);
+    ClipperPaths_to_Slic3rMultiPoints(*output, retval);
     delete output;
 }
 
@@ -171,7 +173,7 @@ offset_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float de
     offset(polygons, *output, delta, scale, joinType, miterLimit);
     
     // convert into ExPolygons
-    ClipperPolygons_to_Slic3rExPolygons(*output, retval);
+    ClipperPaths_to_Slic3rExPolygons(*output, retval);
     delete output;
 }
 
@@ -181,7 +183,7 @@ offset2(Slic3r::Polygons &polygons, ClipperLib::Paths &retval, const float delta
 {
     // read input
     ClipperLib::Paths* input = new ClipperLib::Paths();
-    Slic3rPolygons_to_ClipperPolygons(polygons, *input);
+    Slic3rMultiPoints_to_ClipperPaths(polygons, *input);
     
     // scale input
     scaleClipperPolygons(*input, scale);
@@ -208,7 +210,7 @@ offset2(Slic3r::Polygons &polygons, Slic3r::Polygons &retval, const float delta1
     offset2(polygons, *output, delta1, delta2, scale, joinType, miterLimit);
     
     // convert into ExPolygons
-    ClipperPolygons_to_Slic3rPolygons(*output, retval);
+    ClipperPaths_to_Slic3rMultiPoints(*output, retval);
     delete output;
 }
 
@@ -221,7 +223,7 @@ offset2_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float d
     offset2(polygons, *output, delta1, delta2, scale, joinType, miterLimit);
     
     // convert into ExPolygons
-    ClipperPolygons_to_Slic3rExPolygons(*output, retval);
+    ClipperPaths_to_Slic3rExPolygons(*output, retval);
     delete output;
 }
 
@@ -232,8 +234,8 @@ void _clipper_do(const ClipperLib::ClipType clipType, Slic3r::Polygons &subject,
     // read input
     ClipperLib::Paths* input_subject = new ClipperLib::Paths();
     ClipperLib::Paths* input_clip    = new ClipperLib::Paths();
-    Slic3rPolygons_to_ClipperPolygons(subject, *input_subject);
-    Slic3rPolygons_to_ClipperPolygons(clip,    *input_clip);
+    Slic3rMultiPoints_to_ClipperPaths(subject, *input_subject);
+    Slic3rMultiPoints_to_ClipperPaths(clip,    *input_clip);
     
     // perform safety offset
     if (safety_offset_) {
@@ -258,6 +260,29 @@ void _clipper_do(const ClipperLib::ClipType clipType, Slic3r::Polygons &subject,
     clipper.Execute(clipType, retval, fillType, fillType);
 }
 
+void _clipper_do(const ClipperLib::ClipType clipType, Slic3r::Polylines &subject, 
+    Slic3r::Polygons &clip, ClipperLib::PolyTree &retval, const ClipperLib::PolyFillType fillType)
+{
+    // read input
+    ClipperLib::Paths* input_subject = new ClipperLib::Paths();
+    ClipperLib::Paths* input_clip    = new ClipperLib::Paths();
+    Slic3rMultiPoints_to_ClipperPaths(subject, *input_subject);
+    Slic3rMultiPoints_to_ClipperPaths(clip,    *input_clip);
+    
+    // init Clipper
+    ClipperLib::Clipper clipper;
+    clipper.Clear();
+    
+    // add polygons
+    clipper.AddPaths(*input_subject, ClipperLib::ptSubject, false);
+    delete input_subject;
+    clipper.AddPaths(*input_clip, ClipperLib::ptClip, true);
+    delete input_clip;
+    
+    // perform operation
+    clipper.Execute(clipType, retval, fillType, fillType);
+}
+
 void _clipper(ClipperLib::ClipType clipType, Slic3r::Polygons &subject, 
     Slic3r::Polygons &clip, Slic3r::Polygons &retval, bool safety_offset_)
 {
@@ -266,7 +291,7 @@ void _clipper(ClipperLib::ClipType clipType, Slic3r::Polygons &subject,
     _clipper_do<ClipperLib::Paths>(clipType, subject, clip, *output, ClipperLib::pftNonZero, safety_offset_);
     
     // convert into Polygons
-    ClipperPolygons_to_Slic3rPolygons(*output, retval);
+    ClipperPaths_to_Slic3rMultiPoints(*output, retval);
     delete output;
 }
 
@@ -282,6 +307,19 @@ void _clipper(ClipperLib::ClipType clipType, Slic3r::Polygons &subject,
     delete polytree;
 }
 
+void _clipper(ClipperLib::ClipType clipType, Slic3r::Polylines &subject, 
+    Slic3r::Polygons &clip, Slic3r::Polylines &retval)
+{
+    // perform operation
+    ClipperLib::PolyTree polytree;
+    _clipper_do(clipType, subject, clip, polytree, ClipperLib::pftNonZero);
+    
+    // convert into Polygons
+    ClipperLib::Paths output;
+    ClipperLib::PolyTreeToPaths(polytree, output);
+    ClipperPaths_to_Slic3rMultiPoints(output, retval);
+}
+
 template <class T>
 void diff(Slic3r::Polygons &subject, Slic3r::Polygons &clip, T &retval, bool safety_offset_)
 {
@@ -290,6 +328,11 @@ void diff(Slic3r::Polygons &subject, Slic3r::Polygons &clip, T &retval, bool saf
 template void diff<Slic3r::ExPolygons>(Slic3r::Polygons &subject, Slic3r::Polygons &clip, Slic3r::ExPolygons &retval, bool safety_offset_);
 template void diff<Slic3r::Polygons>(Slic3r::Polygons &subject, Slic3r::Polygons &clip, Slic3r::Polygons &retval, bool safety_offset_);
 
+void diff(Slic3r::Polylines &subject, Slic3r::Polygons &clip, Slic3r::Polylines &retval)
+{
+    _clipper(ClipperLib::ctDifference, subject, clip, retval);
+}
+
 template <class T>
 void intersection(Slic3r::Polygons &subject, Slic3r::Polygons &clip, T &retval, bool safety_offset_)
 {
@@ -298,6 +341,11 @@ void intersection(Slic3r::Polygons &subject, Slic3r::Polygons &clip, T &retval,
 template void intersection<Slic3r::ExPolygons>(Slic3r::Polygons &subject, Slic3r::Polygons &clip, Slic3r::ExPolygons &retval, bool safety_offset_);
 template void intersection<Slic3r::Polygons>(Slic3r::Polygons &subject, Slic3r::Polygons &clip, Slic3r::Polygons &retval, bool safety_offset_);
 
+void intersection(Slic3r::Polylines &subject, Slic3r::Polygons &clip, Slic3r::Polylines &retval)
+{
+    _clipper(ClipperLib::ctIntersection, subject, clip, retval);
+}
+
 void xor_ex(Slic3r::Polygons &subject, Slic3r::Polygons &clip, Slic3r::ExPolygons &retval, 
     bool safety_offset_)
 {
@@ -323,14 +371,14 @@ void simplify_polygons(Slic3r::Polygons &subject, Slic3r::Polygons &retval)
 {
     // convert into Clipper polygons
     ClipperLib::Paths* input_subject = new ClipperLib::Paths();
-    Slic3rPolygons_to_ClipperPolygons(subject, *input_subject);
+    Slic3rMultiPoints_to_ClipperPaths(subject, *input_subject);
     
     ClipperLib::Paths* output = new ClipperLib::Paths();
     ClipperLib::SimplifyPolygons(*input_subject, *output, ClipperLib::pftNonZero);
     delete input_subject;
     
     // convert into Slic3r polygons
-    ClipperPolygons_to_Slic3rPolygons(*output, retval);
+    ClipperPaths_to_Slic3rMultiPoints(*output, retval);
     delete output;
 }
 
@@ -371,7 +419,7 @@ polynode2perl(const ClipperLib::PolyNode& node)
 {
     HV* hv = newHV();
     Slic3r::Polygon p;
-    ClipperPolygon_to_Slic3rPolygon(node.Contour, p);
+    ClipperPath_to_Slic3rMultiPoint(node.Contour, p);
     if (node.IsHole()) {
         (void)hv_stores( hv, "hole", p.to_SV_clone_ref() );
     } else {

+ 15 - 5
xs/src/ClipperUtils.hpp

@@ -21,12 +21,14 @@ void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, Slic3r::ExPoly
 void PolyTreeToExPolygons(ClipperLib::PolyTree& polytree, Slic3r::ExPolygons& expolygons);
 //-----------------------------------------------------------
 
-void Slic3rPolygon_to_ClipperPolygon(const Slic3r::MultiPoint &input, ClipperLib::Path &output);
+void Slic3rMultiPoint_to_ClipperPath(const Slic3r::MultiPoint &input, ClipperLib::Path &output);
 template <class T>
-void Slic3rPolygons_to_ClipperPolygons(const T &input, ClipperLib::Paths &output);
-void ClipperPolygon_to_Slic3rPolygon(const ClipperLib::Path &input, Slic3r::Polygon &output);
-void ClipperPolygons_to_Slic3rPolygons(const ClipperLib::Paths &input, Slic3r::Polygons &output);
-void ClipperPolygons_to_Slic3rExPolygons(const ClipperLib::Paths &input, Slic3r::ExPolygons &output);
+void Slic3rMultiPoints_to_ClipperPaths(const T &input, ClipperLib::Paths &output);
+template <class T>
+void ClipperPath_to_Slic3rMultiPoint(const ClipperLib::Path &input, T &output);
+template <class T>
+void ClipperPaths_to_Slic3rMultiPoints(const ClipperLib::Paths &input, T &output);
+void ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, Slic3r::ExPolygons &output);
 
 void scaleClipperPolygons(ClipperLib::Paths &polygons, const double scale);
 
@@ -63,17 +65,25 @@ void offset2_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const fl
 template <class T>
 void _clipper_do(ClipperLib::ClipType clipType, Slic3r::Polygons &subject, 
     Slic3r::Polygons &clip, T &retval, bool safety_offset_);
+void _clipper_do(ClipperLib::ClipType clipType, Slic3r::Polylines &subject, 
+    Slic3r::Polygons &clip, ClipperLib::Paths &retval);
 void _clipper(ClipperLib::ClipType clipType, Slic3r::Polygons &subject, 
     Slic3r::Polygons &clip, Slic3r::Polygons &retval, bool safety_offset_);
 void _clipper(ClipperLib::ClipType clipType, Slic3r::Polygons &subject, 
     Slic3r::Polygons &clip, Slic3r::ExPolygons &retval, bool safety_offset_);
+void _clipper(ClipperLib::ClipType clipType, Slic3r::Polylines &subject, 
+    Slic3r::Polygons &clip, Slic3r::Polylines &retval);
 
 template <class T>
 void diff(Slic3r::Polygons &subject, Slic3r::Polygons &clip, T &retval, bool safety_offset_);
 
+void diff(Slic3r::Polylines &subject, Slic3r::Polygons &clip, Slic3r::Polylines &retval);
+
 template <class T>
 void intersection(Slic3r::Polygons &subject, Slic3r::Polygons &clip, T &retval, bool safety_offset_);
 
+void intersection(Slic3r::Polylines &subject, Slic3r::Polygons &clip, Slic3r::Polylines &retval);
+
 void xor_ex(Slic3r::Polygons &subject, Slic3r::Polygons &clip, Slic3r::ExPolygons &retval, 
     bool safety_offset_ = false);
 

Some files were not shown because too many files changed in this diff