mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Refactoring: move ooze prevention, wipe and avoid crossing perimeters into nested classes for better isolation
This commit is contained in:
		
							parent
							
								
									3605289bbc
								
							
						
					
					
						commit
						c1e26a70f8
					
				
					 5 changed files with 207 additions and 170 deletions
				
			
		|  | @ -17,9 +17,10 @@ has 'origin'             => (is => 'rw', default => sub { Slic3r::Pointf->new }) | |||
| has 'config'             => (is => 'ro', default => sub { Slic3r::Config::Full->new }); | ||||
| has 'writer'             => (is => 'ro', default => sub { Slic3r::GCode::Writer->new }); | ||||
| has 'placeholder_parser' => (is => 'rw', default => sub { Slic3r::GCode::PlaceholderParser->new }); | ||||
| has 'ooze_prevention'    => (is => 'rw'); | ||||
| has 'ooze_prevention'    => (is => 'rw', default => sub { Slic3r::GCode::OozePrevention->new }); | ||||
| has 'wipe'               => (is => 'rw', default => sub { Slic3r::GCode::Wipe->new }); | ||||
| has 'avoid_crossing_perimeters' => (is => 'rw', default => sub { Slic3r::GCode::AvoidCrossingPerimeters->new }); | ||||
| has 'enable_loop_clipping' => (is => 'rw', default => sub {1}); | ||||
| has 'enable_wipe'        => (is => 'rw', default => sub {0});   # at least one extruder has wipe enabled | ||||
| has 'enable_cooling_markers' => (is =>'rw', default => sub {0}); | ||||
| has 'layer_count'        => (is => 'ro'); | ||||
| has '_layer_index'       => (is => 'rw', default => sub {-1});  # just a counter | ||||
|  | @ -27,14 +28,9 @@ has 'layer'              => (is => 'rw'); | |||
| has '_layer_islands'     => (is => 'rw'); | ||||
| has '_upper_layer_islands'  => (is => 'rw'); | ||||
| has '_seam_position'     => (is => 'ro', default => sub { {} });  # $object => pos | ||||
| has '_external_mp'       => (is => 'rw'); | ||||
| has '_layer_mp'          => (is => 'rw'); | ||||
| has 'new_object'         => (is => 'rw', default => sub {0});   # this flag triggers the use of the external configuration space for avoid_crossing_perimeters for the next travel move | ||||
| has 'straight_once'      => (is => 'rw', default => sub {1});   # this flag disables avoid_crossing_perimeters just for the next travel move | ||||
| has 'first_layer'        => (is => 'rw', default => sub {0});   # this flag triggers first layer speeds | ||||
| has 'elapsed_time'       => (is => 'rw', default => sub {0} );  # seconds | ||||
| has 'last_pos'           => (is => 'rw', default => sub { Slic3r::Point->new(0,0) } ); | ||||
| has '_wipe_path'         => (is => 'rw'); | ||||
| 
 | ||||
| sub apply_print_config { | ||||
|     my ($self, $print_config) = @_; | ||||
|  | @ -49,7 +45,7 @@ sub set_extruders { | |||
|     $self->writer->set_extruders($extruder_ids); | ||||
|      | ||||
|     # enable wipe path generation if any extruder has wipe enabled | ||||
|     $self->enable_wipe(defined first { $self->config->get_at('wipe', $_) } @$extruder_ids); | ||||
|     $self->wipe->enable(defined first { $self->config->get_at('wipe', $_) } @$extruder_ids); | ||||
| } | ||||
| 
 | ||||
| sub set_origin { | ||||
|  | @ -61,16 +57,11 @@ sub set_origin { | |||
|         scale ($self->origin->y - $pointf->y),  #- | ||||
|     ); | ||||
|     $self->last_pos->translate(@translate); | ||||
|     $self->_wipe_path->translate(@translate) if $self->_wipe_path; | ||||
|     $self->wipe->path->translate(@translate) if $self->wipe->path; | ||||
|      | ||||
|     $self->origin($pointf); | ||||
| } | ||||
| 
 | ||||
| sub init_external_mp { | ||||
|     my ($self, $islands) = @_; | ||||
|     $self->_external_mp(Slic3r::MotionPlanner->new($islands)); | ||||
| } | ||||
| 
 | ||||
| sub preamble { | ||||
|     my ($self) = @_; | ||||
|      | ||||
|  | @ -96,9 +87,9 @@ sub change_layer { | |||
|     $self->_layer_islands($layer->islands); | ||||
|     $self->_upper_layer_islands($layer->upper_layer ? $layer->upper_layer->islands : []); | ||||
|     if ($self->config->avoid_crossing_perimeters) { | ||||
|         $self->_layer_mp(Slic3r::MotionPlanner->new( | ||||
|         $self->avoid_crossing_perimeters->init_layer_mp( | ||||
|             union_ex([ map @$_, @{$layer->slices} ], 1), | ||||
|         )); | ||||
|         ); | ||||
|     } | ||||
|      | ||||
|     my $gcode = ""; | ||||
|  | @ -213,7 +204,7 @@ sub extrude_loop { | |||
|     # reset acceleration | ||||
|     $gcode .= $self->writer->set_acceleration($self->config->default_acceleration); | ||||
|      | ||||
|     $self->_wipe_path($paths[0]->polyline->clone) if $self->enable_wipe;  # TODO: don't limit wipe to last path | ||||
|     $self->wipe->path($paths[0]->polyline->clone) if $self->wipe->enable;  # TODO: don't limit wipe to last path | ||||
|      | ||||
|     # make a little move inwards before leaving loop | ||||
|     if ($paths[-1]->role == EXTR_ROLE_EXTERNAL_PERIMETER && defined $self->layer && $self->config->perimeters > 1) { | ||||
|  | @ -324,9 +315,9 @@ sub _extrude_path { | |||
|             $self->writer->extrusion_axis, | ||||
|             $self->config->gcode_comments ? " ; $description" : ""); | ||||
| 
 | ||||
|         if ($self->enable_wipe) { | ||||
|             $self->_wipe_path($path->polyline->clone); | ||||
|             $self->_wipe_path->reverse; | ||||
|         if ($self->wipe->enable) { | ||||
|             $self->wipe->path($path->polyline->clone); | ||||
|             $self->wipe->path->reverse; | ||||
|         } | ||||
|     } | ||||
|     $gcode .= ";_BRIDGE_FAN_END\n" if $path->is_bridge && $self->enable_cooling_markers; | ||||
|  | @ -366,25 +357,8 @@ sub travel_to { | |||
|         ) { | ||||
|         # Just perform a straight travel move without any retraction. | ||||
|         $gcode .= $self->writer->travel_to_xy($self->point_to_gcode($point), $comment); | ||||
|     } elsif ($self->config->avoid_crossing_perimeters && !$self->straight_once) { | ||||
|         # If avoid_crossing_perimeters is enabled and the straight_once flag is not set | ||||
|         # we need to plan a multi-segment travel move inside the configuration space. | ||||
|         if ($self->new_object) { | ||||
|             # If we're moving to a new object we need to use the external configuration space. | ||||
|             $self->new_object(0); | ||||
|              | ||||
|             # represent $point in G-code coordinates | ||||
|             $point = $point->clone; | ||||
|             my $origin = $self->origin; | ||||
|             $point->translate(map scale $_, @$origin); | ||||
|              | ||||
|             # calculate path (external_mp uses G-code coordinates so we set a temporary null origin) | ||||
|             $self->set_origin(Slic3r::Pointf->new(0,0)); | ||||
|             $gcode .= $self->_plan($self->_external_mp, $point, $comment); | ||||
|             $self->set_origin($origin); | ||||
|         } else { | ||||
|             $gcode .= $self->_plan($self->_layer_mp, $point, $comment); | ||||
|         } | ||||
|     } elsif ($self->config->avoid_crossing_perimeters && !$self->avoid_crossing_perimeters->straight_once) { | ||||
|         $gcode .= $self->avoid_crossing_perimeters->travel_to($self, $point, $comment); | ||||
|     } else { | ||||
|         # If avoid_crossing_perimeters is disabled or the straight_once flag is set, | ||||
|         # perform a straight move with a retraction. | ||||
|  | @ -393,41 +367,11 @@ sub travel_to { | |||
|     } | ||||
|      | ||||
|     # Re-allow avoid_crossing_perimeters for the next travel moves | ||||
|     $self->straight_once(0); | ||||
|     $self->avoid_crossing_perimeters->straight_once(0); | ||||
|      | ||||
|     return $gcode; | ||||
| } | ||||
| 
 | ||||
| sub _plan { | ||||
|     my ($self, $mp, $point, $comment) = @_; | ||||
|      | ||||
|     my $gcode = ""; | ||||
|     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 = !$self->config->only_retract_when_crossing_perimeters; | ||||
|     if (!$need_retract) { | ||||
|         $need_retract = 1; | ||||
|         foreach my $island (@{$self->_upper_layer_islands}) { | ||||
|             # discard the island if at any line is not enclosed in it | ||||
|             next if first { !$island->contains_line($_) } @travel; | ||||
|             # okay, this island encloses the full travel path | ||||
|             $need_retract = 0; | ||||
|             last; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     # 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->writer->travel_to_xy($self->point_to_gcode($_->b), $comment), | ||||
|         @travel; | ||||
|     return $gcode; | ||||
| } | ||||
| 
 | ||||
| sub retract { | ||||
|     my ($self, $toolchange) = @_; | ||||
|      | ||||
|  | @ -436,48 +380,8 @@ sub retract { | |||
|     my $gcode = ""; | ||||
|      | ||||
|     # wipe (if it's enabled for this extruder and we have a stored wipe path) | ||||
|     if ($self->config->get_at('wipe', $self->writer->extruder->id) && $self->_wipe_path) { | ||||
|         # 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->writer->config->get('travel_speed') * 0.8; | ||||
|          | ||||
|         # get the retraction length | ||||
|         my $length = $toolchange | ||||
|             ? $self->writer->extruder->retract_length_toolchange | ||||
|             : $self->writer->extruder->retract_length; | ||||
|          | ||||
|         if ($length) { | ||||
|             # 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->writer->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 (TODO: test and/or better math for this) | ||||
|                 my $dE = $length * ($segment_length / $wipe_dist) * 0.95; | ||||
|                 $gcode .= $self->writer->set_speed($wipe_speed*60); | ||||
|                 $gcode .= $self->writer->extrude_to_xy( | ||||
|                     $self->point_to_gcode($line->b), | ||||
|                     -$dE, | ||||
|                     'retract' . ($self->enable_cooling_markers ? ';_WIPE' : ''), | ||||
|                 ); | ||||
|                 $retracted += $dE; | ||||
|             } | ||||
|             $self->writer->extruder->set_retracted($self->writer->extruder->retracted + $retracted); | ||||
|         } | ||||
|     if ($self->config->get_at('wipe', $self->writer->extruder->id) && $self->wipe->path) { | ||||
|         $gcode .= $self->wipe->wipe($self, $toolchange); | ||||
|     } | ||||
|      | ||||
|     # The parent class will decide whether we need to perform an actual retraction | ||||
|  | @ -537,14 +441,196 @@ sub set_extruder { | |||
|     # if ooze prevention is enabled, park current extruder in the nearest | ||||
|     # standby point and set it to the standby temperature | ||||
|     $gcode .= $self->ooze_prevention->pre_toolchange($self) | ||||
|         if $self->ooze_prevention && defined $self->writer->extruder; | ||||
|         if $self->ooze_prevention->enable && defined $self->writer->extruder; | ||||
|      | ||||
|     # append the toolchange command | ||||
|     $gcode .= $self->writer->toolchange($extruder_id); | ||||
|      | ||||
|     # set the new extruder to the operating temperature | ||||
|     $gcode .= $self->ooze_prevention->post_toolchange($self) | ||||
|         if $self->ooze_prevention; | ||||
|         if $self->ooze_prevention->enable; | ||||
|      | ||||
|     return $gcode; | ||||
| } | ||||
| 
 | ||||
| package Slic3r::GCode::OozePrevention; | ||||
| use Moo; | ||||
| 
 | ||||
| use Slic3r::Geometry qw(scale); | ||||
| 
 | ||||
| has 'enable'            => (is => 'rw', default => sub { 0 }); | ||||
| has 'standby_points'    => (is => 'rw'); | ||||
| 
 | ||||
| sub pre_toolchange { | ||||
|     my ($self, $gcodegen) = @_; | ||||
|      | ||||
|     my $gcode = ""; | ||||
|      | ||||
|     # move to the nearest standby point | ||||
|     if (@{$self->standby_points}) { | ||||
|         my $last_pos = $gcodegen->last_pos->clone; | ||||
|         $last_pos->translate(scale +$gcodegen->origin->x, scale +$gcodegen->origin->y);  #)) | ||||
|         my $standby_point = $last_pos->nearest_point($self->standby_points); | ||||
|         $standby_point->translate(scale -$gcodegen->origin->x, scale -$gcodegen->origin->y);  #)) | ||||
|         $gcode .= $gcodegen->travel_to($standby_point); | ||||
|     } | ||||
|      | ||||
|     if ($gcodegen->config->standby_temperature_delta != 0) { | ||||
|         my $temp = defined $gcodegen->layer && $gcodegen->layer->id == 0 | ||||
|             ? $gcodegen->config->get_at('first_layer_temperature', $gcodegen->writer->extruder->id) | ||||
|             : $gcodegen->config->get_at('temperature', $gcodegen->writer->extruder->id); | ||||
|         # we assume that heating is always slower than cooling, so no need to block | ||||
|         $gcode .= $gcodegen->writer->set_temperature($temp + $gcodegen->config->standby_temperature_delta, 0); | ||||
|     } | ||||
|      | ||||
|     return $gcode; | ||||
| } | ||||
| 
 | ||||
| sub post_toolchange { | ||||
|     my ($self, $gcodegen) = @_; | ||||
|      | ||||
|     my $gcode = ""; | ||||
|      | ||||
|     if ($gcodegen->config->standby_temperature_delta != 0) { | ||||
|         my $temp = defined $gcodegen->layer && $gcodegen->layer->id == 0 | ||||
|             ? $gcodegen->config->get_at('first_layer_temperature', $gcodegen->writer->extruder->id) | ||||
|             : $gcodegen->config->get_at('temperature', $gcodegen->writer->extruder->id); | ||||
|         $gcode .= $gcodegen->writer->set_temperature($temp, 1); | ||||
|     } | ||||
|      | ||||
|     return $gcode; | ||||
| } | ||||
| 
 | ||||
| package Slic3r::GCode::Wipe; | ||||
| use Moo; | ||||
| 
 | ||||
| use Slic3r::Geometry qw(scale); | ||||
| 
 | ||||
| has 'enable'            => (is => 'rw', default => sub { 0 }); | ||||
| has 'path'              => (is => 'rw'); | ||||
| 
 | ||||
| sub wipe { | ||||
|     my ($self, $gcodegen, $toolchange) = @_; | ||||
|      | ||||
|     my $gcode = ""; | ||||
|      | ||||
|     # 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 = $gcodegen->writer->config->get('travel_speed') * 0.8; | ||||
|      | ||||
|     # get the retraction length | ||||
|     my $length = $toolchange | ||||
|         ? $gcodegen->writer->extruder->retract_length_toolchange | ||||
|         : $gcodegen->writer->extruder->retract_length; | ||||
|      | ||||
|     if ($length) { | ||||
|         # 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 / $gcodegen->writer->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( | ||||
|             $gcodegen->last_pos, | ||||
|             @{$self->path}[1..$#{$self->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 (TODO: test and/or better math for this) | ||||
|             my $dE = $length * ($segment_length / $wipe_dist) * 0.95; | ||||
|             $gcode .= $gcodegen->writer->set_speed($wipe_speed*60); | ||||
|             $gcode .= $gcodegen->writer->extrude_to_xy( | ||||
|                 $gcodegen->point_to_gcode($line->b), | ||||
|                 -$dE, | ||||
|                 'retract' . ($gcodegen->enable_cooling_markers ? ';_WIPE' : ''), | ||||
|             ); | ||||
|             $retracted += $dE; | ||||
|         } | ||||
|         $gcodegen->writer->extruder->set_retracted($gcodegen->writer->extruder->retracted + $retracted); | ||||
|     } | ||||
|      | ||||
|     return $gcode; | ||||
| } | ||||
| 
 | ||||
| package Slic3r::GCode::AvoidCrossingPerimeters; | ||||
| use Moo; | ||||
| 
 | ||||
| has '_external_mp'       => (is => 'rw'); | ||||
| has '_layer_mp'          => (is => 'rw'); | ||||
| has 'new_object'         => (is => 'rw', default => sub {0});   # this flag triggers the use of the external configuration space for avoid_crossing_perimeters for the next travel move | ||||
| has 'straight_once'      => (is => 'rw', default => sub {1});   # this flag disables avoid_crossing_perimeters just for the next travel move | ||||
| 
 | ||||
| sub init_external_mp { | ||||
|     my ($self, $islands) = @_; | ||||
|     $self->_external_mp(Slic3r::MotionPlanner->new($islands)); | ||||
| } | ||||
| 
 | ||||
| sub init_layer_mp { | ||||
|     my ($self, $islands) = @_; | ||||
|     $self->_layer_mp(Slic3r::MotionPlanner->new($islands)); | ||||
| } | ||||
| 
 | ||||
| sub travel_to { | ||||
|     my ($self, $gcodegen, $point, $comment) = @_; | ||||
|      | ||||
|     my $gcode = ""; | ||||
|      | ||||
|     # If avoid_crossing_perimeters is enabled and the straight_once flag is not set | ||||
|     # we need to plan a multi-segment travel move inside the configuration space. | ||||
|     if ($self->new_object) { | ||||
|         # If we're moving to a new object we need to use the external configuration space. | ||||
|         $self->new_object(0); | ||||
|          | ||||
|         # represent $point in G-code coordinates | ||||
|         $point = $point->clone; | ||||
|         my $origin = $gcodegen->origin; | ||||
|         $point->translate(map scale $_, @$origin); | ||||
|          | ||||
|         # calculate path (external_mp uses G-code coordinates so we set a temporary null origin) | ||||
|         $gcodegen->set_origin(Slic3r::Pointf->new(0,0)); | ||||
|         $gcode .= $self->_plan($gcodegen, $self->_external_mp, $point, $comment); | ||||
|         $gcodegen->set_origin($origin); | ||||
|     } else { | ||||
|         $gcode .= $self->_plan($gcodegen, $self->_layer_mp, $point, $comment); | ||||
|     } | ||||
|      | ||||
|     return $gcode; | ||||
| } | ||||
| 
 | ||||
| sub _plan { | ||||
|     my ($self, $gcodegen, $mp, $point, $comment) = @_; | ||||
|      | ||||
|     my $gcode = ""; | ||||
|     my @travel = @{$mp->shortest_path($gcodegen->last_pos, $point)->lines}; | ||||
|      | ||||
|     # if the path is not contained in a single island we need to retract | ||||
|     my $need_retract = !$gcodegen->config->only_retract_when_crossing_perimeters; | ||||
|     if (!$need_retract) { | ||||
|         $need_retract = 1; | ||||
|         foreach my $island (@{$gcodegen->_upper_layer_islands}) { | ||||
|             # discard the island if at any line is not enclosed in it | ||||
|             next if first { !$island->contains_line($_) } @travel; | ||||
|             # okay, this island encloses the full travel path | ||||
|             $need_retract = 0; | ||||
|             last; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     # perform the retraction | ||||
|     $gcode .= $gcodegen->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 $gcodegen->writer->travel_to_xy($self->point_to_gcode($_->b), $comment), | ||||
|         @travel; | ||||
|      | ||||
|     return $gcode; | ||||
| } | ||||
|  |  | |||
|  | @ -100,7 +100,7 @@ sub process_layer { | |||
|             } | ||||
|         } | ||||
|         $self->skirt_done->{$layer->print_z} = 1; | ||||
|         $self->gcodegen->straight_once(1); | ||||
|         $self->gcodegen->avoid_crossing_perimeters->straight_once(1); | ||||
|     } | ||||
|      | ||||
|     # extrude brim | ||||
|  | @ -110,11 +110,11 @@ sub process_layer { | |||
|         $gcode .= $self->gcodegen->extrude_loop($_, 'brim', $object->config->support_material_speed) | ||||
|             for @{$self->print->brim}; | ||||
|         $self->brim_done(1); | ||||
|         $self->gcodegen->straight_once(1); | ||||
|         $self->gcodegen->avoid_crossing_perimeters->straight_once(1); | ||||
|     } | ||||
|      | ||||
|     for my $copy (@$object_copies) { | ||||
|         $self->gcodegen->new_object(1) if ($self->_last_obj_copy // '') ne "$copy"; | ||||
|         $self->gcodegen->avoid_crossing_perimeters->new_object(1) if ($self->_last_obj_copy // '') ne "$copy"; | ||||
|         $self->_last_obj_copy("$copy"); | ||||
|          | ||||
|         $self->gcodegen->set_origin(Slic3r::Pointf->new(map $self->origin->[$_] + unscale $copy->[$_], X,Y)); | ||||
|  |  | |||
|  | @ -1,48 +0,0 @@ | |||
| package Slic3r::GCode::OozePrevention; | ||||
| use Moo; | ||||
| 
 | ||||
| use Slic3r::Geometry qw(scale); | ||||
| 
 | ||||
| has 'standby_points'    => (is => 'rw', required => 1); | ||||
| 
 | ||||
| sub pre_toolchange { | ||||
|     my ($self, $gcodegen) = @_; | ||||
|      | ||||
|     my $gcode = ""; | ||||
|      | ||||
|     # move to the nearest standby point | ||||
|     if (@{$self->standby_points}) { | ||||
|         my $last_pos = $gcodegen->last_pos->clone; | ||||
|         $last_pos->translate(scale +$gcodegen->origin->x, scale +$gcodegen->origin->y);  #)) | ||||
|         my $standby_point = $last_pos->nearest_point($self->standby_points); | ||||
|         $standby_point->translate(scale -$gcodegen->origin->x, scale -$gcodegen->origin->y);  #)) | ||||
|         $gcode .= $gcodegen->travel_to($standby_point); | ||||
|     } | ||||
|      | ||||
|     if ($gcodegen->config->standby_temperature_delta != 0) { | ||||
|         my $temp = defined $gcodegen->layer && $gcodegen->layer->id == 0 | ||||
|             ? $gcodegen->config->get_at('first_layer_temperature', $gcodegen->writer->extruder->id) | ||||
|             : $gcodegen->config->get_at('temperature', $gcodegen->writer->extruder->id); | ||||
|         # we assume that heating is always slower than cooling, so no need to block | ||||
|         $gcode .= $gcodegen->writer->set_temperature($temp + $gcodegen->config->standby_temperature_delta, 0); | ||||
|     } | ||||
|      | ||||
|     return $gcode; | ||||
| } | ||||
| 
 | ||||
| sub post_toolchange { | ||||
|     my ($self, $gcodegen) = @_; | ||||
|      | ||||
|     my $gcode = ""; | ||||
|      | ||||
|     if ($gcodegen->config->standby_temperature_delta != 0) { | ||||
|         my $temp = defined $gcodegen->layer && $gcodegen->layer->id == 0 | ||||
|             ? $gcodegen->config->get_at('first_layer_temperature', $gcodegen->writer->extruder->id) | ||||
|             : $gcodegen->config->get_at('temperature', $gcodegen->writer->extruder->id); | ||||
|         $gcode .= $gcodegen->writer->set_temperature($temp, 1); | ||||
|     } | ||||
|      | ||||
|     return $gcode; | ||||
| } | ||||
| 
 | ||||
| 1; | ||||
|  | @ -552,7 +552,7 @@ sub write_gcode { | |||
|                 } | ||||
|             } | ||||
|         } | ||||
|         $gcodegen->init_external_mp(union_ex([ map @$_, @islands ])); | ||||
|         $gcodegen->avoid_crossing_perimeters->init_external_mp(union_ex([ map @$_, @islands ])); | ||||
|     } | ||||
|      | ||||
|     # calculate wiping points if needed | ||||
|  | @ -567,10 +567,10 @@ sub write_gcode { | |||
|             } | ||||
|             my $convex_hull = convex_hull([ map @$_, @skirts ]); | ||||
|              | ||||
|             my $oozeprev = Slic3r::GCode::OozePrevention->new( | ||||
|                 standby_points => [ map $_->clone, map @$_, map $_->subdivide(scale 10), @{offset([$convex_hull], scale 3)} ], | ||||
|             $gcodegen->ooze_prevention->enable(1); | ||||
|             $gcodegen->ooze_prevention->standby_points( | ||||
|                 [ map $_->clone, map @$_, map $_->subdivide(scale 10), @{offset([$convex_hull], scale 3)} ] | ||||
|             ); | ||||
|             $gcodegen->ooze_prevention($oozeprev); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci