diff --git a/lib/Slic3r/ExtrusionPath/Collection.pm b/lib/Slic3r/ExtrusionPath/Collection.pm index 53950c252..943a8419e 100644 --- a/lib/Slic3r/ExtrusionPath/Collection.pm +++ b/lib/Slic3r/ExtrusionPath/Collection.pm @@ -29,7 +29,9 @@ sub shortest_path { my $start_at; CYCLE: while (@{$self->paths}) { # find nearest point - $start_at = Slic3r::Point->new(Slic3r::Geometry::nearest_point($start_near, [ $self->endpoints ])); + $start_at = $start_near + ? Slic3r::Point->new(Slic3r::Geometry::nearest_point($start_near, [ $self->endpoints ])) + : $self->endpoints->[0]; # loop through paths to find the one that starts or ends at the point found PATH: for (my $i = 0; $i <= $#{$self->paths}; $i++) { diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm index fa7180c72..ade98aecc 100644 --- a/lib/Slic3r/Geometry.pm +++ b/lib/Slic3r/Geometry.pm @@ -17,6 +17,7 @@ our @EXPORT_OK = qw( clip_segment_complex_polygon longest_segment angle3points polyline_remove_parallel_continuous_edges polyline_remove_acute_vertices polygon_remove_acute_vertices polygon_remove_parallel_continuous_edges + shortest_path ); use Slic3r::Geometry::DouglasPeucker qw(Douglas_Peucker); @@ -611,4 +612,29 @@ sub polygon_remove_acute_vertices { return polyline_remove_acute_vertices($points, 1); } +# accepts an arrayref; each item should be an arrayref whose first +# item is the point to be used for the shortest path, and the second +# one is the value to be returned in output (if the second item +# is not provided, the point will be returned) +sub shortest_path { + my ($items, $start_near) = @_; + + my %values = map +($_->[0] => $_->[1] || $_->[0]), @$items; + my @points = map $_->[0], @$items; + + my $result = []; + my $last_point; + if (!$start_near) { + $start_near = shift @points; + push @$result, $values{$start_near} if $start_near; + } + while (@points) { + $start_near = nearest_point($start_near, [@points]); + @points = grep $_ ne $start_near, @points; + push @$result, $values{$start_near}; + } + + return $result; +} + 1; diff --git a/lib/Slic3r/Perimeter.pm b/lib/Slic3r/Perimeter.pm index 3325f47cb..1d8d3a8b3 100644 --- a/lib/Slic3r/Perimeter.pm +++ b/lib/Slic3r/Perimeter.pm @@ -3,6 +3,7 @@ use Moo; use Math::Clipper ':all'; use Math::ConvexHull 1.0.4 qw(convex_hull); +use Slic3r::Geometry qw(shortest_path); use XXX; use constant X => 0; @@ -31,6 +32,11 @@ sub make_perimeter { # ) my @perimeters = (); # one item per depth; each item + # organize $layer->perimeter_surfaces using a shortest path search + @{ $layer->perimeter_surfaces } = @{shortest_path([ + map [ $_->contour->points->[0], $_ ], @{ $layer->perimeter_surfaces }, + ])}; + foreach my $surface (@{ $layer->perimeter_surfaces }) { # the outer loop must be offsetted by half extrusion width inwards my @last_offsets = ($surface->expolygon);