New algorithm for clipping lines to complex polygons

This commit is contained in:
Alessandro Ranellucci 2011-10-06 12:20:25 +02:00
parent 5812804d6b
commit e2d2574b8b
3 changed files with 53 additions and 8 deletions

View File

@ -90,9 +90,7 @@ sub point_in_polygon {
# if point is not in polygon, let's check whether it belongs to the contour # if point is not in polygon, let's check whether it belongs to the contour
if (!$side && 0) { if (!$side && 0) {
foreach my $line (polygon_lines($polygon)) { return 1 if polygon_segment_having_point($polygon, $point);
return 1 if point_in_segment($point, $line);
}
} }
return $side; return $side;
@ -458,5 +456,22 @@ sub bounding_box_intersect {
return 1; 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; 1;

View File

@ -2,7 +2,7 @@ use Test::More;
use strict; use strict;
use warnings; use warnings;
plan tests => 4; plan tests => 5;
BEGIN { BEGIN {
use FindBin; 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 $line1 = [ [5, 15], [30, 15] ];
my $line2 = [ [75/0.0000001, 437.9853/0.0000001], [62.7484/0.0000001, 440.4223/0.0000001] ]; 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'; isnt Slic3r::Geometry::line_intersection($line1, $line2, 1), undef, 'line_intersection';
#========================================================== #==========================================================

View File

@ -1,6 +1,6 @@
use Test::More; use Test::More;
plan tests => 9; plan tests => 10;
BEGIN { BEGIN {
use FindBin; use FindBin;
@ -9,7 +9,7 @@ BEGIN {
use Slic3r; use Slic3r;
my $square = [ my $square = [ # ccw
[10, 10], [10, 10],
[20, 10], [20, 10],
[20, 20], [20, 20],
@ -21,18 +21,42 @@ my $line = [ [5, 15], [30, 15] ];
my $intersection = Slic3r::Geometry::clip_segment_polygon($line, $square); my $intersection = Slic3r::Geometry::clip_segment_polygon($line, $square);
is_deeply $intersection, [ [10, 15], [20, 15] ], 'line is clipped to square'; is_deeply $intersection, [ [10, 15], [20, 15] ], 'line is clipped to square';
#==========================================================
$intersection = Slic3r::Geometry::clip_segment_polygon([ [0, 15], [8, 15] ], $square); $intersection = Slic3r::Geometry::clip_segment_polygon([ [0, 15], [8, 15] ], $square);
is $intersection, undef, 'external lines are ignored 1'; is $intersection, undef, 'external lines are ignored 1';
#==========================================================
$intersection = Slic3r::Geometry::clip_segment_polygon([ [30, 15], [40, 15] ], $square); $intersection = Slic3r::Geometry::clip_segment_polygon([ [30, 15], [40, 15] ], $square);
is $intersection, undef, 'external lines are ignored 2'; is $intersection, undef, 'external lines are ignored 2';
#==========================================================
$intersection = Slic3r::Geometry::clip_segment_polygon([ [12, 12], [18, 16] ], $square); $intersection = Slic3r::Geometry::clip_segment_polygon([ [12, 12], [18, 16] ], $square);
is_deeply $intersection, [ [12, 12], [18, 16] ], 'internal lines are preserved'; 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([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([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, 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([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([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'; is Slic3r::Geometry::point_in_segment([20, 15], [ [10, 10], [20, 20] ]), 0, 'point not in diagonal segment';
#==========================================================