diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm index 20c49100b..89c87e545 100644 --- a/lib/Slic3r/Geometry.pm +++ b/lib/Slic3r/Geometry.pm @@ -90,9 +90,7 @@ sub point_in_polygon { # if point is not in polygon, let's check whether it belongs to the contour if (!$side && 0) { - foreach my $line (polygon_lines($polygon)) { - return 1 if point_in_segment($point, $line); - } + return 1 if polygon_segment_having_point($polygon, $point); } return $side; @@ -458,5 +456,22 @@ sub bounding_box_intersect { return 1; } +sub clip_segment_complex_polygon { + my ($line, $polygons) = @_; + + my @intersections = grep $_, map line_intersection($line, $_, 1), + map polygon_lines($_), @$polygons; + + @intersections = sort { "$a->[X],$a->[Y]" cmp "$b->[X],$b->[Y]" } @intersections; + + shift(@intersections) if !grep(point_in_polygon($intersections[0], $_), @$polygons) + && !grep(polygon_segment_having_point($_, $intersections[0]), @$polygons); + + my @lines = (); + while (@intersections) { + push @lines, [ shift(@intersections), shift(@intersections) ]; + } + return [@lines]; +} 1; diff --git a/t/geometry.t b/t/geometry.t index 3d9018686..decdad899 100644 --- a/t/geometry.t +++ b/t/geometry.t @@ -2,7 +2,7 @@ use Test::More; use strict; use warnings; -plan tests => 4; +plan tests => 5; BEGIN { use FindBin; @@ -13,8 +13,14 @@ use Slic3r; #========================================================== -my $line1 = [ [73.6310778185108/0.0000001, 371.74239268924/0.0000001], [73.6310778185108/0.0000001, 501.74239268924/0.0000001] ]; -my $line2 = [ [75/0.0000001, 437.9853/0.0000001], [62.7484/0.0000001, 440.4223/0.0000001] ]; +my $line1 = [ [5, 15], [30, 15] ]; +my $line2 = [ [10, 20], [10, 10] ]; +is_deeply Slic3r::Geometry::line_intersection($line1, $line2, 1), [10, 15], 'line_intersection'; + +#========================================================== + +$line1 = [ [73.6310778185108/0.0000001, 371.74239268924/0.0000001], [73.6310778185108/0.0000001, 501.74239268924/0.0000001] ]; +$line2 = [ [75/0.0000001, 437.9853/0.0000001], [62.7484/0.0000001, 440.4223/0.0000001] ]; isnt Slic3r::Geometry::line_intersection($line1, $line2, 1), undef, 'line_intersection'; #========================================================== diff --git a/t/polyclip.t b/t/polyclip.t index 605c4834b..0a66565fe 100644 --- a/t/polyclip.t +++ b/t/polyclip.t @@ -1,6 +1,6 @@ use Test::More; -plan tests => 9; +plan tests => 10; BEGIN { use FindBin; @@ -9,7 +9,7 @@ BEGIN { use Slic3r; -my $square = [ +my $square = [ # ccw [10, 10], [20, 10], [20, 20], @@ -21,18 +21,42 @@ my $line = [ [5, 15], [30, 15] ]; my $intersection = Slic3r::Geometry::clip_segment_polygon($line, $square); is_deeply $intersection, [ [10, 15], [20, 15] ], 'line is clipped to square'; +#========================================================== + $intersection = Slic3r::Geometry::clip_segment_polygon([ [0, 15], [8, 15] ], $square); is $intersection, undef, 'external lines are ignored 1'; +#========================================================== + $intersection = Slic3r::Geometry::clip_segment_polygon([ [30, 15], [40, 15] ], $square); is $intersection, undef, 'external lines are ignored 2'; +#========================================================== + $intersection = Slic3r::Geometry::clip_segment_polygon([ [12, 12], [18, 16] ], $square); is_deeply $intersection, [ [12, 12], [18, 16] ], 'internal lines are preserved'; +#========================================================== + +my $hole_in_square = [ # cw + [14, 14], + [14, 16], + [16, 16], + [16, 14], +]; +my $intersections = Slic3r::Geometry::clip_segment_complex_polygon($line, [ $square, $hole_in_square ]); +is_deeply $intersections, [ + [ [10, 15], [14, 15] ], + [ [16, 15], [20, 15] ], +], 'line is clipped to square with hole'; + +#========================================================== + is Slic3r::Geometry::point_in_segment([10, 10], [ [5, 10], [20, 10] ]), 1, 'point in horizontal segment'; is Slic3r::Geometry::point_in_segment([30, 10], [ [5, 10], [20, 10] ]), 0, 'point not in horizontal segment'; is Slic3r::Geometry::point_in_segment([10, 10], [ [10, 5], [10, 20] ]), 1, 'point in vertical segment'; is Slic3r::Geometry::point_in_segment([10, 30], [ [10, 5], [10, 20] ]), 0, 'point not in vertical segment'; is Slic3r::Geometry::point_in_segment([15, 15], [ [10, 10], [20, 20] ]), 1, 'point in diagonal segment'; is Slic3r::Geometry::point_in_segment([20, 15], [ [10, 10], [20, 20] ]), 0, 'point not in diagonal segment'; + +#==========================================================