mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-08-09 23:05:04 -06:00
Use Clipper for line clipping
This commit is contained in:
parent
1d6a18071a
commit
3025c77675
20 changed files with 202 additions and 211 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) = @_;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue