From 167df0ab8756691b4f4fcfd9241532213537dd4d Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 21 Oct 2014 20:16:45 +0200 Subject: [PATCH] Refactoring: moved most of the low-level G-code to the Slic3r::GCode::Base class. Cleanup of the retraction and wipe logic. --- lib/Slic3r/Extruder.pm | 10 -- lib/Slic3r/GCode.pm | 204 +++++++++-------------- lib/Slic3r/GCode/Base.pm | 240 ++++++++++++++++++++++++++- lib/Slic3r/Point.pm | 9 + t/retraction.t | 4 +- xs/src/libslic3r/Extruder.cpp | 42 ++++- xs/src/libslic3r/Extruder.hpp | 3 +- xs/src/libslic3r/ExtrusionEntity.cpp | 6 +- xs/src/libslic3r/PrintConfig.hpp | 54 +++--- xs/xsp/Extruder.xsp | 2 + xs/xsp/Point.xsp | 6 + 11 files changed, 403 insertions(+), 177 deletions(-) diff --git a/lib/Slic3r/Extruder.pm b/lib/Slic3r/Extruder.pm index 51e7ad2a6..404dc14bc 100644 --- a/lib/Slic3r/Extruder.pm +++ b/lib/Slic3r/Extruder.pm @@ -29,16 +29,6 @@ sub retract_speed_mm_min { return $self->retract_speed * 60; } -sub scaled_wipe_distance { - my ($self, $travel_speed) = @_; - - # how far do we move in XY at travel_speed for the time needed to consume - # retract_length at retract_speed? - # reduce feedrate a bit; travel speed is often too high to move on existing material - # too fast = ripping of existing material; too slow = short wipe path, thus more blob - return scale($self->retract_length / $self->retract_speed * $travel_speed * 0.8); -} - sub extruded_volume { my ($self, $E) = @_; return $E * ($self->filament_diameter**2) * PI/4; diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index b6918baa0..25036ee1f 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -30,7 +30,6 @@ has 'layer_mp' => (is => 'rw'); has 'new_object' => (is => 'rw', default => sub {0}); has 'straight_once' => (is => 'rw', default => sub {1}); has 'elapsed_time' => (is => 'rw', default => sub {0} ); # seconds -has 'lifted' => (is => 'rw', default => sub {0} ); has 'last_pos' => (is => 'rw', default => sub { Slic3r::Point->new(0,0) } ); has 'wipe_path' => (is => 'rw'); @@ -81,49 +80,17 @@ sub change_layer { } my $gcode = ""; - if ($self->config->gcode_flavor =~ /^(?:makerware|sailfish)$/ && defined $self->layer_count) { + if (defined $self->layer_count) { # TODO: cap this to 99% and add an explicit M73 P100 in the end G-code - $gcode .= sprintf "M73 P%s%s\n", - int(99 * ($self->_layer_index / ($self->layer_count - 1))), - ($self->config->gcode_comments ? ' ; update progress' : ''); + $gcode .= $self->update_progress(int(99 * ($self->_layer_index / ($self->layer_count - 1)))); } - $gcode .= $self->move_z($layer->print_z); - return $gcode; -} - -# this method accepts Z in unscaled coordinates -sub move_z { - my ($self, $z, $comment) = @_; - - my $gcode = ""; - - $z += $self->config->z_offset; - my $current_z = $self->z; - my $nominal_z = defined $current_z ? ($current_z - $self->lifted) : undef; - - if (!defined $current_z || $z > $current_z || $z < $nominal_z) { - # we're moving above the current actual Z (so above the lift height of the current - # layer if any) or below the current nominal layer - - # in both cases, we're going to the nominal Z of the next layer - $self->lifted(0); - - if ($self->_extruder->retract_layer_change) { - # this retraction may alter $self->z - $gcode .= $self->retract(move_z => $z); - $current_z = $self->z; # update current z in case retract() changed it - $nominal_z = defined $current_z ? ($current_z - $self->lifted) : undef; - } - $gcode .= $self->G0(undef, $z, 0, $self->config->travel_speed*60, $comment || ('move to next layer (' . $self->layer->id . ')')) - if !defined $current_z || abs($z - $nominal_z) > epsilon; - } elsif ($z < $current_z) { - # we're moving above the current nominal layer height and below the current actual one. - # we're basically advancing to next layer, whose nominal Z is still lower than the previous - # layer Z with lift. - $self->lifted($current_z - $z); + my $z = $layer->print_z + $self->config->z_offset; # in unscaled coordinates + if ($self->_extruder->retract_layer_change && $self->will_move_z($z)) { + $gcode .= $self->retract; + $gcode .= $self->lift; } - + $gcode .= $self->travel_to_z($z, 'move to next layer (' . $self->layer->id . ')'); return $gcode; } @@ -289,8 +256,8 @@ sub _extrude_path { } # calculate extrusion length per distance unit - my $e = $self->_extruder->e_per_mm3 * $path->mm3_per_mm; - $e = 0 if !$self->_extrusion_axis; + my $e_per_mm = $self->_extruder->e_per_mm3 * $path->mm3_per_mm; + $e_per_mm = 0 if !$self->_extrusion_axis; # set speed my $F; @@ -322,7 +289,7 @@ sub _extrude_path { $gcode .= ";_BRIDGE_FAN_START\n" if $path->is_bridge; my $path_length = unscale $path->length; { - $gcode .= $path->gcode($self->_extruder, $e, $F, + $gcode .= $path->gcode($self->_extruder, $e_per_mm, $F, $self->shift_x - $self->_extruder->extruder_offset->x, $self->shift_y - $self->_extruder->extruder_offset->y, #,, $self->_extrusion_axis, @@ -365,11 +332,11 @@ sub travel_to { || (defined $role && $role == EXTR_ROLE_SUPPORTMATERIAL && (first { $_->contains_line($travel) } @{$self->layer->support_islands})) ) { $self->straight_once(0); - $gcode .= $self->G0($point, undef, 0, $self->config->travel_speed*60, $comment || ""); + $gcode .= $self->travel_to_xy($self->point_to_gcode($point), $comment); } elsif (!$self->config->avoid_crossing_perimeters || $self->straight_once) { $self->straight_once(0); $gcode .= $self->retract; - $gcode .= $self->G0($point, undef, 0, $self->config->travel_speed*60, $comment || ""); + $gcode .= $self->travel_to_xy($self->point_to_gcode($point), $comment); } else { if ($self->new_object) { $self->new_object(0); @@ -410,85 +377,75 @@ sub _plan { } } - # do the retract (the travel_to argument is broken) + # perform the retraction $gcode .= $self->retract if $need_retract; # append the actual path and return # use G1 because we rely on paths being straight (G0 may make round paths) - $gcode .= join '', map $self->G1($_->b, undef, 0, $self->config->travel_speed*60, $comment || ""), @travel; + $gcode .= join '', + map $self->travel_to_xy($self->point_to_gcode($_->b), $comment), + @travel; return $gcode; } sub retract { - my ($self, %params) = @_; + my ($self, $toolchange) = @_; return "" if !defined $self->_extruder; - # get the retraction length and abort if none - my ($length, $restart_extra, $comment) = $params{toolchange} - ? ($self->_extruder->retract_length_toolchange, $self->_extruder->retract_restart_extra_toolchange, "retract for tool change") - : ($self->_extruder->retract_length, $self->_extruder->retract_restart_extra, "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; + # wipe (if it's enabled for this extruder and we have a stored wipe path) if ($self->_extruder->wipe && $self->wipe_path) { - my @points = @{$self->wipe_path}; - $wipe_path = Slic3r::Polyline->new($self->last_pos, @{$self->wipe_path}[1..$#{$self->wipe_path}]); - $wipe_path->clip_end($wipe_path->length - $self->_extruder->scaled_wipe_distance($self->config->travel_speed)); - } - - # prepare moves - my $retract = [undef, undef, -$length, $self->_extruder->retract_speed_mm_min, $comment]; - my $lift = ($self->config->retract_lift->[0] == 0 || defined $params{move_z}) && !$self->lifted - ? undef - : [undef, $self->z + $self->config->retract_lift->[0], 0, $self->config->travel_speed*60, 'lift plate during travel']; - - # check that we have a positive wipe length - if ($wipe_path) { - # subdivide the retraction + # Reduce feedrate a bit; travel speed is often too high to move on existing material. + # Too fast = ripping of existing material; too slow = short wipe path, thus more blob. + my $wipe_speed = $self->gcode_config->travel_speed * 0.8; + + # get the retraction length + my $length = $toolchange + ? $self->_extruder->retract_length + : $self->_extruder->retract_length_toolchange; + + # Calculate how long we need to travel in order to consume the required + # amount of retraction. In other words, how far do we move in XY at $wipe_speed + # for the time needed to consume retract_length at retract_speed? + my $wipe_dist = scale($length / $self->_extruder->retract_speed * $wipe_speed); + + # Take the stored wipe path and replace first point with the current actual position + # (they might be different, for example, in case of loop clipping). + my $wipe_path = Slic3r::Polyline->new( + $self->last_pos, + @{$self->wipe_path}[1..$#{$self->wipe_path}], + ); + # + $wipe_path->clip_end($wipe_path->length - $wipe_dist); + + # subdivide the retraction in segments my $retracted = 0; foreach my $line (@{$wipe_path->lines}) { my $segment_length = $line->length; - # reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one - # due to rounding - my $e = $retract->[2] * ($segment_length / $self->_extruder->scaled_wipe_distance($self->config->travel_speed)) * 0.95; - $retracted += $e; - $gcode .= $self->G1($line->b, undef, $e, $self->config->travel_speed*60*0.8, $retract->[3] . ";_WIPE"); + # Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one + # due to rounding (TODO: test and/or better math for this) + my $dE = $length * ($segment_length / $wipe_dist) * 0.95; + $gcode .= $self->set_speed($wipe_speed*60); + $gcode .= $self->extrude_to_xy( + $self->point_to_gcode($line->b), + -$dE, + 'retract;_WIPE', + ); + $retracted += $dE; } - if ($retracted > $retract->[2]) { - # if we retracted less than we had to, retract the remainder - # TODO: add regression test - $gcode .= $self->G1(undef, undef, $retract->[2] - $retracted, $self->_extruder->retract_speed_mm_min, $comment); - } - $gcode .= $self->reset_e; - } elsif ($self->gcode_config->use_firmware_retraction) { - $gcode .= "G10 ; retract\n"; - } else { - $gcode .= $self->G1(@$retract); - - # reset extrusion distance during retracts - # this makes sure we leave sufficient precision in the firmware - $gcode .= $self->reset_e; + $self->_extruder->set_retracted($self->_extruder->retracted + $retracted); } - if (!$self->lifted) { - if (defined $params{move_z} && $self->config->retract_lift->[0] > 0) { - my $travel = [undef, $params{move_z} + $self->config->retract_lift->[0], 0, $self->config->travel_speed*60, 'move to next layer (' . $self->layer->id . ') and lift']; - $gcode .= $self->G0(@$travel); - $self->lifted($self->config->retract_lift->[0]); - } elsif ($lift) { - $gcode .= $self->G1(@$lift); - } - } - $self->_extruder->set_retracted($self->_extruder->retracted + $length); - $self->_extruder->set_restart_extra($restart_extra); - $self->lifted($self->config->retract_lift->[0]) if $lift; - $gcode .= "M103 ; extruder off\n" if $self->config->gcode_flavor eq 'makerware'; + # The parent class will decide whether we need to perform an actual retraction + # (the extruder might be already retracted fully or partially). We call these + # methods even if we performed wipe, since this will ensure the entire retraction + # length is honored in case wipe path was too short.p + $gcode .= $toolchange ? $self->retract_for_toolchange : $self->SUPER::retract; + + $gcode .= $self->reset_e; + $gcode .= $self->lift; return $gcode; } @@ -497,31 +454,8 @@ sub unretract { my ($self) = @_; my $gcode = ""; - $gcode .= "M101 ; extruder on\n" if $self->config->gcode_flavor eq 'makerware'; - - if ($self->lifted) { - $gcode .= $self->G0(undef, $self->z - $self->lifted, 0, $self->config->travel_speed*60, 'restore layer Z'); - $self->lifted(0); - } - - my $to_unretract = $self->_extruder->retracted + $self->_extruder->restart_extra; - if ($to_unretract) { - if ($self->gcode_config->use_firmware_retraction) { - $gcode .= "G11 ; unretract\n"; - $gcode .= $self->reset_e; - } elsif ($self->_extrusion_axis) { - # use G1 instead of G0 because G0 will blend the restart with the previous travel move - $gcode .= sprintf "G1 %s%.5f F%.3f", - $self->_extrusion_axis, - $self->_extruder->extrude($to_unretract), - $self->_extruder->retract_speed_mm_min; - $gcode .= " ; compensate retraction" if $self->config->gcode_comments; - $gcode .= "\n"; - } - $self->_extruder->set_retracted(0); - $self->_extruder->set_restart_extra(0); - } - + $gcode .= $self->unlift; + $gcode .= $self->SUPER::unretract('compensate retraction'); return $gcode; } @@ -553,6 +487,16 @@ sub _G0_G1 { return $self->_Gx($gcode, $e, $F, $comment); } +# convert a model-space scaled point into G-code coordinates +sub point_to_gcode { + my ($self, $point) = @_; + + return Slic3r::Pointf->new( + ($point->x * &Slic3r::SCALING_FACTOR) + $self->shift_x - $self->_extruder->extruder_offset->x, + ($point->y * &Slic3r::SCALING_FACTOR) + $self->shift_y - $self->_extruder->extruder_offset->y, #** + ); +} + sub _Gx { my ($self, $gcode, $e, $F, $comment) = @_; @@ -578,7 +522,7 @@ sub set_extruder { } # prepend retraction on the current extruder - my $gcode = $self->retract(toolchange => 1); + my $gcode = $self->retract(1); # append custom toolchange G-code if (defined $self->_extruder && $self->config->toolchange_gcode) { diff --git a/lib/Slic3r/GCode/Base.pm b/lib/Slic3r/GCode/Base.pm index 3976b7c33..78a06d88f 100644 --- a/lib/Slic3r/GCode/Base.pm +++ b/lib/Slic3r/GCode/Base.pm @@ -2,6 +2,7 @@ package Slic3r::GCode::Base; use Moo; use List::Util qw(min max first); +use Slic3r::Geometry qw(X Y epsilon); has 'gcode_config' => (is => 'ro', default => sub { Slic3r::Config::GCode->new }); has '_extrusion_axis' => (is => 'rw', default => sub { 'E' }); @@ -10,6 +11,8 @@ has '_extruder' => (is => 'rw'); has '_multiple_extruders' => (is => 'rw', default => sub { 0 }); has '_last_acceleration' => (is => 'rw', default => sub { 0 }); has '_last_fan_speed' => (is => 'rw', default => sub { 0 }); +has '_lifted' => (is => 'rw', default => sub { 0 }); +has '_pos' => (is => 'rw', default => sub { Slic3r::Pointf3->new }); sub apply_print_config { my ($self, $print_config) = @_; @@ -105,6 +108,15 @@ sub set_acceleration { $acceleration, ($self->gcode_config->gcode_comments ? ' ; adjust acceleration' : ''); } +sub update_progress { + my ($self, $percent) = @_; + + return "" if $self->gcode_config->gcode_flavor !~ /^(?:makerware|sailfish)$/; + return sprintf "M73 P%s%s\n", + int($percent), + $self->_comment('update progress'); +} + sub need_toolchange { my ($self, $extruder_id) = @_; @@ -138,17 +150,21 @@ sub _toolchange { $extruder_id, ($self->gcode_config->gcode_comments ? ' ; change extruder' : ''); - $gcode .= $self->reset_e; + $gcode .= $self->reset_e(1); } return $gcode; } sub reset_e { - my ($self) = @_; + my ($self, $force) = @_; return "" if $self->config->gcode_flavor =~ /^(?:mach3|makerware|sailfish)$/; - $self->_extruder->set_E(0) if $self->_extruder; + if (defined $self->_extruder) { + return "" if $self->_extruder->E == 0 && !$force; + $self->_extruder->set_E(0) if $self->_extruder; + } + if ($self->_extrusion_axis ne '' && !$self->gcode_config->use_relative_e_distances) { return sprintf "G92 %s0%s\n", $self->gcode_config->extrusion_axis, ($self->config->gcode_comments ? ' ; reset extrusion distance' : ''); } else { @@ -156,6 +172,224 @@ sub reset_e { } } +sub _comment { + my ($self, $comment) = @_; + + return "" if (!defined $comment) || ($comment eq '') || !$self->config->gcode_comments; + return " ; $comment"; +} + +sub set_speed { + my ($self, $F, $comment) = @_; + + return sprintf "G1 F%.3f%s\n", + $F, + $self->_comment($comment); +} + +sub travel_to_xy { + my ($self, $pointf, $comment) = @_; + + $self->_pos->set_x($pointf->x); + $self->_pos->set_y($pointf->y); # )) + return sprintf "G1 X%.3f Y%.3f F%.3f%s\n", + @$pointf, + $self->gcode_config->travel_speed*60, + $self->_comment($comment); +} + +sub travel_to_xyz { + my ($self, $pointf3, $comment) = @_; + + # If target Z is lower than current Z but higher than nominal Z we + # don't perform the Z move but we only move in the XY plane and + # adjust the nominal Z by reducing the lift amount that will be + # used for unlift. + if (!$self->will_move_z($pointf3->z)) { + my $nominal_z = $self->_pos->z - $self->_lifted; + $self->_lifted($self->_lifted - ($pointf3->z - $nominal_z)); + return $self->travel_to_xy(Slic3r::Pointf->new(@$pointf3[X,Y])); + } + + # In all the other cases, we perform an actual XYZ move and cancel + # the lift. + $self->_lifted(0); + return $self->_travel_to_xyz($pointf3, $comment); +} + +sub _travel_to_xyz { + my ($self, $pointf3, $comment) = @_; + + $self->_pos($pointf3); + return sprintf "G1 X%.3f Y%.3f Z%.3f F%.3f%s\n", + @$pointf3, + $self->gcode_config->travel_speed*60, + $self->_comment($comment); +} + +sub travel_to_z { + my ($self, $z, $comment) = @_; + + # If target Z is lower than current Z but higher than nominal Z + # we don't perform the move but we only adjust the nominal Z by + # reducing the lift amount that will be used for unlift. + if (!$self->will_move_z($z)) { + my $nominal_z = $self->_pos->z - $self->_lifted; + $self->_lifted($self->_lifted - ($z - $nominal_z)); + return ""; + } + + # In all the other cases, we perform an actual Z move and cancel + # the lift. + $self->_lifted(0); + return $self->_travel_to_z($z, $comment); +} + +sub _travel_to_z { + my ($self, $z, $comment) = @_; + + $self->_pos->set_z($z); + return sprintf "G1 Z%.3f F%.3f%s\n", + $z, + $self->gcode_config->travel_speed*60, + $self->_comment($comment); +} + +sub will_move_z { + my ($self, $z) = @_; + + # If target Z is lower than current Z but higher than nominal Z + # we don't perform an actual Z move. + if ($self->_lifted > 0) { + my $nominal_z = $self->_pos->z - $self->_lifted; + if ($z >= $nominal_z && $z <= $self->_pos->z) { + return 0; + } + } + return 1; +} + +sub extrude_to_xy { + my ($self, $pointf, $dE, $comment) = @_; + + $self->_pos->set_x($pointf->x); + $self->_pos->set_y($pointf->y); # )) + $self->_extruder->extrude($dE); + return sprintf "G1 X%.3f Y%.3f %s%.5f%s\n", + @$pointf, + $self->_extrusion_axis, + $self->_extruder->E, + $self->_comment($comment); +} + +sub extrude_to_xyz { + my ($self, $pointf3, $dE, $comment) = @_; + + $self->_pos($pointf3); + $self->_lifted(0); + $self->_extruder->extrude($dE); + return sprintf "G1 X%.3f Y%.3f Z%.3f %s%.5f%s\n", + @$pointf3, + $self->_extrusion_axis, + $self->_extruder->E, + $self->_comment($comment); +} + +sub retract { + my ($self) = @_; + + return $self->_retract( + $self->_extruder->retract_length, + $self->_extruder->retract_restart_extra, + 'retract', + ); +} + +sub retract_for_toolchange { + my ($self) = @_; + + return $self->_retract( + $self->_extruder->retract_length_toolchange, + $self->_extruder->retract_restart_extra_toolchange, + 'retract for toolchange', + ); +} + +sub _retract { + my ($self, $length, $restart_extra, $comment) = @_; + + if ($self->gcode_config->use_firmware_retraction) { + return "G10 ; retract\n"; + } + + my $gcode = ""; + my $dE = $self->_extruder->retract($length, $restart_extra); + if ($dE != 0) { + $gcode = sprintf "G1 %s%.5f F%.3f%s\n", + $self->_extrusion_axis, + $self->_extruder->E, + $self->_extruder->retract_speed_mm_min, + $self->_comment($comment . " dE = $dE"); + } + + $gcode .= "M103 ; extruder off\n" + if $self->gcode_config->gcode_flavor eq 'makerware'; + + return $gcode; +} + +sub unretract { + my ($self, $comment) = @_; + + my $gcode = ""; + + $gcode .= "M101 ; extruder on\n" + if $self->gcode_config->gcode_flavor eq 'makerware'; + + if ($self->gcode_config->use_firmware_retraction) { + $gcode .= "G11 ; unretract\n"; + $gcode .= $self->reset_e; + return $gcode; + } + + my $dE = $self->_extruder->unretract; + if ($dE != 0) { + # use G1 instead of G0 because G0 will blend the restart with the previous travel move + $gcode .= sprintf "G1 %s%.5f F%.3f%s\n", + $self->_extrusion_axis, + $self->_extruder->E, + $self->_extruder->retract_speed_mm_min, + $self->_comment($comment); + } + + return $gcode; +} + +# If this method is called more than once before calling unlift(), +# it will not perform subsequent lifts, even if Z was raised manually +# (i.e. with travel_to_z()) and thus _lifted was reduced. +sub lift { + my ($self) = @_; + + if ($self->_lifted == 0 && $self->gcode_config->retract_lift->[0] > 0) { + my $to_lift = $self->gcode_config->retract_lift->[0]; + $self->_lifted($to_lift); + return $self->_travel_to_z($self->_pos->z + $to_lift, 'lift Z'); + } + return ""; +} + +sub unlift { + my ($self) = @_; + + my $gcode = ""; + if ($self->_lifted > 0) { + $gcode .= $self->_travel_to_z($self->_pos->z - $self->_lifted, 'restore layer Z'); + $self->_lifted(0); + } + return $gcode; +} + sub has_multiple_extruders { my ($self) = @_; return $self->_multiple_extruders; diff --git a/lib/Slic3r/Point.pm b/lib/Slic3r/Point.pm index 6ec4e60bc..abb7a5edf 100644 --- a/lib/Slic3r/Point.pm +++ b/lib/Slic3r/Point.pm @@ -7,4 +7,13 @@ sub new_scale { return $class->new(map Slic3r::Geometry::scale($_), @_); } +package Slic3r::Pointf; +use strict; +use warnings; + +sub new_unscale { + my $class = shift; + return $class->new(map Slic3r::Geometry::unscale($_), @_); +} + 1; diff --git a/t/retraction.t b/t/retraction.t index b86255dfc..6c96abd62 100644 --- a/t/retraction.t +++ b/t/retraction.t @@ -17,7 +17,7 @@ use Slic3r::Test qw(_eq); my $test = sub { my ($conf) = @_; $conf ||= $config; - + my $print = Slic3r::Test::init_print('20mm_cube', config => $conf, duplicate => $duplicate); my $tool = 0; @@ -78,7 +78,7 @@ use Slic3r::Test qw(_eq); $expected_amount = $print->print->config->get_at('retract_length_toolchange', $tool) + $print->print->config->get_at('retract_restart_extra_toolchange', $tool); $changed_tool = 0; } - fail 'unretracted by the correct amount' + fail 'unretracted by the correct amount' && exit if !_eq($info->{dist_E}, $expected_amount); $retracted[$tool] = 0; $retracted_length[$tool] = 0; diff --git a/xs/src/libslic3r/Extruder.cpp b/xs/src/libslic3r/Extruder.cpp index d327276f8..d3919e5e4 100644 --- a/xs/src/libslic3r/Extruder.cpp +++ b/xs/src/libslic3r/Extruder.cpp @@ -21,13 +21,49 @@ Extruder::reset() double Extruder::extrude(double dE) { - if (this->config->use_relative_e_distances) { + // in case of relative E distances we always reset to 0 before any output + if (this->config->use_relative_e_distances) this->E = 0; - } this->E += dE; this->absolute_E += dE; - return this->E; + return dE; +} + +/* This method makes sure the extruder is retracted by the specified amount + of filament and returns the amount of filament retracted. + If the extruder is already retracted by the same or a greater amount, + this method is a no-op. + The restart_extra argument sets the extra length to be used for + unretraction. If we're actually performing a retraction, any restart_extra + value supplied will overwrite the previous one if any. */ +double +Extruder::retract(double length, double restart_extra) +{ + // in case of relative E distances we always reset to 0 before any output + if (this->config->use_relative_e_distances) + this->E = 0; + + double to_retract = length - this->retracted; + if (to_retract > 0) { + this->E -= to_retract; + this->absolute_E -= to_retract; + this->retracted += to_retract; + this->restart_extra = restart_extra; + return to_retract; + } else { + return 0; + } +} + +double +Extruder::unretract() +{ + double dE = this->retracted + this->restart_extra; + this->extrude(dE); + this->retracted = 0; + this->restart_extra = 0; + return dE; } Pointf diff --git a/xs/src/libslic3r/Extruder.hpp b/xs/src/libslic3r/Extruder.hpp index 9caa38c89..99182c58a 100644 --- a/xs/src/libslic3r/Extruder.hpp +++ b/xs/src/libslic3r/Extruder.hpp @@ -14,7 +14,8 @@ class Extruder virtual ~Extruder() {} void reset(); double extrude(double dE); - + double retract(double length, double restart_extra); + double unretract(); Pointf extruder_offset() const; double nozzle_diameter() const; diff --git a/xs/src/libslic3r/ExtrusionEntity.cpp b/xs/src/libslic3r/ExtrusionEntity.cpp index fd39fdc9f..725693fae 100644 --- a/xs/src/libslic3r/ExtrusionEntity.cpp +++ b/xs/src/libslic3r/ExtrusionEntity.cpp @@ -123,7 +123,11 @@ ExtrusionPath::gcode(Extruder* extruder, double e, double F, const double line_length = line_it->length() * SCALING_FACTOR; // calculate extrusion length for this line - double E = (e == 0) ? 0 : extruder->extrude(e * line_length); + double E = 0; + if (e > 0) { + extruder->extrude(e * line_length); + E = extruder->E; + } // compose G-code line diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 7b29d9b59..29bfe6646 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -312,6 +312,13 @@ class GCodeConfig : public virtual StaticPrintConfig ConfigOptionString extrusion_axis; ConfigOptionBool gcode_comments; ConfigOptionEnum gcode_flavor; + ConfigOptionFloats retract_length; + ConfigOptionFloats retract_length_toolchange; + ConfigOptionFloats retract_lift; + ConfigOptionFloats retract_restart_extra; + ConfigOptionFloats retract_restart_extra_toolchange; + ConfigOptionInts retract_speed; + ConfigOptionFloat travel_speed; ConfigOptionBool use_firmware_retraction; ConfigOptionBool use_relative_e_distances; @@ -319,6 +326,19 @@ class GCodeConfig : public virtual StaticPrintConfig this->extrusion_axis.value = "E"; this->gcode_comments.value = false; this->gcode_flavor.value = gcfRepRap; + this->retract_length.values.resize(1); + this->retract_length.values[0] = 1; + this->retract_length_toolchange.values.resize(1); + this->retract_length_toolchange.values[0] = 10; + this->retract_lift.values.resize(1); + this->retract_lift.values[0] = 0; + this->retract_restart_extra.values.resize(1); + this->retract_restart_extra.values[0] = 0; + this->retract_restart_extra_toolchange.values.resize(1); + this->retract_restart_extra_toolchange.values[0] = 0; + this->retract_speed.values.resize(1); + this->retract_speed.values[0] = 30; + this->travel_speed.value = 130; this->use_firmware_retraction.value = false; this->use_relative_e_distances.value = false; }; @@ -327,6 +347,13 @@ class GCodeConfig : public virtual StaticPrintConfig if (opt_key == "extrusion_axis") return &this->extrusion_axis; if (opt_key == "gcode_comments") return &this->gcode_comments; if (opt_key == "gcode_flavor") return &this->gcode_flavor; + if (opt_key == "retract_length") return &this->retract_length; + if (opt_key == "retract_length_toolchange") return &this->retract_length_toolchange; + if (opt_key == "retract_lift") return &this->retract_lift; + if (opt_key == "retract_restart_extra") return &this->retract_restart_extra; + if (opt_key == "retract_restart_extra_toolchange") return &this->retract_restart_extra_toolchange; + if (opt_key == "retract_speed") return &this->retract_speed; + if (opt_key == "travel_speed") return &this->travel_speed; if (opt_key == "use_firmware_retraction") return &this->use_firmware_retraction; if (opt_key == "use_relative_e_distances") return &this->use_relative_e_distances; @@ -380,12 +407,6 @@ class PrintConfig : public GCodeConfig ConfigOptionFloat resolution; ConfigOptionFloats retract_before_travel; ConfigOptionBools retract_layer_change; - ConfigOptionFloats retract_length; - ConfigOptionFloats retract_length_toolchange; - ConfigOptionFloats retract_lift; - ConfigOptionFloats retract_restart_extra; - ConfigOptionFloats retract_restart_extra_toolchange; - ConfigOptionInts retract_speed; ConfigOptionFloat skirt_distance; ConfigOptionInt skirt_height; ConfigOptionInt skirts; @@ -396,7 +417,6 @@ class PrintConfig : public GCodeConfig ConfigOptionInts temperature; ConfigOptionInt threads; ConfigOptionString toolchange_gcode; - ConfigOptionFloat travel_speed; ConfigOptionFloat vibration_limit; ConfigOptionBools wipe; ConfigOptionFloat z_offset; @@ -456,18 +476,6 @@ class PrintConfig : public GCodeConfig this->retract_before_travel.values[0] = 2; this->retract_layer_change.values.resize(1); this->retract_layer_change.values[0] = true; - this->retract_length.values.resize(1); - this->retract_length.values[0] = 1; - this->retract_length_toolchange.values.resize(1); - this->retract_length_toolchange.values[0] = 10; - this->retract_lift.values.resize(1); - this->retract_lift.values[0] = 0; - this->retract_restart_extra.values.resize(1); - this->retract_restart_extra.values[0] = 0; - this->retract_restart_extra_toolchange.values.resize(1); - this->retract_restart_extra_toolchange.values[0] = 0; - this->retract_speed.values.resize(1); - this->retract_speed.values[0] = 30; this->skirt_distance.value = 6; this->skirt_height.value = 1; this->skirts.value = 1; @@ -479,7 +487,6 @@ class PrintConfig : public GCodeConfig this->temperature.values[0] = 200; this->threads.value = 2; this->toolchange_gcode.value = ""; - this->travel_speed.value = 130; this->vibration_limit.value = 0; this->wipe.values.resize(1); this->wipe.values[0] = false; @@ -530,12 +537,6 @@ class PrintConfig : public GCodeConfig if (opt_key == "resolution") return &this->resolution; if (opt_key == "retract_before_travel") return &this->retract_before_travel; if (opt_key == "retract_layer_change") return &this->retract_layer_change; - if (opt_key == "retract_length") return &this->retract_length; - if (opt_key == "retract_length_toolchange") return &this->retract_length_toolchange; - if (opt_key == "retract_lift") return &this->retract_lift; - if (opt_key == "retract_restart_extra") return &this->retract_restart_extra; - if (opt_key == "retract_restart_extra_toolchange") return &this->retract_restart_extra_toolchange; - if (opt_key == "retract_speed") return &this->retract_speed; if (opt_key == "skirt_distance") return &this->skirt_distance; if (opt_key == "skirt_height") return &this->skirt_height; if (opt_key == "skirts") return &this->skirts; @@ -546,7 +547,6 @@ class PrintConfig : public GCodeConfig if (opt_key == "temperature") return &this->temperature; if (opt_key == "threads") return &this->threads; if (opt_key == "toolchange_gcode") return &this->toolchange_gcode; - if (opt_key == "travel_speed") return &this->travel_speed; if (opt_key == "vibration_limit") return &this->vibration_limit; if (opt_key == "wipe") return &this->wipe; if (opt_key == "z_offset") return &this->z_offset; diff --git a/xs/xsp/Extruder.xsp b/xs/xsp/Extruder.xsp index 621924a5c..43bdbfabc 100644 --- a/xs/xsp/Extruder.xsp +++ b/xs/xsp/Extruder.xsp @@ -12,6 +12,8 @@ ~Extruder(); void reset(); double extrude(double dE); + double retract(double length, double restart_extra); + double unretract(); int id() const %code%{ RETVAL = THIS->id; %}; diff --git a/xs/xsp/Point.xsp b/xs/xsp/Point.xsp index 774b2fc1a..e1163ea5c 100644 --- a/xs/xsp/Point.xsp +++ b/xs/xsp/Point.xsp @@ -110,4 +110,10 @@ Point::coincides_with(point_sv) %code{% RETVAL = THIS->y; %}; double z() %code{% RETVAL = THIS->z; %}; + void set_x(double val) + %code{% THIS->x = val; %}; + void set_y(double val) + %code{% THIS->y = val; %}; + void set_z(double val) + %code{% THIS->z = val; %}; };