diff --git a/lib/Slic3r/Extruder.pm b/lib/Slic3r/Extruder.pm index 8bac9d0d9..9cfc4dcf7 100644 --- a/lib/Slic3r/Extruder.pm +++ b/lib/Slic3r/Extruder.pm @@ -14,6 +14,7 @@ has 'id' => (is => 'rw', required => 1); has $_ => (is => 'ro', required => 1) for @{&OPTIONS}; has 'retracted' => (is => 'rw', default => sub {0} ); +has 'restart_extra' => (is => 'rw', default => sub {0} ); has 'e_per_mm3' => (is => 'lazy'); has 'retract_speed_mm_min' => (is => 'lazy'); has '_mm3_per_mm_cache' => (is => 'ro', default => sub {{}}); diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 72bc89fa1..b5e944551 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -181,7 +181,7 @@ sub extrude_path { if !points_coincide($self->last_pos, $path->points->[0]); # compensate retraction - $gcode .= $self->unretract if $self->extruder->retracted; + $gcode .= $self->unretract; my $area; # mm^3 of extrudate per mm of tool movement if ($path->role == EXTR_ROLE_BRIDGE) { @@ -276,7 +276,8 @@ sub retract { $gcode .= $self->G1(@$lift); } } - $self->extruder->retracted($self->extruder->retracted + $length + $restart_extra); + $self->extruder->retracted($self->extruder->retracted + $length); + $self->extruder->restart_extra($restart_extra); $self->lifted($self->extruder->retract_lift) if $lift; # reset extrusion distance during retracts @@ -297,9 +298,13 @@ sub unretract { $self->lifted(0); } - $self->speed('retract'); - $gcode .= $self->G0(undef, undef, $self->extruder->retracted, "compensate retraction"); - $self->extruder->retracted(0); + my $to_unretract = $self->extruder->retracted + $self->extruder->restart_extra; + if ($to_unretract) { + $self->speed('retract'); + $gcode .= $self->G0(undef, undef, $to_unretract, "compensate retraction"); + $self->extruder->retracted(0); + $self->extruder->restart_extra(0); + } return $gcode; } diff --git a/lib/Slic3r/Test.pm b/lib/Slic3r/Test.pm index 99a273127..3c92f2eab 100644 --- a/lib/Slic3r/Test.pm +++ b/lib/Slic3r/Test.pm @@ -34,6 +34,7 @@ sub init_print { my $config = Slic3r::Config->new_from_defaults; $config->apply($params{config}) if $params{config}; + $config->set('gcode_comments', 1) if $ENV{SLIC3R_TESTS_GCODE}; my $print = Slic3r::Print->new(config => $config); $print->add_model($model); diff --git a/t/retraction.t b/t/retraction.t index bf3327d48..23192ce89 100644 --- a/t/retraction.t +++ b/t/retraction.t @@ -1,4 +1,4 @@ -use Test::More tests => 9; +use Test::More tests => 12; use strict; use warnings; @@ -19,34 +19,46 @@ my $test = sub { my $print = Slic3r::Test::init_print('20mm_cube', config => $conf); my $tool = 0; + my @toolchange_count = (); # track first usages so that we don't expect retract_length_toolchange when extruders are used for the first time my @retracted = (1); # ignore the first travel move from home to first point my $lifted = 0; my $changed_tool = 0; + my $wait_for_toolchange = 0; Slic3r::Test::GCodeReader->new(gcode => Slic3r::Test::gcode($print))->parse(sub { my ($self, $cmd, $args, $info) = @_; if ($cmd =~ /^T(\d+)/) { $tool = $1; $changed_tool = 1; + $wait_for_toolchange = 0; + $toolchange_count[$tool] //= 0; + $toolchange_count[$tool]++; + } elsif ($cmd =~ /^G[01]$/ && !$args->{Z}) { # ignore lift taking place after retraction + fail 'toolchange happens right after retraction' if $wait_for_toolchange; } if ($info->{dist_Z}) { # lift move or lift + change layer - if (_eq($info->{dist_Z}, $conf->retract_lift->[$tool]) - || (_eq($info->{dist_Z}, $conf->layer_height + $conf->retract_lift->[$tool]) && $conf->retract_lift->[$tool] > 0)) { + if (_eq($info->{dist_Z}, $print->extruders->[$tool]->retract_lift) + || (_eq($info->{dist_Z}, $conf->layer_height + $print->extruders->[$tool]->retract_lift) && $print->extruders->[$tool]->retract_lift > 0)) { fail 'only lifting while retracted' if !$retracted[$tool] && !($conf->g0 && $info->{retracting}); $lifted = 1; } if ($info->{dist_Z} < 0) { fail 'going down only after lifting' if !$lifted; fail 'going down by the same amount of the lift' - if !_eq($info->{dist_Z}, -$conf->retract_lift->[$tool]); + if !_eq($info->{dist_Z}, -$print->extruders->[$tool]->retract_lift); $lifted = 0; } } if ($info->{retracting}) { - fail 'retracted by the correct amount' - if !_eq(-$info->{dist_E}, $conf->retract_length->[$tool]); + if (_eq(-$info->{dist_E}, $print->extruders->[$tool]->retract_length)) { + # okay + } elsif (_eq(-$info->{dist_E}, $print->extruders->[$tool]->retract_length_toolchange)) { + $wait_for_toolchange = 1; + } else { + fail 'retracted by the correct amount'; + } fail 'combining retraction and travel with G0' if $cmd ne 'G0' && $conf->g0 && ($info->{dist_Z} || $info->{dist_XY}); $retracted[$tool] = 1; @@ -54,16 +66,17 @@ my $test = sub { if ($info->{extruding}) { fail 'only extruding while not lifted' if $lifted; if ($retracted[$tool]) { - my $expected_amount = $conf->retract_length->[$tool] + $conf->retract_restart_extra->[$tool]; - if ($changed_tool) { - $expected_amount = $conf->retract_length_toolchange->[$tool] + $conf->retract_restart_extra_toolchange->[$tool]; + my $expected_amount = $print->extruders->[$tool]->retract_length + $print->extruders->[$tool]->retract_restart_extra; + if ($changed_tool && $toolchange_count[$tool] > 1) { + $expected_amount = $print->extruders->[$tool]->retract_length_toolchange + $print->extruders->[$tool]->retract_restart_extra_toolchange; + $changed_tool = 0; } fail 'unretracted by the correct amount' if !_eq($info->{dist_E}, $expected_amount); $retracted[$tool] = 0; } } - if ($info->{travel} && $info->{dist_XY} >= $conf->retract_before_travel->[$tool]) { + if ($info->{travel} && $info->{dist_XY} >= $print->extruders->[$tool]->retract_before_travel) { fail 'retracted before long travel move' if !$retracted[$tool]; } });