mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	Merge branch 'master' into xs
This commit is contained in:
		
						commit
						eb2d20d062
					
				
					 18 changed files with 110 additions and 77 deletions
				
			
		
							
								
								
									
										1
									
								
								MANIFEST
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								MANIFEST
									
										
									
									
									
								
							|  | @ -71,6 +71,7 @@ t/cooling.t | ||||||
| t/custom_gcode.t | t/custom_gcode.t | ||||||
| t/dynamic.t | t/dynamic.t | ||||||
| t/fill.t | t/fill.t | ||||||
|  | t/freeze.t | ||||||
| t/gcode.t | t/gcode.t | ||||||
| t/geometry.t | t/geometry.t | ||||||
| t/layers.t | t/layers.t | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ use List::Util qw(first); | ||||||
| use Math::Geometry::Voronoi; | use Math::Geometry::Voronoi; | ||||||
| use Slic3r::Geometry qw(X Y A B point_in_polygon same_line epsilon); | use Slic3r::Geometry qw(X Y A B point_in_polygon same_line epsilon); | ||||||
| use Slic3r::Geometry::Clipper qw(union_ex JT_MITER); | use Slic3r::Geometry::Clipper qw(union_ex JT_MITER); | ||||||
|  | use Storable qw(); | ||||||
| 
 | 
 | ||||||
| # the constructor accepts an array of polygons  | # the constructor accepts an array of polygons  | ||||||
| # or a Math::Clipper ExPolygon (hashref) | # or a Math::Clipper ExPolygon (hashref) | ||||||
|  | @ -17,19 +18,18 @@ sub new { | ||||||
|     my $self; |     my $self; | ||||||
|     if (@_ == 1 && ref $_[0] eq 'HASH') { |     if (@_ == 1 && ref $_[0] eq 'HASH') { | ||||||
|         $self = [ |         $self = [ | ||||||
|             Slic3r::Polygon->new($_[0]{outer}), |             Slic3r::Polygon->new(@{$_[0]{outer}}), | ||||||
|             map Slic3r::Polygon->new($_), @{$_[0]{holes}}, |             map Slic3r::Polygon->new(@$_), @{$_[0]{holes}}, | ||||||
|         ]; |         ]; | ||||||
|     } else { |     } else { | ||||||
|         $self = [ map Slic3r::Polygon->new($_), @_ ]; |         $self = [ map Slic3r::Polygon->new(@$_), @_ ]; | ||||||
|     } |     } | ||||||
|     bless $self, $class; |     bless $self, $class; | ||||||
|     $self; |     $self; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub clone { | sub clone { | ||||||
|     my $self = shift; |     Storable::dclone($_[0]) | ||||||
|     return (ref $self)->new(map $_->clone, @$self); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub contour { | sub contour { | ||||||
|  | @ -287,7 +287,7 @@ sub medial_axis { | ||||||
|             next if @$polyline == 2; |             next if @$polyline == 2; | ||||||
|             push @result, Slic3r::Polygon->new(@$polyline[0..$#$polyline-1]); |             push @result, Slic3r::Polygon->new(@$polyline[0..$#$polyline-1]); | ||||||
|         } else { |         } else { | ||||||
|             push @result, Slic3r::Polyline->new($polyline); |             push @result, Slic3r::Polyline->new(@$polyline); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |  | ||||||
|  | @ -160,14 +160,14 @@ sub split_at_acute_angles { | ||||||
|             # if the angle between $p[-2], $p[-1], $p3 is too acute |             # if the angle between $p[-2], $p[-1], $p3 is too acute | ||||||
|             # then consider $p3 only as a starting point of a new |             # then consider $p3 only as a starting point of a new | ||||||
|             # path and stop the current one as it is |             # path and stop the current one as it is | ||||||
|             push @paths, $self->clone(polyline => Slic3r::Polyline->new(\@p)); |             push @paths, $self->clone(polyline => Slic3r::Polyline->new(@p)); | ||||||
|             @p = ($p3); |             @p = ($p3); | ||||||
|             push @p, grep $_, shift @points or last; |             push @p, grep $_, shift @points or last; | ||||||
|         } else { |         } else { | ||||||
|             push @p, $p3; |             push @p, $p3; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     push @paths, $self->clone(polyline => Slic3r::Polyline->new(\@p)) |     push @paths, $self->clone(polyline => Slic3r::Polyline->new(@p)) | ||||||
|         if @p > 1; |         if @p > 1; | ||||||
|      |      | ||||||
|     return @paths; |     return @paths; | ||||||
|  | @ -254,7 +254,7 @@ sub detect_arcs { | ||||||
|             } |             } | ||||||
|              |              | ||||||
|             my $arc = Slic3r::ExtrusionPath::Arc->new( |             my $arc = Slic3r::ExtrusionPath::Arc->new( | ||||||
|                 polyline    => Slic3r::Polyline->new(\@arc_points), |                 polyline    => Slic3r::Polyline->new(@arc_points), | ||||||
|                 role        => $self->role, |                 role        => $self->role, | ||||||
|                 flow_spacing => $self->flow_spacing, |                 flow_spacing => $self->flow_spacing, | ||||||
|                 orientation => $orientation, |                 orientation => $orientation, | ||||||
|  | @ -279,7 +279,7 @@ sub detect_arcs { | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     # remaining points form a linear path |     # remaining points form a linear path | ||||||
|     push @paths, $self->clone(polyline => Slic3r::Polyline->new(\@points)) |     push @paths, $self->clone(polyline => Slic3r::Polyline->new(@points)) | ||||||
|         if @points > 1; |         if @points > 1; | ||||||
|      |      | ||||||
|     return @paths; |     return @paths; | ||||||
|  |  | ||||||
|  | @ -71,7 +71,7 @@ sub fill_surface { | ||||||
|                 $x += $m->{distance}; |                 $x += $m->{distance}; | ||||||
|             } |             } | ||||||
|              |              | ||||||
|             push @polygons, Slic3r::Polygon->new($p); |             push @polygons, Slic3r::Polygon->new(@$p); | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         $_->rotate(-$rotate_vector->[0][0], $m->{hex_center}) for @polygons; |         $_->rotate(-$rotate_vector->[0][0], $m->{hex_center}) for @polygons; | ||||||
|  | @ -88,7 +88,7 @@ sub fill_surface { | ||||||
|         # consider polygons as polylines without re-appending the initial point: |         # consider polygons as polylines without re-appending the initial point: | ||||||
|         # this cuts the last segment on purpose, so that the jump to the next  |         # this cuts the last segment on purpose, so that the jump to the next  | ||||||
|         # path is more straight |         # path is more straight | ||||||
|         @paths = map Slic3r::Polyline->new($_), |         @paths = map Slic3r::Polyline->new(@$_), | ||||||
|             @{ Boost::Geometry::Utils::polygon_multi_linestring_intersection( |             @{ Boost::Geometry::Utils::polygon_multi_linestring_intersection( | ||||||
|                 $surface->expolygon, |                 $surface->expolygon, | ||||||
|                 \@polygons, |                 \@polygons, | ||||||
|  | @ -113,7 +113,7 @@ sub fill_surface { | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         # clip paths again to prevent connection segments from crossing the expolygon boundaries |         # clip paths again to prevent connection segments from crossing the expolygon boundaries | ||||||
|         @paths = map Slic3r::Polyline->new($_), |         @paths = map Slic3r::Polyline->new(@$_), | ||||||
|             @{ Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection( |             @{ Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection( | ||||||
|                 [ $surface->expolygon->offset_ex(scaled_epsilon) ], |                 [ $surface->expolygon->offset_ex(scaled_epsilon) ], | ||||||
|                 [ @paths ], |                 [ @paths ], | ||||||
|  |  | ||||||
|  | @ -33,9 +33,9 @@ sub fill_surface { | ||||||
|     my $path = "Math::PlanePath::$1"->new; |     my $path = "Math::PlanePath::$1"->new; | ||||||
|     my @n = $self->get_n($path, [ map +($_ / $distance_between_lines), @{$bounding_box->bb} ]); |     my @n = $self->get_n($path, [ map +($_ / $distance_between_lines), @{$bounding_box->bb} ]); | ||||||
|      |      | ||||||
|     my $polyline = Slic3r::Polyline->new([ |     my $polyline = Slic3r::Polyline->new( | ||||||
|         map [ map {$_*$distance_between_lines} $path->n_to_xy($_) ], @n, |         map [ map {$_*$distance_between_lines} $path->n_to_xy($_) ], @n, | ||||||
|     ]); |     ); | ||||||
|     return {} if !@$polyline; |     return {} if !@$polyline; | ||||||
|      |      | ||||||
|     $self->process_polyline($polyline, $bounding_box); |     $self->process_polyline($polyline, $bounding_box); | ||||||
|  |  | ||||||
|  | @ -8,7 +8,9 @@ use Slic3r::Geometry::Clipper qw(union_ex); | ||||||
| use Slic3r::Surface ':types'; | use Slic3r::Surface ':types'; | ||||||
| 
 | 
 | ||||||
| has 'config'             => (is => 'ro', required => 1); | has 'config'             => (is => 'ro', required => 1); | ||||||
| has 'multiple_extruders' => (is => 'ro', default => sub {0} ); | has 'extruders'          => (is => 'ro', default => sub {0}, required => 1); | ||||||
|  | has 'multiple_extruders' => (is => 'lazy'); | ||||||
|  | has 'enable_wipe'        => (is => 'lazy');   # at least one extruder has wipe enabled | ||||||
| has 'layer_count'        => (is => 'ro', required => 1 ); | has 'layer_count'        => (is => 'ro', required => 1 ); | ||||||
| has 'layer'              => (is => 'rw'); | has 'layer'              => (is => 'rw'); | ||||||
| has '_layer_overhangs'   => (is => 'rw'); | has '_layer_overhangs'   => (is => 'rw'); | ||||||
|  | @ -63,6 +65,16 @@ my %role_speeds = ( | ||||||
|     &EXTR_ROLE_GAPFILL                      => 'gap_fill', |     &EXTR_ROLE_GAPFILL                      => 'gap_fill', | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
|  | sub _build_multiple_extruders { | ||||||
|  |     my $self = shift; | ||||||
|  |     return @{$self->extruders} > 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | sub _build_enable_wipe { | ||||||
|  |     my $self = shift; | ||||||
|  |     return (first { $_->wipe } @{$self->extruders}) ? 1 : 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| sub set_shift { | sub set_shift { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|     my @shift = @_; |     my @shift = @_; | ||||||
|  | @ -144,14 +156,14 @@ sub extrude_loop { | ||||||
|     # find candidate starting points |     # find candidate starting points | ||||||
|     # start looking for concave vertices not being overhangs |     # start looking for concave vertices not being overhangs | ||||||
|     my @concave = $loop->polygon->concave_points; |     my @concave = $loop->polygon->concave_points; | ||||||
|     my @candidates = grep Boost::Geometry::Utils::point_covered_by_multi_polygon($_, $self->_layer_overhangs), |     my @candidates = grep !Boost::Geometry::Utils::point_covered_by_multi_polygon($_, $self->_layer_overhangs), | ||||||
|         @concave; |         @concave; | ||||||
|     if (!@candidates) { |     if (!@candidates) { | ||||||
|         # if none, look for any concave vertex |         # if none, look for any concave vertex | ||||||
|         @candidates = @concave; |         @candidates = @concave; | ||||||
|         if (!@candidates) { |         if (!@candidates) { | ||||||
|             # if none, look for any non-overhang vertex |             # if none, look for any non-overhang vertex | ||||||
|             @candidates = grep Boost::Geometry::Utils::point_covered_by_multi_polygon($_, $self->_layer_overhangs), |             @candidates = grep !Boost::Geometry::Utils::point_covered_by_multi_polygon($_, $self->_layer_overhangs), | ||||||
|                 @{$loop->polygon}; |                 @{$loop->polygon}; | ||||||
|             if (!@candidates) { |             if (!@candidates) { | ||||||
|                 # if none, all points are valid candidates |                 # if none, all points are valid candidates | ||||||
|  | @ -169,7 +181,8 @@ sub extrude_loop { | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     # split the loop at the starting point and make a path |     # split the loop at the starting point and make a path | ||||||
|     my $extrusion_path = $loop->split_at(Slic3r::Geometry::nearest_point($last_pos, \@candidates)); |     my $start_at = Slic3r::Geometry::nearest_point($last_pos, \@candidates); | ||||||
|  |     my $extrusion_path = $loop->split_at($start_at); | ||||||
|      |      | ||||||
|     # clip the path to avoid the extruder to get exactly on the first point of the loop; |     # clip the path to avoid the extruder to get exactly on the first point of the loop; | ||||||
|     # if polyline was shorter than the clipping distance we'd get a null polyline, so |     # if polyline was shorter than the clipping distance we'd get a null polyline, so | ||||||
|  | @ -192,7 +205,7 @@ sub extrude_loop { | ||||||
|         # reapply the nearest point search for starting point |         # reapply the nearest point search for starting point | ||||||
|         @paths = Slic3r::ExtrusionPath::Collection |         @paths = Slic3r::ExtrusionPath::Collection | ||||||
|             ->new(paths => [@paths]) |             ->new(paths => [@paths]) | ||||||
|             ->chained_path($last_pos, 1); |             ->chained_path($start_at, 1); | ||||||
|     } else { |     } else { | ||||||
|         push @paths, $extrusion_path; |         push @paths, $extrusion_path; | ||||||
|     } |     } | ||||||
|  | @ -205,7 +218,7 @@ sub extrude_loop { | ||||||
|      |      | ||||||
|     # extrude along the path |     # extrude along the path | ||||||
|     my $gcode = join '', map $self->extrude_path($_, $description, %params), @paths; |     my $gcode = join '', map $self->extrude_path($_, $description, %params), @paths; | ||||||
|     $self->wipe_path($extrusion_path->polyline); |     $self->wipe_path($extrusion_path->polyline) if $self->enable_wipe; | ||||||
|      |      | ||||||
|     # make a little move inwards before leaving loop |     # make a little move inwards before leaving loop | ||||||
|     if ($loop->role == EXTR_ROLE_EXTERNAL_PERIMETER && $self->config->perimeters > 1) { |     if ($loop->role == EXTR_ROLE_EXTERNAL_PERIMETER && $self->config->perimeters > 1) { | ||||||
|  | @ -295,8 +308,8 @@ sub extrude_path { | ||||||
|             $path_length += $line_length; |             $path_length += $line_length; | ||||||
|             $gcode .= $self->G1($line->[B], undef, $e * $line_length, $description); |             $gcode .= $self->G1($line->[B], undef, $e * $line_length, $description); | ||||||
|         } |         } | ||||||
|         $self->wipe_path(Slic3r::Polyline->new([ reverse @{$path->points} ])) |         $self->wipe_path(Slic3r::Polyline->new(reverse @{$path->points})) | ||||||
|             if $self->extruder->wipe; |             if $self->enable_wipe; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     if ($self->config->cooling) { |     if ($self->config->cooling) { | ||||||
|  | @ -409,7 +422,7 @@ sub retract { | ||||||
|     # wipe |     # wipe | ||||||
|     my $wipe_path; |     my $wipe_path; | ||||||
|     if ($self->extruder->wipe && $self->wipe_path) { |     if ($self->extruder->wipe && $self->wipe_path) { | ||||||
|         $wipe_path = Slic3r::Polyline->new([ $self->last_pos, @{$self->wipe_path}[1..$#{$self->wipe_path}] ]) |         $wipe_path = Slic3r::Polyline->new($self->last_pos, @{$self->wipe_path}[1..$#{$self->wipe_path}]) | ||||||
|             ->clip_start($self->extruder->scaled_wipe_distance); |             ->clip_start($self->extruder->scaled_wipe_distance); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |  | ||||||
|  | @ -888,7 +888,7 @@ sub repaint { | ||||||
|              |              | ||||||
|             # if sequential printing is enabled and we have more than one object |             # if sequential printing is enabled and we have more than one object | ||||||
|             if ($parent->{config}->complete_objects && (map @{$_->instances}, @{$parent->{objects}}) > 1) { |             if ($parent->{config}->complete_objects && (map @{$_->instances}, @{$parent->{objects}}) > 1) { | ||||||
|             	my $convex_hull = Slic3r::Polygon->new(convex_hull([ map @{$_->contour}, @{$parent->{object_previews}->[-1][2]->expolygons} ])); |             	my $convex_hull = Slic3r::Polygon->new(@{convex_hull([ map @{$_->contour}, @{$parent->{object_previews}->[-1][2]->expolygons} ])}); | ||||||
|                 my ($clearance) = @{offset([$convex_hull], $parent->{config}->extruder_clearance_radius / 2 * $parent->{scaling_factor}, 100, JT_ROUND)}; |                 my ($clearance) = @{offset([$convex_hull], $parent->{config}->extruder_clearance_radius / 2 * $parent->{scaling_factor}, 100, JT_ROUND)}; | ||||||
|                 $dc->SetPen($parent->{clearance_pen}); |                 $dc->SetPen($parent->{clearance_pen}); | ||||||
|                 $dc->SetBrush($parent->{transparent_brush}); |                 $dc->SetBrush($parent->{transparent_brush}); | ||||||
|  | @ -899,7 +899,7 @@ sub repaint { | ||||||
|      |      | ||||||
|     # draw skirt |     # draw skirt | ||||||
|     if (@{$parent->{object_previews}} && $parent->{config}->skirts) { |     if (@{$parent->{object_previews}} && $parent->{config}->skirts) { | ||||||
|         my $convex_hull = Slic3r::Polygon->new(convex_hull([ map @{$_->contour}, map @{$_->[2]->expolygons}, @{$parent->{object_previews}} ])); |         my $convex_hull = Slic3r::Polygon->new(@{convex_hull([ map @{$_->contour}, map @{$_->[2]->expolygons}, @{$parent->{object_previews}} ])}); | ||||||
|         ($convex_hull) = @{offset([$convex_hull], $parent->{config}->skirt_distance * $parent->{scaling_factor}, 100, JT_ROUND)}; |         ($convex_hull) = @{offset([$convex_hull], $parent->{config}->skirt_distance * $parent->{scaling_factor}, 100, JT_ROUND)}; | ||||||
|         $dc->SetPen($parent->{skirt_pen}); |         $dc->SetPen($parent->{skirt_pen}); | ||||||
|         $dc->SetBrush($parent->{transparent_brush}); |         $dc->SetBrush($parent->{transparent_brush}); | ||||||
|  | @ -1098,7 +1098,7 @@ sub _trigger_model_object { | ||||||
| 	    $self->bounding_box($self->model_object->bounding_box); | 	    $self->bounding_box($self->model_object->bounding_box); | ||||||
| 	     | 	     | ||||||
|     	my $mesh = $self->model_object->mesh; |     	my $mesh = $self->model_object->mesh; | ||||||
|         $self->convex_hull(Slic3r::Polygon->new(Math::ConvexHull::MonotoneChain::convex_hull($mesh->used_vertices))); |         $self->convex_hull(Slic3r::Polygon->new(@{Math::ConvexHull::MonotoneChain::convex_hull($mesh->used_vertices)})); | ||||||
| 	    $self->facets(scalar @{$mesh->facets}); | 	    $self->facets(scalar @{$mesh->facets}); | ||||||
| 	    $self->vertices(scalar @{$mesh->vertices}); | 	    $self->vertices(scalar @{$mesh->vertices}); | ||||||
| 	     | 	     | ||||||
|  |  | ||||||
|  | @ -38,12 +38,12 @@ sub polygon { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|      |      | ||||||
|     my $e = $self->extents; |     my $e = $self->extents; | ||||||
|     return Slic3r::Polygon->new([ |     return Slic3r::Polygon->new( | ||||||
|         [ $e->[X][MIN], $e->[Y][MIN] ], |         [ $e->[X][MIN], $e->[Y][MIN] ], | ||||||
|         [ $e->[X][MAX], $e->[Y][MIN] ], |         [ $e->[X][MAX], $e->[Y][MIN] ], | ||||||
|         [ $e->[X][MAX], $e->[Y][MAX] ], |         [ $e->[X][MAX], $e->[Y][MAX] ], | ||||||
|         [ $e->[X][MIN], $e->[Y][MAX] ], |         [ $e->[X][MIN], $e->[Y][MAX] ], | ||||||
|     ]); |     ); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| # note to $self | # note to $self | ||||||
|  |  | ||||||
|  | @ -83,7 +83,7 @@ sub diff { | ||||||
|     $clipper->add_subject_polygons($subject); |     $clipper->add_subject_polygons($subject); | ||||||
|     $clipper->add_clip_polygons($safety_offset ? safety_offset($clip) : $clip); |     $clipper->add_clip_polygons($safety_offset ? safety_offset($clip) : $clip); | ||||||
|     return [ |     return [ | ||||||
|         map Slic3r::Polygon->new($_), |         map Slic3r::Polygon->new(@$_), | ||||||
|             @{ $clipper->execute(CT_DIFFERENCE, PFT_NONZERO, PFT_NONZERO) }, |             @{ $clipper->execute(CT_DIFFERENCE, PFT_NONZERO, PFT_NONZERO) }, | ||||||
|     ]; |     ]; | ||||||
| } | } | ||||||
|  | @ -126,7 +126,7 @@ sub intersection { | ||||||
|     $clipper->add_subject_polygons($subject); |     $clipper->add_subject_polygons($subject); | ||||||
|     $clipper->add_clip_polygons($safety_offset ? safety_offset($clip) : $clip); |     $clipper->add_clip_polygons($safety_offset ? safety_offset($clip) : $clip); | ||||||
|     return [ |     return [ | ||||||
|         map Slic3r::Polygon->new($_), |         map Slic3r::Polygon->new(@$_), | ||||||
|             @{ $clipper->execute(CT_INTERSECTION, $jointype, $jointype) }, |             @{ $clipper->execute(CT_INTERSECTION, $jointype, $jointype) }, | ||||||
|     ]; |     ]; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -5,7 +5,7 @@ use List::Util qw(sum first); | ||||||
| use Slic3r::ExtrusionPath ':roles'; | use Slic3r::ExtrusionPath ':roles'; | ||||||
| use Slic3r::Geometry qw(PI A B scale chained_path_items points_coincide); | use Slic3r::Geometry qw(PI A B scale chained_path_items points_coincide); | ||||||
| use Slic3r::Geometry::Clipper qw(safety_offset union_ex diff_ex intersection_ex  | use Slic3r::Geometry::Clipper qw(safety_offset union_ex diff_ex intersection_ex  | ||||||
|     offset offset2_ex PFT_EVENODD union_pt traverse_pt diff intersection); |     offset offset2 offset2_ex PFT_EVENODD union_pt traverse_pt diff intersection); | ||||||
| use Slic3r::Surface ':types'; | use Slic3r::Surface ':types'; | ||||||
| 
 | 
 | ||||||
| has 'layer' => ( | has 'layer' => ( | ||||||
|  | @ -98,12 +98,9 @@ sub make_surfaces { | ||||||
|     # detect thin walls by offsetting slices by half extrusion inwards |     # detect thin walls by offsetting slices by half extrusion inwards | ||||||
|     { |     { | ||||||
|         my $width = $self->perimeter_flow->scaled_width; |         my $width = $self->perimeter_flow->scaled_width; | ||||||
|         my $outgrown = [ |  | ||||||
|             offset2_ex([ map @$_, map $_->expolygon, @{$self->slices} ], -$width, +$width), |  | ||||||
|         ]; |  | ||||||
|         my $diff = diff_ex( |         my $diff = diff_ex( | ||||||
|             [ map $_->p, @{$self->slices} ], |             [ map $_->p, @{$self->slices} ], | ||||||
|             [ map @$_, @$outgrown ], |             [ offset2([ map @$_, map $_->expolygon, @{$self->slices} ], -$width, +$width) ], | ||||||
|             1, |             1, | ||||||
|         ); |         ); | ||||||
|          |          | ||||||
|  | @ -195,7 +192,7 @@ sub make_perimeters { | ||||||
|              |              | ||||||
|             # where offset2() collapses the expolygon, then there's no room for an inner loop |             # where offset2() collapses the expolygon, then there's no room for an inner loop | ||||||
|             # and we can extract the gap for later processing |             # and we can extract the gap for later processing | ||||||
|             { |             if ($Slic3r::Config->gap_fill_speed > 0 && $Slic3r::Config->fill_density > 0) { | ||||||
|                 my $diff = diff_ex( |                 my $diff = diff_ex( | ||||||
|                     [ offset(\@last, -0.5*$spacing) ], |                     [ offset(\@last, -0.5*$spacing) ], | ||||||
|                     # +2 on the offset here makes sure that Clipper float truncation  |                     # +2 on the offset here makes sure that Clipper float truncation  | ||||||
|  | @ -226,19 +223,10 @@ sub make_perimeters { | ||||||
|      |      | ||||||
|     $self->_fill_gaps(\@gaps); |     $self->_fill_gaps(\@gaps); | ||||||
|      |      | ||||||
|     # TODO: can these be removed? |  | ||||||
|     @contours   = grep $_->is_printable($self->perimeter_flow->scaled_width), @contours; |  | ||||||
|     @holes      = grep $_->is_printable($self->perimeter_flow->scaled_width), @holes; |  | ||||||
|      |  | ||||||
|     # find nesting hierarchies separately for contours and holes |     # find nesting hierarchies separately for contours and holes | ||||||
|     my $contours_pt = union_pt(\@contours, PFT_EVENODD); |     my $contours_pt = union_pt(\@contours, PFT_EVENODD); | ||||||
|     my $holes_pt    = union_pt(\@holes, PFT_EVENODD); |     my $holes_pt    = union_pt(\@holes, PFT_EVENODD); | ||||||
|      |      | ||||||
|     # get lower layer slices for overhang check |  | ||||||
|     my @lower_slices = $self->id == 0 |  | ||||||
|         ? () |  | ||||||
|         : map @$_, @{$self->layer->object->layers->[$self->id-1]->slices}; |  | ||||||
|      |  | ||||||
|     # prepare a coderef for traversing the PolyTree object |     # prepare a coderef for traversing the PolyTree object | ||||||
|     # external contours are root items of $contours_pt |     # external contours are root items of $contours_pt | ||||||
|     # internal contours are the ones next to external |     # internal contours are the ones next to external | ||||||
|  | @ -259,7 +247,7 @@ sub make_perimeters { | ||||||
|             # return ccw contours and cw holes |             # return ccw contours and cw holes | ||||||
|             # GCode.pm will convert all of them to ccw, but it needs to know |             # GCode.pm will convert all of them to ccw, but it needs to know | ||||||
|             # what the holes are in order to compute the correct inwards move |             # what the holes are in order to compute the correct inwards move | ||||||
|             my $polygon = Slic3r::Polygon->new($polynode->{outer} // [ reverse @{$polynode->{hole}} ]); |             my $polygon = Slic3r::Polygon->new(defined $polynode->{outer} ? @{$polynode->{outer}} : reverse @{$polynode->{hole}}); | ||||||
|             $polygon->reverse if !$is_contour; |             $polygon->reverse if !$is_contour; | ||||||
|              |              | ||||||
|             my $role = EXTR_ROLE_PERIMETER; |             my $role = EXTR_ROLE_PERIMETER; | ||||||
|  | @ -312,7 +300,7 @@ sub _fill_gaps { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|     my ($gaps) = @_; |     my ($gaps) = @_; | ||||||
|      |      | ||||||
|     return unless $Slic3r::Config->gap_fill_speed > 0 && $Slic3r::Config->fill_density > 0 && @$gaps; |     return unless @$gaps; | ||||||
|      |      | ||||||
|     my $filler = $self->layer->object->fill_maker->filler('rectilinear'); |     my $filler = $self->layer->object->fill_maker->filler('rectilinear'); | ||||||
|     $filler->layer_id($self->layer->id); |     $filler->layer_id($self->layer->id); | ||||||
|  |  | ||||||
|  | @ -2,6 +2,8 @@ package Slic3r::Point; | ||||||
| use strict; | use strict; | ||||||
| use warnings; | use warnings; | ||||||
| 
 | 
 | ||||||
|  | use Storable qw(); | ||||||
|  | 
 | ||||||
| sub new { | sub new { | ||||||
|     my $class = shift; |     my $class = shift; | ||||||
|     my $self; |     my $self; | ||||||
|  | @ -19,8 +21,7 @@ sub new { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub clone { | sub clone { | ||||||
|     my $self = shift; |     Storable::dclone($_[0]) | ||||||
|     return (ref $self)->new(@$self); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub coincides_with { | sub coincides_with { | ||||||
|  |  | ||||||
|  | @ -6,25 +6,20 @@ use Scalar::Util qw(reftype); | ||||||
| use Slic3r::Geometry qw(A B X Y X1 X2 Y1 Y2 polyline_remove_parallel_continuous_edges polyline_remove_acute_vertices | use Slic3r::Geometry qw(A B X Y X1 X2 Y1 Y2 polyline_remove_parallel_continuous_edges polyline_remove_acute_vertices | ||||||
|     polyline_lines move_points same_point); |     polyline_lines move_points same_point); | ||||||
| use Slic3r::Geometry::Clipper qw(JT_SQUARE); | use Slic3r::Geometry::Clipper qw(JT_SQUARE); | ||||||
|  | use Storable qw(); | ||||||
| 
 | 
 | ||||||
| # the constructor accepts an array(ref) of points | # the constructor accepts an array(ref) of points | ||||||
| sub new { | sub new { | ||||||
|     my $class = shift; |     my $class = shift; | ||||||
|     my $self; |  | ||||||
|     if (@_ == 1) { |  | ||||||
|         $self = [ @{$_[0]} ]; |  | ||||||
|     } else { |  | ||||||
|         $self = [ @_ ]; |  | ||||||
|     } |  | ||||||
|      |      | ||||||
|  |     my $self = [ @_ ]; | ||||||
|     bless $self, $class; |     bless $self, $class; | ||||||
|     bless $_, 'Slic3r::Point' for @$self; |     bless $_, 'Slic3r::Point' for @$self; | ||||||
|     $self; |     $self; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub clone { | sub clone { | ||||||
|     my $self = shift; |     Storable::dclone($_[0]) | ||||||
|     return (ref $self)->new(map $_->clone, @$self); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub serialize { | sub serialize { | ||||||
|  | @ -65,7 +60,7 @@ sub simplify { | ||||||
|     my $tolerance = shift || 10; |     my $tolerance = shift || 10; | ||||||
|      |      | ||||||
|     my $simplified = Boost::Geometry::Utils::linestring_simplify($self, $tolerance); |     my $simplified = Boost::Geometry::Utils::linestring_simplify($self, $tolerance); | ||||||
|     return (ref $self)->new($simplified); |     return (ref $self)->new(@$simplified); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub reverse { | sub reverse { | ||||||
|  | @ -83,9 +78,9 @@ sub grow { | ||||||
|     my ($distance, $scale, $joinType, $miterLimit) = @_; |     my ($distance, $scale, $joinType, $miterLimit) = @_; | ||||||
|     $joinType //= JT_SQUARE; |     $joinType //= JT_SQUARE; | ||||||
|      |      | ||||||
|     return map Slic3r::Polygon->new($_), |     return map Slic3r::Polygon->new(@$_), | ||||||
|         Slic3r::Geometry::Clipper::offset( |         Slic3r::Geometry::Clipper::offset( | ||||||
|             [ Slic3r::Polygon->new(@$self, CORE::reverse @$self[1..($#$self-1)]) ], |             [ [ @$self, CORE::reverse @$self[1..($#$self-1)] ] ], | ||||||
|             $distance, $scale, $joinType, $miterLimit, |             $distance, $scale, $joinType, $miterLimit, | ||||||
|         ); |         ); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -170,8 +170,8 @@ sub validate { | ||||||
|                 my $clearance; |                 my $clearance; | ||||||
|                 { |                 { | ||||||
|                     my @points = map [ @$_[X,Y] ], map @{$_->vertices}, @{$self->objects->[$obj_idx]->meshes}; |                     my @points = map [ @$_[X,Y] ], map @{$_->vertices}, @{$self->objects->[$obj_idx]->meshes}; | ||||||
|                     my $convex_hull = Slic3r::Polygon->new(convex_hull(\@points)); |                     my $convex_hull = Slic3r::Polygon->new(@{convex_hull(\@points)}); | ||||||
|                     ($clearance) = map Slic3r::Polygon->new($_),  |                     ($clearance) = map Slic3r::Polygon->new(@$_),  | ||||||
|                                         Slic3r::Geometry::Clipper::offset( |                                         Slic3r::Geometry::Clipper::offset( | ||||||
|                                             [$convex_hull], scale $Slic3r::Config->extruder_clearance_radius / 2, 1, JT_ROUND); |                                             [$convex_hull], scale $Slic3r::Config->extruder_clearance_radius / 2, 1, JT_ROUND); | ||||||
|                 } |                 } | ||||||
|  | @ -665,7 +665,7 @@ sub make_brim { | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     @{$self->brim} = map Slic3r::ExtrusionLoop->pack( |     @{$self->brim} = map Slic3r::ExtrusionLoop->pack( | ||||||
|         polygon         => Slic3r::Polygon->new($_), |         polygon         => Slic3r::Polygon->new(@$_), | ||||||
|         role            => EXTR_ROLE_SKIRT, |         role            => EXTR_ROLE_SKIRT, | ||||||
|         flow_spacing    => $flow->spacing, |         flow_spacing    => $flow->spacing, | ||||||
|     ), reverse traverse_pt( union_pt(\@loops, PFT_EVENODD) ); |     ), reverse traverse_pt( union_pt(\@loops, PFT_EVENODD) ); | ||||||
|  | @ -711,7 +711,7 @@ sub write_gcode { | ||||||
|     # set up our extruder object |     # set up our extruder object | ||||||
|     my $gcodegen = Slic3r::GCode->new( |     my $gcodegen = Slic3r::GCode->new( | ||||||
|         config              => $self->config, |         config              => $self->config, | ||||||
|         multiple_extruders  => (@{$self->extruders} > 1), |         extruders           => $self->extruders, | ||||||
|         layer_count         => $self->layer_count, |         layer_count         => $self->layer_count, | ||||||
|     ); |     ); | ||||||
|     print $fh "G21 ; set units to millimeters\n" if $Slic3r::Config->gcode_flavor ne 'makerware'; |     print $fh "G21 ; set units to millimeters\n" if $Slic3r::Config->gcode_flavor ne 'makerware'; | ||||||
|  |  | ||||||
|  | @ -57,9 +57,15 @@ sub model { | ||||||
|         ], |         ], | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     my $mesh = Slic3r::TriangleMesh->new( | ||||||
|  |         vertices    => $vertices, | ||||||
|  |         facets      => $facets, | ||||||
|  |     ); | ||||||
|  |     $mesh->scale($params{scale}) if $params{scale}; | ||||||
|  |      | ||||||
|     my $model = Slic3r::Model->new; |     my $model = Slic3r::Model->new; | ||||||
|     my $object = $model->add_object(vertices => $vertices); |     my $object = $model->add_object(vertices => $mesh->vertices); | ||||||
|     $object->add_volume(facets => $facets); |     $object->add_volume(facets => $mesh->facets); | ||||||
|     $object->add_instance( |     $object->add_instance( | ||||||
|         offset      => [0,0], |         offset      => [0,0], | ||||||
|         rotation    => $params{rotation} // 0, |         rotation    => $params{rotation} // 0, | ||||||
|  |  | ||||||
|  | @ -12,26 +12,26 @@ BEGIN { | ||||||
| use Slic3r; | use Slic3r; | ||||||
| 
 | 
 | ||||||
| { | { | ||||||
|     my $polygon = Slic3r::Polygon->new([ |     my $polygon = Slic3r::Polygon->new( | ||||||
|         [5,0], [10,0], [15,0], [20,0], [20,10], [20,30], [0,0], |         [5,0], [10,0], [15,0], [20,0], [20,10], [20,30], [0,0], | ||||||
|     ]); |     ); | ||||||
|      |      | ||||||
|     $polygon->merge_continuous_lines; |     $polygon->merge_continuous_lines; | ||||||
|     is scalar(@$polygon), 3, 'merge_continuous_lines'; |     is scalar(@$polygon), 3, 'merge_continuous_lines'; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| { | { | ||||||
|     my $polyline = Slic3r::Polyline->new([ |     my $polyline = Slic3r::Polyline->new( | ||||||
|         [0,0],[1,0],[2,0],[2,1],[2,2],[1,2],[0,2],[0,1],[0,0], |         [0,0],[1,0],[2,0],[2,1],[2,2],[1,2],[0,2],[0,1],[0,0], | ||||||
|     ]); |     ); | ||||||
|     $polyline = $polyline->simplify(1); |     $polyline = $polyline->simplify(1); | ||||||
|     is_deeply $polyline, [ [0, 0], [2, 0], [2, 2], [0, 2], [0, 0] ], 'Douglas-Peucker'; |     is_deeply $polyline, [ [0, 0], [2, 0], [2, 2], [0, 2], [0, 0] ], 'Douglas-Peucker'; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| { | { | ||||||
|     my $polyline = Slic3r::Polyline->new([ |     my $polyline = Slic3r::Polyline->new( | ||||||
|         [0,0],[0.5,0.5],[1,0],[1.25,-0.25],[1.5,.5], |         [0,0],[0.5,0.5],[1,0],[1.25,-0.25],[1.5,.5], | ||||||
|     ]); |     ); | ||||||
|     $polyline->scale(100); |     $polyline->scale(100); | ||||||
|     $polyline = $polyline->simplify(25); |     $polyline = $polyline->simplify(25); | ||||||
|     is_deeply $polyline, [ [0, 0], [50, 50], [125, -25], [150, 50] ], 'Douglas-Peucker'; |     is_deeply $polyline, [ [0, 0], [50, 50], [125, -25], [150, 50] ], 'Douglas-Peucker'; | ||||||
|  | @ -69,7 +69,7 @@ use Slic3r; | ||||||
|         [197.307,292.831], [199.808,313.1906], [191.5298,315.0787], [187.3082,299.8172], [186.4201,295.3766],  |         [197.307,292.831], [199.808,313.1906], [191.5298,315.0787], [187.3082,299.8172], [186.4201,295.3766],  | ||||||
|         [180.595,296.0487], [161.7854,297.4248], [156.8058,297.6214], [154.3395,317.8592], |         [180.595,296.0487], [161.7854,297.4248], [156.8058,297.6214], [154.3395,317.8592], | ||||||
|     ]; |     ]; | ||||||
|     my $polygon = Slic3r::Polygon->new($gear); |     my $polygon = Slic3r::Polygon->new(@$gear); | ||||||
|     $polygon->merge_continuous_lines; |     $polygon->merge_continuous_lines; | ||||||
|     note sprintf "original points: %d\nnew points: %d", scalar(@$gear), scalar(@$polygon); |     note sprintf "original points: %d\nnew points: %d", scalar(@$gear), scalar(@$polygon); | ||||||
|     ok @$polygon < @$gear, 'gear was simplified using merge_continuous_lines'; |     ok @$polygon < @$gear, 'gear was simplified using merge_continuous_lines'; | ||||||
|  | @ -114,7 +114,7 @@ use Slic3r; | ||||||
|         [3368.3,7868.6],[3409.2,7889.5],[3553.8,7963.2],[3596,7981.4], |         [3368.3,7868.6],[3409.2,7889.5],[3553.8,7963.2],[3596,7981.4], | ||||||
|     ]; |     ]; | ||||||
|      |      | ||||||
|     my $polygon = Slic3r::Polygon->new($circle); |     my $polygon = Slic3r::Polygon->new(@$circle); | ||||||
|     $polygon->merge_continuous_lines; |     $polygon->merge_continuous_lines; | ||||||
|     note sprintf "original points: %d\nnew points: %d", scalar(@$circle), scalar(@$polygon); |     note sprintf "original points: %d\nnew points: %d", scalar(@$circle), scalar(@$polygon); | ||||||
|     ok @$polygon >= @$circle/3, 'circle was simplified using merge_continuous_lines'; |     ok @$polygon >= @$circle/3, 'circle was simplified using merge_continuous_lines'; | ||||||
|  |  | ||||||
							
								
								
									
										29
									
								
								t/freeze.t
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								t/freeze.t
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | ||||||
|  | use Test::More tests => 1; | ||||||
|  | use strict; | ||||||
|  | use warnings; | ||||||
|  | 
 | ||||||
|  | BEGIN { | ||||||
|  |     use FindBin; | ||||||
|  |     use lib "$FindBin::Bin/../lib"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | use Slic3r; | ||||||
|  | use Slic3r::Test; | ||||||
|  | use Storable qw(nstore retrieve); | ||||||
|  | use Time::HiRes qw(gettimeofday tv_interval); | ||||||
|  | 
 | ||||||
|  | { | ||||||
|  |     my $t0 = [gettimeofday]; | ||||||
|  |     my $print = Slic3r::Test::init_print('20mm_cube', scale => 2); | ||||||
|  |     my $gcode = Slic3r::Test::gcode($print); | ||||||
|  |     diag sprintf 'Slicing took %s seconds', tv_interval($t0); | ||||||
|  |      | ||||||
|  |     my $t1 = [gettimeofday]; | ||||||
|  |     nstore $print, 'print.dat'; | ||||||
|  |     $print = retrieve 'print.dat'; | ||||||
|  |     diag sprintf 'Freezing and retrieving took %s seconds', tv_interval($t1); | ||||||
|  |      | ||||||
|  |     isa_ok $print, 'Slic3r::Print', 'restored Print object'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | __END__ | ||||||
|  | @ -103,7 +103,7 @@ is_deeply $intersection, [ [120, 120], [180, 160] ], 'internal lines are preserv | ||||||
|         ], 'tangent line is clipped to square with hole'; |         ], 'tangent line is clipped to square with hole'; | ||||||
|     } |     } | ||||||
|     { |     { | ||||||
|         my $polyline = Slic3r::Polyline->new([ [50, 180], [250, 180], [250, 150], [150, 150], [150, 120], [120, 120], [120, 50] ]); |         my $polyline = Slic3r::Polyline->new([50, 180], [250, 180], [250, 150], [150, 150], [150, 120], [120, 120], [120, 50]); | ||||||
|         is_deeply [ map $_, $polyline->clip_with_expolygon($expolygon) ], [ |         is_deeply [ map $_, $polyline->clip_with_expolygon($expolygon) ], [ | ||||||
|             [ [100, 180], [200, 180] ], |             [ [100, 180], [200, 180] ], | ||||||
|             [ [200, 150], [160, 150] ], |             [ [200, 150], [160, 150] ], | ||||||
|  |  | ||||||
|  | @ -21,7 +21,7 @@ use Slic3r::Geometry qw(scale); | ||||||
|     foreach my $point (@$points) { |     foreach my $point (@$points) { | ||||||
|         @$point = map scale $_, @$point; |         @$point = map scale $_, @$point; | ||||||
|     } |     } | ||||||
|     my $polyline = Slic3r::Polyline->new($points); |     my $polyline = Slic3r::Polyline->new(@$points); | ||||||
|     my $serialized = $polyline->serialize; |     my $serialized = $polyline->serialize; | ||||||
|     my $deserialized = Slic3r::Polyline->deserialize($serialized); |     my $deserialized = Slic3r::Polyline->deserialize($serialized); | ||||||
|     is scalar(@$deserialized), scalar(@$points), 'number of deserialized points'; |     is scalar(@$deserialized), scalar(@$points), 'number of deserialized points'; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci