Optimization of travel paths for fills

This commit is contained in:
Alessandro Ranellucci 2011-09-26 10:52:58 +02:00
parent 0cd10441a1
commit 415d1a5170
9 changed files with 230 additions and 136 deletions

View File

@ -42,7 +42,6 @@ Roadmap includes the following goals:
* output some statistics;
* allow the user to customize initial and final GCODE commands;
* support material for internal perimeters;
* travel path optimization;
* ability to infill in the direction of bridges;
* input object transform (scale, rotate, multiply);
* cool;

View File

@ -10,6 +10,7 @@ sub debugf {
use Slic3r::ExtrusionLoop;
use Slic3r::ExtrusionPath;
use Slic3r::ExtrusionPath::Collection;
use Slic3r::Fill;
use Slic3r::Geometry;
use Slic3r::Layer;
@ -21,6 +22,7 @@ use Slic3r::Polyline::Closed;
use Slic3r::Print;
use Slic3r::STL;
use Slic3r::Surface;
use Slic3r::Surface::Collection;
# printer options
our $nozzle_diameter = 0.45;
@ -33,7 +35,7 @@ our $filament_packing_density = 0.85;
# speed options
our $print_feed_rate = 60; # mm/sec
our $travel_feed_rate = 80; # mm/sec
our $travel_feed_rate = 130; # mm/sec
our $bottom_layer_speed_ratio = 0.6;
# accuracy options

View File

@ -22,4 +22,16 @@ sub clip_end {
}
}
sub endpoints {
my $self = shift;
my ($as_arrayref) = @_;
my @points = ($self->points->[0], $self->points->[-1]);
return $as_arrayref ? map($_->p, @points) : @points;
}
sub reverse {
my $self = shift;
@{$self->points} = reverse @{$self->points};
}
1;

View File

@ -0,0 +1,55 @@
package Slic3r::ExtrusionPath::Collection;
use Moo;
use XXX;
has 'paths' => (
is => 'rw',
#isa => 'ArrayRef[Slic3r::ExtrusionPath]',
default => sub { [] },
);
sub add {
my $self = shift;
my ($path) = @_;
push @{$self->paths}, $path;
}
sub endpoints {
my $self = shift;
my ($as_arrayref) = @_;
return map $_->endpoints($as_arrayref), @{$self->paths};
}
sub shortest_path {
my $self = shift;
my ($start_near) = @_;
# get point as arrayref
$start_near = $start_near->p if $start_near && ref $start_near ne 'ARRAY';
my @paths = ();
my $start_at;
CYCLE: while (@{$self->paths}) {
# find nearest point
$start_at = Slic3r::Point->cast(Slic3r::Geometry::nearest_point($start_near, [ $self->endpoints(1) ]));
# loop through paths to find the one that starts or ends at the point found
PATH: for (my $i = 0; $i <= $#{$self->paths}; $i++) {
if ($start_at->id eq $self->paths->[$i]->points->[0]->id) {
push @paths, splice @{$self->paths}, $i, 1;
} elsif ($start_at->id eq $self->paths->[$i]->points->[-1]->id) {
$self->paths->[$i]->reverse;
push @paths, splice @{$self->paths}, $i, 1;
} else {
next PATH;
}
$start_near = $paths[-1]->points->[-1]->p;
next CYCLE;
}
}
return @paths;
}
1;

View File

@ -21,8 +21,12 @@ sub make_fill {
printf "Filling layer %d:\n", $layer->id;
my $max_print_dimension = $print->max_length;
my $n = 1;
SURFACE: foreach my $surface (@{ $layer->fill_surfaces }) {
foreach my $surface_collection (@{ $layer->fill_surfaces }) {
my @path_collection = ();
SURFACE: foreach my $surface (@{ $surface_collection->surfaces }) {
Slic3r::debugf " Processing surface %s:\n", $surface->id;
my $polygon = $surface->mgp_polygon;
@ -158,8 +162,13 @@ sub make_fill {
@paths = map $self->_mgp_from_points_ref($_)->move(map -$_, @shift)->rotate(-$rotate[0], $rotate[1])->points, @paths;
}
push @path_collection, @paths;
}
# save into layer
FINISH: push @{ $layer->fills }, map Slic3r::ExtrusionPath->cast([ @$_ ]), @paths;
FINISH: push @{ $layer->fills }, Slic3r::ExtrusionPath::Collection->new(
paths => [ map Slic3r::ExtrusionPath->cast([ @$_ ]), @path_collection ],
);
}
}

View File

@ -124,6 +124,7 @@ sub nearest_point {
if (!defined $distance || $d < $distance) {
$nearest_point = $p;
$distance = $d;
return $p if $distance < epsilon;
}
}
return $nearest_point;

View File

@ -48,7 +48,8 @@ sub make_perimeter {
}
# create one more offset to be used as boundary for fill
push @{ $layer->fill_surfaces },
push @{ $layer->fill_surfaces }, Slic3r::Surface::Collection->new(
surfaces => [
map Slic3r::Surface->new(
surface_type => $surface->surface_type,
contour => Slic3r::Polyline::Closed->cast($_->{outer}),
@ -56,6 +57,8 @@ sub make_perimeter {
map Slic3r::Polyline::Closed->cast($_), @{$_->{holes}}
],
), $self->offset_polygon($perimeters[-1]),
],
);
}
# generate paths for holes:

View File

@ -143,7 +143,7 @@ sub extrude_fills {
$fill_extruder->make_fill($self, $layer);
Slic3r::debugf " generated %d paths: %s\n",
scalar @{ $layer->fills },
join ' ', map $_->id, @{ $layer->fills } if $Slic3r::debug;
join ' ', map $_->id, map @{$_->paths}, @{ $layer->fills } if $Slic3r::debug;
}
}
@ -286,7 +286,10 @@ sub export_gcode {
}
# extrude fills
$Extrude->($_, 'fill') for @{ $layer->fills };
for my $fill (@{ $layer->fills }) {
my @paths = $fill->shortest_path($last_pos);
$Extrude->($_, 'fill') for @paths;
}
}
# write end commands to file

View File

@ -0,0 +1,10 @@
package Slic3r::Surface::Collection;
use Moo;
has 'surfaces' => (
is => 'rw',
#isa => 'ArrayRef[Slic3r::Surface]',
default => sub { [] },
);
1;