mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 12:41:20 -06:00 
			
		
		
		
	Avoid closures, move planning code to _plan() and layer G-code generation to Slic3r::GCode::Layer
This commit is contained in:
		
							parent
							
								
									08a0bbd7f0
								
							
						
					
					
						commit
						f599ed00c6
					
				
					 5 changed files with 246 additions and 210 deletions
				
			
		
							
								
								
									
										1
									
								
								MANIFEST
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								MANIFEST
									
										
									
									
									
								
							|  | @ -25,6 +25,7 @@ lib/Slic3r/Format/OBJ.pm | ||||||
| lib/Slic3r/Format/STL.pm | lib/Slic3r/Format/STL.pm | ||||||
| lib/Slic3r/GCode.pm | lib/Slic3r/GCode.pm | ||||||
| lib/Slic3r/GCode/CoolingBuffer.pm | lib/Slic3r/GCode/CoolingBuffer.pm | ||||||
|  | lib/Slic3r/GCode/Layer.pm | ||||||
| lib/Slic3r/GCode/MotionPlanner.pm | lib/Slic3r/GCode/MotionPlanner.pm | ||||||
| lib/Slic3r/GCode/Reader.pm | lib/Slic3r/GCode/Reader.pm | ||||||
| lib/Slic3r/GCode/SpiralVase.pm | lib/Slic3r/GCode/SpiralVase.pm | ||||||
|  |  | ||||||
|  | @ -46,6 +46,7 @@ use Slic3r::Format::OBJ; | ||||||
| use Slic3r::Format::STL; | use Slic3r::Format::STL; | ||||||
| use Slic3r::GCode; | use Slic3r::GCode; | ||||||
| use Slic3r::GCode::CoolingBuffer; | use Slic3r::GCode::CoolingBuffer; | ||||||
|  | use Slic3r::GCode::Layer; | ||||||
| use Slic3r::GCode::MotionPlanner; | use Slic3r::GCode::MotionPlanner; | ||||||
| use Slic3r::GCode::Reader; | use Slic3r::GCode::Reader; | ||||||
| use Slic3r::GCode::SpiralVase; | use Slic3r::GCode::SpiralVase; | ||||||
|  |  | ||||||
|  | @ -294,34 +294,6 @@ sub travel_to { | ||||||
|         $self->speed('travel'); |         $self->speed('travel'); | ||||||
|         $gcode .= $self->G0($point, undef, 0, $comment || ""); |         $gcode .= $self->G0($point, undef, 0, $comment || ""); | ||||||
|     } else { |     } else { | ||||||
|         my $plan = sub { |  | ||||||
|             my $mp = shift; |  | ||||||
|              |  | ||||||
|             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 = !$Slic3r::Config->only_retract_when_crossing_perimeters; |  | ||||||
|             if (!$need_retract) { |  | ||||||
|                 $need_retract = 1; |  | ||||||
|                 foreach my $slice (@{$self->layer->slices}) { |  | ||||||
|                     # discard the island if at any line is not enclosed in it |  | ||||||
|                     next if first { !$slice->encloses_line($_, scaled_epsilon) } @travel; |  | ||||||
|                     # okay, this island encloses the full travel path |  | ||||||
|                     $need_retract = 0; |  | ||||||
|                     last; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|              |  | ||||||
|             # do the retract (the travel_to argument is broken) |  | ||||||
|             $gcode .= $self->retract(travel_to => $point) if $need_retract; |  | ||||||
|              |  | ||||||
|             # append the actual path and return |  | ||||||
|             $self->speed('travel'); |  | ||||||
|             $gcode .= join '', map $self->G0($_->[B], undef, 0, $comment || ""), @travel; |  | ||||||
|             return $gcode; |  | ||||||
|         }; |  | ||||||
|          |  | ||||||
|         if ($self->new_object) { |         if ($self->new_object) { | ||||||
|             $self->new_object(0); |             $self->new_object(0); | ||||||
|              |              | ||||||
|  | @ -332,16 +304,45 @@ sub travel_to { | ||||||
|              |              | ||||||
|             # calculate path (external_mp uses G-code coordinates so we temporary need a null shift) |             # calculate path (external_mp uses G-code coordinates so we temporary need a null shift) | ||||||
|             $self->set_shift(0,0); |             $self->set_shift(0,0); | ||||||
|             $gcode .= $plan->($self->external_mp); |             $gcode .= $self->_plan($self->external_mp, $point, $comment); | ||||||
|             $self->set_shift(@shift); |             $self->set_shift(@shift); | ||||||
|         } else { |         } else { | ||||||
|             $gcode .= $plan->($self->layer_mp); |             $gcode .= $self->_plan($self->layer_mp, $point, $comment); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     return $gcode; |     return $gcode; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | sub _plan { | ||||||
|  |     my $self = shift; | ||||||
|  |     my ($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 = !$Slic3r::Config->only_retract_when_crossing_perimeters; | ||||||
|  |     if (!$need_retract) { | ||||||
|  |         $need_retract = 1; | ||||||
|  |         foreach my $slice (@{$self->layer->slices}) { | ||||||
|  |             # discard the island if at any line is not enclosed in it | ||||||
|  |             next if first { !$slice->encloses_line($_, scaled_epsilon) } @travel; | ||||||
|  |             # okay, this island encloses the full travel path | ||||||
|  |             $need_retract = 0; | ||||||
|  |             last; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     # do the retract (the travel_to argument is broken) | ||||||
|  |     $gcode .= $self->retract(travel_to => $point) if $need_retract; | ||||||
|  |      | ||||||
|  |     # append the actual path and return | ||||||
|  |     $self->speed('travel'); | ||||||
|  |     $gcode .= join '', map $self->G0($_->[B], undef, 0, $comment || ""), @travel; | ||||||
|  |     return $gcode; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| sub retract { | sub retract { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|     my %params = @_; |     my %params = @_; | ||||||
|  |  | ||||||
							
								
								
									
										202
									
								
								lib/Slic3r/GCode/Layer.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								lib/Slic3r/GCode/Layer.pm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,202 @@ | ||||||
|  | package Slic3r::GCode::Layer; | ||||||
|  | use Moo; | ||||||
|  | 
 | ||||||
|  | use Slic3r::Geometry qw(X Y unscale); | ||||||
|  | 
 | ||||||
|  | has 'print'                         => (is => 'ro', required => 1, handles => [qw(extruders)]); | ||||||
|  | has 'gcodegen'                      => (is => 'ro', required => 1); | ||||||
|  | has 'shift'                         => (is => 'ro', required => 1); | ||||||
|  | 
 | ||||||
|  | has 'spiralvase'                    => (is => 'lazy'); | ||||||
|  | has 'skirt_done'                    => (is => 'rw', default => sub {0});  # count of skirt layers done | ||||||
|  | has 'brim_done'                     => (is => 'rw'); | ||||||
|  | has 'second_layer_things_done'      => (is => 'rw'); | ||||||
|  | has '_last_obj_copy'                => (is => 'rw'); | ||||||
|  | 
 | ||||||
|  | sub _build_spiralvase { | ||||||
|  |     my $self = shift; | ||||||
|  |      | ||||||
|  |     return $Slic3r::Config->spiral_vase | ||||||
|  |         ? Slic3r::GCode::SpiralVase->new | ||||||
|  |         : undef; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | sub process_layer { | ||||||
|  |     my $self = shift; | ||||||
|  |     my ($layer, $object_copies) = @_; | ||||||
|  |     my $gcode = ""; | ||||||
|  |      | ||||||
|  |     if (!$self->second_layer_things_done && $layer->id == 1) { | ||||||
|  |         for my $t (grep $self->extruders->[$_], 0 .. $#{$Slic3r::Config->temperature}) { | ||||||
|  |             $gcode .= $self->gcodegen->set_temperature($self->extruders->[$t]->temperature, 0, $t) | ||||||
|  |                 if $self->print->extruders->[$t]->temperature && $self->extruders->[$t]->temperature != $self->extruders->[$t]->first_layer_temperature; | ||||||
|  |         } | ||||||
|  |         $gcode .= $self->gcodegen->set_bed_temperature($Slic3r::Config->bed_temperature) | ||||||
|  |             if $Slic3r::Config->bed_temperature && $Slic3r::Config->bed_temperature != $Slic3r::Config->first_layer_bed_temperature; | ||||||
|  |         $self->second_layer_things_done(1); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     # set new layer, but don't move Z as support material contact areas may need an intermediate one | ||||||
|  |     $gcode .= $self->gcodegen->change_layer($layer); | ||||||
|  |      | ||||||
|  |     # prepare callback to call as soon as a Z command is generated | ||||||
|  |     $self->gcodegen->move_z_callback(sub { | ||||||
|  |         $self->gcodegen->move_z_callback(undef);  # circular ref or not? | ||||||
|  |         return "" if !$Slic3r::Config->layer_gcode; | ||||||
|  |         return $Slic3r::Config->replace_options($Slic3r::Config->layer_gcode) . "\n"; | ||||||
|  |     }); | ||||||
|  |      | ||||||
|  |     # extrude skirt | ||||||
|  |     if ($self->skirt_done < $Slic3r::Config->skirt_height) { | ||||||
|  |         $self->gcodegen->set_shift(@{$self->shift}); | ||||||
|  |         $gcode .= $self->gcodegen->set_extruder($self->extruders->[0]);  # move_z requires extruder | ||||||
|  |         $gcode .= $self->gcodegen->move_z($self->gcodegen->layer->print_z); | ||||||
|  |         # skip skirt if we have a large brim | ||||||
|  |         if ($layer->id < $Slic3r::Config->skirt_height) { | ||||||
|  |             # distribute skirt loops across all extruders | ||||||
|  |             for my $i (0 .. $#{$self->print->skirt}) { | ||||||
|  |                 # when printing layers > 0 ignore 'min_skirt_length' and  | ||||||
|  |                 # just use the 'skirts' setting; also just use the current extruder | ||||||
|  |                 last if ($layer->id > 0) && ($i >= $Slic3r::Config->skirts); | ||||||
|  |                 $gcode .= $self->gcodegen->set_extruder($self->extruders->[ ($i/@{$self->extruders}) % @{$self->extruders} ]) | ||||||
|  |                     if $layer->id == 0; | ||||||
|  |                 $gcode .= $self->gcodegen->extrude_loop($self->print->skirt->[$i], 'skirt'); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         $self->skirt_done($self->skirt_done + 1); | ||||||
|  |         $self->gcodegen->straight_once(1); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     # extrude brim | ||||||
|  |     if (!$self->brim_done) { | ||||||
|  |         $gcode .= $self->gcodegen->set_extruder($self->extruders->[$Slic3r::Config->support_material_extruder-1]);  # move_z requires extruder | ||||||
|  |         $gcode .= $self->gcodegen->move_z($self->gcodegen->layer->print_z); | ||||||
|  |         $self->gcodegen->set_shift(@{$self->shift}); | ||||||
|  |         $gcode .= $self->gcodegen->extrude_loop($_, 'brim') for @{$self->print->brim}; | ||||||
|  |         $self->brim_done(1); | ||||||
|  |         $self->gcodegen->straight_once(1); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     for my $copy (@$object_copies) { | ||||||
|  |         $self->gcodegen->new_object(1) if ($self->_last_obj_copy // '') ne "$copy"; | ||||||
|  |         $self->_last_obj_copy("$copy"); | ||||||
|  |          | ||||||
|  |         $self->gcodegen->set_shift(map $self->shift->[$_] + unscale $copy->[$_], X,Y); | ||||||
|  |          | ||||||
|  |         # extrude support material before other things because it might use a lower Z | ||||||
|  |         # and also because we avoid travelling on other things when printing it | ||||||
|  |         if ($self->print->has_support_material) { | ||||||
|  |             $gcode .= $self->gcodegen->move_z($layer->support_material_contact_z) | ||||||
|  |                 if ($layer->support_contact_fills && @{ $layer->support_contact_fills->paths }); | ||||||
|  |             $gcode .= $self->gcodegen->set_extruder($self->extruders->[$Slic3r::Config->support_material_extruder-1]); | ||||||
|  |             if ($layer->support_contact_fills) { | ||||||
|  |                 $gcode .= $self->gcodegen->extrude_path($_, 'support material contact area')  | ||||||
|  |                     for $layer->support_contact_fills->chained_path($self->gcodegen->last_pos);  | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             $gcode .= $self->gcodegen->move_z($layer->print_z); | ||||||
|  |             if ($layer->support_fills) { | ||||||
|  |                 $gcode .= $self->gcodegen->extrude_path($_, 'support material')  | ||||||
|  |                     for $layer->support_fills->chained_path($self->gcodegen->last_pos); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         # set actual Z - this will force a retraction | ||||||
|  |         $gcode .= $self->gcodegen->move_z($layer->print_z); | ||||||
|  |          | ||||||
|  |         # tweak region ordering to save toolchanges | ||||||
|  |         my @region_ids = 0 .. ($self->print->regions_count-1); | ||||||
|  |         if ($self->gcodegen->multiple_extruders) { | ||||||
|  |             my $last_extruder = $self->gcodegen->extruder; | ||||||
|  |             my $best_region_id = first { $self->print->regions->[$_]->extruders->{perimeter} eq $last_extruder } @region_ids; | ||||||
|  |             @region_ids = ($best_region_id, grep $_ != $best_region_id, @region_ids) if $best_region_id; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         foreach my $region_id (@region_ids) { | ||||||
|  |             my $layerm = $layer->regions->[$region_id]; | ||||||
|  |             my $region = $self->print->regions->[$region_id]; | ||||||
|  |              | ||||||
|  |             my @islands = (); | ||||||
|  |             if ($Slic3r::Config->avoid_crossing_perimeters) { | ||||||
|  |                 push @islands, map +{ perimeters => [], fills => [] }, @{$layer->slices}; | ||||||
|  |                 PERIMETER: foreach my $perimeter (@{$layerm->perimeters}) { | ||||||
|  |                     my $p = $perimeter->unpack; | ||||||
|  |                     for my $i (0 .. $#{$layer->slices}-1) { | ||||||
|  |                         if ($layer->slices->[$i]->contour->encloses_point($p->first_point)) { | ||||||
|  |                             push @{ $islands[$i]{perimeters} }, $p; | ||||||
|  |                             next PERIMETER; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     push @{ $islands[-1]{perimeters} }, $p; # optimization | ||||||
|  |                 } | ||||||
|  |                 FILL: foreach my $fill (@{$layerm->fills}) { | ||||||
|  |                     my $f = $fill->unpack; | ||||||
|  |                     for my $i (0 .. $#{$layer->slices}-1) { | ||||||
|  |                         if ($layer->slices->[$i]->contour->encloses_point($f->first_point)) { | ||||||
|  |                             push @{ $islands[$i]{fills} }, $f; | ||||||
|  |                             next FILL; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     push @{ $islands[-1]{fills} }, $f; # optimization | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 push @islands, { | ||||||
|  |                     perimeters  => $layerm->perimeters, | ||||||
|  |                     fills       => $layerm->fills, | ||||||
|  |                 }; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             foreach my $island (@islands) { | ||||||
|  |                 # give priority to infill if we were already using its extruder and it wouldn't | ||||||
|  |                 # be good for perimeters | ||||||
|  |                 if ($Slic3r::Config->infill_first | ||||||
|  |                     || ($self->gcodegen->multiple_extruders && $region->extruders->{infill} eq $self->gcodegen->extruder) && $region->extruders->{infill} ne $region->extruders->{perimeter}) { | ||||||
|  |                     $gcode .= $self->_extrude_infill($island, $region); | ||||||
|  |                     $gcode .= $self->_extrude_perimeters($island, $region); | ||||||
|  |                 } else { | ||||||
|  |                     $gcode .= $self->_extrude_perimeters($island, $region); | ||||||
|  |                     $gcode .= $self->_extrude_infill($island, $region); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     # apply spiral vase post-processing if this layer contains suitable geometry | ||||||
|  |     $gcode = $self->spiralvase->process_layer($gcode, $layer) | ||||||
|  |         if defined $self->spiralvase | ||||||
|  |         && ($layer->id > 0 || $Slic3r::Config->brim_width == 0) | ||||||
|  |         && ($layer->id >= $Slic3r::Config->skirt_height) | ||||||
|  |         && ($layer->id >= $Slic3r::Config->bottom_solid_layers); | ||||||
|  |      | ||||||
|  |     return $gcode; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | sub _extrude_perimeters { | ||||||
|  |     my $self = shift; | ||||||
|  |     my ($island, $region) = @_; | ||||||
|  |      | ||||||
|  |     return "" if !@{ $island->{perimeters} }; | ||||||
|  |     return $self->gcodegen->set_extruder($region->extruders->{perimeter}) | ||||||
|  |         . $self->gcodegen->extrude($_, 'perimeter') for @{ $island->{perimeters} }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | sub _extrude_infill { | ||||||
|  |     my $self = shift; | ||||||
|  |     my ($island, $region) = @_; | ||||||
|  |      | ||||||
|  |     return "" if !@{ $island->{fills} }; | ||||||
|  |      | ||||||
|  |     my $gcode = ""; | ||||||
|  |     $gcode .= $self->gcodegen->set_extruder($region->extruders->{infill}); | ||||||
|  |     for my $fill (@{ $island->{fills} }) { | ||||||
|  |         if ($fill->isa('Slic3r::ExtrusionPath::Collection')) { | ||||||
|  |             $gcode .= $self->gcodegen->extrude($_, 'fill')  | ||||||
|  |                 for $fill->chained_path($self->gcodegen->last_pos); | ||||||
|  |         } else { | ||||||
|  |             $gcode .= $self->gcodegen->extrude($fill, 'fill') ; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return $gcode; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 1; | ||||||
|  | @ -759,183 +759,12 @@ sub write_gcode { | ||||||
|         )); |         )); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     # prepare the SpiralVase processor if it's possible |     # prepare the layer processor | ||||||
|     my $spiralvase = $Slic3r::Config->spiral_vase |     my $layer_gcode = Slic3r::GCode::Layer->new( | ||||||
|         ? Slic3r::GCode::SpiralVase->new |         print       => $self, | ||||||
|         : undef; |         gcodegen    => $gcodegen, | ||||||
|      |         shift       => \@shift, | ||||||
|     # prepare the logic to print one layer |     ); | ||||||
|     my $skirt_done = 0;  # count of skirt layers done |  | ||||||
|     my $brim_done = 0; |  | ||||||
|     my $second_layer_things_done = 0; |  | ||||||
|     my $last_obj_copy = ""; |  | ||||||
|     my $extrude_layer = sub { |  | ||||||
|         my ($layer, $object_copies) = @_; |  | ||||||
|         my $gcode = ""; |  | ||||||
|          |  | ||||||
|         if (!$second_layer_things_done && $layer->id == 1) { |  | ||||||
|             for my $t (grep $self->extruders->[$_], 0 .. $#{$Slic3r::Config->temperature}) { |  | ||||||
|                 $gcode .= $gcodegen->set_temperature($self->extruders->[$t]->temperature, 0, $t) |  | ||||||
|                     if $self->extruders->[$t]->temperature && $self->extruders->[$t]->temperature != $self->extruders->[$t]->first_layer_temperature; |  | ||||||
|             } |  | ||||||
|             $gcode .= $gcodegen->set_bed_temperature($Slic3r::Config->bed_temperature) |  | ||||||
|                 if $Slic3r::Config->bed_temperature && $Slic3r::Config->bed_temperature != $Slic3r::Config->first_layer_bed_temperature; |  | ||||||
|             $second_layer_things_done = 1; |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         # set new layer, but don't move Z as support material contact areas may need an intermediate one |  | ||||||
|         $gcode .= $gcodegen->change_layer($layer); |  | ||||||
|          |  | ||||||
|         # prepare callback to call as soon as a Z command is generated |  | ||||||
|         $gcodegen->move_z_callback(sub { |  | ||||||
|             $gcodegen->move_z_callback(undef);  # circular ref or not? |  | ||||||
|             return "" if !$Slic3r::Config->layer_gcode; |  | ||||||
|             return $Slic3r::Config->replace_options($Slic3r::Config->layer_gcode) . "\n"; |  | ||||||
|         }); |  | ||||||
|          |  | ||||||
|         # extrude skirt |  | ||||||
|         if ($skirt_done < $Slic3r::Config->skirt_height) { |  | ||||||
|             $gcodegen->set_shift(@shift); |  | ||||||
|             $gcode .= $gcodegen->set_extruder($self->extruders->[0]);  # move_z requires extruder |  | ||||||
|             $gcode .= $gcodegen->move_z($gcodegen->layer->print_z); |  | ||||||
|             # skip skirt if we have a large brim |  | ||||||
|             if ($layer->id < $Slic3r::Config->skirt_height) { |  | ||||||
|                 # distribute skirt loops across all extruders |  | ||||||
|                 for my $i (0 .. $#{$self->skirt}) { |  | ||||||
|                     # when printing layers > 0 ignore 'min_skirt_length' and  |  | ||||||
|                     # just use the 'skirts' setting; also just use the current extruder |  | ||||||
|                     last if ($layer->id > 0) && ($i >= $Slic3r::Config->skirts); |  | ||||||
|                     $gcode .= $gcodegen->set_extruder($self->extruders->[ ($i/@{$self->extruders}) % @{$self->extruders} ]) |  | ||||||
|                         if $layer->id == 0; |  | ||||||
|                     $gcode .= $gcodegen->extrude_loop($self->skirt->[$i], 'skirt'); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             $skirt_done++; |  | ||||||
|             $gcodegen->straight_once(1); |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         # extrude brim |  | ||||||
|         if (!$brim_done) { |  | ||||||
|             $gcode .= $gcodegen->set_extruder($self->extruders->[$Slic3r::Config->support_material_extruder-1]);  # move_z requires extruder |  | ||||||
|             $gcode .= $gcodegen->move_z($gcodegen->layer->print_z); |  | ||||||
|             $gcodegen->set_shift(@shift); |  | ||||||
|             $gcode .= $gcodegen->extrude_loop($_, 'brim') for @{$self->brim}; |  | ||||||
|             $brim_done = 1; |  | ||||||
|             $gcodegen->straight_once(1); |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         for my $copy (@$object_copies) { |  | ||||||
|             $gcodegen->new_object(1) if $last_obj_copy && $last_obj_copy ne "$copy"; |  | ||||||
|             $last_obj_copy = "$copy"; |  | ||||||
|              |  | ||||||
|             $gcodegen->set_shift(map $shift[$_] + unscale $copy->[$_], X,Y); |  | ||||||
|              |  | ||||||
|             # extrude support material before other things because it might use a lower Z |  | ||||||
|             # and also because we avoid travelling on other things when printing it |  | ||||||
|             if ($self->has_support_material) { |  | ||||||
|                 $gcode .= $gcodegen->move_z($layer->support_material_contact_z) |  | ||||||
|                     if ($layer->support_contact_fills && @{ $layer->support_contact_fills->paths }); |  | ||||||
|                 $gcode .= $gcodegen->set_extruder($self->extruders->[$Slic3r::Config->support_material_extruder-1]); |  | ||||||
|                 if ($layer->support_contact_fills) { |  | ||||||
|                     $gcode .= $gcodegen->extrude_path($_, 'support material contact area')  |  | ||||||
|                         for $layer->support_contact_fills->chained_path($gcodegen->last_pos);  |  | ||||||
|                 } |  | ||||||
|                  |  | ||||||
|                 $gcode .= $gcodegen->move_z($layer->print_z); |  | ||||||
|                 if ($layer->support_fills) { |  | ||||||
|                     $gcode .= $gcodegen->extrude_path($_, 'support material')  |  | ||||||
|                         for $layer->support_fills->chained_path($gcodegen->last_pos); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|              |  | ||||||
|             # set actual Z - this will force a retraction |  | ||||||
|             $gcode .= $gcodegen->move_z($layer->print_z); |  | ||||||
|              |  | ||||||
|             # tweak region ordering to save toolchanges |  | ||||||
|             my @region_ids = 0 .. ($self->regions_count-1); |  | ||||||
|             if ($gcodegen->multiple_extruders) { |  | ||||||
|                 my $last_extruder = $gcodegen->extruder; |  | ||||||
|                 my $best_region_id = first { $self->regions->[$_]->extruders->{perimeter} eq $last_extruder } @region_ids; |  | ||||||
|                 @region_ids = ($best_region_id, grep $_ != $best_region_id, @region_ids) if $best_region_id; |  | ||||||
|             } |  | ||||||
|              |  | ||||||
|             foreach my $region_id (@region_ids) { |  | ||||||
|                 my $layerm = $layer->regions->[$region_id]; |  | ||||||
|                 my $region = $self->regions->[$region_id]; |  | ||||||
|                  |  | ||||||
|                 my @islands = (); |  | ||||||
|                 if ($Slic3r::Config->avoid_crossing_perimeters) { |  | ||||||
|                     push @islands, map +{ perimeters => [], fills => [] }, @{$layer->slices}; |  | ||||||
|                     PERIMETER: foreach my $perimeter (@{$layerm->perimeters}) { |  | ||||||
|                         my $p = $perimeter->unpack; |  | ||||||
|                         for my $i (0 .. $#{$layer->slices}-1) { |  | ||||||
|                             if ($layer->slices->[$i]->contour->encloses_point($p->first_point)) { |  | ||||||
|                                 push @{ $islands[$i]{perimeters} }, $p; |  | ||||||
|                                 next PERIMETER; |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                         push @{ $islands[-1]{perimeters} }, $p; # optimization |  | ||||||
|                     } |  | ||||||
|                     FILL: foreach my $fill (@{$layerm->fills}) { |  | ||||||
|                         my $f = $fill->unpack; |  | ||||||
|                         for my $i (0 .. $#{$layer->slices}-1) { |  | ||||||
|                             if ($layer->slices->[$i]->contour->encloses_point($f->first_point)) { |  | ||||||
|                                 push @{ $islands[$i]{fills} }, $f; |  | ||||||
|                                 next FILL; |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                         push @{ $islands[-1]{fills} }, $f; # optimization |  | ||||||
|                     } |  | ||||||
|                 } else { |  | ||||||
|                     push @islands, { |  | ||||||
|                         perimeters  => $layerm->perimeters, |  | ||||||
|                         fills       => $layerm->fills, |  | ||||||
|                     }; |  | ||||||
|                 } |  | ||||||
|                  |  | ||||||
|                 foreach my $island (@islands) { |  | ||||||
|                     my $extrude_perimeters = sub { |  | ||||||
|                         return if !@{ $island->{perimeters} }; |  | ||||||
|                         $gcode .= $gcodegen->set_extruder($region->extruders->{perimeter}); |  | ||||||
|                         $gcode .= $gcodegen->extrude($_, 'perimeter') for @{ $island->{perimeters} }; |  | ||||||
|                     }; |  | ||||||
|                      |  | ||||||
|                     my $extrude_fills = sub { |  | ||||||
|                         return if !@{ $island->{fills} }; |  | ||||||
|                         $gcode .= $gcodegen->set_extruder($region->extruders->{infill}); |  | ||||||
|                         for my $fill (@{ $island->{fills} }) { |  | ||||||
|                             if ($fill->isa('Slic3r::ExtrusionPath::Collection')) { |  | ||||||
|                                 $gcode .= $gcodegen->extrude($_, 'fill')  |  | ||||||
|                                     for $fill->chained_path($gcodegen->last_pos); |  | ||||||
|                             } else { |  | ||||||
|                                 $gcode .= $gcodegen->extrude($fill, 'fill') ; |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                     }; |  | ||||||
|                      |  | ||||||
|                     # give priority to infill if we were already using its extruder and it wouldn't |  | ||||||
|                     # be good for perimeters |  | ||||||
|                     if ($Slic3r::Config->infill_first |  | ||||||
|                         || ($gcodegen->multiple_extruders && $region->extruders->{infill} eq $gcodegen->extruder) && $region->extruders->{infill} ne $region->extruders->{perimeter}) { |  | ||||||
|                         $extrude_fills->(); |  | ||||||
|                         $extrude_perimeters->(); |  | ||||||
|                     } else { |  | ||||||
|                         $extrude_perimeters->(); |  | ||||||
|                         $extrude_fills->(); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         # apply spiral vase post-processing if this layer contains suitable geometry |  | ||||||
|         $gcode = $spiralvase->process_layer($gcode, $layer) |  | ||||||
|             if defined $spiralvase |  | ||||||
|             && ($layer->id > 0 || $Slic3r::Config->brim_width == 0) |  | ||||||
|             && ($layer->id >= $Slic3r::Config->skirt_height) |  | ||||||
|             && ($layer->id >= $Slic3r::Config->bottom_solid_layers); |  | ||||||
|          |  | ||||||
|         return $gcode; |  | ||||||
|     }; |  | ||||||
|      |      | ||||||
|     # do all objects for each layer |     # do all objects for each layer | ||||||
|     if ($Slic3r::Config->complete_objects) { |     if ($Slic3r::Config->complete_objects) { | ||||||
|  | @ -970,7 +799,7 @@ sub write_gcode { | ||||||
|                             if $Slic3r::Config->first_layer_bed_temperature; |                             if $Slic3r::Config->first_layer_bed_temperature; | ||||||
|                         $print_first_layer_temperature->(); |                         $print_first_layer_temperature->(); | ||||||
|                     } |                     } | ||||||
|                     print $fh $buffer->append($extrude_layer->($layer, [$copy]), $layer); |                     print $fh $buffer->append($layer_gcode->process_layer($layer, [$copy]), $layer); | ||||||
|                 } |                 } | ||||||
|                 print $fh $buffer->flush; |                 print $fh $buffer->flush; | ||||||
|                 $finished_objects++; |                 $finished_objects++; | ||||||
|  | @ -981,8 +810,10 @@ sub write_gcode { | ||||||
|             config      => $Slic3r::Config, |             config      => $Slic3r::Config, | ||||||
|             gcodegen    => $gcodegen, |             gcodegen    => $gcodegen, | ||||||
|         ); |         ); | ||||||
|         print $fh $buffer->append($extrude_layer->($_, $_->object->copies), $_) |         my @layers = sort { $a->print_z <=> $b->print_z } map @{$_->layers}, @{$self->objects}; | ||||||
|             for sort { $a->print_z <=> $b->print_z } map @{$_->layers}, @{$self->objects}; |         foreach my $layer (@layers) { | ||||||
|  |             print $fh $buffer->append($layer_gcode->process_layer($layer, $layer->object->copies), $layer); | ||||||
|  |         } | ||||||
|         print $fh $buffer->flush; |         print $fh $buffer->flush; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci