mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 20:51:12 -06:00 
			
		
		
		
	Support material
This commit is contained in:
		
							parent
							
								
									e0e2023a5a
								
							
						
					
					
						commit
						7b67fae686
					
				
					 12 changed files with 135 additions and 17 deletions
				
			
		|  | @ -37,6 +37,7 @@ Slic3r current key features are: | ||||||
| * multiple solid layers near horizontal external surfaces; | * multiple solid layers near horizontal external surfaces; | ||||||
| * ability to scale, rotate and duplicate input object; | * ability to scale, rotate and duplicate input object; | ||||||
| * customizable initial and final GCODE; | * customizable initial and final GCODE; | ||||||
|  | * support material; | ||||||
| * use different speed for bottom layer and perimeters. | * use different speed for bottom layer and perimeters. | ||||||
| 
 | 
 | ||||||
| Experimental features include: | Experimental features include: | ||||||
|  | @ -150,6 +151,7 @@ The author is Alessandro Ranellucci (me). | ||||||
|         --end-gcode         Load final gcode from the supplied file. This will overwrite  |         --end-gcode         Load final gcode from the supplied file. This will overwrite  | ||||||
|                             the default commands (turn off temperature [M104 S0], |                             the default commands (turn off temperature [M104 S0], | ||||||
|                             home X axis [G28 X], disable motors [M84]). |                             home X axis [G28 X], disable motors [M84]). | ||||||
|  |         --support-material  Generate support material for overhangs | ||||||
|        |        | ||||||
|       Retraction options: |       Retraction options: | ||||||
|         --retract-length    Length of retraction in mm when pausing extrusion  |         --retract-length    Length of retraction in mm when pausing extrusion  | ||||||
|  |  | ||||||
|  | @ -95,6 +95,7 @@ our $fill_pattern       = 'rectilinear'; | ||||||
| our $solid_fill_pattern = 'rectilinear'; | our $solid_fill_pattern = 'rectilinear'; | ||||||
| our $fill_density       = 0.4;  # 1 = 100% | our $fill_density       = 0.4;  # 1 = 100% | ||||||
| our $fill_angle         = 45; | our $fill_angle         = 45; | ||||||
|  | our $support_material   = 0; | ||||||
| our $start_gcode = "G28 ; home all axes"; | our $start_gcode = "G28 ; home all axes"; | ||||||
| our $end_gcode = <<"END"; | our $end_gcode = <<"END"; | ||||||
| M104 S0 ; turn off temperature | M104 S0 ; turn off temperature | ||||||
|  |  | ||||||
|  | @ -215,6 +215,11 @@ our $Options = { | ||||||
|         cli     => 'fill-angle=i', |         cli     => 'fill-angle=i', | ||||||
|         type    => 'i', |         type    => 'i', | ||||||
|     }, |     }, | ||||||
|  |     'support_material' => { | ||||||
|  |         label   => 'Generate support material', | ||||||
|  |         cli     => 'support-material', | ||||||
|  |         type    => 'bool', | ||||||
|  |     }, | ||||||
|     'start_gcode' => { |     'start_gcode' => { | ||||||
|         label   => 'Start GCODE', |         label   => 'Start GCODE', | ||||||
|         cli     => 'start-gcode=s', |         cli     => 'start-gcode=s', | ||||||
|  |  | ||||||
|  | @ -149,7 +149,7 @@ sub extrude_path { | ||||||
|      |      | ||||||
|     # extrude arc or line |     # extrude arc or line | ||||||
|     $self->print_feed_rate( |     $self->print_feed_rate( | ||||||
|         $path->role =~ /^(perimeter|skirt)$/o   ? $self->perimeter_speed |         $path->role =~ /^(perimeter|skirt|support-material)$/o ? $self->perimeter_speed | ||||||
|             : $path->role eq 'small-perimeter'  ? $self->small_perimeter_speed |             : $path->role eq 'small-perimeter'  ? $self->small_perimeter_speed | ||||||
|             : $path->role eq 'fill'             ? $self->infill_speed |             : $path->role eq 'fill'             ? $self->infill_speed | ||||||
|             : $path->role eq 'solid-fill'       ? $self->solid_infill_speed |             : $path->role eq 'solid-fill'       ? $self->solid_infill_speed | ||||||
|  |  | ||||||
|  | @ -44,4 +44,9 @@ sub split_at { | ||||||
|     ); |     ); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | sub split_at_first_point { | ||||||
|  |     my $self = shift; | ||||||
|  |     return $self->split_at($self->polygon->[0]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| 1; | 1; | ||||||
|  |  | ||||||
|  | @ -17,7 +17,7 @@ has 'depth_layers' => (is => 'ro', default => sub {1}); | ||||||
| 
 | 
 | ||||||
| has 'flow_spacing' => (is => 'rw'); | has 'flow_spacing' => (is => 'rw'); | ||||||
| 
 | 
 | ||||||
| # perimeter/fill/solid-fill/bridge/skirt | # perimeter/fill/solid-fill/bridge/skirt/support-material | ||||||
| has 'role'         => (is => 'rw', required => 1); | has 'role'         => (is => 'rw', required => 1); | ||||||
| 
 | 
 | ||||||
| sub BUILD { | sub BUILD { | ||||||
|  | @ -45,6 +45,22 @@ sub clip_end { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | sub clip_with_expolygon { | ||||||
|  |     my $self = shift; | ||||||
|  |     my ($expolygon) = @_; | ||||||
|  |      | ||||||
|  |     my @paths = (); | ||||||
|  |     foreach my $polyline ($self->polyline->clip_with_expolygon($expolygon)) { | ||||||
|  |         push @paths, (ref $self)->new( | ||||||
|  |             polyline        => $polyline, | ||||||
|  |             depth_layers    => $self->depth_layers, | ||||||
|  |             flow_spacing    => $self->flow_spacing, | ||||||
|  |             role            => $self->role, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     return @paths; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| sub points { | sub points { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|     return $self->polyline; |     return $self->polyline; | ||||||
|  |  | ||||||
|  | @ -34,17 +34,16 @@ sub BUILD { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|     $self->fillers->{$_} ||= $FillTypes{$_}->new(print => $self->print) |     $self->fillers->{$_} ||= $FillTypes{$_}->new(print => $self->print) | ||||||
|         for ('rectilinear', $Slic3r::fill_pattern, $Slic3r::solid_fill_pattern); |         for ('rectilinear', $Slic3r::fill_pattern, $Slic3r::solid_fill_pattern); | ||||||
|  |      | ||||||
|  |     my $max_print_dimension = $self->print->max_length * sqrt(2); | ||||||
|  |     $_->max_print_dimension($max_print_dimension) for values %{$self->fillers}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub make_fill { | sub make_fill { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|     my ($layer) = @_; |     my ($layer) = @_; | ||||||
|      |      | ||||||
|     my $max_print_dimension = $self->print->max_length * sqrt(2); |     $_->layer($layer) for values %{$self->fillers}; | ||||||
|     for (values %{$self->fillers}) { |  | ||||||
|         $_->layer($layer); |  | ||||||
|         $_->max_print_dimension($max_print_dimension); |  | ||||||
|     } |  | ||||||
|      |      | ||||||
|     printf "Filling layer %d:\n", $layer->id; |     printf "Filling layer %d:\n", $layer->id; | ||||||
|      |      | ||||||
|  |  | ||||||
|  | @ -18,13 +18,15 @@ sub infill_direction { | ||||||
|     $rotate[1] = [ $self->max_print_dimension * sqrt(2) / 2, $self->max_print_dimension * sqrt(2) / 2 ]; |     $rotate[1] = [ $self->max_print_dimension * sqrt(2) / 2, $self->max_print_dimension * sqrt(2) / 2 ]; | ||||||
|     @shift = @{$rotate[1]}; |     @shift = @{$rotate[1]}; | ||||||
|      |      | ||||||
|     # alternate fill direction |     if ($self->layer) { | ||||||
|     if (($self->layer->id / $surface->depth_layers) % 2) { |         # alternate fill direction | ||||||
|         $rotate[0] = Slic3r::Geometry::deg2rad($Slic3r::fill_angle) + PI/2; |         if (($self->layer->id / $surface->depth_layers) % 2) { | ||||||
|  |             $rotate[0] = Slic3r::Geometry::deg2rad($Slic3r::fill_angle) + PI/2; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|          |          | ||||||
|     # use bridge angle |     # use bridge angle | ||||||
|     if ($surface->surface_type eq 'bottom' && $self->layer->id > 0 && defined $surface->bridge_angle) { |     if (defined $surface->bridge_angle) { | ||||||
|         Slic3r::debugf "Filling bridge with angle %d\n", $surface->bridge_angle; |         Slic3r::debugf "Filling bridge with angle %d\n", $surface->bridge_angle; | ||||||
|         $rotate[0] = Slic3r::Geometry::deg2rad($surface->bridge_angle); |         $rotate[0] = Slic3r::Geometry::deg2rad($surface->bridge_angle); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -66,10 +66,16 @@ has 'skirts' => ( | ||||||
|     default => sub { [] }, |     default => sub { [] }, | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
|  | # ordered collection of extrusion paths to fill surfaces for support material | ||||||
|  | has 'support_fills' => ( | ||||||
|  |     is      => 'rw', | ||||||
|  |     #isa     => 'Slic3r::ExtrusionPath::Collection', | ||||||
|  | ); | ||||||
|  | 
 | ||||||
| # ordered collection of extrusion paths to fill surfaces | # ordered collection of extrusion paths to fill surfaces | ||||||
| has 'fills' => ( | has 'fills' => ( | ||||||
|     is      => 'rw', |     is      => 'rw', | ||||||
|     #isa     => 'ArrayRef[Slic3r::ExtrusionPath]', |     #isa     => 'ArrayRef[Slic3r::ExtrusionPath::Collection]', | ||||||
|     default => sub { [] }, |     default => sub { [] }, | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -342,6 +342,7 @@ sub extrude_skirt { | ||||||
|     my @points = ( |     my @points = ( | ||||||
|         (map @$_, map @{$_->expolygon}, map @{$_->slices}, @layers), |         (map @$_, map @{$_->expolygon}, map @{$_->slices}, @layers), | ||||||
|         (map @$_, map @{$_->thin_walls}, @layers), |         (map @$_, map @{$_->thin_walls}, @layers), | ||||||
|  |         (map @{$_->polyline}, map @{$_->support_fills->paths}, grep $_->support_fills, @layers), | ||||||
|     ); |     ); | ||||||
|     return if !@points; |     return if !@points; | ||||||
|      |      | ||||||
|  | @ -451,6 +452,74 @@ sub infill_every_layers { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | sub generate_support_material { | ||||||
|  |     my $self = shift; | ||||||
|  |      | ||||||
|  |     # generate paths for the pattern that we're going to use | ||||||
|  |     my $support_pattern = []; | ||||||
|  |     { | ||||||
|  |         # get all surfaces needing support material | ||||||
|  |         my @surfaces = grep $_->surface_type eq 'bottom' && !defined $_->bridge_angle, | ||||||
|  |             map @{$_->slices}, grep $_->id > 0, @{$self->layers} or return; | ||||||
|  |          | ||||||
|  |         my @support_material_areas = @{union_ex([ map $_->p, @surfaces ])}; | ||||||
|  |          | ||||||
|  |         for (1..$Slic3r::perimeters+1) { | ||||||
|  |             foreach my $expolygon (@support_material_areas) { | ||||||
|  |                 push @$support_pattern, | ||||||
|  |                     map Slic3r::ExtrusionLoop->new( | ||||||
|  |                         polygon => $_, | ||||||
|  |                         role    => 'support-material', | ||||||
|  |                     )->split_at_first_point, @$expolygon; | ||||||
|  |             } | ||||||
|  |             @support_material_areas = map $_->offset_ex(- scale $Slic3r::flow_spacing), | ||||||
|  |                 @support_material_areas; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         my $fill = Slic3r::Fill->new(print => $self); | ||||||
|  |         foreach my $expolygon (@support_material_areas) { | ||||||
|  |             my @paths = $fill->fillers->{rectilinear}->fill_surface( | ||||||
|  |                 Slic3r::Surface->new( | ||||||
|  |                     expolygon       => $expolygon, | ||||||
|  |                     bridge_angle    => $Slic3r::fill_angle + 45, | ||||||
|  |                 ), | ||||||
|  |                 density         => 0.15, | ||||||
|  |                 flow_spacing    => $Slic3r::flow_spacing, | ||||||
|  |             ); | ||||||
|  |             my $params = shift @paths; | ||||||
|  |              | ||||||
|  |             push @$support_pattern, | ||||||
|  |                 map Slic3r::ExtrusionPath->new( | ||||||
|  |                     polyline        => Slic3r::Polyline->new(@$_), | ||||||
|  |                     role            => 'support-material', | ||||||
|  |                     depth_layers    => 1, | ||||||
|  |                     flow_spacing    => $params->{flow_spacing}, | ||||||
|  |                 ), @paths; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     # now apply the pattern to layers below unsupported surfaces | ||||||
|  |     my (@a, @b) = (); | ||||||
|  |     for (my $i = $#{$self->layers}; $i >=0; $i--) { | ||||||
|  |         my $layer = $self->layers->[$i]; | ||||||
|  |         my @c = (); | ||||||
|  |         if (@b) { | ||||||
|  |             @c = @{diff_ex( | ||||||
|  |                 [ map @$_, @b ], | ||||||
|  |                 [ map @$_, map $_->expolygon->offset_ex(scale $Slic3r::flow_width), @{$layer->slices} ], | ||||||
|  |             )}; | ||||||
|  |             $layer->support_fills(Slic3r::ExtrusionPath::Collection->new); | ||||||
|  |             foreach my $expolygon (@c) { | ||||||
|  |                 push @{$layer->support_fills->paths}, map $_->clip_with_expolygon($expolygon), @$support_pattern; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         @b = @{union_ex([ map @$_, @c, @a ])}; | ||||||
|  |         @a = map $_->expolygon->offset_ex(scale 2), | ||||||
|  |             grep $_->surface_type eq 'bottom' && !defined $_->bridge_angle, | ||||||
|  |             @{$layer->slices}; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| sub export_gcode { | sub export_gcode { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|     my ($file) = @_; |     my ($file) = @_; | ||||||
|  | @ -522,6 +591,12 @@ sub export_gcode { | ||||||
|                 print $fh $extruder->extrude_path($_, 'fill')  |                 print $fh $extruder->extrude_path($_, 'fill')  | ||||||
|                     for $fill->shortest_path($extruder->last_pos); |                     for $fill->shortest_path($extruder->last_pos); | ||||||
|             } |             } | ||||||
|  |              | ||||||
|  |             # extrude support material | ||||||
|  |             if ($layer->support_fills) { | ||||||
|  |                 print $fh $extruder->extrude_path($_, 'support material')  | ||||||
|  |                     for $layer->support_fills->shortest_path($extruder->last_pos); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |  | ||||||
|  | @ -35,10 +35,6 @@ sub go { | ||||||
|         $print = Slic3r::Print->new_from_mesh($mesh); |         $print = Slic3r::Print->new_from_mesh($mesh); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     # make skirt |  | ||||||
|     $self->status_cb->(15, "Generating skirt..."); |  | ||||||
|     $print->extrude_skirt; |  | ||||||
|      |  | ||||||
|     # make perimeters |     # make perimeters | ||||||
|     # this will add a set of extrusion loops to each layer |     # this will add a set of extrusion loops to each layer | ||||||
|     # as well as generate infill boundaries |     # as well as generate infill boundaries | ||||||
|  | @ -118,6 +114,16 @@ sub go { | ||||||
|     # free memory |     # free memory | ||||||
|     @{$_->fill_surfaces} = () for @{$print->layers}; |     @{$_->fill_surfaces} = () for @{$print->layers}; | ||||||
|      |      | ||||||
|  |     # generate support material | ||||||
|  |     if ($Slic3r::support_material) { | ||||||
|  |         $self->status_cb->(85, "Generating support material..."); | ||||||
|  |         $print->generate_support_material; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     # make skirt | ||||||
|  |     $self->status_cb->(88, "Generating skirt..."); | ||||||
|  |     $print->extrude_skirt; | ||||||
|  |      | ||||||
|     # output everything to a GCODE file |     # output everything to a GCODE file | ||||||
|     $self->status_cb->(90, "Exporting GCODE..."); |     $self->status_cb->(90, "Exporting GCODE..."); | ||||||
|     $print->export_gcode($self->expanded_output_filepath); |     $print->export_gcode($self->expanded_output_filepath); | ||||||
|  |  | ||||||
|  | @ -167,6 +167,7 @@ Usage: slic3r.pl [ OPTIONS ] file.stl | ||||||
|     --end-gcode         Load final gcode from the supplied file. This will overwrite  |     --end-gcode         Load final gcode from the supplied file. This will overwrite  | ||||||
|                         the default commands (turn off temperature [M104 S0], |                         the default commands (turn off temperature [M104 S0], | ||||||
|                         home X axis [G28 X], disable motors [M84]). |                         home X axis [G28 X], disable motors [M84]). | ||||||
|  |     --support-material  Generate support material for overhangs | ||||||
|    |    | ||||||
|   Retraction options: |   Retraction options: | ||||||
|     --retract-length    Length of retraction in mm when pausing extrusion  |     --retract-length    Length of retraction in mm when pausing extrusion  | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci