Optimization of travel paths for perimeters
This commit is contained in:
parent
03341f3485
commit
0cd10441a1
@ -8,6 +8,7 @@ sub debugf {
|
||||
printf @_ if $debug;
|
||||
}
|
||||
|
||||
use Slic3r::ExtrusionLoop;
|
||||
use Slic3r::ExtrusionPath;
|
||||
use Slic3r::Fill;
|
||||
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';
|
||||
|
||||
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;
|
||||
|
@ -115,4 +115,33 @@ sub polygon_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;
|
||||
|
@ -58,40 +58,18 @@ sub make_perimeter {
|
||||
), $self->offset_polygon($perimeters[-1]),
|
||||
}
|
||||
|
||||
# generate paths for holes
|
||||
# generate paths for holes:
|
||||
# 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
|
||||
# holes and so on
|
||||
foreach my $hole (map @$_, values %holes) {
|
||||
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
|
||||
# holes and so on;
|
||||
# then we generate paths for contours:
|
||||
# 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
|
||||
# innermost loop (that is, internal one), then without interrupting
|
||||
# our path we go onto the outer loop and continue; this should ensure
|
||||
# good surface quality
|
||||
foreach my $polylines (values %contours) {
|
||||
my @path_points = ();
|
||||
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 ]);
|
||||
foreach my $p (map @$_, values %holes, values %contours) {
|
||||
push @{ $layer->perimeters }, Slic3r::ExtrusionLoop->cast($p);
|
||||
}
|
||||
|
||||
# generate skirt on bottom layer
|
||||
@ -158,20 +136,4 @@ sub _mgp_from_polygons_ref {
|
||||
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;
|
||||
|
@ -18,11 +18,11 @@ sub id {
|
||||
}
|
||||
|
||||
sub cast {
|
||||
my $self = shift;
|
||||
my $class = shift;
|
||||
my ($points) = @_;
|
||||
|
||||
@$points = map { ref $_ eq 'ARRAY' ? Slic3r::Point->cast($_) : $_ } @$points;
|
||||
return __PACKAGE__->new(points => $points);
|
||||
return $class->new(points => $points);
|
||||
}
|
||||
|
||||
sub lines {
|
||||
@ -82,4 +82,15 @@ sub make_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;
|
||||
|
@ -183,6 +183,7 @@ sub export_gcode {
|
||||
|
||||
# make up a subroutine to generate G1 commands
|
||||
my $extrusion_distance = 0;
|
||||
my $last_pos; # on XY plane
|
||||
my $G1 = sub {
|
||||
my ($point, $z, $e, $comment) = @_;
|
||||
printf $fh "G1";
|
||||
@ -191,6 +192,7 @@ sub export_gcode {
|
||||
printf $fh " X%.${dec}f Y%.${dec}f",
|
||||
($point->x * $Slic3r::resolution) + $shift[X],
|
||||
($point->y * $Slic3r::resolution) + $shift[Y]; #**
|
||||
$last_pos = $point->p;
|
||||
}
|
||||
if ($z) {
|
||||
printf $fh " Z%.${dec}f", $z;
|
||||
@ -269,7 +271,19 @@ sub export_gcode {
|
||||
$Extrude->($_, 'skirt') for @{ $layer->skirts };
|
||||
|
||||
# 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->($_, 'fill') for @{ $layer->fills };
|
||||
|
Loading…
Reference in New Issue
Block a user