Use Clipper for line clipping
This commit is contained in:
parent
1d6a18071a
commit
3025c77675
@ -8,7 +8,7 @@ use Boost::Geometry::Utils;
|
|||||||
use List::Util qw(first);
|
use List::Util qw(first);
|
||||||
use Math::Geometry::Voronoi;
|
use Math::Geometry::Voronoi;
|
||||||
use Slic3r::Geometry qw(X Y A B point_in_polygon epsilon scaled_epsilon);
|
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 {
|
sub wkt {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
@ -77,7 +77,7 @@ sub clip_line {
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
map Slic3r::Line->new(@$_),
|
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 = ();
|
my @polylines = ();
|
||||||
foreach my $line (@{$polygon->lines}) {
|
foreach my $line (@{$polygon->lines}) {
|
||||||
# remove the areas that are already covered from this line
|
# 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
|
# 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
|
# grow the remaining lines and add them to the covered areas
|
||||||
push @$covered, map $grow->($_, $width*1.1), @$clipped;
|
push @$covered, map $grow->($_, $width*1.1), @$clipped;
|
||||||
|
@ -6,7 +6,7 @@ extends 'Slic3r::Fill::Base';
|
|||||||
has 'cache' => (is => 'rw', default => sub {{}});
|
has 'cache' => (is => 'rw', default => sub {{}});
|
||||||
|
|
||||||
use Slic3r::Geometry qw(PI X Y MIN MAX scale scaled_epsilon);
|
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] }
|
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:
|
# consider polygons as polylines without re-appending the initial point:
|
||||||
# this cuts the last segment on purpose, so that the jump to the next
|
# this cuts the last segment on purpose, so that the jump to the next
|
||||||
# path is more straight
|
# path is more straight
|
||||||
@paths = map Slic3r::Polyline->new(@$_),
|
@paths = @{intersection_pl(
|
||||||
@{ Boost::Geometry::Utils::polygon_multi_linestring_intersection(
|
[ map Slic3r::Polyline->new(@$_), @polygons ],
|
||||||
$surface->expolygon->pp,
|
[ @{$surface->expolygon} ],
|
||||||
[ map $_->pp, @polygons ],
|
|
||||||
)};
|
)};
|
||||||
|
|
||||||
# connect paths
|
# connect paths
|
||||||
{
|
{
|
||||||
my $collection = Slic3r::Polyline::Collection->new(@paths);
|
my $collection = Slic3r::Polyline::Collection->new(@paths);
|
||||||
@paths = ();
|
@paths = ();
|
||||||
foreach my $path (@{$collection->chained_path(0)}) {
|
foreach my $path (@{$collection->chained_path_from($collection->leftmost_point, 0)}) {
|
||||||
if (@paths) {
|
if (@paths) {
|
||||||
# distance between first point of this path and last point of last path
|
# distance between first point of this path and last point of last path
|
||||||
my $distance = $paths[-1]->last_point->distance_to($path->first_point);
|
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
|
# clip paths again to prevent connection segments from crossing the expolygon boundaries
|
||||||
@paths = map Slic3r::Polyline->new(@$_),
|
@paths = @{intersection_pl(
|
||||||
@{ Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection(
|
\@paths,
|
||||||
[ map $_->pp, @{$surface->expolygon->offset_ex(scaled_epsilon)} ],
|
[ @{$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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return { flow_spacing => $params{flow_spacing} }, @paths;
|
return { flow_spacing => $params{flow_spacing} }, @paths;
|
||||||
|
@ -6,6 +6,7 @@ extends 'Slic3r::Fill::Base';
|
|||||||
has 'cache' => (is => 'rw', default => sub {{}});
|
has 'cache' => (is => 'rw', default => sub {{}});
|
||||||
|
|
||||||
use Slic3r::Geometry qw(A B X Y MIN scale unscale scaled_epsilon);
|
use Slic3r::Geometry qw(A B X Y MIN scale unscale scaled_epsilon);
|
||||||
|
use Slic3r::Geometry::Clipper qw(intersection_pl offset);
|
||||||
|
|
||||||
sub fill_surface {
|
sub fill_surface {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
@ -47,7 +48,7 @@ sub fill_surface {
|
|||||||
$vertical_line->[A][X] += $line_oscillation;
|
$vertical_line->[A][X] += $line_oscillation;
|
||||||
$vertical_line->[B][X] -= $line_oscillation;
|
$vertical_line->[B][X] -= $line_oscillation;
|
||||||
}
|
}
|
||||||
push @vertical_lines, $vertical_line;
|
push @vertical_lines, Slic3r::Polyline->new(@$vertical_line);
|
||||||
$i++;
|
$i++;
|
||||||
$x += $line_spacing;
|
$x += $line_spacing;
|
||||||
}
|
}
|
||||||
@ -57,11 +58,7 @@ sub fill_surface {
|
|||||||
# the minimum offset for preventing edge lines from being clipped is scaled_epsilon;
|
# 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
|
# however we use a larger offset to support expolygons with slightly skewed sides and
|
||||||
# not perfectly straight
|
# not perfectly straight
|
||||||
my @polylines = map Slic3r::Polyline->new(@$_),
|
my @polylines = @{intersection_pl(\@vertical_lines, $expolygon->offset($line_spacing*0.05))};
|
||||||
@{ Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection(
|
|
||||||
[ map $_->pp, @{$expolygon->offset_ex($line_spacing*0.05)} ],
|
|
||||||
[ @vertical_lines ],
|
|
||||||
) };
|
|
||||||
|
|
||||||
# connect lines
|
# connect lines
|
||||||
unless ($params{dont_connect}) {
|
unless ($params{dont_connect}) {
|
||||||
@ -78,7 +75,7 @@ sub fill_surface {
|
|||||||
}
|
}
|
||||||
: sub { $_[X] <= $diagonal_distance && $_[Y] <= $diagonal_distance };
|
: 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) {
|
if (@polylines) {
|
||||||
my $first_point = $polyline->first_point;
|
my $first_point = $polyline->first_point;
|
||||||
my $last_point = $polylines[-1]->last_point;
|
my $last_point = $polylines[-1]->last_point;
|
||||||
|
@ -14,7 +14,7 @@ has '_tolerance' => (is => 'lazy');
|
|||||||
|
|
||||||
use List::Util qw(first);
|
use List::Util qw(first);
|
||||||
use Slic3r::Geometry qw(A B scale epsilon);
|
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
|
# clearance (in mm) from the perimeters
|
||||||
has '_inner_margin' => (is => 'ro', default => sub { scale 0.5 });
|
has '_inner_margin' => (is => 'ro', default => sub { scale 0.5 });
|
||||||
@ -91,7 +91,7 @@ sub BUILD {
|
|||||||
for my $m (0 .. $#{$outer[$i]}) {
|
for my $m (0 .. $#{$outer[$i]}) {
|
||||||
for my $n (0 .. $#{$outer[$j]}) {
|
for my $n (0 .. $#{$outer[$j]}) {
|
||||||
my $line = Slic3r::Line->new($outer[$i][$m], $outer[$j][$n]);
|
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
|
# this line does not cross any polygon
|
||||||
my $dist = $line->length;
|
my $dist = $line->length;
|
||||||
$edges->{$outer[$i][$m]}{$outer[$j][$n]} = $dist;
|
$edges->{$outer[$i][$m]}{$outer[$j][$n]} = $dist;
|
||||||
@ -112,7 +112,7 @@ sub BUILD {
|
|||||||
for my $m (0 .. $#{$inner[$i]}) {
|
for my $m (0 .. $#{$inner[$i]}) {
|
||||||
for my $n (0 .. $#{$inner[$j]}) {
|
for my $n (0 .. $#{$inner[$j]}) {
|
||||||
my $line = Slic3r::Line->new($inner[$i][$m], $inner[$j][$n]);
|
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
|
# this line does not cross any polygon
|
||||||
my $dist = $line->length * CROSSING_FACTOR;
|
my $dist = $line->length * CROSSING_FACTOR;
|
||||||
$edges->{$inner[$i][$m]}{$inner[$j][$n]} = $dist;
|
$edges->{$inner[$i][$m]}{$inner[$j][$n]} = $dist;
|
||||||
|
@ -11,9 +11,9 @@ our @EXPORT_OK = qw(
|
|||||||
point_in_polygon point_in_segment segment_in_segment
|
point_in_polygon point_in_segment segment_in_segment
|
||||||
point_is_on_left_of_segment polyline_lines polygon_lines
|
point_is_on_left_of_segment polyline_lines polygon_lines
|
||||||
point_along_segment polygon_segment_having_point polygon_has_subsegment
|
point_along_segment polygon_segment_having_point polygon_has_subsegment
|
||||||
polygon_has_vertex can_connect_points deg2rad rad2deg
|
deg2rad rad2deg
|
||||||
rotate_points move_points clip_segment_polygon
|
rotate_points move_points
|
||||||
sum_vectors multiply_vector subtract_vectors dot perp polygon_points_visibility
|
dot perp polygon_points_visibility
|
||||||
line_intersection bounding_box bounding_box_intersect
|
line_intersection bounding_box bounding_box_intersect
|
||||||
angle3points three_points_aligned line_direction
|
angle3points three_points_aligned line_direction
|
||||||
polyline_remove_parallel_continuous_edges polyline_remove_acute_vertices
|
polyline_remove_parallel_continuous_edges polyline_remove_acute_vertices
|
||||||
@ -229,14 +229,6 @@ sub polygon_has_subsegment {
|
|||||||
return 0;
|
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
|
# polygon must be simple (non complex) and ccw
|
||||||
sub polygon_is_convex {
|
sub polygon_is_convex {
|
||||||
my ($points) = @_;
|
my ($points) = @_;
|
||||||
@ -247,29 +239,6 @@ sub polygon_is_convex {
|
|||||||
return 1;
|
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 {
|
sub deg2rad {
|
||||||
my ($degrees) = @_;
|
my ($degrees) = @_;
|
||||||
return PI() * $degrees / 180;
|
return PI() * $degrees / 180;
|
||||||
@ -315,65 +284,6 @@ sub move_points_3D {
|
|||||||
], @points;
|
], @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 {
|
sub normal {
|
||||||
my ($line1, $line2) = @_;
|
my ($line1, $line2) = @_;
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ our @ISA = qw(Exporter);
|
|||||||
our @EXPORT_OK = qw(offset offset_ex
|
our @EXPORT_OK = qw(offset offset_ex
|
||||||
diff_ex diff union_ex intersection_ex xor_ex JT_ROUND JT_MITER
|
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
|
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);
|
use Slic3r::Geometry qw(scale);
|
||||||
|
|
||||||
|
@ -562,12 +562,10 @@ sub _detect_bridge_direction {
|
|||||||
|
|
||||||
my @lines = ();
|
my @lines = ();
|
||||||
for (my $x = $bounding_box->x_min; $x <= $bounding_box->x_max; $x += $line_increment) {
|
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(@$_), @{ intersection_pl(\@lines, [ map @$_, @$inset ]) };
|
||||||
my @clipped_lines = map Slic3r::Line->new(@$_),
|
|
||||||
map @{ Boost::Geometry::Utils::polygon_multi_linestring_intersection($_->pp, \@lines) }, @$inset;
|
|
||||||
|
|
||||||
# remove any line not having both endpoints within anchors
|
# remove any line not having both endpoints within anchors
|
||||||
@clipped_lines = grep {
|
@clipped_lines = grep {
|
||||||
|
78
t/polyclip.t
78
t/polyclip.t
@ -2,7 +2,7 @@ use Test::More;
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
plan tests => 24;
|
plan tests => 23;
|
||||||
|
|
||||||
BEGIN {
|
BEGIN {
|
||||||
use FindBin;
|
use FindBin;
|
||||||
@ -31,24 +31,6 @@ my $square = Slic3r::Polygon->new( # ccw
|
|||||||
|
|
||||||
my $line = Slic3r::Line->new([50, 150], [300, 150]);
|
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, 150)), 1, 'point on hole contour is recognized';
|
||||||
is $expolygon->encloses_point(Slic3r::Point->new(140, 140)), 1, 'point on hole corner 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]));
|
my $intersection = $expolygon->clip_line(Slic3r::Line->new([150,180], [150,150]));
|
||||||
is_deeply [ map $_->pp, @$intersections ], [
|
is $intersection->[0]->length, Slic3r::Line->new([150, 180], [150, 160])->length,
|
||||||
[ [150, 180], [150, 160] ],
|
'line is clipped to square with hole';
|
||||||
], 'line is clipped to square with hole';
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
my $intersections = $expolygon->clip_line(Slic3r::Line->new([150,150], [150,120]));
|
my $intersection = $expolygon->clip_line(Slic3r::Line->new([150,150], [150,120]));
|
||||||
is_deeply [ map $_->pp, @$intersections ], [
|
is $intersection->[0]->length, Slic3r::Line->new([150, 140], [150, 120])->length,
|
||||||
[ [150, 140], [150, 120] ],
|
'line is clipped to square with hole';
|
||||||
], 'line is clipped to square with hole';
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
my $intersections = $expolygon->clip_line(Slic3r::Line->new([120,180], [180,180]));
|
my $intersection = $expolygon->clip_line(Slic3r::Line->new([120,180], [180,180]));
|
||||||
is_deeply [ map $_->pp, @$intersections ], [
|
is $intersection->[0]->length, Slic3r::Line->new([120,180], [180,180])->length,
|
||||||
[ [120,180], [180,180] ],
|
'line is clipped to square with hole';
|
||||||
], 'line is clipped to square with hole';
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
my $intersections = $expolygon->clip_line($line);
|
my $intersection = $expolygon->clip_line($line);
|
||||||
is_deeply [ map $_->pp, @$intersections ], [
|
is $intersection->[0]->length, Slic3r::Line->new([100, 150], [140, 150])->length,
|
||||||
[ [100, 150], [140, 150] ],
|
'line is clipped to square with hole';
|
||||||
[ [160, 150], [200, 150] ],
|
is $intersection->[1]->length, Slic3r::Line->new([160, 150], [200, 150])->length,
|
||||||
], 'line is clipped to square with hole';
|
'line is clipped to square with hole';
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
my $intersections = $expolygon->clip_line(Slic3r::Line->new(reverse @$line));
|
my $intersection = $expolygon->clip_line(Slic3r::Line->new(reverse @$line));
|
||||||
is_deeply [ map $_->pp, @$intersections ], [
|
is $intersection->[0]->length, Slic3r::Line->new([200, 150], [160, 150])->length,
|
||||||
[ [200, 150], [160, 150] ],
|
'reverse line is clipped to square with hole';
|
||||||
[ [140, 150], [100, 150] ],
|
is $intersection->[1]->length, Slic3r::Line->new([140, 150], [100, 150])->length,
|
||||||
], 'reverse line is clipped to square with hole';
|
'reverse line is clipped to square with hole';
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
my $intersections = $expolygon->clip_line(Slic3r::Line->new([100,180], [200,180]));
|
my $intersection = $expolygon->clip_line(Slic3r::Line->new([100,180], [200,180]));
|
||||||
is_deeply [ map $_->pp, @$intersections ], [
|
is $intersection->[0]->length, Slic3r::Line->new([100,180], [200,180])->length,
|
||||||
[ [100, 180], [200, 180] ],
|
'tangent line is clipped to square with hole';
|
||||||
], '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]);
|
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);
|
my $expolygon = Slic3r::ExPolygon->new($large_circle, $small_circle);
|
||||||
$line = Slic3r::Line->new_scale([152.742,288.086671142818], [152.742,34.166466971035]);
|
$line = Slic3r::Line->new_scale([152.742,288.086671142818], [152.742,34.166466971035]);
|
||||||
|
|
||||||
my $intersections = $expolygon->clip_line($line);
|
my $intersection = $expolygon->clip_line($line);
|
||||||
is_deeply [ map $_->pp, @$intersections ], [
|
is $intersection->[0]->length, Slic3r::Line->new([152742000, 288086661], [152742000, 215178843])->length,
|
||||||
[ [152742000, 288086661], [152742000, 215178843], ],
|
'line is clipped to square with hole';
|
||||||
[ [152742000, 108087507], [152742000, 35166477] ],
|
is $intersection->[1]->length, Slic3r::Line->new([152742000, 108087507], [152742000, 35166477])->length,
|
||||||
], 'line is clipped to square with hole';
|
'line is clipped to square with hole';
|
||||||
}
|
}
|
||||||
|
|
||||||
#==========================================================
|
#==========================================================
|
||||||
|
@ -8,11 +8,11 @@ void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, Slic3r::ExPoly
|
|||||||
{
|
{
|
||||||
size_t cnt = expolygons.size();
|
size_t cnt = expolygons.size();
|
||||||
expolygons.resize(cnt + 1);
|
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());
|
expolygons[cnt].holes.resize(polynode.ChildCount());
|
||||||
for (int i = 0; i < polynode.ChildCount(); ++i)
|
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 ...
|
//Add outer polygons contained by (nested within) holes ...
|
||||||
for (int j = 0; j < polynode.Childs[i]->ChildCount(); ++j)
|
for (int j = 0; j < polynode.Childs[i]->ChildCount(); ++j)
|
||||||
AddOuterPolyNodeToExPolygons(*polynode.Childs[i]->Childs[j], expolygons);
|
AddOuterPolyNodeToExPolygons(*polynode.Childs[i]->Childs[j], expolygons);
|
||||||
@ -27,8 +27,9 @@ void PolyTreeToExPolygons(ClipperLib::PolyTree& polytree, Slic3r::ExPolygons& ex
|
|||||||
}
|
}
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
|
|
||||||
|
template <class T>
|
||||||
void
|
void
|
||||||
ClipperPolygon_to_Slic3rPolygon(const ClipperLib::Path &input, Slic3r::Polygon &output)
|
ClipperPath_to_Slic3rMultiPoint(const ClipperLib::Path &input, T &output)
|
||||||
{
|
{
|
||||||
output.points.clear();
|
output.points.clear();
|
||||||
for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit) {
|
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
|
void
|
||||||
ClipperPolygons_to_Slic3rPolygons(const ClipperLib::Paths &input, Slic3r::Polygons &output)
|
ClipperPaths_to_Slic3rMultiPoints(const ClipperLib::Paths &input, T &output)
|
||||||
{
|
{
|
||||||
output.clear();
|
output.clear();
|
||||||
for (ClipperLib::Paths::const_iterator it = input.begin(); it != input.end(); ++it) {
|
for (ClipperLib::Paths::const_iterator it = input.begin(); it != input.end(); ++it) {
|
||||||
Slic3r::Polygon p;
|
typename T::value_type p;
|
||||||
ClipperPolygon_to_Slic3rPolygon(*it, p);
|
ClipperPath_to_Slic3rMultiPoint(*it, p);
|
||||||
output.push_back(p);
|
output.push_back(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ClipperPolygons_to_Slic3rExPolygons(const ClipperLib::Paths &input, Slic3r::ExPolygons &output)
|
ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, Slic3r::ExPolygons &output)
|
||||||
{
|
{
|
||||||
// init Clipper
|
// init Clipper
|
||||||
ClipperLib::Clipper clipper;
|
ClipperLib::Clipper clipper;
|
||||||
@ -67,7 +69,7 @@ ClipperPolygons_to_Slic3rExPolygons(const ClipperLib::Paths &input, Slic3r::ExPo
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Slic3rPolygon_to_ClipperPolygon(const Slic3r::MultiPoint &input, ClipperLib::Path &output)
|
Slic3rMultiPoint_to_ClipperPath(const Slic3r::MultiPoint &input, ClipperLib::Path &output)
|
||||||
{
|
{
|
||||||
output.clear();
|
output.clear();
|
||||||
for (Slic3r::Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit) {
|
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>
|
template <class T>
|
||||||
void
|
void
|
||||||
Slic3rPolygons_to_ClipperPolygons(const T &input, ClipperLib::Paths &output)
|
Slic3rMultiPoints_to_ClipperPaths(const T &input, ClipperLib::Paths &output)
|
||||||
{
|
{
|
||||||
output.clear();
|
output.clear();
|
||||||
for (typename T::const_iterator it = input.begin(); it != input.end(); ++it) {
|
for (typename T::const_iterator it = input.begin(); it != input.end(); ++it) {
|
||||||
ClipperLib::Path p;
|
ClipperLib::Path p;
|
||||||
Slic3rPolygon_to_ClipperPolygon(*it, p);
|
Slic3rMultiPoint_to_ClipperPath(*it, p);
|
||||||
output.push_back(p);
|
output.push_back(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,7 +106,7 @@ offset(Slic3r::Polygons &polygons, ClipperLib::Paths &retval, const float delta,
|
|||||||
{
|
{
|
||||||
// read input
|
// read input
|
||||||
ClipperLib::Paths* input = new ClipperLib::Paths();
|
ClipperLib::Paths* input = new ClipperLib::Paths();
|
||||||
Slic3rPolygons_to_ClipperPolygons(polygons, *input);
|
Slic3rMultiPoints_to_ClipperPaths(polygons, *input);
|
||||||
|
|
||||||
// scale input
|
// scale input
|
||||||
scaleClipperPolygons(*input, scale);
|
scaleClipperPolygons(*input, scale);
|
||||||
@ -126,7 +128,7 @@ offset(Slic3r::Polygons &polygons, Slic3r::Polygons &retval, const float delta,
|
|||||||
offset(polygons, *output, delta, scale, joinType, miterLimit);
|
offset(polygons, *output, delta, scale, joinType, miterLimit);
|
||||||
|
|
||||||
// convert into ExPolygons
|
// convert into ExPolygons
|
||||||
ClipperPolygons_to_Slic3rPolygons(*output, retval);
|
ClipperPaths_to_Slic3rMultiPoints(*output, retval);
|
||||||
delete output;
|
delete output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +138,7 @@ offset(Slic3r::Polylines &polylines, ClipperLib::Paths &retval, const float delt
|
|||||||
{
|
{
|
||||||
// read input
|
// read input
|
||||||
ClipperLib::Paths* input = new ClipperLib::Paths();
|
ClipperLib::Paths* input = new ClipperLib::Paths();
|
||||||
Slic3rPolygons_to_ClipperPolygons(polylines, *input);
|
Slic3rMultiPoints_to_ClipperPaths(polylines, *input);
|
||||||
|
|
||||||
// scale input
|
// scale input
|
||||||
scaleClipperPolygons(*input, scale);
|
scaleClipperPolygons(*input, scale);
|
||||||
@ -158,7 +160,7 @@ offset(Slic3r::Polylines &polylines, Slic3r::Polygons &retval, const float delta
|
|||||||
offset(polylines, *output, delta, scale, joinType, miterLimit);
|
offset(polylines, *output, delta, scale, joinType, miterLimit);
|
||||||
|
|
||||||
// convert into ExPolygons
|
// convert into ExPolygons
|
||||||
ClipperPolygons_to_Slic3rPolygons(*output, retval);
|
ClipperPaths_to_Slic3rMultiPoints(*output, retval);
|
||||||
delete output;
|
delete output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +173,7 @@ offset_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float de
|
|||||||
offset(polygons, *output, delta, scale, joinType, miterLimit);
|
offset(polygons, *output, delta, scale, joinType, miterLimit);
|
||||||
|
|
||||||
// convert into ExPolygons
|
// convert into ExPolygons
|
||||||
ClipperPolygons_to_Slic3rExPolygons(*output, retval);
|
ClipperPaths_to_Slic3rExPolygons(*output, retval);
|
||||||
delete output;
|
delete output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +183,7 @@ offset2(Slic3r::Polygons &polygons, ClipperLib::Paths &retval, const float delta
|
|||||||
{
|
{
|
||||||
// read input
|
// read input
|
||||||
ClipperLib::Paths* input = new ClipperLib::Paths();
|
ClipperLib::Paths* input = new ClipperLib::Paths();
|
||||||
Slic3rPolygons_to_ClipperPolygons(polygons, *input);
|
Slic3rMultiPoints_to_ClipperPaths(polygons, *input);
|
||||||
|
|
||||||
// scale input
|
// scale input
|
||||||
scaleClipperPolygons(*input, scale);
|
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);
|
offset2(polygons, *output, delta1, delta2, scale, joinType, miterLimit);
|
||||||
|
|
||||||
// convert into ExPolygons
|
// convert into ExPolygons
|
||||||
ClipperPolygons_to_Slic3rPolygons(*output, retval);
|
ClipperPaths_to_Slic3rMultiPoints(*output, retval);
|
||||||
delete output;
|
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);
|
offset2(polygons, *output, delta1, delta2, scale, joinType, miterLimit);
|
||||||
|
|
||||||
// convert into ExPolygons
|
// convert into ExPolygons
|
||||||
ClipperPolygons_to_Slic3rExPolygons(*output, retval);
|
ClipperPaths_to_Slic3rExPolygons(*output, retval);
|
||||||
delete output;
|
delete output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,8 +234,8 @@ void _clipper_do(const ClipperLib::ClipType clipType, Slic3r::Polygons &subject,
|
|||||||
// read input
|
// read input
|
||||||
ClipperLib::Paths* input_subject = new ClipperLib::Paths();
|
ClipperLib::Paths* input_subject = new ClipperLib::Paths();
|
||||||
ClipperLib::Paths* input_clip = new ClipperLib::Paths();
|
ClipperLib::Paths* input_clip = new ClipperLib::Paths();
|
||||||
Slic3rPolygons_to_ClipperPolygons(subject, *input_subject);
|
Slic3rMultiPoints_to_ClipperPaths(subject, *input_subject);
|
||||||
Slic3rPolygons_to_ClipperPolygons(clip, *input_clip);
|
Slic3rMultiPoints_to_ClipperPaths(clip, *input_clip);
|
||||||
|
|
||||||
// perform safety offset
|
// perform safety offset
|
||||||
if (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);
|
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,
|
void _clipper(ClipperLib::ClipType clipType, Slic3r::Polygons &subject,
|
||||||
Slic3r::Polygons &clip, Slic3r::Polygons &retval, bool safety_offset_)
|
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_);
|
_clipper_do<ClipperLib::Paths>(clipType, subject, clip, *output, ClipperLib::pftNonZero, safety_offset_);
|
||||||
|
|
||||||
// convert into Polygons
|
// convert into Polygons
|
||||||
ClipperPolygons_to_Slic3rPolygons(*output, retval);
|
ClipperPaths_to_Slic3rMultiPoints(*output, retval);
|
||||||
delete output;
|
delete output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,6 +307,19 @@ void _clipper(ClipperLib::ClipType clipType, Slic3r::Polygons &subject,
|
|||||||
delete polytree;
|
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>
|
template <class T>
|
||||||
void diff(Slic3r::Polygons &subject, Slic3r::Polygons &clip, T &retval, bool safety_offset_)
|
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::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_);
|
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>
|
template <class T>
|
||||||
void intersection(Slic3r::Polygons &subject, Slic3r::Polygons &clip, T &retval, bool safety_offset_)
|
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::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_);
|
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,
|
void xor_ex(Slic3r::Polygons &subject, Slic3r::Polygons &clip, Slic3r::ExPolygons &retval,
|
||||||
bool safety_offset_)
|
bool safety_offset_)
|
||||||
{
|
{
|
||||||
@ -323,14 +371,14 @@ void simplify_polygons(Slic3r::Polygons &subject, Slic3r::Polygons &retval)
|
|||||||
{
|
{
|
||||||
// convert into Clipper polygons
|
// convert into Clipper polygons
|
||||||
ClipperLib::Paths* input_subject = new ClipperLib::Paths();
|
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::Paths* output = new ClipperLib::Paths();
|
||||||
ClipperLib::SimplifyPolygons(*input_subject, *output, ClipperLib::pftNonZero);
|
ClipperLib::SimplifyPolygons(*input_subject, *output, ClipperLib::pftNonZero);
|
||||||
delete input_subject;
|
delete input_subject;
|
||||||
|
|
||||||
// convert into Slic3r polygons
|
// convert into Slic3r polygons
|
||||||
ClipperPolygons_to_Slic3rPolygons(*output, retval);
|
ClipperPaths_to_Slic3rMultiPoints(*output, retval);
|
||||||
delete output;
|
delete output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,7 +419,7 @@ polynode2perl(const ClipperLib::PolyNode& node)
|
|||||||
{
|
{
|
||||||
HV* hv = newHV();
|
HV* hv = newHV();
|
||||||
Slic3r::Polygon p;
|
Slic3r::Polygon p;
|
||||||
ClipperPolygon_to_Slic3rPolygon(node.Contour, p);
|
ClipperPath_to_Slic3rMultiPoint(node.Contour, p);
|
||||||
if (node.IsHole()) {
|
if (node.IsHole()) {
|
||||||
(void)hv_stores( hv, "hole", p.to_SV_clone_ref() );
|
(void)hv_stores( hv, "hole", p.to_SV_clone_ref() );
|
||||||
} else {
|
} else {
|
||||||
|
@ -21,12 +21,14 @@ void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, Slic3r::ExPoly
|
|||||||
void PolyTreeToExPolygons(ClipperLib::PolyTree& polytree, Slic3r::ExPolygons& expolygons);
|
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>
|
template <class T>
|
||||||
void Slic3rPolygons_to_ClipperPolygons(const T &input, ClipperLib::Paths &output);
|
void Slic3rMultiPoints_to_ClipperPaths(const T &input, ClipperLib::Paths &output);
|
||||||
void ClipperPolygon_to_Slic3rPolygon(const ClipperLib::Path &input, Slic3r::Polygon &output);
|
template <class T>
|
||||||
void ClipperPolygons_to_Slic3rPolygons(const ClipperLib::Paths &input, Slic3r::Polygons &output);
|
void ClipperPath_to_Slic3rMultiPoint(const ClipperLib::Path &input, T &output);
|
||||||
void ClipperPolygons_to_Slic3rExPolygons(const ClipperLib::Paths &input, Slic3r::ExPolygons &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);
|
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>
|
template <class T>
|
||||||
void _clipper_do(ClipperLib::ClipType clipType, Slic3r::Polygons &subject,
|
void _clipper_do(ClipperLib::ClipType clipType, Slic3r::Polygons &subject,
|
||||||
Slic3r::Polygons &clip, T &retval, bool safety_offset_);
|
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,
|
void _clipper(ClipperLib::ClipType clipType, Slic3r::Polygons &subject,
|
||||||
Slic3r::Polygons &clip, Slic3r::Polygons &retval, bool safety_offset_);
|
Slic3r::Polygons &clip, Slic3r::Polygons &retval, bool safety_offset_);
|
||||||
void _clipper(ClipperLib::ClipType clipType, Slic3r::Polygons &subject,
|
void _clipper(ClipperLib::ClipType clipType, Slic3r::Polygons &subject,
|
||||||
Slic3r::Polygons &clip, Slic3r::ExPolygons &retval, bool safety_offset_);
|
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>
|
template <class T>
|
||||||
void diff(Slic3r::Polygons &subject, Slic3r::Polygons &clip, T &retval, bool safety_offset_);
|
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>
|
template <class T>
|
||||||
void intersection(Slic3r::Polygons &subject, Slic3r::Polygons &clip, T &retval, bool safety_offset_);
|
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,
|
void xor_ex(Slic3r::Polygons &subject, Slic3r::Polygons &clip, Slic3r::ExPolygons &retval,
|
||||||
bool safety_offset_ = false);
|
bool safety_offset_ = false);
|
||||||
|
|
||||||
|
@ -66,18 +66,16 @@ double
|
|||||||
Polygon::area() const
|
Polygon::area() const
|
||||||
{
|
{
|
||||||
ClipperLib::Path p;
|
ClipperLib::Path p;
|
||||||
Slic3rPolygon_to_ClipperPolygon(*this, p);
|
Slic3rMultiPoint_to_ClipperPath(*this, p);
|
||||||
return ClipperLib::Area(p);
|
return ClipperLib::Area(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Polygon::is_counter_clockwise() const
|
Polygon::is_counter_clockwise() const
|
||||||
{
|
{
|
||||||
ClipperLib::Path* p = new ClipperLib::Path();
|
ClipperLib::Path p;
|
||||||
Slic3rPolygon_to_ClipperPolygon(*this, *p);
|
Slic3rMultiPoint_to_ClipperPath(*this, p);
|
||||||
bool orientation = ClipperLib::Orientation(*p);
|
return ClipperLib::Orientation(p);
|
||||||
delete p;
|
|
||||||
return orientation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -41,4 +41,15 @@ PolylineCollection::chained_path_from(const Point* start_near, bool no_reverse)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Point*
|
||||||
|
PolylineCollection::leftmost_point() const
|
||||||
|
{
|
||||||
|
const Point* p = NULL;
|
||||||
|
for (Polylines::const_iterator it = this->polylines.begin(); it != this->polylines.end(); ++it) {
|
||||||
|
if (p == NULL || it->points.front().x < p->x)
|
||||||
|
p = &(it->points.front());
|
||||||
|
}
|
||||||
|
return new Point (*p);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ class PolylineCollection
|
|||||||
Polylines polylines;
|
Polylines polylines;
|
||||||
PolylineCollection* chained_path(bool no_reverse) const;
|
PolylineCollection* chained_path(bool no_reverse) const;
|
||||||
PolylineCollection* chained_path_from(const Point* start_near, bool no_reverse) const;
|
PolylineCollection* chained_path_from(const Point* start_near, bool no_reverse) const;
|
||||||
|
Point* leftmost_point() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
//#define use_xyz
|
//#define use_xyz
|
||||||
|
|
||||||
//use_lines: Enables line clipping. Adds a very minor cost to performance.
|
//use_lines: Enables line clipping. Adds a very minor cost to performance.
|
||||||
//#define use_lines
|
#define use_lines
|
||||||
|
|
||||||
//When enabled, code developed with earlier versions of Clipper
|
//When enabled, code developed with earlier versions of Clipper
|
||||||
//(ie prior to ver 6) should compile without changes.
|
//(ie prior to ver 6) should compile without changes.
|
||||||
|
@ -4,7 +4,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Slic3r::XS;
|
use Slic3r::XS;
|
||||||
use Test::More tests => 5;
|
use Test::More tests => 11;
|
||||||
|
|
||||||
my $square = [ # ccw
|
my $square = [ # ccw
|
||||||
[200, 100],
|
[200, 100],
|
||||||
@ -88,4 +88,22 @@ my $expolygon = Slic3r::ExPolygon->new($square, $hole_in_square);
|
|||||||
is $result->[0]->area, $expolygon->area, 'diff_ex';
|
is $result->[0]->area, $expolygon->area, 'diff_ex';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $polyline = Slic3r::Polyline->new([50,150], [300,150]);
|
||||||
|
{
|
||||||
|
my $result = Slic3r::Geometry::Clipper::intersection_pl([$polyline], [$square, $hole_in_square]);
|
||||||
|
is scalar(@$result), 2, 'intersection_pl - correct number of result lines';
|
||||||
|
# results are in no particular order
|
||||||
|
is scalar(grep $_->length == 40, @$result), 2, 'intersection_pl - result lines have correct length';
|
||||||
|
}
|
||||||
|
{
|
||||||
|
my $result = Slic3r::Geometry::Clipper::diff_pl([$polyline], [$square, $hole_in_square]);
|
||||||
|
is scalar(@$result), 3, 'diff_pl - correct number of result lines';
|
||||||
|
# results are in no particular order
|
||||||
|
is scalar(grep $_->length == 50, @$result), 1, 'diff_pl - the left result line has correct length';
|
||||||
|
is scalar(grep $_->length == 100, @$result), 1, 'diff_pl - two right result line has correct length';
|
||||||
|
is scalar(grep $_->length == 20, @$result), 1, 'diff_pl - the central result line has correct length';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
@ -91,6 +91,15 @@ diff_ex(subject, clip, safety_offset = false)
|
|||||||
OUTPUT:
|
OUTPUT:
|
||||||
RETVAL
|
RETVAL
|
||||||
|
|
||||||
|
Polylines
|
||||||
|
diff_pl(subject, clip)
|
||||||
|
Polylines subject
|
||||||
|
Polygons clip
|
||||||
|
CODE:
|
||||||
|
diff(subject, clip, RETVAL);
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
Polygons
|
Polygons
|
||||||
intersection(subject, clip, safety_offset = false)
|
intersection(subject, clip, safety_offset = false)
|
||||||
Polygons subject
|
Polygons subject
|
||||||
@ -111,6 +120,15 @@ intersection_ex(subject, clip, safety_offset = false)
|
|||||||
OUTPUT:
|
OUTPUT:
|
||||||
RETVAL
|
RETVAL
|
||||||
|
|
||||||
|
Polylines
|
||||||
|
intersection_pl(subject, clip)
|
||||||
|
Polylines subject
|
||||||
|
Polygons clip
|
||||||
|
CODE:
|
||||||
|
intersection(subject, clip, RETVAL);
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
ExPolygons
|
ExPolygons
|
||||||
xor_ex(subject, clip, safety_offset = false)
|
xor_ex(subject, clip, safety_offset = false)
|
||||||
Polygons subject
|
Polygons subject
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
%code{% const char* CLASS = "Slic3r::Point"; RETVAL = THIS->midpoint(); %};
|
%code{% const char* CLASS = "Slic3r::Point"; RETVAL = THIS->midpoint(); %};
|
||||||
Point* point_at(double distance)
|
Point* point_at(double distance)
|
||||||
%code{% const char* CLASS = "Slic3r::Point"; RETVAL = THIS->point_at(distance); %};
|
%code{% const char* CLASS = "Slic3r::Point"; RETVAL = THIS->point_at(distance); %};
|
||||||
|
Polyline* as_polyline()
|
||||||
|
%code{% const char* CLASS = "Slic3r::Polyline"; RETVAL = new Polyline(); RETVAL->points.push_back(THIS->a); RETVAL->points.push_back(THIS->b); %};
|
||||||
%{
|
%{
|
||||||
|
|
||||||
Line*
|
Line*
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
%code{% const char* CLASS = "Slic3r::Polyline::Collection"; RETVAL = THIS->chained_path_from(start_near, no_reverse); %};
|
%code{% const char* CLASS = "Slic3r::Polyline::Collection"; RETVAL = THIS->chained_path_from(start_near, no_reverse); %};
|
||||||
int count()
|
int count()
|
||||||
%code{% RETVAL = THIS->polylines.size(); %};
|
%code{% RETVAL = THIS->polylines.size(); %};
|
||||||
|
Point* leftmost_point()
|
||||||
|
%code{% const char* CLASS = "Slic3r::Point"; RETVAL = THIS->leftmost_point(); %};
|
||||||
%{
|
%{
|
||||||
|
|
||||||
PolylineCollection*
|
PolylineCollection*
|
||||||
|
@ -22,6 +22,7 @@ ClipperLib::PolyFillType T_UV
|
|||||||
Points T_ARRAYREF
|
Points T_ARRAYREF
|
||||||
Lines T_ARRAYREF
|
Lines T_ARRAYREF
|
||||||
Polygons T_ARRAYREF
|
Polygons T_ARRAYREF
|
||||||
|
Polylines T_ARRAYREF
|
||||||
ExPolygons T_ARRAYREF
|
ExPolygons T_ARRAYREF
|
||||||
|
|
||||||
# we return these types whenever we want the items to be returned
|
# we return these types whenever we want the items to be returned
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
%typemap{Points};
|
%typemap{Points};
|
||||||
%typemap{Lines};
|
%typemap{Lines};
|
||||||
%typemap{Polygons};
|
%typemap{Polygons};
|
||||||
|
%typemap{Polylines};
|
||||||
%typemap{ExPolygons};
|
%typemap{ExPolygons};
|
||||||
%typemap{Polygons*};
|
%typemap{Polygons*};
|
||||||
%typemap{TriangleMeshPtrs};
|
%typemap{TriangleMeshPtrs};
|
||||||
|
Loading…
Reference in New Issue
Block a user