mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Refactoring: split support material code into several methods
This commit is contained in:
		
							parent
							
								
									e6efda4ba4
								
							
						
					
					
						commit
						bdf825d078
					
				
					 1 changed files with 149 additions and 97 deletions
				
			
		|  | @ -17,11 +17,52 @@ sub flow { | ||||||
| sub generate { | sub generate { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|      |      | ||||||
|     my $flow = $self->flow; |     # Determine the top surfaces of the support, defined as: | ||||||
|  |     # contact = overhangs - margin | ||||||
|  |     # This method is responsible for identifying what contact surfaces | ||||||
|  |     # should the support material expose to the object in order to guarantee | ||||||
|  |     # that it will be effective, regardless of how it's built below. | ||||||
|  |     my ($contact, $overhang) = $self->contact_area; | ||||||
|  |      | ||||||
|  |     # Determine the top surfaces of the object. We need these to determine  | ||||||
|  |     # the layer heights of support material and to clip support to the object | ||||||
|  |     # silhouette. | ||||||
|  |     my ($top) = $self->object_top($contact); | ||||||
|  |      | ||||||
|  |     # We now know the upper and lower boundaries for our support material object | ||||||
|  |     # (@$contact_z and @$top_z), so we can generate intermediate layers. | ||||||
|  |     my ($support_z) = $self->support_layers_z([ sort keys %$contact ], [ sort keys %$top ]); | ||||||
|  |      | ||||||
|  |     # If we wanted to apply some special logic to the first support layers lying on | ||||||
|  |     # object's top surfaces this is the place to detect them | ||||||
|  |      | ||||||
|  |     # Propagate contact layers downwards to generate interface layers | ||||||
|  |     my ($interface) = $self->generate_interface_layers($support_z, $contact, $top); | ||||||
|  |      | ||||||
|  |     # Propagate contact layers and interface layers downwards to generate | ||||||
|  |     # the main support layers. | ||||||
|  |     my ($base) = $self->generate_base_layers($support_z, $contact, $interface, $top); | ||||||
|  |      | ||||||
|  |     # Install support layers into object. | ||||||
|  |     push @{$self->object->support_layers}, map Slic3r::Layer::Support->new( | ||||||
|  |         object  => $self->object, | ||||||
|  |         id      => $_, | ||||||
|  |         height  => ($_ == 0) ? $support_z->[$_] : ($support_z->[$_] - $support_z->[$_-1]), | ||||||
|  |         print_z => $support_z->[$_], | ||||||
|  |         slice_z => -1, | ||||||
|  |         slices  => [], | ||||||
|  |     ), 0 .. $#$support_z; | ||||||
|  |      | ||||||
|  |     # Generate the actual toolpaths and save them into each layer. | ||||||
|  |     $self->generate_toolpaths($overhang, $contact, $interface, $base); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | sub contact_area { | ||||||
|  |     my ($self) = @_; | ||||||
|      |      | ||||||
|     # how much we extend support around the actual contact area |     # how much we extend support around the actual contact area | ||||||
|     #my $margin      = $flow->scaled_width / 2; |     #my $margin = $flow->scaled_width / 2; | ||||||
|     my $margin      = scale 3; |     my $margin = scale 3; | ||||||
|      |      | ||||||
|     # increment used to reach $margin in steps to avoid trespassing thin objects |     # increment used to reach $margin in steps to avoid trespassing thin objects | ||||||
|     my $margin_step = $margin/3; |     my $margin_step = $margin/3; | ||||||
|  | @ -33,12 +74,6 @@ sub generate { | ||||||
|         Slic3r::debugf "Threshold angle = %d°\n", rad2deg($threshold_rad); |         Slic3r::debugf "Threshold angle = %d°\n", rad2deg($threshold_rad); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     # shape of contact area |  | ||||||
|     my $contact_loops   = 1; |  | ||||||
|     my $circle_radius   = 1.5 * $flow->scaled_width; |  | ||||||
|     my $circle_distance = 3 * $circle_radius; |  | ||||||
|     my $circle          = Slic3r::Polygon->new(map [ $circle_radius * cos $_, $circle_radius * sin $_ ], (5*PI/3, 4*PI/3, PI, 2*PI/3, PI/3, 0)); |  | ||||||
|      |  | ||||||
|     # determine contact areas |     # determine contact areas | ||||||
|     my %contact  = ();  # contact_z => [ polygons ] |     my %contact  = ();  # contact_z => [ polygons ] | ||||||
|     my %overhang = ();  # contact_z => [ expolygons ] - this stores the actual overhang supported by each contact layer |     my %overhang = ();  # contact_z => [ expolygons ] - this stores the actual overhang supported by each contact layer | ||||||
|  | @ -131,7 +166,14 @@ sub generate { | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     my @contact_z = sort keys %contact; |      | ||||||
|  |     return (\%contact, \%overhang); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | sub object_top { | ||||||
|  |     my ($self, $contact) = @_; | ||||||
|  |      | ||||||
|  |     my $flow = $self->flow; | ||||||
|      |      | ||||||
|     # find object top surfaces |     # find object top surfaces | ||||||
|     # we'll use them to clip our support and detect where does it stick |     # we'll use them to clip our support and detect where does it stick | ||||||
|  | @ -144,10 +186,10 @@ sub generate { | ||||||
|                 # first add all the 'new' contact areas to the current projection |                 # first add all the 'new' contact areas to the current projection | ||||||
|                 # ('new' means all the areas that are lower than the last top layer |                 # ('new' means all the areas that are lower than the last top layer | ||||||
|                 # we considered) |                 # we considered) | ||||||
|                 my $min_top = min(keys %top) // max(keys %contact); |                 my $min_top = min(keys %top) // max(keys %$contact); | ||||||
|                 # use <= instead of just < because otherwise we'd ignore any contact regions |                 # use <= instead of just < because otherwise we'd ignore any contact regions | ||||||
|                 # having the same Z of top layers |                 # having the same Z of top layers | ||||||
|                 push @$projection, map @{$contact{$_}}, grep { $_ > $layer->print_z && $_ <= $min_top } keys %contact; |                 push @$projection, map @{$contact->{$_}}, grep { $_ > $layer->print_z && $_ <= $min_top } keys %$contact; | ||||||
|                  |                  | ||||||
|                 # now find whether any projection falls onto this top surface |                 # now find whether any projection falls onto this top surface | ||||||
|                 my $touching = intersection($projection, [ map $_->p, @top ]); |                 my $touching = intersection($projection, [ map $_->p, @top ]); | ||||||
|  | @ -164,25 +206,67 @@ sub generate { | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     my @top_z = sort keys %top; |  | ||||||
|      |      | ||||||
|     # we now know the upper and lower boundaries for our support material object |     return \%top; | ||||||
|     # (@contact_z and @top_z), so we can generate intermediate layers | } | ||||||
|     my @support_layers = $self->_compute_support_layers(\@contact_z, \@top_z); | 
 | ||||||
|  | sub support_layers_z { | ||||||
|  |     my ($self, $contact_z, $top_z) = @_; | ||||||
|      |      | ||||||
|     # if we wanted to apply some special logic to the first support layers lying on |     my $flow = $self->flow; | ||||||
|     # object's top surfaces this is the place to detect them |      | ||||||
|  |     # quick table to check whether a given Z is a top surface | ||||||
|  |     my %top = map { $_ => 1 } @$top_z; | ||||||
|  |      | ||||||
|  |     # determine layer height for any non-contact layer | ||||||
|  |     # we use max() to prevent many ultra-thin layers to be inserted in case | ||||||
|  |     # layer_height > nozzle_diameter * 0.75 | ||||||
|  |     my $support_material_height = max($self->object->config->layer_height, $flow->nozzle_diameter * 0.75); | ||||||
|  |      | ||||||
|  |     my @z = sort { $a <=> $b } @$contact_z, @$top_z, | ||||||
|  |         (map { $_ + $flow->nozzle_diameter } @$top_z); | ||||||
|  |      | ||||||
|  |     # enforce first layer height | ||||||
|  |     my $first_layer_height = $self->object->config->get_value('first_layer_height'); | ||||||
|  |     shift @z while @z && $z[0] <= $first_layer_height; | ||||||
|  |     unshift @z, $first_layer_height; | ||||||
|  |      | ||||||
|  |     for (my $i = $#z; $i >= 0; $i--) { | ||||||
|  |         my $target_height = $support_material_height; | ||||||
|  |         if ($i > 0 && $top{ $z[$i-1] }) { | ||||||
|  |             $target_height = $flow->nozzle_diameter; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         # enforce first layer height | ||||||
|  |         if (($i == 0 && $z[$i] > $target_height + $first_layer_height) | ||||||
|  |             || ($z[$i] - $z[$i-1] > $target_height + Slic3r::Geometry::epsilon)) { | ||||||
|  |             splice @z, $i, 0, ($z[$i] - $target_height); | ||||||
|  |             $i++; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     # remove duplicates and make sure all 0.x values have the leading 0 | ||||||
|  |     { | ||||||
|  |         my %sl = map { 1 * $_ => 1 } @z; | ||||||
|  |         @z = sort { $a <=> $b } keys %sl; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     return \@z; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | sub generate_interface_layers { | ||||||
|  |     my ($self, $support_z, $contact, $top) = @_; | ||||||
|      |      | ||||||
|     # let's now generate interface layers below contact areas |     # let's now generate interface layers below contact areas | ||||||
|     my %interface = ();  # layer_id => [ polygons ] |     my %interface = ();  # layer_id => [ polygons ] | ||||||
|     my $interface_layers = $self->object->config->support_material_interface_layers; |     my $interface_layers = $self->object->config->support_material_interface_layers; | ||||||
|     for my $layer_id (0 .. $#support_layers) { |     for my $layer_id (0 .. $#$support_z) { | ||||||
|         my $z = $support_layers[$layer_id]; |         my $z = $support_z->[$layer_id]; | ||||||
|         my $this = $contact{$z} // next; |         my $this = $contact->{$z} // next; | ||||||
|          |          | ||||||
|         # count contact layer as interface layer |         # count contact layer as interface layer | ||||||
|         for (my $i = $layer_id-1; $i >= 0 && $i > $layer_id-$interface_layers; $i--) { |         for (my $i = $layer_id-1; $i >= 0 && $i > $layer_id-$interface_layers; $i--) { | ||||||
|             $z = $support_layers[$i]; |             $z = $support_z->[$i]; | ||||||
|             # Compute interface area on this layer as diff of upper contact area |             # Compute interface area on this layer as diff of upper contact area | ||||||
|             # (or upper interface area) and layer slices. |             # (or upper interface area) and layer slices. | ||||||
|             # This diff is responsible of the contact between support material and |             # This diff is responsible of the contact between support material and | ||||||
|  | @ -194,43 +278,54 @@ sub generate { | ||||||
|                     @{ $interface{$i} || [] },      # interface regions already applied to this layer |                     @{ $interface{$i} || [] },      # interface regions already applied to this layer | ||||||
|                 ], |                 ], | ||||||
|                 [ |                 [ | ||||||
|                     @{ $top{$z} || [] },            # top slices on this layer |                     @{ $top->{$z} || [] },          # top slices on this layer | ||||||
|                     @{ $contact{$z} || [] },        # contact regions on this layer |                     @{ $contact->{$z} || [] },      # contact regions on this layer | ||||||
|                 ], |                 ], | ||||||
|                 1, |                 1, | ||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     return \%interface; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | sub generate_base_layers { | ||||||
|  |     my ($self, $support_z, $contact, $interface, $top) = @_; | ||||||
|  |      | ||||||
|     # let's now generate support layers under interface layers |     # let's now generate support layers under interface layers | ||||||
|     my %support   = ();  # layer_id => [ polygons ] |     my $base = {};  # layer_id => [ polygons ] | ||||||
|     { |     { | ||||||
|         for my $i (reverse 0 .. $#support_layers-1) { |         for my $i (reverse 0 .. $#$support_z-1) { | ||||||
|             my $z = $support_layers[$i]; |             my $z = $support_z->[$i]; | ||||||
|             $support{$i} = diff( |             $base->{$i} = diff( | ||||||
|                 [ |                 [ | ||||||
|                     @{ $support{$i+1} || [] },      # support regions on upper layer |                     @{ $base->{$i+1} || [] },         # support regions on upper layer | ||||||
|                     @{ $interface{$i+1} || [] },    # interface regions on upper layer |                     @{ $interface->{$i+1} || [] },    # interface regions on upper layer | ||||||
|                 ], |                 ], | ||||||
|                 [ |                 [ | ||||||
|                     @{ $top{$z} || [] },            # top slices on this layer |                     @{ $top->{$z} || [] },            # top slices on this layer | ||||||
|                     @{ $interface{$i} || [] },      # interface regions on this layer |                     @{ $interface->{$i} || [] },      # interface regions on this layer | ||||||
|                     @{ $contact{$z} || [] },        # contact regions on this layer |                     @{ $contact->{$z} || [] },        # contact regions on this layer | ||||||
|                 ], |                 ], | ||||||
|                 1, |                 1, | ||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     push @{$self->object->support_layers}, map Slic3r::Layer::Support->new( |     return $base; | ||||||
|         object  => $self->object, | } | ||||||
|         id      => $_, |  | ||||||
|         height  => ($_ == 0) ? $support_layers[$_] : ($support_layers[$_] - $support_layers[$_-1]), |  | ||||||
|         print_z => $support_layers[$_], |  | ||||||
|         slice_z => -1, |  | ||||||
|         slices  => [], |  | ||||||
|     ), 0 .. $#support_layers; |  | ||||||
| 
 | 
 | ||||||
|  | sub generate_toolpaths { | ||||||
|  |     my ($self, $overhang, $contact, $interface, $base) = @_; | ||||||
|  |      | ||||||
|  |     my $flow = $self->flow; | ||||||
|  |      | ||||||
|  |     # shape of contact area | ||||||
|  |     my $contact_loops   = 1; | ||||||
|  |     my $circle_radius   = 1.5 * $flow->scaled_width; | ||||||
|  |     my $circle_distance = 3 * $circle_radius; | ||||||
|  |     my $circle          = Slic3r::Polygon->new(map [ $circle_radius * cos $_, $circle_radius * sin $_ ], (5*PI/3, 4*PI/3, PI, 2*PI/3, PI/3, 0)); | ||||||
|  |      | ||||||
|     Slic3r::debugf "Generating patterns\n"; |     Slic3r::debugf "Generating patterns\n"; | ||||||
|      |      | ||||||
|     # prepare fillers |     # prepare fillers | ||||||
|  | @ -255,22 +350,23 @@ sub generate { | ||||||
|     my $process_layer = sub { |     my $process_layer = sub { | ||||||
|         my ($layer_id) = @_; |         my ($layer_id) = @_; | ||||||
|         my $layer = $self->object->support_layers->[$layer_id]; |         my $layer = $self->object->support_layers->[$layer_id]; | ||||||
|  |         my $z = $layer->print_z; | ||||||
|          |          | ||||||
|         my $overhang    = $overhang{$support_layers[$layer_id]} || []; |         my $overhang    = $overhang->{$z}           || []; | ||||||
|         my $contact     = $contact{$support_layers[$layer_id]}  || []; |         my $contact     = $contact->{$z}            || []; | ||||||
|         my $interface   = $interface{$layer_id} || []; |         my $interface   = $interface->{$layer_id}   || []; | ||||||
|         my $support     = $support{$layer_id}   || []; |         my $base        = $base->{$layer_id}        || []; | ||||||
|          |          | ||||||
|         if (0) { |         if (0) { | ||||||
|             require "Slic3r/SVG.pm"; |             require "Slic3r/SVG.pm"; | ||||||
|             Slic3r::SVG::output("layer_" . $support_layers[$layer_id] . ".svg", |             Slic3r::SVG::output("layer_" . $z . ".svg", | ||||||
|                 red_expolygons      => union_ex($contact), |                 red_expolygons      => union_ex($contact), | ||||||
|                 green_expolygons    => union_ex($interface), |                 green_expolygons    => union_ex($interface), | ||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         # islands |         # islands | ||||||
|         $layer->support_islands->append(@{union_ex([ @$interface, @$support, @$contact ])}); |         $layer->support_islands->append(@{union_ex([ @$interface, @$base, @$contact ])}); | ||||||
|          |          | ||||||
|         # contact |         # contact | ||||||
|         my $contact_infill = []; |         my $contact_infill = []; | ||||||
|  | @ -325,11 +421,11 @@ sub generate { | ||||||
|             # steal some space from support |             # steal some space from support | ||||||
|             $interface = intersection( |             $interface = intersection( | ||||||
|                 offset([ @$interface, @$contact_infill ], scale 3), |                 offset([ @$interface, @$contact_infill ], scale 3), | ||||||
|                 [ @$interface, @$support, @$contact_infill ], |                 [ @$interface, @$base, @$contact_infill ], | ||||||
|                 1, |                 1, | ||||||
|             ); |             ); | ||||||
|             $support = diff( |             $base = diff( | ||||||
|                 $support, |                 $base, | ||||||
|                 $interface, |                 $interface, | ||||||
|             ); |             ); | ||||||
|              |              | ||||||
|  | @ -354,14 +450,14 @@ sub generate { | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         # support or flange |         # support or flange | ||||||
|         if (@$support) { |         if (@$base) { | ||||||
|             my $filler = $fillers{support}; |             my $filler = $fillers{support}; | ||||||
|             $filler->angle($angles[ ($layer_id) % @angles ]); |             $filler->angle($angles[ ($layer_id) % @angles ]); | ||||||
|             my $density         = $support_density; |             my $density         = $support_density; | ||||||
|             my $flow_spacing    = $flow->spacing; |             my $flow_spacing    = $flow->spacing; | ||||||
|              |              | ||||||
|             # TODO: use offset2_ex() |             # TODO: use offset2_ex() | ||||||
|             my $to_infill = union_ex($support, 1); |             my $to_infill = union_ex($base, 1); | ||||||
|             my @paths = (); |             my @paths = (); | ||||||
|              |              | ||||||
|             # base flange |             # base flange | ||||||
|  | @ -406,7 +502,7 @@ sub generate { | ||||||
|          |          | ||||||
|         if (0) { |         if (0) { | ||||||
|             require "Slic3r/SVG.pm"; |             require "Slic3r/SVG.pm"; | ||||||
|             Slic3r::SVG::output("islands_" . $support_layers[$layer_id] . ".svg", |             Slic3r::SVG::output("islands_" . $z . ".svg", | ||||||
|                 red_expolygons      => union_ex($contact), |                 red_expolygons      => union_ex($contact), | ||||||
|                 green_expolygons    => union_ex($interface), |                 green_expolygons    => union_ex($interface), | ||||||
|                 green_polylines     => [ map $_->unpack->polyline, @{$layer->support_contact_fills} ], |                 green_polylines     => [ map $_->unpack->polyline, @{$layer->support_contact_fills} ], | ||||||
|  | @ -429,48 +525,4 @@ sub generate { | ||||||
|     ); |     ); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub _compute_support_layers { |  | ||||||
|     my ($self, $contact_z, $top_z) = @_; |  | ||||||
|      |  | ||||||
|     my $flow = $self->flow; |  | ||||||
|      |  | ||||||
|     # quick table to check whether a given Z is a top surface |  | ||||||
|     my %top = map { $_ => 1 } @$top_z; |  | ||||||
|      |  | ||||||
|     # determine layer height for any non-contact layer |  | ||||||
|     # we use max() to prevent many ultra-thin layers to be inserted in case |  | ||||||
|     # layer_height > nozzle_diameter * 0.75 |  | ||||||
|     my $support_material_height = max($self->object->config->layer_height, $flow->nozzle_diameter * 0.75); |  | ||||||
|      |  | ||||||
|     my @support_layers = sort { $a <=> $b } @$contact_z, @$top_z, |  | ||||||
|         (map { $_ + $flow->nozzle_diameter } @$top_z); |  | ||||||
|      |  | ||||||
|     # enforce first layer height |  | ||||||
|     my $first_layer_height = $self->object->config->get_value('first_layer_height'); |  | ||||||
|     shift @support_layers while @support_layers && $support_layers[0] <= $first_layer_height; |  | ||||||
|     unshift @support_layers, $first_layer_height; |  | ||||||
|      |  | ||||||
|     for (my $i = $#support_layers; $i >= 0; $i--) { |  | ||||||
|         my $target_height = $support_material_height; |  | ||||||
|         if ($i > 0 && $top{ $support_layers[$i-1] }) { |  | ||||||
|             $target_height = $flow->nozzle_diameter; |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         # enforce first layer height |  | ||||||
|         if (($i == 0 && $support_layers[$i] > $target_height + $first_layer_height) |  | ||||||
|             || ($support_layers[$i] - $support_layers[$i-1] > $target_height + Slic3r::Geometry::epsilon)) { |  | ||||||
|             splice @support_layers, $i, 0, ($support_layers[$i] - $target_height); |  | ||||||
|             $i++; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     # remove duplicates and make sure all 0.x values have the leading 0 |  | ||||||
|     { |  | ||||||
|         my %sl = map { 1 * $_ => 1 } @support_layers; |  | ||||||
|         @support_layers = sort { $a <=> $b } keys %sl; |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     return @support_layers; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 1; | 1; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci