mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	Fix generation of contact loops
This commit is contained in:
		
							parent
							
								
									06e7a1ae68
								
							
						
					
					
						commit
						4cba5111a3
					
				
					 1 changed files with 41 additions and 35 deletions
				
			
		|  | @ -3,8 +3,8 @@ use Moo; | ||||||
| 
 | 
 | ||||||
| use List::Util qw(sum min max); | use List::Util qw(sum min max); | ||||||
| use Slic3r::ExtrusionPath ':roles'; | use Slic3r::ExtrusionPath ':roles'; | ||||||
| use Slic3r::Geometry qw(scale PI rad2deg deg2rad); | use Slic3r::Geometry qw(scale scaled_epsilon PI rad2deg deg2rad); | ||||||
| use Slic3r::Geometry::Clipper qw(offset diff union_ex intersection offset_ex offset2); | use Slic3r::Geometry::Clipper qw(offset diff union union_ex intersection offset_ex offset2); | ||||||
| use Slic3r::Surface ':types'; | use Slic3r::Surface ':types'; | ||||||
| 
 | 
 | ||||||
| has 'config' => (is => 'rw', required => 1); | has 'config' => (is => 'rw', required => 1); | ||||||
|  | @ -12,6 +12,12 @@ has 'flow'   => (is => 'rw', required => 1); | ||||||
| 
 | 
 | ||||||
| use constant DEBUG_CONTACT_ONLY => 0; | use constant DEBUG_CONTACT_ONLY => 0; | ||||||
| 
 | 
 | ||||||
|  | # how much we extend support around the actual contact area | ||||||
|  | use constant MARGIN => 1.5; | ||||||
|  |      | ||||||
|  | # increment used to reach MARGIN in steps to avoid trespassing thin objects | ||||||
|  | use constant MARGIN_STEP => MARGIN/3; | ||||||
|  | 
 | ||||||
| sub generate { | sub generate { | ||||||
|     my ($self, $object) = @_; |     my ($self, $object) = @_; | ||||||
|      |      | ||||||
|  | @ -62,12 +68,6 @@ sub generate { | ||||||
| sub contact_area { | sub contact_area { | ||||||
|     my ($self, $object) = @_; |     my ($self, $object) = @_; | ||||||
|      |      | ||||||
|     # how much we extend support around the actual contact area |  | ||||||
|     my $margin = $self->flow->scaled_width * 3; |  | ||||||
|      |  | ||||||
|     # increment used to reach $margin in steps to avoid trespassing thin objects |  | ||||||
|     my $margin_step = $margin/3; |  | ||||||
|      |  | ||||||
|     # if user specified a custom angle threshold, convert it to radians |     # if user specified a custom angle threshold, convert it to radians | ||||||
|     my $threshold_rad; |     my $threshold_rad; | ||||||
|     if ($self->config->support_material_threshold) { |     if ($self->config->support_material_threshold) { | ||||||
|  | @ -77,7 +77,7 @@ sub contact_area { | ||||||
|      |      | ||||||
|     # 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 => [ polygons ] - this stores the actual overhang supported by each contact layer | ||||||
|     for my $layer_id (1 .. $#{$object->layers}) { |     for my $layer_id (1 .. $#{$object->layers}) { | ||||||
|         last if $layer_id > $self->config->raft_layers && !$self->config->support_material; |         last if $layer_id > $self->config->raft_layers && !$self->config->support_material; | ||||||
|         my $layer = $object->layers->[$layer_id]; |         my $layer = $object->layers->[$layer_id]; | ||||||
|  | @ -91,8 +91,7 @@ sub contact_area { | ||||||
|              |              | ||||||
|             # If a threshold angle was specified, use a different logic for detecting overhangs. |             # If a threshold angle was specified, use a different logic for detecting overhangs. | ||||||
|             if (defined $threshold_rad |             if (defined $threshold_rad | ||||||
|                 || $layer_id <= $self->config->support_material_enforce_layers |                 || $layer_id <= $self->config->support_material_enforce_layers + $self->config->raft_layers) { | ||||||
|                 || $layer_id <= $self->config->raft_layers) { |  | ||||||
|                 my $d = defined $threshold_rad |                 my $d = defined $threshold_rad | ||||||
|                     ? scale $lower_layer->height * ((cos $threshold_rad) / (sin $threshold_rad)) |                     ? scale $lower_layer->height * ((cos $threshold_rad) / (sin $threshold_rad)) | ||||||
|                     : 0; |                     : 0; | ||||||
|  | @ -115,6 +114,10 @@ sub contact_area { | ||||||
|                     offset([ map $_->p, @{$layerm->slices} ], -$fw/2), |                     offset([ map $_->p, @{$layerm->slices} ], -$fw/2), | ||||||
|                     [ map @$_, @{$lower_layer->slices} ], |                     [ map @$_, @{$lower_layer->slices} ], | ||||||
|                 ); |                 ); | ||||||
|  |                  | ||||||
|  |                 # collapse very tiny spots | ||||||
|  |                 $diff = offset2($diff, -$fw/10, +$fw/10); | ||||||
|  |                  | ||||||
|                 # $diff now contains the ring or stripe comprised between the boundary of  |                 # $diff now contains the ring or stripe comprised between the boundary of  | ||||||
|                 # lower slices and the centerline of the last perimeter in this overhanging layer. |                 # lower slices and the centerline of the last perimeter in this overhanging layer. | ||||||
|                 # Void $diff means that there's no upper perimeter whose centerline is |                 # Void $diff means that there's no upper perimeter whose centerline is | ||||||
|  | @ -124,7 +127,7 @@ sub contact_area { | ||||||
|             # TODO: this is the place to remove bridged areas |             # TODO: this is the place to remove bridged areas | ||||||
|              |              | ||||||
|             next if !@$diff; |             next if !@$diff; | ||||||
|             push @overhang, @{union_ex($diff)};  # NOTE: this is not the full overhang as it misses the outermost half of the perimeter width! |             push @overhang, @$diff;  # NOTE: this is not the full overhang as it misses the outermost half of the perimeter width! | ||||||
|              |              | ||||||
|             # Let's define the required contact area by using a max gap of half the upper  |             # Let's define the required contact area by using a max gap of half the upper  | ||||||
|             # extrusion width and extending the area according to the configured margin. |             # extrusion width and extending the area according to the configured margin. | ||||||
|  | @ -132,7 +135,7 @@ sub contact_area { | ||||||
|             # on the other side of the object (if it's very thin). |             # on the other side of the object (if it's very thin). | ||||||
|             { |             { | ||||||
|                 my @slices_margin = @{offset([ map @$_, @{$lower_layer->slices} ], $fw/2)}; |                 my @slices_margin = @{offset([ map @$_, @{$lower_layer->slices} ], $fw/2)}; | ||||||
|                 for ($fw/2, map {$margin_step} 1..($margin / $margin_step)) { |                 for ($fw/2, map {scale MARGIN_STEP} 1..(MARGIN / MARGIN_STEP)) { | ||||||
|                     $diff = diff( |                     $diff = diff( | ||||||
|                         offset($diff, $_), |                         offset($diff, $_), | ||||||
|                         \@slices_margin, |                         \@slices_margin, | ||||||
|  | @ -328,7 +331,8 @@ sub generate_toolpaths { | ||||||
|     my $contact_loops   = 1; |     my $contact_loops   = 1; | ||||||
|     my $circle_radius   = 1.5 * $flow->scaled_width; |     my $circle_radius   = 1.5 * $flow->scaled_width; | ||||||
|     my $circle_distance = 3 * $circle_radius; |     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)); |     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"; | ||||||
|      |      | ||||||
|  | @ -379,20 +383,24 @@ sub generate_toolpaths { | ||||||
|          |          | ||||||
|         # contact |         # contact | ||||||
|         my $contact_infill = []; |         my $contact_infill = []; | ||||||
|         if ($contact && $contact_loops > 0) { |         if (@$contact && $contact_loops > 0) { | ||||||
|             $contact = [ grep $_->is_counter_clockwise, @$contact ]; |  | ||||||
|              |  | ||||||
|             # generate the outermost loop |             # generate the outermost loop | ||||||
|             my @loops0; |             my @loops0; | ||||||
|             { |             { | ||||||
|                 # find centerline of the external loop of the contours |                 # find centerline of the external loop of the contours | ||||||
|                 my @external_loops = @{offset($contact, -$flow->scaled_width/2)}; |                 my @external_loops = @{offset($contact, -$flow->scaled_width/2)}; | ||||||
|                  |                  | ||||||
|  |                 # only consider the loops facing the overhang | ||||||
|  |                 { | ||||||
|  |                     my $overhang_with_margin = offset($overhang, +$flow->scaled_width/2); | ||||||
|  |                     @external_loops = grep { @{intersection([$_], $overhang_with_margin)} } @external_loops; | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|                 # apply a pattern to the loop |                 # apply a pattern to the loop | ||||||
|                 my @positions = map Slic3r::Polygon->new(@$_)->split_at_first_point->regular_points($circle_distance), @external_loops; |                 my @positions = map Slic3r::Polygon->new(@$_)->split_at_first_point->regular_points($circle_distance), @external_loops; | ||||||
|                 @loops0 = @{diff( |                 @loops0 = @{diff( | ||||||
|                     [ @external_loops ], |                     [ @external_loops ], | ||||||
|                     [ map $circle->clone->translate(@$_), @positions ], |                     [ map { my $c = $circle->clone; $c->translate(@$_); $c } @positions ], | ||||||
|                 )}; |                 )}; | ||||||
|             } |             } | ||||||
|              |              | ||||||
|  | @ -406,12 +414,19 @@ sub generate_toolpaths { | ||||||
|             # clip such loops to the side oriented towards the object |             # clip such loops to the side oriented towards the object | ||||||
|             @loops = map Slic3r::Polyline->new(@$_), |             @loops = map Slic3r::Polyline->new(@$_), | ||||||
|                 @{ Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection( |                 @{ Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection( | ||||||
|                     [ map $_->pp, @{offset_ex([ map @$_, @$overhang ], +scale 3)} ], |                     [ map $_->pp, @{offset_ex($overhang, +scale MARGIN)} ], | ||||||
|                     [ map Slic3r::Polygon->new(@$_)->split_at_first_point->pp, @loops ], |                     [ map $_->split_at_first_point->pp, @loops ], | ||||||
|                 ) }; |                 ) }; | ||||||
|              |              | ||||||
|             # add the contact infill area to the interface area |             # add the contact infill area to the interface area | ||||||
|             $contact_infill = offset2(\@loops0, -($contact_loops + 0.5) * $flow->scaled_spacing, +0.5*$flow->scaled_spacing); |             # note that growing loops by $circle_radius ensures no tiny | ||||||
|  |             # extrusions are left inside the circles; however it creates | ||||||
|  |             # a very large gap between loops and contact_infill, so maybe another | ||||||
|  |             # solution should be found to achieve both goals | ||||||
|  |             $contact_infill = diff( | ||||||
|  |                 $contact, | ||||||
|  |                 [ map $_->grow($circle_radius), @loops ], | ||||||
|  |             ); | ||||||
|              |              | ||||||
|             # transform loops into ExtrusionPath objects |             # transform loops into ExtrusionPath objects | ||||||
|             @loops = map Slic3r::ExtrusionPath->new( |             @loops = map Slic3r::ExtrusionPath->new( | ||||||
|  | @ -428,25 +443,16 @@ sub generate_toolpaths { | ||||||
|             $fillers{interface}->angle($interface_angle); |             $fillers{interface}->angle($interface_angle); | ||||||
|              |              | ||||||
|             # steal some space from support |             # steal some space from support | ||||||
|             $interface = intersection( |             $interface = offset([ @$interface, @$contact_infill ], scaled_epsilon); | ||||||
|                 offset([ @$interface, @$contact_infill ], scale 3), |  | ||||||
|                 [ @$interface, @$base, @$contact_infill ], |  | ||||||
|                 1, |  | ||||||
|             ) if 0; # this causes bad overlapping with other layers as it doesn't take Z overlap into account |  | ||||||
|             $base = diff( |  | ||||||
|                 $base, |  | ||||||
|                 $interface, |  | ||||||
|             ); |  | ||||||
|              |              | ||||||
|             my @paths = (); |             my @paths = (); | ||||||
|             foreach my $expolygon (@{union_ex($interface)}) { |             foreach my $expolygon (@{union_ex($interface)}) { | ||||||
|                 my @p = $fillers{interface}->fill_surface( |                 my ($params, @p) = $fillers{interface}->fill_surface( | ||||||
|                     Slic3r::Surface->new(expolygon => $expolygon, surface_type => S_TYPE_INTERNAL), |                     Slic3r::Surface->new(expolygon => $expolygon, surface_type => S_TYPE_INTERNAL), | ||||||
|                     density         => $interface_density, |                     density         => $interface_density, | ||||||
|                     flow_spacing    => $flow->spacing, |                     flow_spacing    => $flow->spacing, | ||||||
|                     complete        => 1, |                     complete        => 1, | ||||||
|                 ); |                 ); | ||||||
|                 my $params = shift @p; |  | ||||||
|                  |                  | ||||||
|                 push @paths, map Slic3r::ExtrusionPath->new( |                 push @paths, map Slic3r::ExtrusionPath->new( | ||||||
|                     polyline        => Slic3r::Polyline->new(@$_), |                     polyline        => Slic3r::Polyline->new(@$_), | ||||||
|  | @ -455,6 +461,7 @@ sub generate_toolpaths { | ||||||
|                     flow_spacing    => $params->{flow_spacing}, |                     flow_spacing    => $params->{flow_spacing}, | ||||||
|                 ), @p; |                 ), @p; | ||||||
|             } |             } | ||||||
|  |              | ||||||
|             $layer->support_interface_fills->append(@paths); |             $layer->support_interface_fills->append(@paths); | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  | @ -490,13 +497,12 @@ sub generate_toolpaths { | ||||||
|             } |             } | ||||||
|              |              | ||||||
|             foreach my $expolygon (@$to_infill) { |             foreach my $expolygon (@$to_infill) { | ||||||
|                 my @p = $filler->fill_surface( |                 my ($params, @p) = $filler->fill_surface( | ||||||
|                     Slic3r::Surface->new(expolygon => $expolygon, surface_type => S_TYPE_INTERNAL), |                     Slic3r::Surface->new(expolygon => $expolygon, surface_type => S_TYPE_INTERNAL), | ||||||
|                     density         => $density, |                     density         => $density, | ||||||
|                     flow_spacing    => $flow_spacing, |                     flow_spacing    => $flow_spacing, | ||||||
|                     complete        => 1, |                     complete        => 1, | ||||||
|                 ); |                 ); | ||||||
|                 my $params = shift @p; |  | ||||||
|                  |                  | ||||||
|                 push @paths, map Slic3r::ExtrusionPath->new( |                 push @paths, map Slic3r::ExtrusionPath->new( | ||||||
|                     polyline        => Slic3r::Polyline->new(@$_), |                     polyline        => Slic3r::Polyline->new(@$_), | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci