diff --git a/README.markdown b/README.markdown index 95c565c98..dabd97a88 100644 --- a/README.markdown +++ b/README.markdown @@ -239,6 +239,7 @@ The author of the Silk icon set is Mark James. --retract-lift Lift Z by the given distance in mm when retracting (default: 0) --retract-layer-change Enforce a retraction before each Z move (default: yes) + --wipe Wipe the nozzle while doing a retraction (default: no) Retraction options for multi-extruder setups: --retract-length-toolchange diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm index 3e147a440..dc0763be3 100644 --- a/lib/Slic3r/Config.pm +++ b/lib/Slic3r/Config.pm @@ -794,6 +794,15 @@ END deserialize => $deserialize_comma, default => [1], }, + 'wipe' => { + label => 'Wipe before retract', + tooltip => 'This flag will move the nozzle while retracting to minimize the possible blob on leaky extruders.', + cli => 'wipe!', + type => 'bool', + serialize => $serialize_comma, + deserialize => $deserialize_comma, + default => [0], + }, 'retract_length_toolchange' => { label => 'Length', tooltip => 'When retraction is triggered before changing tool, filament is pulled back by the specified amount (the length is measured on raw filament, before it enters the extruder).', @@ -1065,7 +1074,7 @@ sub new_from_cli { } $args{$_} = $Options->{$_}{deserialize}->($args{$_}) - for grep exists $args{$_}, qw(print_center bed_size duplicate_grid extruder_offset retract_layer_change); + for grep exists $args{$_}, qw(print_center bed_size duplicate_grid extruder_offset retract_layer_change wipe); return $class->new(%args); } diff --git a/lib/Slic3r/Extruder.pm b/lib/Slic3r/Extruder.pm index bc124dad2..526ac5048 100644 --- a/lib/Slic3r/Extruder.pm +++ b/lib/Slic3r/Extruder.pm @@ -1,13 +1,13 @@ package Slic3r::Extruder; use Moo; -use Slic3r::Geometry qw(PI); +use Slic3r::Geometry qw(PI scale); use constant OPTIONS => [qw( extruder_offset nozzle_diameter filament_diameter extrusion_multiplier temperature first_layer_temperature retract_length retract_lift retract_speed retract_restart_extra retract_before_travel - retract_layer_change retract_length_toolchange retract_restart_extra_toolchange + retract_layer_change retract_length_toolchange retract_restart_extra_toolchange wipe )]; has 'id' => (is => 'rw', required => 1); @@ -18,6 +18,7 @@ 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 'scaled_wipe_distance' => (is => 'lazy'); # scaled mm has '_mm3_per_mm_cache' => (is => 'ro', default => sub {{}}); sub _build_bridge_flow { @@ -35,6 +36,11 @@ sub _build_retract_speed_mm_min { return $self->retract_speed * 60; } +sub _build_scaled_wipe_distance { + my $self = shift; + return scale $self->retract_length / $self->retract_speed * $Slic3r::Config->travel_speed; +} + sub make_flow { my $self = shift; return Slic3r::Flow->new(nozzle_diameter => $self->nozzle_diameter, @_); diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 52efe6b39..92190cf7d 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -28,6 +28,7 @@ has 'last_pos' => (is => 'rw', default => sub { Slic3r::Point->new(0,0 has 'last_speed' => (is => 'rw', default => sub {""}); has 'last_f' => (is => 'rw', default => sub {""}); has 'last_fan_speed' => (is => 'rw', default => sub {0}); +has 'wipe_path' => (is => 'rw'); has 'dec' => (is => 'ro', default => sub { 3 } ); # used for vibration limit: @@ -64,10 +65,12 @@ sub set_shift { my @shift = @_; # if shift increases (goes towards right), last_pos decreases because it goes towards left - $self->last_pos->translate( + my @translate = ( scale ($self->shift_x - $shift[X]), scale ($self->shift_y - $shift[Y]), ); + $self->last_pos->translate(@translate); + $self->wipe_path->translate(@translate) if $self->wipe_path; $self->shift_x($shift[X]); $self->shift_y($shift[Y]); @@ -150,6 +153,7 @@ sub extrude_loop { # extrude along the path my $gcode = $self->extrude_path($extrusion_path, $description); + $self->wipe_path($extrusion_path->polyline); # make a little move inwards before leaving loop if ($loop->role == EXTR_ROLE_EXTERNAL_PERIMETER) { @@ -236,12 +240,15 @@ sub extrude_path { $path_length = unscale $path->length; $gcode .= $self->G2_G3($path->points->[-1], $path->orientation, $path->center, $e * unscale $path_length, $description); + $self->wipe_path(undef); } else { foreach my $line ($path->lines) { my $line_length = unscale $line->length; $path_length += $line_length; $gcode .= $self->G1($line->[B], undef, $e * $line_length, $description); } + $self->wipe_path(Slic3r::Polyline->new([ reverse @{$path->points} ])) + if $Slic3r::Config->wipe; } if ($Slic3r::Config->cooling) { @@ -347,6 +354,14 @@ sub retract { # if we already retracted, reduce the required amount of retraction $length -= $self->extruder->retracted; return "" unless $length > 0; + my $gcode = ""; + + # wipe + my $wipe_path; + if ($Slic3r::Config->wipe && $self->wipe_path) { + $wipe_path = Slic3r::Polyline->new([ $self->last_pos, @{$self->wipe_path}[1..$#{$self->wipe_path}] ]) + ->clip_start($self->extruder->scaled_wipe_distance); + } # prepare moves $self->speed('retract'); @@ -355,7 +370,6 @@ sub retract { ? undef : [undef, $self->z + $self->extruder->retract_lift, 0, 'lift plate during travel']; - my $gcode = ""; if (($Slic3r::Config->g0 || $Slic3r::Config->gcode_flavor eq 'mach3') && $params{travel_to}) { if ($lift) { # combine lift and retract @@ -371,7 +385,18 @@ sub retract { my $travel = [undef, $params{move_z}, $retract->[2], "change layer and $comment"]; $gcode .= $self->G0(@$travel); } else { - $gcode .= $self->G1(@$retract); + if ($wipe_path) { + $self->speed('travel'); + # subdivide the retraction + my $total_wipe_length = $wipe_path->length; + + for (1 .. $#$wipe_path) { + my $segment_length = $wipe_path->[$_-1]->distance_to($wipe_path->[$_]); + $gcode .= $self->G1($wipe_path->[$_], undef, $retract->[2] * ($segment_length / $total_wipe_length), $retract->[3] . ";_WIPE"); + } + } else { + $gcode .= $self->G1(@$retract); + } if (!$self->lifted) { if (defined $params{move_z} && $self->extruder->retract_lift > 0) { my $travel = [undef, $params{move_z} + $self->extruder->retract_lift, 0, 'move to next layer (' . $self->layer->id . ') and lift']; diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index 9a956ce81..235c841b1 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -691,7 +691,7 @@ sub build { $self->_build_extruder_pages; } -sub _extruder_options { qw(nozzle_diameter extruder_offset retract_length retract_lift retract_speed retract_restart_extra retract_before_travel +sub _extruder_options { qw(nozzle_diameter extruder_offset retract_length retract_lift retract_speed retract_restart_extra retract_before_travel wipe retract_layer_change retract_length_toolchange retract_restart_extra_toolchange) } sub config { @@ -725,7 +725,7 @@ sub _build_extruder_pages { title => 'Retraction', options => [ map "${_}#${extruder_idx}", - qw(retract_length retract_lift retract_speed retract_restart_extra retract_before_travel retract_layer_change) + qw(retract_length retract_lift retract_speed retract_restart_extra retract_before_travel retract_layer_change wipe) ], }, { diff --git a/lib/Slic3r/Polyline.pm b/lib/Slic3r/Polyline.pm index 1df68e80c..12fe0cb9b 100644 --- a/lib/Slic3r/Polyline.pm +++ b/lib/Slic3r/Polyline.pm @@ -168,6 +168,7 @@ sub scale { return $self; } +# removes the given distance from the end of the polyline sub clip_end { my $self = shift; my ($distance) = @_; @@ -188,6 +189,30 @@ sub clip_end { } } +# only keeps the given distance at the beginning of the polyline +sub clip_start { + my $self = shift; + my ($distance) = @_; + + my $points = [ $self->[0] ]; + + for (my $i = 1; $distance > 0 && $i <= $#$self; $i++) { + my $point = $self->[$i]; + my $segment_length = $point->distance_to($self->[$i-1]); + if ($segment_length <= $distance) { + $distance -= $segment_length; + push @$points, $point; + next; + } + + my $new_point = Slic3r::Geometry::point_along_segment($self->[$i-1], $point, $distance); + push @$points, Slic3r::Point->new($new_point); + $distance = 0; + } + + return (ref $self)->new($points); +} + package Slic3r::Polyline::Collection; use Moo; diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index e19ec2730..2cf12bf63 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -958,7 +958,7 @@ sub write_gcode { Slic3r::debugf " fan = %d%%, speed = %d%%\n", $fan_speed, $speed_factor * 100; if ($speed_factor < 1) { - $gcode =~ s/^(?=.*? [XY])(?=.*? E)(?set_fan($Slic3r::Config->bridge_fan_speed, 1) /gmex; $gcode =~ s/^;_BRIDGE_FAN_END\n/ $gcodegen->set_fan($fan_speed, 1) /gmex; } + $gcode =~ s/;_WIPE//g; return $gcode; }; diff --git a/slic3r.pl b/slic3r.pl index 5c5c80b16..9850a9916 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -292,6 +292,7 @@ $j --retract-lift Lift Z by the given distance in mm when retracting (default: $config->{retract_lift}[0]) --retract-layer-change Enforce a retraction before each Z move (default: yes) + --wipe Wipe the nozzle while doing a retraction (default: no) Retraction options for multi-extruder setups: --retract-length-toolchange