From 055273fbc87550b828bbd42c2effb22b853e32c3 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Wed, 28 Aug 2013 18:12:20 +0200 Subject: [PATCH] Huge speed boost by reducing the number of method calls in GCode.pm --- lib/Slic3r/ExtrusionPath.pm | 5 ++ lib/Slic3r/GCode.pm | 137 +++++++++++++++++------------- lib/Slic3r/GCode/CoolingBuffer.pm | 3 +- lib/Slic3r/GCode/Reader.pm | 2 +- t/vibrationlimit.t | 2 +- 5 files changed, 85 insertions(+), 64 deletions(-) diff --git a/lib/Slic3r/ExtrusionPath.pm b/lib/Slic3r/ExtrusionPath.pm index 0bcd3b78..b0e0fc99 100644 --- a/lib/Slic3r/ExtrusionPath.pm +++ b/lib/Slic3r/ExtrusionPath.pm @@ -65,6 +65,11 @@ sub points { return $self->polyline; } +sub last_point { + my $self = shift; + return $self->polyline->[-1]; +} + sub is_perimeter { my $self = shift; return $self->role == EXTR_ROLE_PERIMETER diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 2fc41006..56ddd9ec 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -36,7 +36,6 @@ 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 } ); sub _build_speeds { my $self = shift; @@ -317,29 +316,89 @@ sub extrude_path { # calculate extrusion length per distance unit my $e = $self->extruder->e_per_mm3 * $area; + $e = 0 if !$self->config->extrusion_axis; # set speed $self->speed( $params{speed} || $role_speeds{$path->role} || die "Unknown role: " . $path->role ); + my $F = $self->speeds->{$self->speed} // $self->speed; + if ($self->layer->id == 0) { + $F = $self->config->first_layer_speed =~ /^(\d+(?:\.\d+)?)%$/ + ? sprintf("%.3f", $F * $1/100) + : $self->config->first_layer_speed * 60; + } # extrude arc or line + $gcode .= ";_BRIDGE_FAN_START\n" if $path->is_bridge; my $path_length = 0; if ($path->isa('Slic3r::ExtrusionPath::Arc')) { $path_length = unscale $path->length; - $gcode .= $self->G2_G3($path->points->[-1], $path->orientation, - $path->center, $e * unscale $path_length, $description); + + # calculate extrusion length for this arc + my $E = 0; + if ($e) { + $E = $e * $path_length; + $self->extruder->e(0) if $self->config->use_relative_e_distances; + $self->total_extrusion_length($self->total_extrusion_length + $E); + $E = $self->extruder->e($self->extruder->e + $E); + } + + # compose G-code line + my $point = $path->points->[-1]; + $gcode .= $path->orientation eq 'cw' ? "G2" : "G3"; + $gcode .= sprintf " X%.3f Y%.3f", + ($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]; #** + + # XY distance of the center from the start position + $gcode .= sprintf " I%.3f J%.3f", + ($path->center->[X] - $self->last_pos->[X]) * &Slic3r::SCALING_FACTOR, + ($path->center->[Y] - $self->last_pos->[Y]) * &Slic3r::SCALING_FACTOR; + + $gcode .= sprintf(" %s%.5f", $self->config->extrusion_axis, $E) + if $E; + $gcode .= " F$F"; + $gcode .= " ; $description" + if $self->config->gcode_comments; + $gcode .= "\n"; + $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); + my $local_F = $F; + foreach my $line ($path->lines) { + $path_length += my $line_length = unscale $line->length; + + # calculate extrusion length for this line + my $E = 0; + if ($e) { + $E = $e * $line_length; + $self->extruder->e(0) if $self->config->use_relative_e_distances; + $self->total_extrusion_length($self->total_extrusion_length + $E); + $E = $self->extruder->e($self->extruder->e + $E); + } + + # compose G-code line + $gcode .= sprintf "G1 X%.3f Y%.3f", + ($line->[B]->x * &Slic3r::SCALING_FACTOR) + $self->shift_x - $self->extruder->extruder_offset->[X], + ($line->[B]->y * &Slic3r::SCALING_FACTOR) + $self->shift_y - $self->extruder->extruder_offset->[Y]; #** + $gcode .= sprintf(" %s%.5f", $self->config->extrusion_axis, $E) + if $E; + $gcode .= " F$local_F" + if $local_F; + $gcode .= " ; $description" + if $self->config->gcode_comments; + $gcode .= "\n"; + + # only include F in the first line + $local_F = 0; } $self->wipe_path(Slic3r::Polyline->new(reverse @{$path->points})) if $self->enable_wipe; } + $gcode .= ";_BRIDGE_FAN_END\n" if $path->is_bridge; + $self->last_pos($path->last_point); if ($self->config->cooling) { - my $path_time = $path_length / $self->speeds->{$self->last_speed} * 60; + my $path_time = $path_length / $F * 60; if ($self->layer->id == 0) { $path_time = $self->config->first_layer_speed =~ /^(\d+(?:\.\d+)?)%$/ ? $path_time / ($1/100) @@ -574,69 +633,30 @@ sub G1 { sub _G0_G1 { my ($self, $gcode, $point, $z, $e, $comment) = @_; - my $dec = $self->dec; - if (defined $point) { - $gcode .= sprintf " X%.${dec}f Y%.${dec}f", + if ($point) { + $gcode .= sprintf " X%.3f Y%.3f", ($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]; #** $self->last_pos($point->clone); } if (defined $z && (!defined $self->z || $z != $self->z)) { $self->z($z); - $gcode .= sprintf " Z%.${dec}f", $z; + $gcode .= sprintf " Z%.3f", $z; } return $self->_Gx($gcode, $e, $comment); } -sub G2_G3 { - my ($self, $point, $orientation, $center, $e, $comment) = @_; - my $dec = $self->dec; - - my $gcode = $orientation eq 'cw' ? "G2" : "G3"; - - $gcode .= sprintf " X%.${dec}f Y%.${dec}f", - ($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]; #** - - # XY distance of the center from the start position - $gcode .= sprintf " I%.${dec}f J%.${dec}f", - ($center->[X] - $self->last_pos->[X]) * &Slic3r::SCALING_FACTOR, - ($center->[Y] - $self->last_pos->[Y]) * &Slic3r::SCALING_FACTOR; - - $self->last_pos($point); - return $self->_Gx($gcode, $e, $comment); -} - sub _Gx { my ($self, $gcode, $e, $comment) = @_; - my $dec = $self->dec; - # output speed if it's different from last one used - # (goal: reduce gcode size) - my $append_bridge_off = 0; - my $F; - if ($self->speed ne $self->last_speed) { - if ($self->speed eq 'bridge') { - $gcode = ";_BRIDGE_FAN_START\n$gcode"; - } elsif ($self->last_speed eq 'bridge') { - $append_bridge_off = 1; - } - - # apply the speed reduction for print moves on bottom layer - $F = $self->speed eq 'retract' - ? ($self->extruder->retract_speed_mm_min) - : $self->speeds->{$self->speed} // $self->speed; - if ($e && $self->layer && $self->layer->id == 0 && $comment !~ /retract/) { - $F = $self->config->first_layer_speed =~ /^(\d+(?:\.\d+)?)%$/ - ? ($F * $1/100) - : $self->config->first_layer_speed * 60; - } - $self->last_speed($self->speed); - $self->last_f($F); - } - $gcode .= sprintf " F%.${dec}f", $F if defined $F; + my $F = $self->speed eq 'retract' + ? ($self->extruder->retract_speed_mm_min) + : $self->speeds->{$self->speed} // $self->speed; + $self->last_speed($self->speed); + $self->last_f($F); + $gcode .= sprintf " F%.3f", $F; # output extrusion distance if ($e && $self->config->extrusion_axis) { @@ -646,10 +666,7 @@ sub _Gx { $gcode .= sprintf " %s%.5f", $self->config->extrusion_axis, $self->extruder->e; } - $gcode .= sprintf " ; %s", $comment if $comment && $self->config->gcode_comments; - if ($append_bridge_off) { - $gcode = ";_BRIDGE_FAN_END\n$gcode"; - } + $gcode .= " ; $comment" if $comment && $self->config->gcode_comments; return "$gcode\n"; } diff --git a/lib/Slic3r/GCode/CoolingBuffer.pm b/lib/Slic3r/GCode/CoolingBuffer.pm index 45283bef..d95b5fec 100644 --- a/lib/Slic3r/GCode/CoolingBuffer.pm +++ b/lib/Slic3r/GCode/CoolingBuffer.pm @@ -56,10 +56,9 @@ sub flush { Slic3r::debugf " fan = %d%%, speed = %d%%\n", $fan_speed, $speed_factor * 100; if ($speed_factor < 1) { - my $dec = $self->gcodegen->dec; $gcode =~ s/^(?=.*? [XY])(?=.*? E)(?!;_WIPE)(?min_print_speed ? $self->min_print_speed : $new_speed) + $1 . sprintf("%.3f", $new_speed < $self->min_print_speed ? $self->min_print_speed : $new_speed) /gexm; } } diff --git a/lib/Slic3r/GCode/Reader.pm b/lib/Slic3r/GCode/Reader.pm index cfcca854..251f1f2b 100644 --- a/lib/Slic3r/GCode/Reader.pm +++ b/lib/Slic3r/GCode/Reader.pm @@ -49,7 +49,7 @@ sub parse { } # run callback - #$cb->($self, $command, \%args, \%info); + $cb->($self, $command, \%args, \%info); # update coordinates if ($command =~ /^(?:G[01]|G92)$/) { diff --git a/t/vibrationlimit.t b/t/vibrationlimit.t index ff39073e..2553e226 100644 --- a/t/vibrationlimit.t +++ b/t/vibrationlimit.t @@ -58,7 +58,7 @@ my $test = sub { my $one_axis_would_trigger_limit_without_pause = 0; foreach my $axis (qw(X Y)) { # are we changing direction on this axis? - my $dir = $info->{"dist_$axis"} <=> 0; + my $dir = $info->{"dist_$axis"} <=> ($args->{$axis} // $self->$axis); if ($dir != 0 && $dir{$axis} != $dir) { # this move changes direction on this axis if ($dir{$axis} != 0) {