Optimization of travel paths for perimeters
This commit is contained in:
parent
03341f3485
commit
0cd10441a1
@ -8,6 +8,7 @@ sub debugf {
|
|||||||
printf @_ if $debug;
|
printf @_ if $debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use Slic3r::ExtrusionLoop;
|
||||||
use Slic3r::ExtrusionPath;
|
use Slic3r::ExtrusionPath;
|
||||||
use Slic3r::Fill;
|
use Slic3r::Fill;
|
||||||
use Slic3r::Geometry;
|
use Slic3r::Geometry;
|
||||||
|
31
lib/Slic3r/ExtrusionLoop.pm
Normal file
31
lib/Slic3r/ExtrusionLoop.pm
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package Slic3r::ExtrusionLoop;
|
||||||
|
use Moo;
|
||||||
|
|
||||||
|
use XXX;
|
||||||
|
|
||||||
|
extends 'Slic3r::Polyline::Closed';
|
||||||
|
|
||||||
|
sub split_at {
|
||||||
|
my $self = shift;
|
||||||
|
my ($point) = @_;
|
||||||
|
|
||||||
|
$point = Slic3r::Point->cast($point);
|
||||||
|
|
||||||
|
# find index of point
|
||||||
|
my $i = -1;
|
||||||
|
for (my $n = 0; $n <= $#{$self->points}; $n++) {
|
||||||
|
if ($point->id eq $self->points->[$n]->id) {
|
||||||
|
$i = $n;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
die "Point not found" if $i == -1;
|
||||||
|
|
||||||
|
my @new_points = ();
|
||||||
|
push @new_points, @{$self->points}[$i .. $#{$self->points}];
|
||||||
|
push @new_points, @{$self->points}[0 .. $i];
|
||||||
|
|
||||||
|
return Slic3r::ExtrusionPath->new(points => [@new_points]);
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
@ -3,4 +3,23 @@ use Moo;
|
|||||||
|
|
||||||
extends 'Slic3r::Polyline';
|
extends 'Slic3r::Polyline';
|
||||||
|
|
||||||
|
sub clip_end {
|
||||||
|
my $self = shift;
|
||||||
|
my ($distance) = @_;
|
||||||
|
|
||||||
|
while ($distance > 0) {
|
||||||
|
my $last_point = pop @{$self->points};
|
||||||
|
|
||||||
|
my $last_segment_length = $last_point->distance_to($self->points->[-1]);
|
||||||
|
if ($last_segment_length <= $distance) {
|
||||||
|
$distance -= $last_segment_length;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $new_point = Slic3r::Geometry::point_along_segment($last_point->p, $self->points->[-1]->p, $distance);
|
||||||
|
push @{$self->points}, Slic3r::Point->cast($new_point);
|
||||||
|
$distance = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -115,4 +115,33 @@ sub polygon_lines {
|
|||||||
return @lines;
|
return @lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub nearest_point {
|
||||||
|
my ($point, $points) = @_;
|
||||||
|
|
||||||
|
my ($nearest_point, $distance);
|
||||||
|
foreach my $p (@$points) {
|
||||||
|
my $d = distance_between_points($point, $p);
|
||||||
|
if (!defined $distance || $d < $distance) {
|
||||||
|
$nearest_point = $p;
|
||||||
|
$distance = $d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $nearest_point;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub point_along_segment {
|
||||||
|
my ($p1, $p2, $distance) = @_;
|
||||||
|
|
||||||
|
my $point = [ @$p1 ];
|
||||||
|
|
||||||
|
my $line_length = sqrt( (($p2->[X] - $p1->[X])**2) + (($p2->[Y] - $p1->[Y])**2) );
|
||||||
|
for (X, Y) {
|
||||||
|
if ($p1->[$_] != $p2->[$_]) {
|
||||||
|
$point->[$_] = $p1->[$_] + ($p2->[$_] - $p1->[$_]) * $distance / $line_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $point;
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -58,40 +58,18 @@ sub make_perimeter {
|
|||||||
), $self->offset_polygon($perimeters[-1]),
|
), $self->offset_polygon($perimeters[-1]),
|
||||||
}
|
}
|
||||||
|
|
||||||
# generate paths for holes
|
# generate paths for holes:
|
||||||
# we start from innermost loops (that is, external ones), do them
|
# we start from innermost loops (that is, external ones), do them
|
||||||
# for all holes, than go on with inner loop and do that for all
|
# for all holes, than go on with inner loop and do that for all
|
||||||
# holes and so on
|
# holes and so on;
|
||||||
foreach my $hole (map @$_, values %holes) {
|
# then we generate paths for contours:
|
||||||
my @points = @$hole;
|
|
||||||
push @points, [ @{$points[0]} ];
|
|
||||||
# to avoid blobs, the first point is replaced by the point of
|
|
||||||
# the segment which is $Slic3r::flow_width / $Slic3r::resolution
|
|
||||||
# away from it to avoid the extruder to get two times there
|
|
||||||
$points[0] = $self->_get_point_along_line($points[0], $points[1],
|
|
||||||
$Slic3r::flow_width / $Slic3r::resolution);
|
|
||||||
push @{ $layer->perimeters }, Slic3r::ExtrusionPath->cast([@points]);
|
|
||||||
}
|
|
||||||
|
|
||||||
# generate paths for contours
|
|
||||||
# this time we do something different: we do contour loops for one
|
# this time we do something different: we do contour loops for one
|
||||||
# shape (that is, one original surface) at a time: we start from the
|
# shape (that is, one original surface) at a time: we start from the
|
||||||
# innermost loop (that is, internal one), then without interrupting
|
# innermost loop (that is, internal one), then without interrupting
|
||||||
# our path we go onto the outer loop and continue; this should ensure
|
# our path we go onto the outer loop and continue; this should ensure
|
||||||
# good surface quality
|
# good surface quality
|
||||||
foreach my $polylines (values %contours) {
|
foreach my $p (map @$_, values %holes, values %contours) {
|
||||||
my @path_points = ();
|
push @{ $layer->perimeters }, Slic3r::ExtrusionLoop->cast($p);
|
||||||
foreach my $p (map $self->_mgp_from_points_ref($_), @$polylines) {
|
|
||||||
my $points = $p->points;
|
|
||||||
# to avoid blobs, the first point is replaced by the point of
|
|
||||||
# the segment which is $Slic3r::flow_width / $Slic3r::resolution
|
|
||||||
# away from it to avoid the extruder to get two times there
|
|
||||||
push @$points, [ @{$points->[0]} ];
|
|
||||||
$points->[0] = $self->_get_point_along_line($points->[0], $points->[1],
|
|
||||||
$Slic3r::flow_width / $Slic3r::resolution);
|
|
||||||
push @path_points, @$points;
|
|
||||||
}
|
|
||||||
push @{ $layer->perimeters }, Slic3r::ExtrusionPath->cast([ reverse @path_points ]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# generate skirt on bottom layer
|
# generate skirt on bottom layer
|
||||||
@ -158,20 +136,4 @@ sub _mgp_from_polygons_ref {
|
|||||||
return $p;
|
return $p;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _get_point_along_line {
|
|
||||||
my $self = shift;
|
|
||||||
my ($p1, $p2, $distance) = @_;
|
|
||||||
|
|
||||||
my $point = [ @$p1 ];
|
|
||||||
|
|
||||||
my $line_length = sqrt( (($p2->[X] - $p1->[X])**2) + (($p2->[Y] - $p1->[Y])**2) );
|
|
||||||
for (X, Y) {
|
|
||||||
if ($p1->[$_] != $p2->[$_]) {
|
|
||||||
$point->[$_] = $p1->[$_] + ($p2->[$_] - $p1->[$_]) * $distance / $line_length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $point;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -18,11 +18,11 @@ sub id {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub cast {
|
sub cast {
|
||||||
my $self = shift;
|
my $class = shift;
|
||||||
my ($points) = @_;
|
my ($points) = @_;
|
||||||
|
|
||||||
@$points = map { ref $_ eq 'ARRAY' ? Slic3r::Point->cast($_) : $_ } @$points;
|
@$points = map { ref $_ eq 'ARRAY' ? Slic3r::Point->cast($_) : $_ } @$points;
|
||||||
return __PACKAGE__->new(points => $points);
|
return $class->new(points => $points);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub lines {
|
sub lines {
|
||||||
@ -82,4 +82,15 @@ sub make_clockwise {
|
|||||||
$self->reverse_points if $self->is_counter_clockwise;
|
$self->reverse_points if $self->is_counter_clockwise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub nearest_point_to {
|
||||||
|
my $self = shift;
|
||||||
|
my ($point) = @_;
|
||||||
|
|
||||||
|
# get point as arrayref
|
||||||
|
$point = ref $point eq 'ARRAY' ? $point : $point->p;
|
||||||
|
|
||||||
|
$point = Slic3r::Geometry::nearest_point($point, $self->p);
|
||||||
|
return Slic3r::Point->cast($point);
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -183,6 +183,7 @@ sub export_gcode {
|
|||||||
|
|
||||||
# make up a subroutine to generate G1 commands
|
# make up a subroutine to generate G1 commands
|
||||||
my $extrusion_distance = 0;
|
my $extrusion_distance = 0;
|
||||||
|
my $last_pos; # on XY plane
|
||||||
my $G1 = sub {
|
my $G1 = sub {
|
||||||
my ($point, $z, $e, $comment) = @_;
|
my ($point, $z, $e, $comment) = @_;
|
||||||
printf $fh "G1";
|
printf $fh "G1";
|
||||||
@ -191,6 +192,7 @@ sub export_gcode {
|
|||||||
printf $fh " X%.${dec}f Y%.${dec}f",
|
printf $fh " X%.${dec}f Y%.${dec}f",
|
||||||
($point->x * $Slic3r::resolution) + $shift[X],
|
($point->x * $Slic3r::resolution) + $shift[X],
|
||||||
($point->y * $Slic3r::resolution) + $shift[Y]; #**
|
($point->y * $Slic3r::resolution) + $shift[Y]; #**
|
||||||
|
$last_pos = $point->p;
|
||||||
}
|
}
|
||||||
if ($z) {
|
if ($z) {
|
||||||
printf $fh " Z%.${dec}f", $z;
|
printf $fh " Z%.${dec}f", $z;
|
||||||
@ -269,7 +271,19 @@ sub export_gcode {
|
|||||||
$Extrude->($_, 'skirt') for @{ $layer->skirts };
|
$Extrude->($_, 'skirt') for @{ $layer->skirts };
|
||||||
|
|
||||||
# extrude perimeters
|
# extrude perimeters
|
||||||
$Extrude->($_, 'perimeter') for @{ $layer->perimeters };
|
for my $loop (@{ $layer->perimeters }) {
|
||||||
|
# find the point of the loop that is closest to the current extruder position
|
||||||
|
my $start_at = $last_pos ? $loop->nearest_point_to($last_pos) : $loop->points->[0];
|
||||||
|
|
||||||
|
# split the loop at the starting point and make a path
|
||||||
|
my $extrusion_path = $loop->split_at($start_at);
|
||||||
|
|
||||||
|
# clip the path to avoid the extruder to get exactly on the first point of the loop
|
||||||
|
$extrusion_path->clip_end($Slic3r::flow_width / $Slic3r::resolution);
|
||||||
|
|
||||||
|
# extrude along the path
|
||||||
|
$Extrude->($extrusion_path, 'perimeter')
|
||||||
|
}
|
||||||
|
|
||||||
# extrude fills
|
# extrude fills
|
||||||
$Extrude->($_, 'fill') for @{ $layer->fills };
|
$Extrude->($_, 'fill') for @{ $layer->fills };
|
||||||
|
Loading…
Reference in New Issue
Block a user