From 081f65852decba1edf4a7715e331598f0f8d29ba Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 26 Sep 2011 11:42:08 +0200 Subject: [PATCH] Refactor extrusion logic in a dedicated class --- lib/Slic3r.pm | 1 + lib/Slic3r/Extruder.pm | 146 ++++++++++++++++++++++++++++++++++++++++ lib/Slic3r/Perimeter.pm | 3 +- lib/Slic3r/Print.pm | 118 +++----------------------------- 4 files changed, 158 insertions(+), 110 deletions(-) create mode 100644 lib/Slic3r/Extruder.pm diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index f6fff16d..f089fdb1 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -8,6 +8,7 @@ sub debugf { printf @_ if $debug; } +use Slic3r::Extruder; use Slic3r::ExtrusionLoop; use Slic3r::ExtrusionPath; use Slic3r::ExtrusionPath::Collection; diff --git a/lib/Slic3r/Extruder.pm b/lib/Slic3r/Extruder.pm new file mode 100644 index 00000000..21f41cf2 --- /dev/null +++ b/lib/Slic3r/Extruder.pm @@ -0,0 +1,146 @@ +package Slic3r::Extruder; +use Moo; + +has 'shift_x' => (is => 'ro', default => sub {0} ); +has 'shift_y' => (is => 'ro', default => sub {0} ); +has 'z' => (is => 'rw', default => sub {0} ); + +has 'extrusion_distance' => (is => 'rw', default => sub {0} ); +has 'retracted' => (is => 'rw', default => sub {0} ); +has 'last_pos' => (is => 'rw', default => sub { [0,0] } ); + +# calculate speeds +has 'travel_feed_rate' => ( + is => 'ro', + default => sub { $Slic3r::travel_feed_rate * 60 }, # mm/min +); +has 'print_feed_rate' => ( + is => 'ro', + default => sub { $Slic3r::print_feed_rate * 60 }, # mm/min +); +has 'retract_speed' => ( + is => 'ro', + default => sub { $Slic3r::retract_speed * 60 }, # mm/min +); + +# calculate number of decimals +has 'dec' => ( + is => 'ro', + default => sub { length((1 / $Slic3r::resolution) - 1) + 1 }, +); + +use XXX; + +use constant PI => 4 * atan2(1, 1); +use constant X => 0; +use constant Y => 1; + +sub move_z { + my $self = shift; + my ($z) = @_; + + # TODO: retraction + return $self->G1(undef, $z, 0, 'move to next layer'); +} + +sub extrude_loop { + my $self = shift; + my ($loop, $description) = @_; + + # find the point of the loop that is closest to the current extruder position + my $start_at = $loop->nearest_point_to($self->last_pos); + + # 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 + return $self->extrude($extrusion_path, $description); +} + +sub extrude { + my $self = shift; + my ($path, $description) = @_; + + my $gcode = ""; + + # reset extrusion distance counter + if (!$Slic3r::use_relative_e_distances) { + $self->extrusion_distance(0); + $gcode .= "G92 E0 ; reset extrusion distance\n"; + } + + # go to first point of extrusion path + $gcode .= $self->G1($path->points->[0], undef, 0, "move to first $description point"); + + # compensate retraction + if ($self->retracted) { + $gcode .= $self->G1(undef, undef, ($Slic3r::retract_length + $Slic3r::retract_restart_extra), + "compensate retraction"); + $self->retracted(0); + } + + # extrude while going to next points + foreach my $line ($path->lines) { + # calculate how much filament to drive into the extruder + # to get the desired amount of extruded plastic + my $e = $line->a->distance_to($line->b) * $Slic3r::resolution + * $Slic3r::flow_width + * $Slic3r::layer_height + / (($Slic3r::filament_diameter ** 2) * PI) + / $Slic3r::filament_packing_density; + + $gcode .= $self->G1($line->b, undef, $e, $description); + } + + # retract + if ($Slic3r::retract_length > 0) { + $gcode .= $self->G1(undef, undef, -$Slic3r::retract_length, "retract"); + $self->retracted(1); + } + + return $gcode; +} + +sub G1 { + my $self = shift; + my ($point, $z, $e, $comment) = @_; + my $dec = $self->dec; + + my $gcode = "G1"; + + if ($point) { + $gcode .= sprintf " X%.${dec}f Y%.${dec}f", + ($point->x * $Slic3r::resolution) + $self->shift_x, + ($point->y * $Slic3r::resolution) + $self->shift_y; #** + $self->last_pos($point->p); + } + if ($z && $z != $self->z) { + $self->z($z); + $gcode .= sprintf " Z%.${dec}f", $z; + } + + # apply the speed reduction for print moves on bottom layer + my $speed_multiplier = $e + ? $Slic3r::bottom_layer_speed_ratio + : 1; + + if ($e) { + $self->extrusion_distance(0) if $Slic3r::use_relative_e_distances; + $self->extrusion_distance($self->extrusion_distance + $e); + $gcode .= sprintf " F%.${dec}f E%.5f", + $e < 0 + ? $self->retract_speed + : ($self->print_feed_rate * $speed_multiplier), + $self->extrusion_distance; + } else { + $gcode .= sprintf " F%.${dec}f", ($self->travel_feed_rate * $speed_multiplier); + } + $gcode .= sprintf " ; %s", $comment if $comment; + + return "$gcode\n"; +} + +1; diff --git a/lib/Slic3r/Perimeter.pm b/lib/Slic3r/Perimeter.pm index cbfc1be5..9f9532a9 100644 --- a/lib/Slic3r/Perimeter.pm +++ b/lib/Slic3r/Perimeter.pm @@ -86,8 +86,7 @@ sub make_perimeter { for (my $i = $Slic3r::skirts - 1; $i >= 0; $i--) { my $distance = ($Slic3r::skirt_distance + ($Slic3r::flow_width * $i)) / $Slic3r::resolution; my $outline = offset([$convex_hull_points], $distance, 0.1, JT_ROUND); - push @{$outline->[0]}, $outline->[0][0]; # repeat first point as last to complete the loop - push @{ $layer->skirts }, Slic3r::ExtrusionPath->cast([ @{$outline->[0]} ]); + push @{ $layer->skirts }, Slic3r::ExtrusionLoop->cast([ @{$outline->[0]} ]); } } } diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index bc3aa3f8..b7ad165f 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -4,7 +4,6 @@ use Moo; use Math::Clipper ':all'; use XXX; -use constant PI => 4 * atan2(1, 1); use constant X => 0; use constant Y => 1; @@ -151,20 +150,6 @@ sub export_gcode { my $self = shift; my ($file) = @_; - # calculate speed for gcode commands - my $travel_feed_rate = $Slic3r::travel_feed_rate * 60; # mm/min - my $print_feed_rate = $Slic3r::print_feed_rate * 60; # mm/min - my $retract_speed = $Slic3r::retract_speed * 60; # mm/min - - # calculate number of decimals - my $dec = length((1 / $Slic3r::resolution) - 1) + 1; - - # calculate X,Y shift to center print around specified origin - my @shift = ( - $Slic3r::print_center->[X] - ($self->x_length * $Slic3r::resolution / 2), - $Slic3r::print_center->[Y] - ($self->y_length * $Slic3r::resolution / 2), - ); - # open output gcode file open my $fh, ">", $file or die "Failed to open $file for writing\n"; @@ -182,113 +167,30 @@ 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"; + my $extruder = Slic3r::Extruder->new( - if ($point) { - 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; - } + # calculate X,Y shift to center print around specified origin + shift_x => $Slic3r::print_center->[X] - ($self->x_length * $Slic3r::resolution / 2), + shift_y => $Slic3r::print_center->[Y] - ($self->y_length * $Slic3r::resolution / 2), - # apply the speed reduction for print moves on bottom layer - my $speed_multiplier = defined $z && $z == 0 && $point - ? $Slic3r::bottom_layer_speed_ratio - : 1; - - if ($e) { - $extrusion_distance = 0 if $Slic3r::use_relative_e_distances; - $extrusion_distance += $e; - printf $fh " F%.${dec}f E%.5f", - $e < 0 - ? $retract_speed - : ($print_feed_rate * $speed_multiplier), - $extrusion_distance; - } else { - printf $fh " F%.${dec}f", ($travel_feed_rate * $speed_multiplier); - } - printf $fh " ; %s", $comment if $comment; - print $fh "\n"; - }; - - my $z; - my $retracted = 0; - my $Extrude = sub { - my ($path, $description) = @_; - - # reset extrusion distance counter - if (!$Slic3r::use_relative_e_distances) { - $extrusion_distance = 0; - print $fh "G92 E0 ; reset extrusion distance\n"; - } - - # go to first point while compensating retraction - $G1->($path->points->[0], $z, 0, "move to first $description point"); - - # compensate retraction - if ($retracted) { - $G1->(undef, undef, ($Slic3r::retract_length + $Slic3r::retract_restart_extra), - "compensate retraction"); - } - - # extrude while going to next points - foreach my $line ($path->lines) { - # calculate how much filament to drive into the extruder - # to get the desired amount of extruded plastic - my $e = $line->a->distance_to($line->b) * $Slic3r::resolution - * $Slic3r::flow_width - * $Slic3r::layer_height - / (($Slic3r::filament_diameter ** 2) * PI) - / $Slic3r::filament_packing_density; - - $G1->($line->b, $z, $e, $description); - } - - # retract - if ($Slic3r::retract_length > 0) { - $G1->(undef, undef, -$Slic3r::retract_length, "retract"); - $retracted = 1; - } - }; + ); # write gcode commands layer by layer foreach my $layer (@{ $self->layers }) { - $z = ($layer->z * $Slic3r::resolution); # go to layer - # TODO: retraction - printf $fh "G1 Z%.${dec}f F%.${dec}f ; move to next layer\n", - $z, $travel_feed_rate; + printf $fh $extruder->move_z($layer->z * $Slic3r::resolution); # extrude skirts - $Extrude->($_, 'skirt') for @{ $layer->skirts }; + printf $fh $extruder->extrude_loop($_, 'skirt') for @{ $layer->skirts }; # extrude 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') - } + printf $fh $extruder->extrude_loop($_, 'perimeter') for @{ $layer->perimeters }; # extrude fills for my $fill (@{ $layer->fills }) { - my @paths = $fill->shortest_path($last_pos); - $Extrude->($_, 'fill') for @paths; + printf $fh $extruder->extrude($_, 'fill') + for $fill->shortest_path($extruder->last_pos); } }