mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	New algorithm for overhang detection
This commit is contained in:
		
							parent
							
								
									015580629b
								
							
						
					
					
						commit
						7e875393f5
					
				
					 3 changed files with 65 additions and 42 deletions
				
			
		|  | @ -60,6 +60,17 @@ sub pack { | |||
| # no-op, this allows to use both packed and non-packed objects in Collections | ||||
| sub unpack { $_[0] } | ||||
| 
 | ||||
| sub clone { | ||||
|     my $self = shift; | ||||
|     my %p = @_; | ||||
|      | ||||
|     $p{polyline} ||= $self->polyline->clone; | ||||
|     return (ref $self)->new( | ||||
|         (map { $_ => $self->$_ } qw(polyline height flow_spacing role)), | ||||
|         %p, | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| sub clip_with_polygon { | ||||
|     my $self = shift; | ||||
|     my ($polygon) = @_; | ||||
|  | @ -71,16 +82,24 @@ 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, | ||||
|             height          => $self->height, | ||||
|             flow_spacing    => $self->flow_spacing, | ||||
|             role            => $self->role, | ||||
|         ); | ||||
|     } | ||||
|     return @paths; | ||||
|     return map $self->clone(polyline => $_), | ||||
|         $self->polyline->clip_with_expolygon($expolygon); | ||||
| } | ||||
| 
 | ||||
| sub intersect_expolygons { | ||||
|     my $self = shift; | ||||
|     my ($expolygons) = @_; | ||||
|      | ||||
|     return map $self->clone(polyline => Slic3r::Polyline->new(@$_)), | ||||
|         @{Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection($expolygons, [$self->polyline])}; | ||||
| } | ||||
| 
 | ||||
| sub subtract_expolygons { | ||||
|     my $self = shift; | ||||
|     my ($expolygons) = @_; | ||||
|      | ||||
|     return map $self->clone(polyline => Slic3r::Polyline->new(@$_)), | ||||
|         @{Boost::Geometry::Utils::multi_linestring_multi_polygon_difference([$self->polyline], $expolygons)}; | ||||
| } | ||||
| 
 | ||||
| sub simplify { | ||||
|  | @ -141,22 +160,15 @@ sub split_at_acute_angles { | |||
|             # if the angle between $p[-2], $p[-1], $p3 is too acute | ||||
|             # then consider $p3 only as a starting point of a new | ||||
|             # path and stop the current one as it is | ||||
|             push @paths, (ref $self)->new( | ||||
|                 polyline        => Slic3r::Polyline->new(\@p), | ||||
|                 role            => $self->role, | ||||
|                 height          => $self->height, | ||||
|              ); | ||||
|             push @paths, $self->clone(polyline => Slic3r::Polyline->new(\@p)); | ||||
|             @p = ($p3); | ||||
|             push @p, grep $_, shift @points or last; | ||||
|         } else { | ||||
|             push @p, $p3; | ||||
|         } | ||||
|     } | ||||
|     push @paths, (ref $self)->new( | ||||
|         polyline        => Slic3r::Polyline->new(\@p), | ||||
|         role            => $self->role, | ||||
|         height          => $self->height, | ||||
|     ) if @p > 1; | ||||
|     push @paths, $self->clone(polyline => Slic3r::Polyline->new(\@p)) | ||||
|         if @p > 1; | ||||
|      | ||||
|     return @paths; | ||||
| } | ||||
|  | @ -251,12 +263,8 @@ sub detect_arcs { | |||
|             ); | ||||
|              | ||||
|             # points 0..$i form a linear path | ||||
|             push @paths, (ref $self)->new( | ||||
|                 polyline        => Slic3r::Polyline->new(@points[0..$i]), | ||||
|                 role            => $self->role, | ||||
|                 flow_spacing    => $self->flow_spacing, | ||||
|                 height          => $self->height, | ||||
|             ) if $i > 0; | ||||
|             push @paths, $self->clone(polyline => Slic3r::Polyline->new(@points[0..$i])) | ||||
|                 if $i > 0; | ||||
|              | ||||
|             # add our arc | ||||
|             push @paths, $arc; | ||||
|  | @ -271,12 +279,8 @@ sub detect_arcs { | |||
|     } | ||||
|      | ||||
|     # remaining points form a linear path | ||||
|     push @paths, (ref $self)->new( | ||||
|         polyline        => Slic3r::Polyline->new(\@points), | ||||
|         role            => $self->role, | ||||
|         flow_spacing    => $self->flow_spacing, | ||||
|         height          => $self->height, | ||||
|     ) if @points > 1; | ||||
|     push @paths, $self->clone(polyline => Slic3r::Polyline->new(\@points)) | ||||
|         if @points > 1; | ||||
|      | ||||
|     return @paths; | ||||
| } | ||||
|  |  | |||
|  | @ -5,11 +5,13 @@ use List::Util qw(min max first); | |||
| use Slic3r::ExtrusionPath ':roles'; | ||||
| use Slic3r::Geometry qw(scale unscale scaled_epsilon points_coincide PI X Y B); | ||||
| use Slic3r::Geometry::Clipper qw(union_ex); | ||||
| use Slic3r::Surface ':types'; | ||||
| 
 | ||||
| has 'config'             => (is => 'ro', required => 1); | ||||
| has 'multiple_extruders' => (is => 'ro', default => sub {0} ); | ||||
| has 'layer_count'        => (is => 'ro', required => 1 ); | ||||
| has 'layer'              => (is => 'rw'); | ||||
| has '_layer_overhangs'   => (is => 'rw'); | ||||
| has 'move_z_callback'    => (is => 'rw'); | ||||
| has 'shift_x'            => (is => 'rw', default => sub {0} ); | ||||
| has 'shift_y'            => (is => 'rw', default => sub {0} ); | ||||
|  | @ -82,6 +84,11 @@ sub change_layer { | |||
|     my ($layer) = @_; | ||||
|      | ||||
|     $self->layer($layer); | ||||
|     $self->_layer_overhangs( | ||||
|         $layer->id > 0 | ||||
|             ? [ map $_->expolygon, grep $_->surface_type == S_TYPE_BOTTOM, map @{$_->slices}, @{$layer->regions} ] | ||||
|             : [] | ||||
|         ); | ||||
|     if ($self->config->avoid_crossing_perimeters) { | ||||
|         $self->layer_mp(Slic3r::GCode::MotionPlanner->new( | ||||
|             islands => union_ex([ map @$_, @{$layer->slices} ], undef, 1), | ||||
|  | @ -152,8 +159,29 @@ sub extrude_loop { | |||
|     $extrusion_path->clip_end(scale $extrusion_path->flow_spacing * &Slic3r::LOOP_CLIPPING_LENGTH_OVER_SPACING); | ||||
|     return '' if !@{$extrusion_path->polyline}; | ||||
|      | ||||
|     my @paths = (); | ||||
|     # detect overhanging/bridging perimeters | ||||
|     if ($extrusion_path->is_perimeter && @{$self->_layer_overhangs}) { | ||||
|         # get non-overhang paths by subtracting overhangs from the loop | ||||
|         push @paths, | ||||
|             $extrusion_path->subtract_expolygons($self->_layer_overhangs); | ||||
|          | ||||
|         # get overhang paths by intersecting overhangs with the loop | ||||
|         push @paths, | ||||
|             map { $_->role(EXTR_ROLE_OVERHANG_PERIMETER); $_ } | ||||
|             $extrusion_path->intersect_expolygons($self->_layer_overhangs); | ||||
|          | ||||
|         # reapply the nearest point search for starting point | ||||
|         # (TODO: choose the nearest point not on an overhang) | ||||
|         @paths = Slic3r::ExtrusionPath::Collection | ||||
|             ->new(paths => [@paths]) | ||||
|             ->chained_path($last_pos); | ||||
|     } else { | ||||
|         push @paths, $extrusion_path; | ||||
|     } | ||||
|      | ||||
|     # extrude along the path | ||||
|     my $gcode = $self->extrude_path($extrusion_path, $description); | ||||
|     my $gcode = join '', map $self->extrude_path($_, $description), @paths; | ||||
|     $self->wipe_path($extrusion_path->polyline); | ||||
|      | ||||
|     # make a little move inwards before leaving loop | ||||
|  |  | |||
|  | @ -267,15 +267,6 @@ sub make_perimeters { | |||
|                 $role = EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER; | ||||
|             } | ||||
|              | ||||
|             if ($self->id > 0) { | ||||
|                 # A perimeter is considered overhang if its centerline exceeds the lower layer slices | ||||
|                 my $is_overhang = $is_contour | ||||
|                     ? @{diff([$polygon], \@lower_slices)} | ||||
|                     : !@{intersection([$polygon], \@lower_slices)}; | ||||
|                  | ||||
|                 $role = EXTR_ROLE_OVERHANG_PERIMETER if $is_overhang; | ||||
|             } | ||||
|              | ||||
|             push @loops, Slic3r::ExtrusionLoop->pack( | ||||
|                 polygon         => $polygon, | ||||
|                 role            => $role, | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci