mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 12:41:20 -06:00 
			
		
		
		
	Merge branch 'master' into xs
This commit is contained in:
		
						commit
						ff795f2918
					
				
					 13 changed files with 175 additions and 60 deletions
				
			
		
							
								
								
									
										26
									
								
								Build.PL
									
										
									
									
									
								
							
							
						
						
									
										26
									
								
								Build.PL
									
										
									
									
									
								
							|  | @ -27,16 +27,28 @@ my %recommends = qw( | |||
|     Class::XSAccessor               0 | ||||
|     Growl::GNTP                     0.15 | ||||
|     XML::SAX::ExpatXS               0 | ||||
|     Wx                              0.9901 | ||||
| ); | ||||
| 
 | ||||
| # removed: | ||||
| # Wx 0.9901 | ||||
| 
 | ||||
| my @try = ( | ||||
|     $ENV{CPANM} // (), | ||||
|     File::Spec->catfile($Config{sitebin}, 'cpanm'), | ||||
|     File::Spec->catfile($Config{installscript}, 'cpanm'), | ||||
| ); | ||||
| 
 | ||||
| my $cpanm; | ||||
| if (defined $ENV{CPANM} && -x $ENV{CPANM}) { | ||||
|     $cpanm = $ENV{CPANM}; | ||||
| } elsif (-x (my $c = File::Spec->catfile($Config{installscript}, 'cpanm'))) { | ||||
|     $cpanm = $c; | ||||
| } elsif ($^O = /^(?:darwin|linux)$/ && system(qw(which cpanm)) == 0) { | ||||
|     $cpanm = 'cpanm'; | ||||
| foreach my $path (@try) { | ||||
|     if (-e $path) {  # don't use -x because it fails on Windows | ||||
|         $cpanm = $path; | ||||
|         last; | ||||
|     } | ||||
| } | ||||
| if (!$cpanm) { | ||||
|     if ($^O =~ /^(?:darwin|linux)$/ && system(qw(which cpanm)) == 0) { | ||||
|         $cpanm = 'cpanm'; | ||||
|     } | ||||
| } | ||||
| die <<'EOF' | ||||
| cpanm was not found. Please install it before running this script. | ||||
|  |  | |||
|  | @ -3,8 +3,8 @@ use Moo; | |||
| 
 | ||||
| extends 'Slic3r::Fill::Base'; | ||||
| 
 | ||||
| use Slic3r::Geometry qw(scale unscale X); | ||||
| use Slic3r::Geometry::Clipper qw(offset2 union_pt traverse_pt PFT_EVENODD); | ||||
| use Slic3r::Geometry qw(scale unscale X nearest_point_index); | ||||
| use Slic3r::Geometry::Clipper qw(offset offset2 union_pt traverse_pt PFT_EVENODD); | ||||
| 
 | ||||
| sub fill_surface { | ||||
|     my $self = shift; | ||||
|  | @ -27,16 +27,26 @@ sub fill_surface { | |||
|         $flow_spacing = unscale $distance; | ||||
|     } | ||||
|      | ||||
|     my @loops = my @last = @$expolygon; | ||||
|     # compensate the overlap which is good for rectilinear but harmful for concentric | ||||
|     # where the perimeter/infill spacing should be equal to any other loop spacing | ||||
|     my @loops = my @last = offset($expolygon, -&Slic3r::INFILL_OVERLAP_OVER_SPACING * $min_spacing / 2); | ||||
|     while (@last) { | ||||
|         push @loops, @last = offset2(\@last, -1.5*$distance,  +0.5*$distance); | ||||
|     } | ||||
|      | ||||
|     # generate paths from the outermost to the innermost, to avoid  | ||||
|     # adhesion problems of the first central tiny loops | ||||
|     my @paths = map Slic3r::Polygon->new(@$_)->split_at_first_point, | ||||
|     @loops = map Slic3r::Polygon->new(@$_), | ||||
|         reverse traverse_pt( union_pt(\@loops, PFT_EVENODD) ); | ||||
|      | ||||
|     # order paths using a nearest neighbor search | ||||
|     my @paths = (); | ||||
|     my $last_pos = [0,0]; | ||||
|     foreach my $loop (@loops) { | ||||
|         push @paths, $loop->split_at_index(nearest_point_index($last_pos, $loop)); | ||||
|         $last_pos = $paths[-1][-1]; | ||||
|     } | ||||
|      | ||||
|     # clip the paths to avoid the extruder to get exactly on the first point of the loop | ||||
|     my $clip_length = scale $flow_spacing * &Slic3r::LOOP_CLIPPING_LENGTH_OVER_SPACING; | ||||
|     $_->clip_end($clip_length) for @paths; | ||||
|  |  | |||
|  | @ -190,8 +190,6 @@ sub extrude_loop { | |||
|             $extrusion_path->intersect_expolygons($self->_layer_overhangs); | ||||
|          | ||||
|         # reapply the nearest point search for starting point | ||||
|         # (TODO: choose the nearest point not on an overhang - make sure wipe and | ||||
|         # inwards move consider the new actual starting point) | ||||
|         @paths = Slic3r::ExtrusionPath::Collection | ||||
|             ->new(paths => [@paths]) | ||||
|             ->chained_path($last_pos, 1); | ||||
|  | @ -443,9 +441,16 @@ sub retract { | |||
|             $self->speed('travel'); | ||||
|              | ||||
|             # subdivide the retraction | ||||
|             my $retracted = 0; | ||||
|             for (1 .. $#$wipe_path) { | ||||
|                 my $segment_length = $wipe_path->[$_-1]->distance_to($wipe_path->[$_]); | ||||
|                 $gcode .= $self->G1($wipe_path->[$_], undef, $retract->[2] * ($segment_length / $total_wipe_length), $retract->[3] . ";_WIPE"); | ||||
|                 $retracted += my $e = $retract->[2] * ($segment_length / $total_wipe_length); | ||||
|                 $gcode .= $self->G1($wipe_path->[$_], undef, $e, $retract->[3] . ";_WIPE"); | ||||
|             } | ||||
|             if ($retracted > $retract->[2]) { | ||||
|                 # if we retracted less than we had to, retract the remainder | ||||
|                 # TODO: add regression test | ||||
|                 $gcode .= $self->G1(undef, undef, $retract->[2] - $retracted, $comment); | ||||
|             } | ||||
|         } else { | ||||
|             $self->speed('retract'); | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ our @EXPORT_OK = qw( | |||
|     point_is_on_left_of_segment polyline_lines polygon_lines nearest_point | ||||
|     point_along_segment polygon_segment_having_point polygon_has_subsegment | ||||
|     polygon_has_vertex polyline_length can_connect_points deg2rad rad2deg | ||||
|     rotate_points move_points clip_segment_polygon | ||||
|     rotate_points move_points clip_segment_polygon nearest_point_index | ||||
|     sum_vectors multiply_vector subtract_vectors dot perp polygon_points_visibility | ||||
|     line_intersection bounding_box bounding_box_intersect same_point same_line | ||||
|     longest_segment angle3points three_points_aligned line_direction | ||||
|  |  | |||
|  | @ -62,6 +62,18 @@ sub scale { | |||
|     $self; | ||||
| } | ||||
| 
 | ||||
| sub translate { | ||||
|     my $self = shift; | ||||
|     my @shift = @_; | ||||
|      | ||||
|     for my $axis (X .. $#{$self->extents}) { | ||||
|         $self->extents->[$axis][MIN] += $shift[$axis]; | ||||
|         $self->extents->[$axis][MAX] += $shift[$axis]; | ||||
|     } | ||||
|      | ||||
|     $self; | ||||
| } | ||||
| 
 | ||||
| sub size { | ||||
|     my $self = shift; | ||||
|      | ||||
|  |  | |||
|  | @ -256,7 +256,11 @@ sub make_perimeters { | |||
|         foreach my $polynode (@nodes) { | ||||
|             push @loops, $traverse->($polynode->{children}, $depth+1, $is_contour); | ||||
|              | ||||
|             # return ccw contours and cw holes | ||||
|             # 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 | ||||
|             my $polygon = Slic3r::Polygon->new($polynode->{outer} // [ reverse @{$polynode->{hole}} ]); | ||||
|             $polygon->reverse if !$is_contour; | ||||
|              | ||||
|             my $role = EXTR_ROLE_PERIMETER; | ||||
|             if ($is_contour ? $depth == 0 : !@{ $polynode->{children} }) { | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ use Slic3r::Geometry qw(X Y Z MIN move_points); | |||
| 
 | ||||
| has 'materials' => (is => 'ro', default => sub { {} }); | ||||
| has 'objects'   => (is => 'ro', default => sub { [] }); | ||||
| has '_bounding_box' => (is => 'rw'); | ||||
| 
 | ||||
| sub read_from_file { | ||||
|     my $class = shift; | ||||
|  | @ -57,6 +58,7 @@ sub add_object { | |||
|      | ||||
|     my $object = Slic3r::Model::Object->new(model => $self, @_); | ||||
|     push @{$self->objects}, $object; | ||||
|     $self->_bounding_box(undef); | ||||
|     return $object; | ||||
| } | ||||
| 
 | ||||
|  | @ -70,11 +72,6 @@ sub set_material { | |||
|     ); | ||||
| } | ||||
| 
 | ||||
| sub scale { | ||||
|     my $self = shift; | ||||
|     $_->scale(@_) for @{$self->objects}; | ||||
| } | ||||
| 
 | ||||
| sub arrange_objects { | ||||
|     my $self = shift; | ||||
|     my ($config) = @_; | ||||
|  | @ -151,8 +148,9 @@ sub _arrange { | |||
|         return ($config->duplicate_grid->[X] * $config->duplicate_grid->[Y]), @positions; | ||||
|     } else { | ||||
|         my $total_parts = $config->duplicate * @items; | ||||
|         my $partx = max(map $_->size->[X], @items); | ||||
|         my $party = max(map $_->size->[Y], @items); | ||||
|         my @sizes = map $_->size, @items; | ||||
|         my $partx = max(map $_->[X], @sizes); | ||||
|         my $party = max(map $_->[Y], @sizes); | ||||
|         return $config->duplicate, | ||||
|             Slic3r::Geometry::arrange | ||||
|                 ($total_parts, $partx, $party, (map $_, @{$config->bed_size}), | ||||
|  | @ -172,12 +170,16 @@ sub used_vertices { | |||
| 
 | ||||
| sub size { | ||||
|     my $self = shift; | ||||
|     return [ Slic3r::Geometry::size_3D($self->used_vertices) ]; | ||||
|     return $self->bounding_box->size; | ||||
| } | ||||
| 
 | ||||
| sub bounding_box { | ||||
|     my $self = shift; | ||||
|     return Slic3r::Geometry::BoundingBox->new_from_points_3D($self->used_vertices); | ||||
|      | ||||
|     if (!defined $self->_bounding_box) { | ||||
|         $self->_bounding_box(Slic3r::Geometry::BoundingBox->new_from_points_3D($self->used_vertices)); | ||||
|     } | ||||
|     return $self->_bounding_box; | ||||
| } | ||||
| 
 | ||||
| sub align_to_origin { | ||||
|  | @ -198,9 +200,18 @@ sub align_to_origin { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| sub scale { | ||||
|     my $self = shift; | ||||
|     $_->scale(@_) for @{$self->objects}; | ||||
|     $self->_bounding_box->scale(@_) if defined $self->_bounding_box; | ||||
| } | ||||
| 
 | ||||
| sub move { | ||||
|     my $self = shift; | ||||
|     $_->move(@_) for @{$self->objects}; | ||||
|     my @shift = @_; | ||||
|      | ||||
|     $_->move(@shift) for @{$self->objects}; | ||||
|     $self->_bounding_box->translate(@shift) if defined $self->_bounding_box; | ||||
| } | ||||
| 
 | ||||
| # flattens everything to a single mesh | ||||
|  | @ -286,6 +297,7 @@ has 'vertices'  => (is => 'ro', default => sub { [] }); | |||
| has 'volumes'   => (is => 'ro', default => sub { [] }); | ||||
| has 'instances' => (is => 'rw'); | ||||
| has 'layer_height_ranges' => (is => 'rw', default => sub { [] }); # [ z_min, z_max, layer_height ] | ||||
| has '_bounding_box' => (is => 'rw'); | ||||
| 
 | ||||
| sub add_volume { | ||||
|     my $self = shift; | ||||
|  | @ -304,6 +316,8 @@ sub add_volume { | |||
|      | ||||
|     my $volume = Slic3r::Model::Volume->new(object => $self, %args); | ||||
|     push @{$self->volumes}, $volume; | ||||
|     $self->_bounding_box(undef); | ||||
|     $self->model->_bounding_box(undef); | ||||
|     return $volume; | ||||
| } | ||||
| 
 | ||||
|  | @ -312,6 +326,7 @@ sub add_instance { | |||
|      | ||||
|     $self->instances([]) if !defined $self->instances; | ||||
|     push @{$self->instances}, Slic3r::Model::Instance->new(object => $self, @_); | ||||
|     $self->model->_bounding_box(undef); | ||||
|     return $self->instances->[-1]; | ||||
| } | ||||
| 
 | ||||
|  | @ -333,7 +348,7 @@ sub used_vertices { | |||
| 
 | ||||
| sub size { | ||||
|     my $self = shift; | ||||
|     return [ Slic3r::Geometry::size_3D($self->used_vertices) ]; | ||||
|     return $self->bounding_box->size; | ||||
| } | ||||
| 
 | ||||
| sub center { | ||||
|  | @ -343,7 +358,11 @@ sub center { | |||
| 
 | ||||
| sub bounding_box { | ||||
|     my $self = shift; | ||||
|     return Slic3r::Geometry::BoundingBox->new_from_points_3D($self->used_vertices); | ||||
|      | ||||
|     if (!defined $self->_bounding_box) { | ||||
|         $self->_bounding_box(Slic3r::Geometry::BoundingBox->new_from_points_3D($self->used_vertices)); | ||||
|     } | ||||
|     return $self->_bounding_box; | ||||
| } | ||||
| 
 | ||||
| sub align_to_origin { | ||||
|  | @ -359,7 +378,10 @@ sub align_to_origin { | |||
| 
 | ||||
| sub move { | ||||
|     my $self = shift; | ||||
|     @{$self->vertices} = move_points_3D([ @_ ], @{$self->vertices}); | ||||
|     my @shift = @_; | ||||
|      | ||||
|     @{$self->vertices} = move_points_3D([ @shift ], @{$self->vertices}); | ||||
|     $self->_bounding_box->translate(@shift) if defined $self->_bounding_box; | ||||
| } | ||||
| 
 | ||||
| sub scale { | ||||
|  | @ -371,6 +393,8 @@ sub scale { | |||
|     foreach my $vertex (@{$self->vertices}) { | ||||
|         $vertex->[$_] *= $factor for X,Y,Z; | ||||
|     } | ||||
|      | ||||
|     $self->_bounding_box->scale($factor) if defined $self->_bounding_box; | ||||
| } | ||||
| 
 | ||||
| sub rotate { | ||||
|  | @ -384,6 +408,8 @@ sub rotate { | |||
|     foreach my $vertex (@{$self->vertices}) { | ||||
|         @$vertex = (@{ +(Slic3r::Geometry::rotate_points($rad, undef, [ $vertex->[X], $vertex->[Y] ]))[0] }, $vertex->[Z]); | ||||
|     } | ||||
|      | ||||
|     $self->_bounding_box(undef); | ||||
| } | ||||
| 
 | ||||
| sub materials_count { | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ use parent 'Slic3r::Polyline'; | |||
| 
 | ||||
| use Slic3r::Geometry qw(polygon_lines polygon_remove_parallel_continuous_edges | ||||
|     polygon_remove_acute_vertices polygon_segment_having_point point_in_polygon | ||||
|     PI X1 X2 Y1 Y2); | ||||
|     PI X1 X2 Y1 Y2 epsilon); | ||||
| use Slic3r::Geometry::Clipper qw(JT_MITER); | ||||
| 
 | ||||
| sub lines { | ||||
|  | @ -159,7 +159,7 @@ sub concave_points { | |||
|     my $self = shift; | ||||
|      | ||||
|     return map $self->[$_], | ||||
|         grep Slic3r::Geometry::angle3points(@$self[$_, $_-1, $_+1]) < PI, | ||||
|         grep Slic3r::Geometry::angle3points(@$self[$_, $_-1, $_+1]) < PI - epsilon, | ||||
|         -1 .. ($#$self-1); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -145,6 +145,12 @@ sub slice { | |||
|     my $self = shift; | ||||
|     my %params = @_; | ||||
|      | ||||
|     # make sure all layers contain layer region objects for all regions | ||||
|     my $regions_count = $self->print->regions_count; | ||||
|     foreach my $layer (@{ $self->layers }) { | ||||
|         $layer->region($_) for 0 .. ($regions_count-1); | ||||
|     } | ||||
|      | ||||
|     # process facets | ||||
|     for my $region_id (0 .. $#{$self->meshes}) { | ||||
|         my $mesh = $self->meshes->[$region_id];  # ignore undef meshes | ||||
|  | @ -152,8 +158,7 @@ sub slice { | |||
|         my $apply_lines = sub { | ||||
|             my $lines = shift; | ||||
|             foreach my $layer_id (keys %$lines) { | ||||
|                 my $layerm = $self->layers->[$layer_id]->region($region_id); | ||||
|                 push @{$layerm->lines}, @{$lines->{$layer_id}}; | ||||
|                 push @{$self->layers->[$layer_id]->regions->[$region_id]->lines}, @{$lines->{$layer_id}}; | ||||
|             } | ||||
|         }; | ||||
|         Slic3r::parallelize( | ||||
|  | @ -192,9 +197,6 @@ sub slice { | |||
|     pop @{$self->layers} while @{$self->layers} && (!map @{$_->lines}, @{$self->layers->[-1]->regions}); | ||||
|      | ||||
|     foreach my $layer (@{ $self->layers }) { | ||||
|         # make sure all layers contain layer region objects for all regions | ||||
|         $layer->region($_) for 0 .. ($self->print->regions_count-1); | ||||
|          | ||||
|         Slic3r::debugf "Making surfaces for layer %d (slice z = %f):\n", | ||||
|             $layer->id, unscale $layer->slice_z if $Slic3r::debug; | ||||
|          | ||||
|  |  | |||
|  | @ -27,6 +27,13 @@ sub model { | |||
|         $facets = [ | ||||
|             [0,1,2], [0,2,3], [4,5,6], [4,6,7], [0,4,7], [0,7,1], [1,7,6], [1,6,2], [2,6,5], [2,5,3], [4,0,3], [4,3,5], | ||||
|         ], | ||||
|     } elsif ($model_name eq 'cube_with_hole') { | ||||
|         $vertices = [ | ||||
|             [0,0,0],[0,0,10],[0,20,0],[0,20,10],[20,0,0],[20,0,10],[5,5,0],[15,5,0],[5,15,0],[20,20,0],[15,15,0],[20,20,10],[5,5,10],[5,15,10],[15,5,10],[15,15,10] | ||||
|         ]; | ||||
|         $facets = [ | ||||
|             [0,1,2],[2,1,3],[1,0,4],[5,1,4],[6,7,4],[8,2,9],[0,2,8],[10,8,9],[0,8,6],[0,6,4],[4,7,9],[7,10,9],[2,3,9],[9,3,11],[12,1,5],[13,3,12],[14,12,5],[3,1,12],[11,3,13],[11,15,5],[11,13,15],[15,14,5],[5,4,9],[11,5,9],[8,13,12],[6,8,12],[10,15,13],[8,10,13],[15,10,14],[14,10,7],[14,7,12],[12,7,6] | ||||
|         ], | ||||
|     } elsif ($model_name eq 'V') { | ||||
|         $vertices = [ | ||||
|             [-14,0,20],[-14,15,20],[0,0,0],[0,15,0],[-4,0,20],[-4,15,20],[5,0,7.14286],[10,0,0],[24,0,20],[14,0,20],[10,15,0],[5,15,7.14286],[14,15,20],[24,15,20] | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| package Slic3r::TriangleMesh; | ||||
| use Moo; | ||||
| 
 | ||||
| use List::Util qw(reduce min max); | ||||
| use Slic3r::Geometry qw(X Y Z A B unscale same_point); | ||||
| use Slic3r::Geometry::Clipper qw(union_ex); | ||||
| use Storable; | ||||
|  | @ -37,6 +38,7 @@ sub analyze { | |||
|     $self->facets_edges([]); | ||||
|     $self->edges_facets([]); | ||||
|     my %table = ();  # edge_coordinates => edge_id | ||||
|     my $vertices = $self->vertices;  # save method calls | ||||
|      | ||||
|     for (my $facet_id = 0; $facet_id <= $#{$self->facets}; $facet_id++) { | ||||
|         my $facet = $self->facets->[$facet_id]; | ||||
|  | @ -46,8 +48,10 @@ sub analyze { | |||
|         # this is needed to get all intersection lines in a consistent order | ||||
|         # (external on the right of the line) | ||||
|         { | ||||
|             my @z_order = sort { $self->vertices->[$facet->[$a]][Z] <=> $self->vertices->[$facet->[$b]][Z] } -3..-1; | ||||
|             @$facet[-3..-1] = (@$facet[$z_order[0]..-1], @$facet[-3..($z_order[0]-1)]); | ||||
|             my $lowest_vertex_idx = reduce { | ||||
|                 $vertices->[ $facet->[$a] ][Z] < $vertices->[ $facet->[$b] ][Z] ? $a : $b | ||||
|             } -3 .. -1; | ||||
|             @$facet[-3..-1] = (@$facet[$lowest_vertex_idx..-1], @$facet[-3..($lowest_vertex_idx-1)]); | ||||
|         } | ||||
|          | ||||
|         # ignore the normal if provided | ||||
|  | @ -420,13 +424,11 @@ sub slice_facet { | |||
|         if $Slic3r::debug; | ||||
|      | ||||
|     # find the vertical extents of the facet | ||||
|     my ($min_z, $max_z) = (99999999999, -99999999999); | ||||
|     foreach my $vertex (@vertices) { | ||||
|         my $vertex_z = $self->vertices->[$vertex][Z]; | ||||
|         $min_z = $vertex_z if $vertex_z < $min_z; | ||||
|         $max_z = $vertex_z if $vertex_z > $max_z; | ||||
|     } | ||||
|     Slic3r::debugf "z: min = %.0f, max = %.0f\n", $min_z, $max_z; | ||||
|     my @z = map $_->[Z], @{$self->vertices}[@vertices]; | ||||
|     my $min_z = min(@z); | ||||
|     my $max_z = max(@z); | ||||
|     Slic3r::debugf "z: min = %.0f, max = %.0f\n", $min_z, $max_z | ||||
|         if $Slic3r::debug; | ||||
|      | ||||
|     if ($max_z == $min_z) { | ||||
|         Slic3r::debugf "Facet is horizontal; ignoring\n"; | ||||
|  | @ -435,10 +437,11 @@ sub slice_facet { | |||
|      | ||||
|     # calculate the layer extents | ||||
|     my ($min_layer, $max_layer) = $print_object->get_layer_range($min_z, $max_z); | ||||
|     Slic3r::debugf "layers: min = %s, max = %s\n", $min_layer, $max_layer; | ||||
|     Slic3r::debugf "layers: min = %s, max = %s\n", $min_layer, $max_layer | ||||
|         if $Slic3r::debug; | ||||
|      | ||||
|     my $lines = {};  # layer_id => [ lines ] | ||||
|     for (my $layer_id = $min_layer; $layer_id <= $max_layer; $layer_id++) { | ||||
|     for my $layer_id ($min_layer .. $max_layer) { | ||||
|         my $layer = $print_object->layers->[$layer_id]; | ||||
|         $lines->{$layer_id} ||= []; | ||||
|         push @{ $lines->{$layer_id} }, $self->intersect_facet($facet_id, $layer->slice_z); | ||||
|  | @ -451,25 +454,27 @@ sub intersect_facet { | |||
|     my ($facet_id, $z) = @_; | ||||
|      | ||||
|     my @vertices_ids        = @{$self->facets->[$facet_id]}[-3..-1]; | ||||
|     my %vertices            = map { $_ => $self->vertices->[$_] } @vertices_ids;  # cache vertices | ||||
|     my @edge_ids            = @{$self->facets_edges->[$facet_id]}; | ||||
|     my @edge_vertices_ids   = $self->_facet_edges($facet_id); | ||||
|      | ||||
|     my (@lines, @points, @intersection_points, @points_on_layer) = (); | ||||
|     my (@points, @intersection_points, @points_on_layer) = (); | ||||
|          | ||||
|     for my $e (0..2) { | ||||
|         my $edge_id         = $edge_ids[$e]; | ||||
|         my ($a_id, $b_id)   = @{$edge_vertices_ids[$e]}; | ||||
|         my ($a, $b)         = map $self->vertices->[$_], ($a_id, $b_id); | ||||
|         my ($a, $b)         = @vertices{$a_id, $b_id}; | ||||
|         #printf "Az = %f, Bz = %f, z = %f\n", $a->[Z], $b->[Z], $z; | ||||
|          | ||||
|         if ($a->[Z] == $b->[Z] && $a->[Z] == $z) { | ||||
|             # edge is horizontal and belongs to the current layer | ||||
|             my $edge_type = (grep $self->vertices->[$_][Z] < $z, @vertices_ids) ? FE_TOP : FE_BOTTOM; | ||||
|             my $edge_type = (grep $vertices{$_}[Z] < $z, @vertices_ids) ? FE_TOP : FE_BOTTOM; | ||||
|             if ($edge_type == FE_TOP) { | ||||
|                 ($a, $b) = ($b, $a); | ||||
|                 ($a_id, $b_id) = ($b_id, $a_id); | ||||
|             } | ||||
|             push @lines, pack I_FMT, ( | ||||
|             # We assume that this method is never being called for horizontal | ||||
|             # facets, so no other edge is going to be on this layer. | ||||
|             return pack I_FMT, ( | ||||
|                 $b->[X], $b->[Y],       # I_B | ||||
|                 $a_id,                  # I_A_ID | ||||
|                 $b_id,                  # I_B_ID | ||||
|  | @ -499,14 +504,13 @@ sub intersect_facet { | |||
|                 $b->[X] + ($a->[X] - $b->[X]) * ($z - $b->[Z]) / ($a->[Z] - $b->[Z]), | ||||
|                 $b->[Y] + ($a->[Y] - $b->[Y]) * ($z - $b->[Z]) / ($a->[Z] - $b->[Z]), | ||||
|                 undef, | ||||
|                 $edge_id, | ||||
|                 $edge_ids[$e], | ||||
|             ]; | ||||
|             push @intersection_points, $#points; | ||||
|             #print "Intersects at $z!\n"; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     return @lines if @lines; | ||||
|     if (@points_on_layer == 2 && @intersection_points == 1) { | ||||
|         $points[ $points_on_layer[1] ] = undef; | ||||
|         @points = grep $_, @points; | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| use Test::More tests => 3; | ||||
| use Test::More tests => 5; | ||||
| use strict; | ||||
| use warnings; | ||||
| 
 | ||||
|  | @ -41,6 +41,37 @@ use Slic3r::Test; | |||
|         ok !$has_cw_loops, 'all perimeters extruded ccw'; | ||||
|     } | ||||
|      | ||||
|     { | ||||
|         $config->set('external_perimeter_speed', 68); | ||||
|         my $print = Slic3r::Test::init_print('cube_with_hole', config => $config); | ||||
|         my $has_cw_loops = my $has_outwards_move = 0; | ||||
|         my $cur_loop; | ||||
|         my %external_loops = ();  # print_z => count of external loops | ||||
|         Slic3r::GCode::Reader->new(gcode => Slic3r::Test::gcode($print))->parse(sub { | ||||
|             my ($self, $cmd, $args, $info) = @_; | ||||
|              | ||||
|             if ($info->{extruding} && $info->{dist_XY} > 0) { | ||||
|                 $cur_loop ||= [ [$self->X, $self->Y] ]; | ||||
|                 push @$cur_loop, [ @$info{qw(new_X new_Y)} ]; | ||||
|             } else { | ||||
|                 if ($cur_loop) { | ||||
|                     $has_cw_loops = 1 if !Slic3r::Geometry::Clipper::is_counter_clockwise($cur_loop); | ||||
|                     if ($self->F == $config->external_perimeter_speed*60) { | ||||
|                         my $move_dest = [ @$info{qw(new_X new_Y)} ]; | ||||
|                         $external_loops{$self->Z}++; | ||||
|                         $has_outwards_move = 1 | ||||
|                             if !Slic3r::Polygon->new(@$cur_loop)->encloses_point($move_dest) | ||||
|                                 ? ($external_loops{$self->Z} == 2)  # contour should include destination | ||||
|                                 : ($external_loops{$self->Z} == 1); # hole should not | ||||
|                     } | ||||
|                     $cur_loop = undef; | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|         ok !$has_cw_loops, 'all perimeters extruded ccw'; | ||||
|         ok !$has_outwards_move, 'move inwards after completing external loop'; | ||||
|     } | ||||
|      | ||||
|     { | ||||
|         my $print = Slic3r::Test::init_print('L', config => $config); | ||||
|         my $loop_starts_from_convex_point = 0; | ||||
|  |  | |||
							
								
								
									
										14
									
								
								t/slice.t
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								t/slice.t
									
										
									
									
									
								
							|  | @ -2,7 +2,7 @@ use Test::More; | |||
| use strict; | ||||
| use warnings; | ||||
| 
 | ||||
| plan tests => 17; | ||||
| plan tests => 16; | ||||
| 
 | ||||
| BEGIN { | ||||
|     use FindBin; | ||||
|  | @ -20,11 +20,13 @@ my @points = ([3, 4], [8, 5], [1, 9]);  # XY coordinates of the facet vertices | |||
| # the first point of the intersection lines is replaced by -1 because TriangleMesh.pm | ||||
| # is saving memory and doesn't store point A anymore since it's not actually needed. | ||||
| 
 | ||||
| is_deeply lines(20, 20, 20), [ | ||||
|     [ -1, $points[1] ],  # $points[0] | ||||
|     [ -1, $points[2] ],  # $points[1] | ||||
|     [ -1, $points[0] ],  # $points[2] | ||||
| ], 'horizontal'; | ||||
| # We disable this test because intersect_facet() now assumes we never feed a horizontal | ||||
| # facet to it. | ||||
| # is_deeply lines(20, 20, 20), [ | ||||
| #     [ -1, $points[1] ],  # $points[0] | ||||
| #     [ -1, $points[2] ],  # $points[1] | ||||
| #     [ -1, $points[0] ],  # $points[2] | ||||
| # ], 'horizontal'; | ||||
| 
 | ||||
| is_deeply lines(22, 20, 20), [ [ -1, $points[2] ] ], 'lower edge on layer';  # $points[1] | ||||
| is_deeply lines(20, 20, 22), [ [ -1, $points[1] ] ], 'lower edge on layer';  # $points[0] | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci