mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	More tests and related fixes to bridge detection. #1917
This commit is contained in:
		
							parent
							
								
									c4bfe64fb8
								
							
						
					
					
						commit
						f7e8a99078
					
				
					 3 changed files with 50 additions and 30 deletions
				
			
		|  | @ -1,19 +1,20 @@ | |||
| package Slic3r::Layer::BridgeDetector; | ||||
| use Moo; | ||||
| 
 | ||||
| use List::Util qw(first sum); | ||||
| use Slic3r::Geometry qw(PI scaled_epsilon rad2deg epsilon); | ||||
| use List::Util qw(first sum max); | ||||
| use Slic3r::Geometry qw(PI unscale scaled_epsilon rad2deg epsilon); | ||||
| use Slic3r::Geometry::Clipper qw(intersection_pl intersection_ex); | ||||
| 
 | ||||
| has 'lower_slices'      => (is => 'rw', required => 1);  # ExPolygons or ExPolygonCollection | ||||
| has 'perimeter_flow'    => (is => 'rw', required => 1); | ||||
| has 'infill_flow'       => (is => 'rw', required => 1); | ||||
| has 'resolution'        => (is => 'rw', default => sub { PI/36 }); | ||||
| 
 | ||||
| sub detect_angle { | ||||
|     my ($self, $expolygon) = @_; | ||||
|      | ||||
|     my $grown = $expolygon->offset(+$self->perimeter_flow->scaled_width); | ||||
|     my $anchors_offset = $self->infill_flow->scaled_width; | ||||
|      | ||||
|     my $grown = $expolygon->offset(+$anchors_offset); | ||||
|     my @lower = @{$self->lower_slices};       # expolygons | ||||
|      | ||||
|     # detect what edges lie on lower slices | ||||
|  | @ -55,8 +56,10 @@ sub detect_angle { | |||
|             $bridge_angle = $line->direction; | ||||
|         } | ||||
|     } elsif (@edges) { | ||||
|         # inset the bridge expolygon; we'll use this one to clip our test lines | ||||
|         my $inset = $expolygon->offset_ex($self->infill_flow->scaled_width); | ||||
|         # Outset the bridge expolygon by half the amount we used for detecting anchors; | ||||
|         # we'll use this one to clip our test lines and be sure that their endpoints | ||||
|         # are inside the anchors and not on their contours leading to false negatives. | ||||
|         my $clip_area = $expolygon->offset_ex(+$anchors_offset/2); | ||||
|          | ||||
|         # detect anchors as intersection between our bridge expolygon and the lower slices | ||||
|         my $anchors = intersection_ex( | ||||
|  | @ -69,14 +72,15 @@ sub detect_angle { | |||
|             # we'll now try several directions using a rudimentary visibility check: | ||||
|             # bridge in several directions and then sum the length of lines having both | ||||
|             # endpoints within anchors | ||||
|             my %directions = ();  # angle => score | ||||
|             my %directions_coverage     = ();  # angle => score | ||||
|             my %directions_avg_length   = ();  # angle => score | ||||
|             my $line_increment = $self->infill_flow->scaled_width; | ||||
|             for (my $angle = 0; $angle < PI; $angle += $self->resolution) { | ||||
|                 my $my_inset   = [ map $_->clone, @$inset ]; | ||||
|                 my $my_anchors = [ map $_->clone, @$anchors ]; | ||||
|                 my $my_clip_area    = [ map $_->clone, @$clip_area ]; | ||||
|                 my $my_anchors      = [ map $_->clone, @$anchors ]; | ||||
|                  | ||||
|                 # rotate everything - the center point doesn't matter | ||||
|                 $_->rotate($angle, [0,0]) for @$my_inset, @$my_anchors; | ||||
|                 $_->rotate($angle, [0,0]) for @$my_clip_area, @$my_anchors; | ||||
|              | ||||
|                 # generate lines in this direction | ||||
|                 my $bounding_box = Slic3r::Geometry::BoundingBox->new_from_points([ map @$_, map @$_, @$my_anchors ]); | ||||
|  | @ -89,8 +93,8 @@ sub detect_angle { | |||
|                     ); | ||||
|                 } | ||||
|                  | ||||
|                 my @clipped_lines = map Slic3r::Line->new(@$_), @{ intersection_pl(\@lines, [ map @$_, @$my_inset ]) }; | ||||
|              | ||||
|                 my @clipped_lines = map Slic3r::Line->new(@$_), @{ intersection_pl(\@lines, [ map @$_, @$my_clip_area ]) }; | ||||
|                  | ||||
|                 # remove any line not having both endpoints within anchors | ||||
|                 # NOTE: these calls to contains_point() probably need to check whether the point  | ||||
|                 # is on the anchor boundaries too | ||||
|  | @ -99,15 +103,29 @@ sub detect_angle { | |||
|                     (first { $_->contains_point($line->a) } @$my_anchors) | ||||
|                         && (first { $_->contains_point($line->b) } @$my_anchors); | ||||
|                 } @clipped_lines; | ||||
|              | ||||
|                  | ||||
|                 my @lengths = map $_->length, @clipped_lines; | ||||
|                  | ||||
|                 # sum length of bridged lines | ||||
|                 $directions{$angle} = sum(map $_->length, @clipped_lines) // 0; | ||||
|             } | ||||
|          | ||||
|             # this could be slightly optimized with a max search instead of the sort | ||||
|             my @sorted_directions = sort { $directions{$a} <=> $directions{$b} } keys %directions; | ||||
|                 $directions_coverage{$angle} = sum(@lengths) // 0; | ||||
|              | ||||
|                 # max length of bridged lines | ||||
|                 $directions_avg_length{$angle} = @lengths ? (max(@lengths)) : -1; | ||||
|             } | ||||
|              | ||||
|             # the best direction is the one causing most lines to be bridged (thus most coverage) | ||||
|             # and shortest max line length | ||||
|             my @sorted_directions = sort { | ||||
|                 my $cmp; | ||||
|                 my $coverage_diff = $directions_coverage{$a} - $directions_coverage{$b}; | ||||
|                 if (abs($coverage_diff) < $self->infill_flow->scaled_width) { | ||||
|                     $cmp = $directions_avg_length{$b} <=> $directions_avg_length{$a}; | ||||
|                 } else { | ||||
|                     $cmp = ($coverage_diff > 0) ? 1 : -1; | ||||
|                 } | ||||
|                 $cmp; | ||||
|             } keys %directions_coverage; | ||||
|              | ||||
|             # the best direction is the one causing most lines to be bridged | ||||
|             $bridge_angle = $sorted_directions[-1]; | ||||
|         } | ||||
|     } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci