diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 1180b76ff..4519d933a 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -6,6 +6,7 @@ use Slic3r::ExtrusionPath ':roles'; use Slic3r::Geometry qw(scale unscale scaled_epsilon points_coincide PI X Y B); use Slic3r::Geometry::Clipper qw(union_ex); +has 'config' => (is => 'ro', required => 1); has 'multiple_extruders' => (is => 'ro', default => sub {0} ); has 'layer_count' => (is => 'ro', required => 1 ); has 'layer' => (is => 'rw'); @@ -15,6 +16,7 @@ has 'shift_y' => (is => 'rw', default => sub {0} ); has 'z' => (is => 'rw'); has 'speed' => (is => 'rw'); +has 'speeds' => (is => 'lazy'); # mm/min has 'external_mp' => (is => 'rw'); has 'layer_mp' => (is => 'rw'); has 'new_object' => (is => 'rw', default => sub {0}); @@ -35,15 +37,14 @@ has 'dec' => (is => 'ro', default => sub { 3 } ); has 'last_dir' => (is => 'ro', default => sub { [0,0] }); has 'dir_time' => (is => 'ro', default => sub { [0,0] }); -# calculate speeds (mm/min) -has 'speeds' => ( - is => 'ro', - default => sub {+{ - map { $_ => 60 * $Slic3r::Config->get_value("${_}_speed") } +sub _build_speeds { + my $self = shift; + return { + map { $_ => 60 * $self->config->get_value("${_}_speed") } qw(travel perimeter small_perimeter external_perimeter infill solid_infill top_solid_infill support_material bridge gap_fill retract), - }}, -); + }; +} # assign speeds to roles my %role_speeds = ( @@ -81,17 +82,17 @@ sub change_layer { my ($layer) = @_; $self->layer($layer); - if ($Slic3r::Config->avoid_crossing_perimeters) { + if ($self->config->avoid_crossing_perimeters) { $self->layer_mp(Slic3r::GCode::MotionPlanner->new( islands => union_ex([ map @$_, @{$layer->slices} ], undef, 1), )); } my $gcode = ""; - if ($Slic3r::Config->gcode_flavor =~ /^(?:makerbot|sailfish)$/) { + if ($self->config->gcode_flavor =~ /^(?:makerbot|sailfish)$/) { $gcode .= sprintf "M73 P%s%s\n", int(99 * ($layer->id / ($self->layer_count - 1))), - ($Slic3r::Config->gcode_comments ? ' ; update progress' : ''); + ($self->config->gcode_comments ? ' ; update progress' : ''); } return $gcode; } @@ -102,7 +103,7 @@ sub move_z { my ($z, $comment) = @_; $z *= &Slic3r::SCALING_FACTOR; - $z += $Slic3r::Config->z_offset; + $z += $self->config->z_offset; my $gcode = ""; my $current_z = $self->z; @@ -136,9 +137,9 @@ sub extrude_loop { # find the point of the loop that is closest to the current extruder position # or randomize if requested my $last_pos = $self->last_pos; - if ($Slic3r::Config->randomize_start && $loop->role == EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER) { - $last_pos = Slic3r::Point->new(scale $Slic3r::Config->print_center->[X], scale $Slic3r::Config->bed_size->[Y]); - $last_pos->rotate(rand(2*PI), $Slic3r::Config->print_center); + if ($self->config->randomize_start && $loop->role == EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER) { + $last_pos = Slic3r::Point->new(scale $self->config->print_center->[X], scale $self->config->bed_size->[Y]); + $last_pos->rotate(rand(2*PI), $self->config->print_center); } my $start_index = $loop->nearest_point_index_to($last_pos); @@ -156,7 +157,7 @@ sub extrude_loop { $self->wipe_path($extrusion_path->polyline); # make a little move inwards before leaving loop - if ($loop->role == EXTR_ROLE_EXTERNAL_PERIMETER && $Slic3r::Config->perimeters > 1) { + if ($loop->role == EXTR_ROLE_EXTERNAL_PERIMETER && $self->config->perimeters > 1) { # detect angle between last and first segment # the side depends on the original winding order of the polygon (left for contours, right for holes) my @points = $was_clockwise ? (-2, 1) : (1, -2); @@ -187,7 +188,7 @@ sub extrude_path { $path->simplify(&Slic3r::SCALED_RESOLUTION); # detect arcs - if ($Slic3r::Config->gcode_arcs && !$recursive) { + if ($self->config->gcode_arcs && !$recursive) { my $gcode = ""; foreach my $arc_path ($path->detect_arcs) { $gcode .= $self->extrude_path($arc_path, $description, 1); @@ -204,12 +205,12 @@ sub extrude_path { # adjust acceleration my $acceleration; - if ($Slic3r::Config->perimeter_acceleration && $path->is_perimeter) { - $acceleration = $Slic3r::Config->perimeter_acceleration; - } elsif ($Slic3r::Config->infill_acceleration && $path->is_fill) { - $acceleration = $Slic3r::Config->infill_acceleration; - } elsif ($Slic3r::Config->infill_acceleration && ($path->role == EXTR_ROLE_BRIDGE || $path->role == EXTR_ROLE_INTERNALBRIDGE)) { - $acceleration = $Slic3r::Config->bridge_acceleration; + if ($self->config->perimeter_acceleration && $path->is_perimeter) { + $acceleration = $self->config->perimeter_acceleration; + } elsif ($self->config->infill_acceleration && $path->is_fill) { + $acceleration = $self->config->infill_acceleration; + } elsif ($self->config->infill_acceleration && ($path->role == EXTR_ROLE_BRIDGE || $path->role == EXTR_ROLE_INTERNALBRIDGE)) { + $acceleration = $self->config->bridge_acceleration; } $gcode .= $self->set_acceleration($acceleration) if $acceleration; @@ -251,19 +252,19 @@ sub extrude_path { if $self->extruder->wipe; } - if ($Slic3r::Config->cooling) { + if ($self->config->cooling) { my $path_time = $path_length / $self->speeds->{$self->last_speed} * 60; if ($self->layer->id == 0) { - $path_time = $Slic3r::Config->first_layer_speed =~ /^(\d+(?:\.\d+)?)%$/ + $path_time = $self->config->first_layer_speed =~ /^(\d+(?:\.\d+)?)%$/ ? $path_time / ($1/100) - : $path_length / $Slic3r::Config->first_layer_speed * 60; + : $path_length / $self->config->first_layer_speed * 60; } $self->elapsed_time($self->elapsed_time + $path_time); } # reset acceleration - $gcode .= $self->set_acceleration($Slic3r::Config->default_acceleration) - if $acceleration && $Slic3r::Config->default_acceleration; + $gcode .= $self->set_acceleration($self->config->default_acceleration) + if $acceleration && $self->config->default_acceleration; return $gcode; } @@ -282,13 +283,13 @@ sub travel_to { $travel->translate(-$self->shift_x, -$self->shift_y); if ($travel->length < scale $self->extruder->retract_before_travel - || ($Slic3r::Config->only_retract_when_crossing_perimeters && first { $_->encloses_line($travel, scaled_epsilon) } @{$self->layer->slices}) + || ($self->config->only_retract_when_crossing_perimeters && first { $_->encloses_line($travel, scaled_epsilon) } @{$self->layer->slices}) || ($role == EXTR_ROLE_SUPPORTMATERIAL && $self->layer->support_islands_enclose_line($travel)) ) { $self->straight_once(0); $self->speed('travel'); $gcode .= $self->G0($point, undef, 0, $comment || ""); - } elsif (!$Slic3r::Config->avoid_crossing_perimeters || $self->straight_once) { + } elsif (!$self->config->avoid_crossing_perimeters || $self->straight_once) { $self->straight_once(0); $gcode .= $self->retract(travel_to => $point); $self->speed('travel'); @@ -322,7 +323,7 @@ sub _plan { my @travel = $mp->shortest_path($self->last_pos, $point)->lines; # if the path is not contained in a single island we need to retract - my $need_retract = !$Slic3r::Config->only_retract_when_crossing_perimeters; + my $need_retract = !$self->config->only_retract_when_crossing_perimeters; if (!$need_retract) { $need_retract = 1; foreach my $slice (@{$self->layer->slices}) { @@ -370,7 +371,7 @@ sub retract { ? undef : [undef, $self->z + $self->extruder->retract_lift, 0, 'lift plate during travel']; - if (($Slic3r::Config->g0 || $Slic3r::Config->gcode_flavor eq 'mach3') && $params{travel_to}) { + if (($self->config->g0 || $self->config->gcode_flavor eq 'mach3') && $params{travel_to}) { $self->speed('travel'); if ($lift) { # combine lift and retract @@ -381,7 +382,7 @@ sub retract { my $travel = [$params{travel_to}, undef, $retract->[2], "travel and $comment"]; $gcode .= $self->G0(@$travel); } - } elsif (($Slic3r::Config->g0 || $Slic3r::Config->gcode_flavor eq 'mach3') && defined $params{move_z}) { + } elsif (($self->config->g0 || $self->config->gcode_flavor eq 'mach3') && defined $params{move_z}) { # combine Z change and retraction $self->speed('travel'); my $travel = [undef, $params{move_z}, $retract->[2], "change layer and $comment"]; @@ -417,7 +418,7 @@ sub retract { # reset extrusion distance during retracts # this makes sure we leave sufficient precision in the firmware - $gcode .= $self->reset_e if $Slic3r::Config->gcode_flavor !~ /^(?:mach3|makerbot)$/; + $gcode .= $self->reset_e if $self->config->gcode_flavor !~ /^(?:mach3|makerbot)$/; return $gcode; } @@ -448,8 +449,8 @@ sub reset_e { my $self = shift; $self->extrusion_distance(0); - return sprintf "G92 %s0%s\n", $Slic3r::Config->extrusion_axis, ($Slic3r::Config->gcode_comments ? ' ; reset extrusion distance' : '') - if $Slic3r::Config->extrusion_axis && !$Slic3r::Config->use_relative_e_distances; + return sprintf "G92 %s0%s\n", $self->config->extrusion_axis, ($self->config->gcode_comments ? ' ; reset extrusion distance' : '') + if $self->config->extrusion_axis && !$self->config->use_relative_e_distances; } sub set_acceleration { @@ -458,12 +459,12 @@ sub set_acceleration { return "" if !$acceleration; return sprintf "M204 S%s%s\n", - $acceleration, ($Slic3r::Config->gcode_comments ? ' ; adjust acceleration' : ''); + $acceleration, ($self->config->gcode_comments ? ' ; adjust acceleration' : ''); } sub G0 { my $self = shift; - return $self->G1(@_) if !($Slic3r::Config->g0 || $Slic3r::Config->gcode_flavor eq 'mach3'); + return $self->G1(@_) if !($self->config->g0 || $self->config->gcode_flavor eq 'mach3'); return $self->_G0_G1("G0", @_); } @@ -533,9 +534,9 @@ sub _Gx { ? ($self->extruder->retract_speed_mm_min) : $self->speeds->{$self->speed} // $self->speed; if ($e && $self->layer && $self->layer->id == 0 && $comment !~ /retract/) { - $F = $Slic3r::Config->first_layer_speed =~ /^(\d+(?:\.\d+)?)%$/ + $F = $self->config->first_layer_speed =~ /^(\d+(?:\.\d+)?)%$/ ? ($F * $1/100) - : $Slic3r::Config->first_layer_speed * 60; + : $self->config->first_layer_speed * 60; } $self->last_speed($self->speed); $self->last_f($F); @@ -543,14 +544,14 @@ sub _Gx { $gcode .= sprintf " F%.${dec}f", $F if defined $F; # output extrusion distance - if ($e && $Slic3r::Config->extrusion_axis) { - $self->extrusion_distance(0) if $Slic3r::Config->use_relative_e_distances; + if ($e && $self->config->extrusion_axis) { + $self->extrusion_distance(0) if $self->config->use_relative_e_distances; $self->extrusion_distance($self->extrusion_distance + $e); $self->total_extrusion_length($self->total_extrusion_length + $e); - $gcode .= sprintf " %s%.5f", $Slic3r::Config->extrusion_axis, $self->extrusion_distance; + $gcode .= sprintf " %s%.5f", $self->config->extrusion_axis, $self->extrusion_distance; } - $gcode .= sprintf " ; %s", $comment if $comment && $Slic3r::Config->gcode_comments; + $gcode .= sprintf " ; %s", $comment if $comment && $self->config->gcode_comments; if ($append_bridge_off) { $gcode .= "\n;_BRIDGE_FAN_END"; } @@ -575,8 +576,8 @@ sub set_extruder { $gcode .= $self->retract(toolchange => 1) if defined $self->extruder; # append custom toolchange G-code - if (defined $self->extruder && $Slic3r::Config->toolchange_gcode) { - $gcode .= sprintf "%s\n", $Slic3r::Config->replace_options($Slic3r::Config->toolchange_gcode, { + if (defined $self->extruder && $self->config->toolchange_gcode) { + $gcode .= sprintf "%s\n", $self->config->replace_options($self->config->toolchange_gcode, { previous_extruder => $self->extruder->id, next_extruder => $extruder->id, }); @@ -585,11 +586,11 @@ sub set_extruder { # set the new extruder $self->extruder($extruder); my $toolchange_gcode = sprintf "%s%d%s\n", - ($Slic3r::Config->gcode_flavor =~ /^(?:makerbot|sailfish)$/ ? 'M108 T' : 'T'), + ($self->config->gcode_flavor =~ /^(?:makerbot|sailfish)$/ ? 'M108 T' : 'T'), $extruder->id, - ($Slic3r::Config->gcode_comments ? ' ; change extruder' : ''); + ($self->config->gcode_comments ? ' ; change extruder' : ''); - if ($Slic3r::Config->gcode_flavor =~ /^(?:makerbot|sailfish)$/) { + if ($self->config->gcode_flavor =~ /^(?:makerbot|sailfish)$/) { $gcode .= $self->reset_e; $gcode .= $toolchange_gcode; } else { @@ -607,18 +608,18 @@ sub set_fan { if ($self->last_fan_speed != $speed || $dont_save) { $self->last_fan_speed($speed) if !$dont_save; if ($speed == 0) { - my $code = $Slic3r::Config->gcode_flavor eq 'teacup' + my $code = $self->config->gcode_flavor eq 'teacup' ? 'M106 S0' - : $Slic3r::Config->gcode_flavor =~ /^(?:makerbot|sailfish)$/ + : $self->config->gcode_flavor =~ /^(?:makerbot|sailfish)$/ ? 'M127' : 'M107'; - return sprintf "$code%s\n", ($Slic3r::Config->gcode_comments ? ' ; disable fan' : ''); + return sprintf "$code%s\n", ($self->config->gcode_comments ? ' ; disable fan' : ''); } else { - if ($Slic3r::Config->gcode_flavor =~ /^(?:makerbot|sailfish)$/) { - return sprintf "M126%s\n", ($Slic3r::Config->gcode_comments ? ' ; enable fan' : ''); + if ($self->config->gcode_flavor =~ /^(?:makerbot|sailfish)$/) { + return sprintf "M126%s\n", ($self->config->gcode_comments ? ' ; enable fan' : ''); } else { - return sprintf "M106 %s%d%s\n", ($Slic3r::Config->gcode_flavor eq 'mach3' ? 'P' : 'S'), - (255 * $speed / 100), ($Slic3r::Config->gcode_comments ? ' ; enable fan' : ''); + return sprintf "M106 %s%d%s\n", ($self->config->gcode_flavor eq 'mach3' ? 'P' : 'S'), + (255 * $speed / 100), ($self->config->gcode_comments ? ' ; enable fan' : ''); } } } @@ -629,17 +630,17 @@ sub set_temperature { my $self = shift; my ($temperature, $wait, $tool) = @_; - return "" if $wait && $Slic3r::Config->gcode_flavor =~ /^(?:makerbot|sailfish)$/; + return "" if $wait && $self->config->gcode_flavor =~ /^(?:makerbot|sailfish)$/; - my ($code, $comment) = ($wait && $Slic3r::Config->gcode_flavor ne 'teacup') + my ($code, $comment) = ($wait && $self->config->gcode_flavor ne 'teacup') ? ('M109', 'wait for temperature to be reached') : ('M104', 'set temperature'); my $gcode = sprintf "$code %s%d %s; $comment\n", - ($Slic3r::Config->gcode_flavor eq 'mach3' ? 'P' : 'S'), $temperature, - (defined $tool && ($self->multiple_extruders || $Slic3r::Config->gcode_flavor =~ /^(?:makerbot|sailfish)$/)) ? "T$tool " : ""; + ($self->config->gcode_flavor eq 'mach3' ? 'P' : 'S'), $temperature, + (defined $tool && ($self->multiple_extruders || $self->config->gcode_flavor =~ /^(?:makerbot|sailfish)$/)) ? "T$tool " : ""; $gcode .= "M116 ; wait for temperature to be reached\n" - if $Slic3r::Config->gcode_flavor eq 'teacup' && $wait; + if $self->config->gcode_flavor eq 'teacup' && $wait; return $gcode; } @@ -648,14 +649,14 @@ sub set_bed_temperature { my $self = shift; my ($temperature, $wait) = @_; - my ($code, $comment) = ($wait && $Slic3r::Config->gcode_flavor ne 'teacup') - ? (($Slic3r::Config->gcode_flavor =~ /^(?:makerbot|sailfish)$/ ? 'M109' : 'M190'), 'wait for bed temperature to be reached') + my ($code, $comment) = ($wait && $self->config->gcode_flavor ne 'teacup') + ? (($self->config->gcode_flavor =~ /^(?:makerbot|sailfish)$/ ? 'M109' : 'M190'), 'wait for bed temperature to be reached') : ('M140', 'set bed temperature'); my $gcode = sprintf "$code %s%d ; $comment\n", - ($Slic3r::Config->gcode_flavor eq 'mach3' ? 'P' : 'S'), $temperature; + ($self->config->gcode_flavor eq 'mach3' ? 'P' : 'S'), $temperature; $gcode .= "M116 ; wait for bed temperature to be reached\n" - if $Slic3r::Config->gcode_flavor eq 'teacup' && $wait; + if $self->config->gcode_flavor eq 'teacup' && $wait; return $gcode; } @@ -665,8 +666,8 @@ sub _limit_frequency { my $self = shift; my ($point) = @_; - return '' if $Slic3r::Config->vibration_limit == 0; - my $min_time = 1 / ($Slic3r::Config->vibration_limit * 60); # in minutes + return '' if $self->config->vibration_limit == 0; + my $min_time = 1 / ($self->config->vibration_limit * 60); # in minutes # calculate the move vector and move direction my $vector = Slic3r::Line->new($self->last_pos, $point)->vector; diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 9acbe2cf3..04fc20ed8 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -688,6 +688,7 @@ sub write_gcode { # set up our extruder object my $gcodegen = Slic3r::GCode->new( + config => $self->config, multiple_extruders => (@{$self->extruders} > 1), layer_count => $self->layer_count, ); diff --git a/t/gcode.t b/t/gcode.t index c41307d4f..61c940faf 100644 --- a/t/gcode.t +++ b/t/gcode.t @@ -11,8 +11,10 @@ use Slic3r; use Slic3r::Geometry qw(scale); { - local $Slic3r::Config = Slic3r::Config->new_from_defaults; - my $gcodegen = Slic3r::GCode->new(layer_count => 1); + my $gcodegen = Slic3r::GCode->new( + config => Slic3r::Config->new_from_defaults, + layer_count => 1, + ); $gcodegen->set_shift(10, 10); is_deeply $gcodegen->last_pos, [scale -10, scale -10], 'last_pos is shifted correctly'; }