mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 12:41:20 -06:00 
			
		
		
		
	Extrusion of perimeters
This commit is contained in:
		
							parent
							
								
									55a523e1fa
								
							
						
					
					
						commit
						febd655e22
					
				
					 11 changed files with 206 additions and 5 deletions
				
			
		|  | @ -32,6 +32,12 @@ has 'surfaces' => ( | |||
|     default => sub { [] }, | ||||
| ); | ||||
| 
 | ||||
| has 'perimeters' => ( | ||||
|     is      => 'rw', | ||||
|     isa     => 'ArrayRef[Slic3r::Polyline]', | ||||
|     default => sub { [] }, | ||||
| ); | ||||
| 
 | ||||
| sub z { | ||||
|     my $self = shift; | ||||
|     return $self->id * $Slic3r::layer_height / $Slic3r::resolution; | ||||
|  | @ -313,7 +319,7 @@ sub merge_contiguous_surfaces { | |||
|                 ); | ||||
|                  | ||||
|                 printf "  merging into new surface %s\n", $new_surface->id; | ||||
|                 push @{ $self->surfaces }, $surface; | ||||
|                 push @{ $self->surfaces }, $new_surface; | ||||
|                  | ||||
|                 $self->remove_surface($_) for ($surface, $neighbor_surface); | ||||
|             } | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| package Slic3r::Line; | ||||
| use Moose; | ||||
| 
 | ||||
| use Moose::Util::TypeConstraints; | ||||
| use Scalar::Util qw(weaken); | ||||
| 
 | ||||
| has 'a' => ( | ||||
|  | @ -21,6 +22,11 @@ has 'polyline' => ( | |||
|     weak_ref    => 1, | ||||
| ); | ||||
| 
 | ||||
| has 'solid_side' => ( | ||||
|     is      => 'rw', | ||||
|     isa     => enum([qw(left right)]),  # going from a to b | ||||
| ); | ||||
| 
 | ||||
| sub BUILD { | ||||
|     my $self = shift; | ||||
|      | ||||
|  | @ -45,6 +51,12 @@ sub coincides_with { | |||
|         || ($self->a->coincides_with($line->b) && $self->b->coincides_with($line->a)); | ||||
| } | ||||
| 
 | ||||
| sub has_endpoint { | ||||
|     my $self = shift; | ||||
|     my ($point) = @_;#printf "    %s has endpoint %s: %s\n", $self->id, $point->id, ($point eq $self->a || $point eq $self->b); | ||||
|     return $point->coincides_with($self->a) || $point->coincides_with($self->b); | ||||
| } | ||||
| 
 | ||||
| sub slope { | ||||
|     my $self = shift; | ||||
|     return undef if $self->b->x == $self->a->x;  # line is vertical | ||||
|  |  | |||
							
								
								
									
										104
									
								
								lib/Slic3r/Perimeter.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								lib/Slic3r/Perimeter.pm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,104 @@ | |||
| package Slic3r::Perimeter; | ||||
| use Moose; | ||||
| 
 | ||||
| use Math::Geometry::Planar; | ||||
| *Math::Geometry::Planar::OffsetPolygon = *Math::Geometry::Planar::Offset::OffsetPolygon; | ||||
| 
 | ||||
| sub make_perimeter { | ||||
|     my $self = shift; | ||||
|     my ($layer) = @_; | ||||
|     printf "Making perimeter for layer %d:\n", $layer->id; | ||||
|      | ||||
|     # skip entire section if no perimeters are requested | ||||
|     return unless $Slic3r::perimeter_offsets > 0; | ||||
|      | ||||
|     my (@perimeters, %contours, %holes) = (); | ||||
|     foreach my $surface (@{ $layer->surfaces }) { | ||||
|         $contours{$surface} = []; | ||||
|         $holes{$surface} = []; | ||||
|          | ||||
|         # first perimeter | ||||
|         { | ||||
|             my $polygon = $surface->mgp_polygon; | ||||
|             my ($contour_p, @holes_p) = @{ $polygon->polygons }; | ||||
|             push @{ $contours{$surface} }, $contour_p; | ||||
|             push @{ $holes{$surface} }, @holes_p; | ||||
|             push @perimeters, $polygon; | ||||
|         } | ||||
|          | ||||
|         # create other offsets | ||||
|         for (my $loop = 1; $loop < $Slic3r::perimeter_offsets; $loop++) { | ||||
|             my ($contour_p, @holes_p) = map $self->_mgp_from_points_ref($_), @{ $perimeters[-1]->polygons }; | ||||
|              | ||||
|             # generate offsets | ||||
|             my $contour_offsets = $contour_p->offset_polygon($Slic3r::flow_width / $Slic3r::resolution); | ||||
|             my @hole_offsets = map @$_, map $_->offset_polygon(- $Slic3r::flow_width / $Slic3r::resolution), @holes_p; | ||||
|              | ||||
|             # now we subtract perimeter offsets from the contour offset polygon | ||||
|             # this will generate a single polygon with correct holes and also | ||||
|             # will take care of collisions between contour offset and holes | ||||
|             foreach my $contour_points (@$contour_offsets) { | ||||
|                 my $tmp = $self->_mgp_from_points_ref($contour_points)->convert2gpc; | ||||
|                 foreach my $hole_points (@hole_offsets) { | ||||
|                     $hole_points = $self->_mgp_from_points_ref($hole_points)->convert2gpc; | ||||
|                     $tmp = GpcClip('DIFFERENCE', $tmp, $hole_points); | ||||
|                 } | ||||
|                  | ||||
|                 my ($result) = Gpc2Polygons($tmp); | ||||
|                 # now we've got $result, which is a Math::Geometry::Planar | ||||
|                 # representing the inner surface including hole perimeters | ||||
|                  | ||||
|                 my $result_polylines = $result->polygons; | ||||
|                  | ||||
|                 ($contour_p, @holes_p) = @$result_polylines; | ||||
|                 push @{ $contours{$surface} }, $contour_p; | ||||
|                 push @{ $holes{$surface} }, @holes_p; | ||||
|                 push @perimeters, $result; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     # generate paths for holes | ||||
|     # we start from innermost loops (that is, external ones), do them | ||||
|     # for all holes, than go on with inner loop and do that for all | ||||
|     # holes and so on | ||||
|     foreach my $p (map @$_, values %holes) { | ||||
|         push @{ $layer->perimeters }, Slic3r::Polyline->new_from_points(@{ $p->points }); | ||||
|     } | ||||
|      | ||||
|     # generate paths for contours | ||||
|     # this time we do something different: we do contour loops for one | ||||
|     # shape (that is, one original surface) at a time: we start from the | ||||
|     # innermost loop (that is, internal one), then without interrupting  | ||||
|     # our path we go onto the outer loop and continue; this should ensure | ||||
|     # good surface quality | ||||
|     foreach my $polylines (values %contours) { | ||||
|         my @path_points = (); | ||||
|         foreach my $p (map $self->_mgp_from_points_ref($_), @$polylines) { | ||||
|             my $points = $p->points; | ||||
|             # TODO: the initial $points->[0] should be replaced by the point of | ||||
|             # the segment which is $Slic3r::flow_width / $Slic3r::resolution  | ||||
|             # away from it to avoid the extruder to get two times there | ||||
|             push @path_points, @$points, $points->[0]; | ||||
|         } | ||||
|         push @{ $layer->perimeters }, Slic3r::Polyline->new_from_points(reverse @path_points); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| sub _mgp_from_points_ref { | ||||
|     my $self = shift; | ||||
|     my ($points) = @_; | ||||
|     my $p = Math::Geometry::Planar->new; | ||||
|     $p->points($points); | ||||
|     return $p; | ||||
| } | ||||
| 
 | ||||
| sub _mgp_from_polygons_ref { | ||||
|     my $self = shift; | ||||
|     my ($polygons) = @_; | ||||
|     my $p = Math::Geometry::Planar->new; | ||||
|     $p->polygons($polygons); | ||||
|     return $p; | ||||
| } | ||||
| 
 | ||||
| 1; | ||||
|  | @ -35,6 +35,8 @@ sub coincides_with { | |||
|     my $self = shift; | ||||
|     my ($point) = @_; | ||||
|      | ||||
|     $point = Slic3r::Point->new(x => $point->[0], y => $point->[1]) #== | ||||
|         if ref $point eq 'ARRAY'; | ||||
|     return $self->x == $point->x && $self->y == $point->y; #= | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -26,7 +26,7 @@ sub BUILD { | |||
| 
 | ||||
| sub id { | ||||
|     my $self = shift; | ||||
|     return join '-', map($_->id, $self->points); | ||||
|     return join '-', map($_->id, $self->ordered_points(1)); | ||||
| } | ||||
| 
 | ||||
| sub new_from_points { | ||||
|  | @ -61,4 +61,44 @@ sub points { | |||
|     return values %points; | ||||
| } | ||||
| 
 | ||||
| sub ordered_points { | ||||
|     my $self = shift; | ||||
|     my ($as_objects) = @_; | ||||
|     my $points = []; | ||||
|      | ||||
|     #printf "\n\n==> Number of lines: %d\n", scalar @{ $self->lines }; | ||||
|     my @lines = @{ $self->lines }; | ||||
|     while (@lines && @$points < @{ $self->lines }) { | ||||
|         #printf "\nNumber of points: %d\n", scalar @{ $points }; | ||||
|         my @temp = @lines; | ||||
|         @lines = (); | ||||
|         foreach my $line (@temp) { | ||||
|             #printf "Line: %s\n", $line->id; | ||||
|             my $point; | ||||
|             if (!@$points) { | ||||
|                 # make sure we start from a point not connected to another segment if any | ||||
|                 push @$points, sort { @{$a->lines} <=> @{$b->lines} } $line->points; | ||||
|                 next; | ||||
|             } elsif ($line->has_endpoint($points->[-1])) { | ||||
|                 $point = +(grep $points->[-1] ne $_, $line->points)[0]; | ||||
|             } | ||||
|             if (!$point) { | ||||
|                 #printf "  no point found, retrying\n"; | ||||
|                 push @lines, $line; | ||||
|                 next; | ||||
|             } | ||||
|             #printf "  adding point %s\n", $point->id; | ||||
|             push @$points, $point; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     pop @$points | ||||
|         if $self->isa('Slic3r::Polyline::Closed') && $points->[0]->coincides_with($points->[-1]); | ||||
|      | ||||
|     return @$points if $as_objects; | ||||
|      | ||||
|     $points = [ map [ $_->x, $_->y ], @$points ]; #] | ||||
|     return $points; | ||||
| } | ||||
| 
 | ||||
| 1; | ||||
|  |  | |||
|  | @ -58,4 +58,15 @@ sub encloses_point { | |||
|     return $side; | ||||
| } | ||||
| 
 | ||||
| sub mgp_polygon { | ||||
|     my $self = shift; | ||||
|      | ||||
|     # we need a list of ordered points | ||||
|     my $points = $self->ordered_points; | ||||
|      | ||||
|     my $p = Math::Geometry::Planar->new; | ||||
|     $p->points($points); | ||||
|     return $p; | ||||
| } | ||||
| 
 | ||||
| 1; | ||||
|  |  | |||
|  | @ -26,4 +26,16 @@ sub layer { | |||
|     return $self->layers->[$layer_id]; | ||||
| } | ||||
| 
 | ||||
| sub extrude_perimeters { | ||||
|     my $self = shift; | ||||
|      | ||||
|     my $perimeter_extruder = Slic3r::Perimeter->new; | ||||
|      | ||||
|     foreach my $layer (@{ $self->layers }) { | ||||
|         $perimeter_extruder->make_perimeter($layer); | ||||
|         printf "  generated paths: %s\n", | ||||
|             join '  ', map $_->id, @{ $layer->perimeters }; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 1; | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| package Slic3r::Surface; | ||||
| use Moose; | ||||
| 
 | ||||
| use Math::Geometry::Planar; | ||||
| use Moose::Util::TypeConstraints; | ||||
| 
 | ||||
| has 'contour' => ( | ||||
|  | @ -55,4 +56,12 @@ sub encloses_point { | |||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| sub mgp_polygon { | ||||
|     my $self = shift; | ||||
|      | ||||
|     my $p = Math::Geometry::Planar->new; | ||||
|     $p->polygons([ map $_->points, $self->contour->mgp_polygon, map($_->mgp_polygon, @{ $self->holes }) ]); | ||||
|     return $p; | ||||
| } | ||||
| 
 | ||||
| 1; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci