Refactoring: moved most of the low-level G-code to the Slic3r::GCode::Base class. Cleanup of the retraction and wipe logic.

This commit is contained in:
Alessandro Ranellucci 2014-10-21 20:16:45 +02:00
parent 33edda0a69
commit 167df0ab87
11 changed files with 403 additions and 177 deletions

View File

@ -29,16 +29,6 @@ sub retract_speed_mm_min {
return $self->retract_speed * 60; 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 { sub extruded_volume {
my ($self, $E) = @_; my ($self, $E) = @_;
return $E * ($self->filament_diameter**2) * PI/4; return $E * ($self->filament_diameter**2) * PI/4;

View File

@ -30,7 +30,6 @@ has 'layer_mp' => (is => 'rw');
has 'new_object' => (is => 'rw', default => sub {0}); has 'new_object' => (is => 'rw', default => sub {0});
has 'straight_once' => (is => 'rw', default => sub {1}); has 'straight_once' => (is => 'rw', default => sub {1});
has 'elapsed_time' => (is => 'rw', default => sub {0} ); # seconds 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 'last_pos' => (is => 'rw', default => sub { Slic3r::Point->new(0,0) } );
has 'wipe_path' => (is => 'rw'); has 'wipe_path' => (is => 'rw');
@ -81,49 +80,17 @@ sub change_layer {
} }
my $gcode = ""; 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 # TODO: cap this to 99% and add an explicit M73 P100 in the end G-code
$gcode .= sprintf "M73 P%s%s\n", $gcode .= $self->update_progress(int(99 * ($self->_layer_index / ($self->layer_count - 1))));
int(99 * ($self->_layer_index / ($self->layer_count - 1))),
($self->config->gcode_comments ? ' ; update progress' : '');
} }
$gcode .= $self->move_z($layer->print_z); my $z = $layer->print_z + $self->config->z_offset; # in unscaled coordinates
return $gcode; if ($self->_extruder->retract_layer_change && $self->will_move_z($z)) {
} $gcode .= $self->retract;
$gcode .= $self->lift;
# 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 . ')')) $gcode .= $self->travel_to_z($z, '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);
}
return $gcode; return $gcode;
} }
@ -289,8 +256,8 @@ sub _extrude_path {
} }
# calculate extrusion length per distance unit # calculate extrusion length per distance unit
my $e = $self->_extruder->e_per_mm3 * $path->mm3_per_mm; my $e_per_mm = $self->_extruder->e_per_mm3 * $path->mm3_per_mm;
$e = 0 if !$self->_extrusion_axis; $e_per_mm = 0 if !$self->_extrusion_axis;
# set speed # set speed
my $F; my $F;
@ -322,7 +289,7 @@ sub _extrude_path {
$gcode .= ";_BRIDGE_FAN_START\n" if $path->is_bridge; $gcode .= ";_BRIDGE_FAN_START\n" if $path->is_bridge;
my $path_length = unscale $path->length; 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_x - $self->_extruder->extruder_offset->x,
$self->shift_y - $self->_extruder->extruder_offset->y, #,, $self->shift_y - $self->_extruder->extruder_offset->y, #,,
$self->_extrusion_axis, $self->_extrusion_axis,
@ -365,11 +332,11 @@ sub travel_to {
|| (defined $role && $role == EXTR_ROLE_SUPPORTMATERIAL && (first { $_->contains_line($travel) } @{$self->layer->support_islands})) || (defined $role && $role == EXTR_ROLE_SUPPORTMATERIAL && (first { $_->contains_line($travel) } @{$self->layer->support_islands}))
) { ) {
$self->straight_once(0); $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) { } elsif (!$self->config->avoid_crossing_perimeters || $self->straight_once) {
$self->straight_once(0); $self->straight_once(0);
$gcode .= $self->retract; $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 { } else {
if ($self->new_object) { if ($self->new_object) {
$self->new_object(0); $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; $gcode .= $self->retract if $need_retract;
# append the actual path and return # append the actual path and return
# use G1 because we rely on paths being straight (G0 may make round paths) # 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; return $gcode;
} }
sub retract { sub retract {
my ($self, %params) = @_; my ($self, $toolchange) = @_;
return "" if !defined $self->_extruder; 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 = ""; my $gcode = "";
# wipe # wipe (if it's enabled for this extruder and we have a stored wipe path)
my $wipe_path;
if ($self->_extruder->wipe && $self->wipe_path) { if ($self->_extruder->wipe && $self->wipe_path) {
my @points = @{$self->wipe_path}; # Reduce feedrate a bit; travel speed is often too high to move on existing material.
$wipe_path = Slic3r::Polyline->new($self->last_pos, @{$self->wipe_path}[1..$#{$self->wipe_path}]); # Too fast = ripping of existing material; too slow = short wipe path, thus more blob.
$wipe_path->clip_end($wipe_path->length - $self->_extruder->scaled_wipe_distance($self->config->travel_speed)); my $wipe_speed = $self->gcode_config->travel_speed * 0.8;
}
# prepare moves # get the retraction length
my $retract = [undef, undef, -$length, $self->_extruder->retract_speed_mm_min, $comment]; my $length = $toolchange
my $lift = ($self->config->retract_lift->[0] == 0 || defined $params{move_z}) && !$self->lifted ? $self->_extruder->retract_length
? undef : $self->_extruder->retract_length_toolchange;
: [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 # Calculate how long we need to travel in order to consume the required
if ($wipe_path) { # amount of retraction. In other words, how far do we move in XY at $wipe_speed
# subdivide the retraction # 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; my $retracted = 0;
foreach my $line (@{$wipe_path->lines}) { foreach my $line (@{$wipe_path->lines}) {
my $segment_length = $line->length; my $segment_length = $line->length;
# reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one # Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one
# due to rounding # due to rounding (TODO: test and/or better math for this)
my $e = $retract->[2] * ($segment_length / $self->_extruder->scaled_wipe_distance($self->config->travel_speed)) * 0.95; my $dE = $length * ($segment_length / $wipe_dist) * 0.95;
$retracted += $e; $gcode .= $self->set_speed($wipe_speed*60);
$gcode .= $self->G1($line->b, undef, $e, $self->config->travel_speed*60*0.8, $retract->[3] . ";_WIPE"); $gcode .= $self->extrude_to_xy(
$self->point_to_gcode($line->b),
-$dE,
'retract;_WIPE',
);
$retracted += $dE;
} }
if ($retracted > $retract->[2]) { $self->_extruder->set_retracted($self->_extruder->retracted + $retracted);
# 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 # The parent class will decide whether we need to perform an actual retraction
# this makes sure we leave sufficient precision in the firmware # (the extruder might be already retracted fully or partially). We call these
$gcode .= $self->reset_e; # methods even if we performed wipe, since this will ensure the entire retraction
} # length is honored in case wipe path was too short.p
if (!$self->lifted) { $gcode .= $toolchange ? $self->retract_for_toolchange : $self->SUPER::retract;
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'; $gcode .= $self->reset_e;
$gcode .= $self->lift;
return $gcode; return $gcode;
} }
@ -497,31 +454,8 @@ sub unretract {
my ($self) = @_; my ($self) = @_;
my $gcode = ""; my $gcode = "";
$gcode .= "M101 ; extruder on\n" if $self->config->gcode_flavor eq 'makerware'; $gcode .= $self->unlift;
$gcode .= $self->SUPER::unretract('compensate retraction');
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);
}
return $gcode; return $gcode;
} }
@ -553,6 +487,16 @@ sub _G0_G1 {
return $self->_Gx($gcode, $e, $F, $comment); 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 { sub _Gx {
my ($self, $gcode, $e, $F, $comment) = @_; my ($self, $gcode, $e, $F, $comment) = @_;
@ -578,7 +522,7 @@ sub set_extruder {
} }
# prepend retraction on the current extruder # prepend retraction on the current extruder
my $gcode = $self->retract(toolchange => 1); my $gcode = $self->retract(1);
# append custom toolchange G-code # append custom toolchange G-code
if (defined $self->_extruder && $self->config->toolchange_gcode) { if (defined $self->_extruder && $self->config->toolchange_gcode) {

View File

@ -2,6 +2,7 @@ package Slic3r::GCode::Base;
use Moo; use Moo;
use List::Util qw(min max first); 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 'gcode_config' => (is => 'ro', default => sub { Slic3r::Config::GCode->new });
has '_extrusion_axis' => (is => 'rw', default => sub { 'E' }); 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 '_multiple_extruders' => (is => 'rw', default => sub { 0 });
has '_last_acceleration' => (is => 'rw', default => sub { 0 }); has '_last_acceleration' => (is => 'rw', default => sub { 0 });
has '_last_fan_speed' => (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 { sub apply_print_config {
my ($self, $print_config) = @_; my ($self, $print_config) = @_;
@ -105,6 +108,15 @@ sub set_acceleration {
$acceleration, ($self->gcode_config->gcode_comments ? ' ; adjust 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 { sub need_toolchange {
my ($self, $extruder_id) = @_; my ($self, $extruder_id) = @_;
@ -138,17 +150,21 @@ sub _toolchange {
$extruder_id, $extruder_id,
($self->gcode_config->gcode_comments ? ' ; change extruder' : ''); ($self->gcode_config->gcode_comments ? ' ; change extruder' : '');
$gcode .= $self->reset_e; $gcode .= $self->reset_e(1);
} }
return $gcode; return $gcode;
} }
sub reset_e { sub reset_e {
my ($self) = @_; my ($self, $force) = @_;
return "" if $self->config->gcode_flavor =~ /^(?:mach3|makerware|sailfish)$/; return "" if $self->config->gcode_flavor =~ /^(?:mach3|makerware|sailfish)$/;
if (defined $self->_extruder) {
return "" if $self->_extruder->E == 0 && !$force;
$self->_extruder->set_E(0) if $self->_extruder; $self->_extruder->set_E(0) if $self->_extruder;
}
if ($self->_extrusion_axis ne '' && !$self->gcode_config->use_relative_e_distances) { 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' : ''); return sprintf "G92 %s0%s\n", $self->gcode_config->extrusion_axis, ($self->config->gcode_comments ? ' ; reset extrusion distance' : '');
} else { } 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 { sub has_multiple_extruders {
my ($self) = @_; my ($self) = @_;
return $self->_multiple_extruders; return $self->_multiple_extruders;

View File

@ -7,4 +7,13 @@ sub new_scale {
return $class->new(map Slic3r::Geometry::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; 1;

View File

@ -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); $expected_amount = $print->print->config->get_at('retract_length_toolchange', $tool) + $print->print->config->get_at('retract_restart_extra_toolchange', $tool);
$changed_tool = 0; $changed_tool = 0;
} }
fail 'unretracted by the correct amount' fail 'unretracted by the correct amount' && exit
if !_eq($info->{dist_E}, $expected_amount); if !_eq($info->{dist_E}, $expected_amount);
$retracted[$tool] = 0; $retracted[$tool] = 0;
$retracted_length[$tool] = 0; $retracted_length[$tool] = 0;

View File

@ -21,13 +21,49 @@ Extruder::reset()
double double
Extruder::extrude(double dE) 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 = 0;
}
this->E += dE; this->E += dE;
this->absolute_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 Pointf

View File

@ -14,7 +14,8 @@ class Extruder
virtual ~Extruder() {} virtual ~Extruder() {}
void reset(); void reset();
double extrude(double dE); double extrude(double dE);
double retract(double length, double restart_extra);
double unretract();
Pointf extruder_offset() const; Pointf extruder_offset() const;
double nozzle_diameter() const; double nozzle_diameter() const;

View File

@ -123,7 +123,11 @@ ExtrusionPath::gcode(Extruder* extruder, double e, double F,
const double line_length = line_it->length() * SCALING_FACTOR; const double line_length = line_it->length() * SCALING_FACTOR;
// calculate extrusion length for this line // 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 // compose G-code line

View File

@ -312,6 +312,13 @@ class GCodeConfig : public virtual StaticPrintConfig
ConfigOptionString extrusion_axis; ConfigOptionString extrusion_axis;
ConfigOptionBool gcode_comments; ConfigOptionBool gcode_comments;
ConfigOptionEnum<GCodeFlavor> gcode_flavor; ConfigOptionEnum<GCodeFlavor> 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_firmware_retraction;
ConfigOptionBool use_relative_e_distances; ConfigOptionBool use_relative_e_distances;
@ -319,6 +326,19 @@ class GCodeConfig : public virtual StaticPrintConfig
this->extrusion_axis.value = "E"; this->extrusion_axis.value = "E";
this->gcode_comments.value = false; this->gcode_comments.value = false;
this->gcode_flavor.value = gcfRepRap; 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_firmware_retraction.value = false;
this->use_relative_e_distances.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 == "extrusion_axis") return &this->extrusion_axis;
if (opt_key == "gcode_comments") return &this->gcode_comments; if (opt_key == "gcode_comments") return &this->gcode_comments;
if (opt_key == "gcode_flavor") return &this->gcode_flavor; 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_firmware_retraction") return &this->use_firmware_retraction;
if (opt_key == "use_relative_e_distances") return &this->use_relative_e_distances; if (opt_key == "use_relative_e_distances") return &this->use_relative_e_distances;
@ -380,12 +407,6 @@ class PrintConfig : public GCodeConfig
ConfigOptionFloat resolution; ConfigOptionFloat resolution;
ConfigOptionFloats retract_before_travel; ConfigOptionFloats retract_before_travel;
ConfigOptionBools retract_layer_change; 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; ConfigOptionFloat skirt_distance;
ConfigOptionInt skirt_height; ConfigOptionInt skirt_height;
ConfigOptionInt skirts; ConfigOptionInt skirts;
@ -396,7 +417,6 @@ class PrintConfig : public GCodeConfig
ConfigOptionInts temperature; ConfigOptionInts temperature;
ConfigOptionInt threads; ConfigOptionInt threads;
ConfigOptionString toolchange_gcode; ConfigOptionString toolchange_gcode;
ConfigOptionFloat travel_speed;
ConfigOptionFloat vibration_limit; ConfigOptionFloat vibration_limit;
ConfigOptionBools wipe; ConfigOptionBools wipe;
ConfigOptionFloat z_offset; ConfigOptionFloat z_offset;
@ -456,18 +476,6 @@ class PrintConfig : public GCodeConfig
this->retract_before_travel.values[0] = 2; this->retract_before_travel.values[0] = 2;
this->retract_layer_change.values.resize(1); this->retract_layer_change.values.resize(1);
this->retract_layer_change.values[0] = true; 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_distance.value = 6;
this->skirt_height.value = 1; this->skirt_height.value = 1;
this->skirts.value = 1; this->skirts.value = 1;
@ -479,7 +487,6 @@ class PrintConfig : public GCodeConfig
this->temperature.values[0] = 200; this->temperature.values[0] = 200;
this->threads.value = 2; this->threads.value = 2;
this->toolchange_gcode.value = ""; this->toolchange_gcode.value = "";
this->travel_speed.value = 130;
this->vibration_limit.value = 0; this->vibration_limit.value = 0;
this->wipe.values.resize(1); this->wipe.values.resize(1);
this->wipe.values[0] = false; this->wipe.values[0] = false;
@ -530,12 +537,6 @@ class PrintConfig : public GCodeConfig
if (opt_key == "resolution") return &this->resolution; if (opt_key == "resolution") return &this->resolution;
if (opt_key == "retract_before_travel") return &this->retract_before_travel; 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_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_distance") return &this->skirt_distance;
if (opt_key == "skirt_height") return &this->skirt_height; if (opt_key == "skirt_height") return &this->skirt_height;
if (opt_key == "skirts") return &this->skirts; 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 == "temperature") return &this->temperature;
if (opt_key == "threads") return &this->threads; if (opt_key == "threads") return &this->threads;
if (opt_key == "toolchange_gcode") return &this->toolchange_gcode; 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 == "vibration_limit") return &this->vibration_limit;
if (opt_key == "wipe") return &this->wipe; if (opt_key == "wipe") return &this->wipe;
if (opt_key == "z_offset") return &this->z_offset; if (opt_key == "z_offset") return &this->z_offset;

View File

@ -12,6 +12,8 @@
~Extruder(); ~Extruder();
void reset(); void reset();
double extrude(double dE); double extrude(double dE);
double retract(double length, double restart_extra);
double unretract();
int id() const int id() const
%code%{ RETVAL = THIS->id; %}; %code%{ RETVAL = THIS->id; %};

View File

@ -110,4 +110,10 @@ Point::coincides_with(point_sv)
%code{% RETVAL = THIS->y; %}; %code{% RETVAL = THIS->y; %};
double z() double z()
%code{% RETVAL = THIS->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; %};
}; };