diff --git a/MANIFEST b/MANIFEST index 6e59ce2e5..e7498665e 100644 --- a/MANIFEST +++ b/MANIFEST @@ -24,6 +24,7 @@ lib/Slic3r/Format/AMF/Parser.pm lib/Slic3r/Format/OBJ.pm lib/Slic3r/Format/STL.pm lib/Slic3r/GCode.pm +lib/Slic3r/GCode/CoolingBuffer.pm lib/Slic3r/GCode/MotionPlanner.pm lib/Slic3r/Geometry.pm lib/Slic3r/Geometry/Clipper.pm diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index 478165bc3..eddc2939b 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -45,6 +45,7 @@ use Slic3r::Format::AMF; use Slic3r::Format::OBJ; use Slic3r::Format::STL; use Slic3r::GCode; +use Slic3r::GCode::CoolingBuffer; use Slic3r::GCode::MotionPlanner; use Slic3r::Geometry qw(PI); use Slic3r::Layer; diff --git a/lib/Slic3r/GCode/CoolingBuffer.pm b/lib/Slic3r/GCode/CoolingBuffer.pm new file mode 100644 index 000000000..d88e6c2e0 --- /dev/null +++ b/lib/Slic3r/GCode/CoolingBuffer.pm @@ -0,0 +1,77 @@ +package Slic3r::GCode::CoolingBuffer; +use Moo; + +has 'config' => (is => 'ro', required => 1); +has 'gcodegen' => (is => 'ro', required => 1); +has 'gcode' => (is => 'rw', default => sub {""}); +has 'layer_id' => (is => 'rw'); +has 'last_z' => (is => 'rw'); +has 'min_print_speed' => (is => 'lazy'); + +sub _build_min_print_speed { + my $self = shift; + return 60 * $self->config->min_print_speed; +} + +sub append { + my $self = shift; + my ($gcode, $layer) = @_; + + my $return = ""; + if (defined $self->last_z && $self->last_z != $layer->print_z) { + $return = $self->flush; + $self->gcodegen->elapsed_time(0); + } + + $self->layer_id($layer->id); + $self->last_z($layer->print_z); + $self->gcode($self->gcode . $gcode); + + return $return; +} + +sub flush { + my $self = shift; + + my $gcode = $self->gcode; + $self->gcode(""); + + my $fan_speed = $self->config->fan_always_on ? $self->config->min_fan_speed : 0; + my $speed_factor = 1; + if ($self->config->cooling) { + my $layer_time = $self->gcodegen->elapsed_time; + Slic3r::debugf "Layer %d estimated printing time: %d seconds\n", $self->layer_id, $layer_time; + if ($layer_time < $self->config->slowdown_below_layer_time) { + $fan_speed = $self->config->max_fan_speed; + $speed_factor = $layer_time / $self->config->slowdown_below_layer_time; + } elsif ($layer_time < $self->config->fan_below_layer_time) { + $fan_speed = $self->config->max_fan_speed - ($self->config->max_fan_speed - $self->config->min_fan_speed) + * ($layer_time - $self->config->slowdown_below_layer_time) + / ($self->config->fan_below_layer_time - $self->config->slowdown_below_layer_time); #/ + } + 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) + /gexm; + } + $fan_speed = 0 if $self->layer_id < $self->config->disable_fan_first_layers; + } + $gcode = $self->gcodegen->set_fan($fan_speed) . $gcode; + + # bridge fan speed + if (!$self->config->cooling || $self->config->bridge_fan_speed == 0 || $self->layer_id < $self->config->disable_fan_first_layers) { + $gcode =~ s/^;_BRIDGE_FAN_(?:START|END)\n//gm; + } else { + $gcode =~ s/^;_BRIDGE_FAN_START\n/ $self->gcodegen->set_fan($self->config->bridge_fan_speed, 1) /gmex; + $gcode =~ s/^;_BRIDGE_FAN_END\n/ $self->gcodegen->set_fan($fan_speed, 1) /gmex; + } + $gcode =~ s/;_WIPE//g; + + return $gcode; +} + +1; diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 64747ca6f..189b665bd 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -716,8 +716,6 @@ sub write_gcode { multiple_extruders => (@{$self->extruders} > 1), layer_count => $self->layer_count, ); - my $min_print_speed = 60 * $Slic3r::Config->min_print_speed; - my $dec = $gcodegen->dec; print $fh "G21 ; set units to millimeters\n"; print $fh $gcodegen->set_fan(0, 1) if $Slic3r::Config->cooling && $Slic3r::Config->disable_fan_first_layers; @@ -801,7 +799,6 @@ sub write_gcode { # set new layer, but don't move Z as support material contact areas may need an intermediate one $gcode .= $gcodegen->change_layer($layer); - $gcodegen->elapsed_time(0); # prepare callback to call as soon as a Z command is generated $gcodegen->move_z_callback(sub { @@ -943,42 +940,6 @@ sub write_gcode { } } } - return if !$gcode; - - my $fan_speed = $Slic3r::Config->fan_always_on ? $Slic3r::Config->min_fan_speed : 0; - my $speed_factor = 1; - if ($Slic3r::Config->cooling) { - my $layer_time = $gcodegen->elapsed_time; - Slic3r::debugf "Layer %d estimated printing time: %d seconds\n", $layer->id, $layer_time; - if ($layer_time < $Slic3r::Config->slowdown_below_layer_time) { - $fan_speed = $Slic3r::Config->max_fan_speed; - $speed_factor = $layer_time / $Slic3r::Config->slowdown_below_layer_time; - } elsif ($layer_time < $Slic3r::Config->fan_below_layer_time) { - $fan_speed = $Slic3r::Config->max_fan_speed - ($Slic3r::Config->max_fan_speed - $Slic3r::Config->min_fan_speed) - * ($layer_time - $Slic3r::Config->slowdown_below_layer_time) - / ($Slic3r::Config->fan_below_layer_time - $Slic3r::Config->slowdown_below_layer_time); #/ - } - Slic3r::debugf " fan = %d%%, speed = %d%%\n", $fan_speed, $speed_factor * 100; - - if ($speed_factor < 1) { - $gcode =~ s/^(?=.*? [XY])(?=.*? E)(?!;_WIPE)(?id < $Slic3r::Config->disable_fan_first_layers; - } - $gcode = $gcodegen->set_fan($fan_speed) . $gcode; - - # bridge fan speed - if (!$Slic3r::Config->cooling || $Slic3r::Config->bridge_fan_speed == 0 || $layer->id < $Slic3r::Config->disable_fan_first_layers) { - $gcode =~ s/^;_BRIDGE_FAN_(?:START|END)\n//gm; - } else { - $gcode =~ s/^;_BRIDGE_FAN_START\n/ $gcodegen->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; }; @@ -1001,6 +962,11 @@ sub write_gcode { print $fh $gcodegen->G0(Slic3r::Point->new(0,0), undef, 0, 'move to origin position for next object'); } + my $buffer = Slic3r::GCode::CoolingBuffer->new( + config => $Slic3r::Config, + gcodegen => $gcodegen, + ); + for my $layer (@{$self->objects->[$obj_idx]->layers}) { # if we are printing the bottom layer of an object, and we have already finished # another one, set first layer temperatures. this happens before the Z move @@ -1010,15 +976,20 @@ sub write_gcode { if $Slic3r::Config->first_layer_bed_temperature; $print_first_layer_temperature->(); } - print $fh $extrude_layer->($layer, [$copy]); + print $fh $buffer->append($extrude_layer->($layer, [$copy]), $layer); } + print $fh $buffer->flush; $finished_objects++; } } } else { - print $fh $extrude_layer->($_, $_->object->copies) - for sort { $a->print_z <=> $b->print_z } - map @{$_->layers}, @{$self->objects}; + my $buffer = Slic3r::GCode::CoolingBuffer->new( + config => $Slic3r::Config, + gcodegen => $gcodegen, + ); + print $fh $buffer->append($extrude_layer->($_, $_->object->copies), $_) + for sort { $a->print_z <=> $b->print_z } map @{$_->layers}, @{$self->objects}; + print $fh $buffer->flush; } # save statistic data