mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-20 07:11:12 -06:00 
			
		
		
		
	Skeining algorithm totally rewritten
This commit is contained in:
		
							parent
							
								
									3274f3978b
								
							
						
					
					
						commit
						ad27f25c71
					
				
					 8 changed files with 180 additions and 144 deletions
				
			
		|  | @ -55,6 +55,7 @@ our $flow_width; | ||||||
| # print options | # print options | ||||||
| our $perimeter_offsets  = 3; | our $perimeter_offsets  = 3; | ||||||
| our $solid_layers       = 3; | our $solid_layers       = 3; | ||||||
|  | our $bridge_overlap     = 2;    # mm | ||||||
| our $fill_type          = 'rectilinear'; | our $fill_type          = 'rectilinear'; | ||||||
| our $fill_density       = 0.4;  # 1 = 100% | our $fill_density       = 0.4;  # 1 = 100% | ||||||
| our $fill_angle         = 0; | our $fill_angle         = 0; | ||||||
|  |  | ||||||
|  | @ -5,7 +5,7 @@ use warnings; | ||||||
| require Exporter; | require Exporter; | ||||||
| our @ISA = qw(Exporter); | our @ISA = qw(Exporter); | ||||||
| our @EXPORT_OK = qw( | our @EXPORT_OK = qw( | ||||||
|     epsilon slope line_atan lines_parallel three_points_aligned |     PI epsilon slope line_atan lines_parallel three_points_aligned | ||||||
|     line_point_belongs_to_segment points_coincide distance_between_points  |     line_point_belongs_to_segment points_coincide distance_between_points  | ||||||
|     line_length midpoint point_in_polygon point_in_segment segment_in_segment |     line_length midpoint point_in_polygon point_in_segment segment_in_segment | ||||||
|     point_is_on_left_of_segment polyline_lines polygon_lines nearest_point |     point_is_on_left_of_segment polyline_lines polygon_lines nearest_point | ||||||
|  | @ -14,10 +14,10 @@ our @EXPORT_OK = qw( | ||||||
|     rotate_points move_points remove_coinciding_points clip_segment_polygon |     rotate_points move_points remove_coinciding_points clip_segment_polygon | ||||||
|     sum_vectors multiply_vector subtract_vectors dot perp polygon_points_visibility |     sum_vectors multiply_vector subtract_vectors dot perp polygon_points_visibility | ||||||
|     line_intersection bounding_box bounding_box_intersect  |     line_intersection bounding_box bounding_box_intersect  | ||||||
|     clip_segment_complex_polygon longest_segment |     clip_segment_complex_polygon longest_segment angle3points | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| use Slic3r::Geometry::DouglasPeucker; | use Slic3r::Geometry::DouglasPeucker (); | ||||||
| use XXX; | use XXX; | ||||||
| 
 | 
 | ||||||
| use constant PI => 4 * atan2(1, 1); | use constant PI => 4 * atan2(1, 1); | ||||||
|  | @ -564,4 +564,15 @@ sub clip_segment_complex_polygon { | ||||||
|     return [@lines]; |     return [@lines]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | sub angle3points { | ||||||
|  |     my ($p1, $p2, $p3) = @_; | ||||||
|  |     # p1 is the center | ||||||
|  |      | ||||||
|  |     my $angle = atan2($p2->[X] - $p1->[X], $p2->[Y] - $p1->[Y]) | ||||||
|  |               - atan2($p3->[X] - $p1->[X], $p3->[Y] - $p1->[Y]); | ||||||
|  |      | ||||||
|  |     # we only want to return only positive angles | ||||||
|  |     return $angle <= 0 ? $angle + 2*PI() : $angle; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| 1; | 1; | ||||||
|  |  | ||||||
|  | @ -160,7 +160,7 @@ sub angle3points					# Angle between three points in radians | ||||||
|  { |  { | ||||||
|   my $p1	= shift ; |   my $p1	= shift ; | ||||||
|   my $p2	= shift ; |   my $p2	= shift ; | ||||||
|   return( sprintf("%0.6f",atan2( (@$p2[1] - @$p1[1]),( @$p2[0] - @$p1[0] ))) ) ; |   return atan2( (@$p2[1] - @$p1[1]),( @$p2[0] - @$p1[0] )); | ||||||
|  } |  } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -3,9 +3,12 @@ use Moo; | ||||||
| 
 | 
 | ||||||
| use Math::Clipper ':all'; | use Math::Clipper ':all'; | ||||||
| use Math::ConvexHull qw(convex_hull); | use Math::ConvexHull qw(convex_hull); | ||||||
|  | use Slic3r::Geometry qw(polygon_lines points_coincide angle3points polyline_lines); | ||||||
| use XXX; | use XXX; | ||||||
| 
 | 
 | ||||||
| use constant PI => 4 * atan2(1, 1); | use constant PI => 4 * atan2(1, 1); | ||||||
|  | use constant A => 0; | ||||||
|  | use constant B => 1; | ||||||
| 
 | 
 | ||||||
| # a sequential number of layer, starting at 0 | # a sequential number of layer, starting at 0 | ||||||
| has 'id' => ( | has 'id' => ( | ||||||
|  | @ -100,6 +103,7 @@ sub add_line { | ||||||
|     my ($line) = @_; |     my ($line) = @_; | ||||||
|      |      | ||||||
|     $line = Slic3r::Line->cast($line); |     $line = Slic3r::Line->cast($line); | ||||||
|  |     return if $line->a->coincides_with($line->b); | ||||||
|      |      | ||||||
|     push @{ $self->lines }, $line; |     push @{ $self->lines }, $line; | ||||||
|     return $line; |     return $line; | ||||||
|  | @ -118,141 +122,78 @@ sub remove_surface { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| # build polylines of lines which do not already belong to a surface | # build polylines of lines which do not already belong to a surface | ||||||
| # okay, this code is a mess.  will need some refactoring.  sorry. |  | ||||||
| sub make_polylines { | sub make_polylines { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|      |      | ||||||
|     # remove line duplicates |     my @lines = (); | ||||||
|     if (0) { |     push @lines, map $_->p, @{$self->lines}; | ||||||
|         # this removes any couple of coinciding Slic3r::Line::FacetEdge |  | ||||||
|         my %lines_map = (); |  | ||||||
|         foreach my $line (grep $_->isa('Slic3r::Line::FacetEdge'), @{ $self->lines }) { |  | ||||||
|             my $ordered_id = $line->ordered_id; |  | ||||||
|             if (exists $lines_map{$ordered_id}) { |  | ||||||
|                 delete $lines_map{$ordered_id}; |  | ||||||
|                 next; |  | ||||||
|             } |  | ||||||
|             $lines_map{$ordered_id} = $line; |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         @{ $self->lines } = (values(%lines_map), grep !$_->isa('Slic3r::Line::FacetEdge'), @{ $self->lines }); |  | ||||||
|     } |  | ||||||
|     if (1) { |  | ||||||
|         # this removes any duplicate, leaving one |  | ||||||
|         my %lines_map = map { join(',', sort map $_->id, @{$_->points} ) => "$_" } @{ $self->lines }; |  | ||||||
|         %lines_map = reverse %lines_map; |  | ||||||
|         @{ $self->lines } = grep $lines_map{"$_"}, @{ $self->lines }; |  | ||||||
|     } |  | ||||||
|      |      | ||||||
|     # now remove lines that are already part of a surface |     #use Slic3r::SVG; | ||||||
|     if (1) { |     #Slic3r::SVG::output(undef, "lines.svg", | ||||||
|         my @lines = @{ $self->lines }; |     #    lines       => [ map $_->p, grep !$_->isa('Slic3r::Line::FacetEdge'), @{$self->lines} ], | ||||||
|         @{ $self->lines } = (); |     #    red_lines   => [ map $_->p, grep  $_->isa('Slic3r::Line::FacetEdge'), @{$self->lines} ], | ||||||
|         LINE: foreach my $line (@lines) { |     #); | ||||||
|             if (!$line->isa('Slic3r::Line::FacetEdge')) { |      | ||||||
|                 push @{ $self->lines }, $line; |     my $get_point_id = sub { sprintf "%d,%d", @{$_[0]} }; | ||||||
|                 next LINE; |  | ||||||
|             } |  | ||||||
|             foreach my $surface (@{$self->surfaces}) { |  | ||||||
|                 if ($surface->surface_type eq $line->edge_type && $surface->contour->has_segment($line)) { |  | ||||||
|                     next LINE; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             push @{ $self->lines }, $line; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|      |      | ||||||
|     # make a cache of line endpoints |  | ||||||
|     my (%pointmap) = (); |     my (%pointmap) = (); | ||||||
|     foreach my $line (@{ $self->lines }) { |     foreach my $line (@lines) { | ||||||
|         for my $point (@{ $line->points }) { |         my $point_id = $get_point_id->($line->[A]); | ||||||
|             $pointmap{$point->id} ||= []; |         $pointmap{$point_id} ||= []; | ||||||
|             push @{ $pointmap{$point->id} }, $line; |         push @{ $pointmap{$point_id} }, $line; | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     foreach my $point_id (keys %pointmap) { |  | ||||||
|         $pointmap{$point_id} = [ |  | ||||||
|             sort { $a->isa('Slic3r::Line::FacetEdge') <=> $b->isa('Slic3r::Line::FacetEdge') }  |  | ||||||
|                 @{$pointmap{$point_id}} ]; |  | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     if (0) { |     my $n = 0; | ||||||
|         # defensive programming |     my @polylines = (); | ||||||
|         for (keys %pointmap) { |     while (my $first_line = shift @lines) { | ||||||
|             next if @{$pointmap{$_}} == 2; |         my @points = @$first_line; | ||||||
|              |         my %seen_points = map { $get_point_id->($points[$_]) => $_ } 0..1; | ||||||
|             use Slic3r::SVG; |  | ||||||
|             Slic3r::SVG::output(undef, "lines_and_points.svg", |  | ||||||
|                 lines       => [ map $_->p, grep !$_->isa('Slic3r::Line::FacetEdge'), @{$self->lines} ], |  | ||||||
|                 red_lines   => [ map $_->p, grep $_->isa('Slic3r::Line::FacetEdge'), @{$self->lines} ], |  | ||||||
|                 points      => [ map [split /,/], keys %pointmap ], |  | ||||||
|                 red_points  => [ [split /,/, $_ ] ], |  | ||||||
|             ); |  | ||||||
|              |  | ||||||
|             YYY $pointmap{$_}; |  | ||||||
|              |  | ||||||
|             die sprintf "No point should be endpoint of less or more than 2 lines ($_ => %d)!", scalar(@{$pointmap{$_}}); |  | ||||||
|         } |  | ||||||
|          |          | ||||||
|         while (my @single_line_points = grep @{$pointmap{$_}} == 1, keys %pointmap) { |         CYCLE: while (1) { | ||||||
|             for my $point_id (@single_line_points) { |             my $next_lines = $pointmap{ $get_point_id->($points[-1]) } | ||||||
|                 foreach my $lines (values %pointmap) { |                 or die sprintf "No lines start at point %d,%d. This shouldn't happen", @{$points[-1]}; | ||||||
|                     next unless $pointmap{$point_id}->[0]; |             last CYCLE if !@$next_lines; | ||||||
|                     @$lines = grep $_ ne $pointmap{$point_id}->[0], @$lines; |              | ||||||
|                 } |             my @ordered_next_lines = sort  | ||||||
|                 delete $pointmap{$point_id}; |                 { angle3points($points[-1], $points[-2], $next_lines->[$a][B]) <=> angle3points($points[-1], $points[-2], $next_lines->[$b][B]) }  | ||||||
|  |                 0..$#$next_lines; | ||||||
|  |              | ||||||
|  |             #if (@$next_lines > 1) { | ||||||
|  |             #    Slic3r::SVG::output(undef, "next_line.svg", | ||||||
|  |             #        lines        => $next_lines, | ||||||
|  |             #        red_lines    => [ polyline_lines([@points]) ], | ||||||
|  |             #        green_lines  => [ $next_lines->[ $ordered_next_lines[0] ] ], | ||||||
|  |             #    ); | ||||||
|  |             #} | ||||||
|  |              | ||||||
|  |             my ($next_line) = splice @$next_lines, $ordered_next_lines[0], 1; | ||||||
|  |              | ||||||
|  |              | ||||||
|  |             push @points, $next_line->[B]; | ||||||
|  |              | ||||||
|  |             my $point_id = $get_point_id->($points[-1]); | ||||||
|  |             if ($seen_points{$point_id}) { | ||||||
|  |                 splice @points, 0, $seen_points{$point_id}; | ||||||
|  |                 last CYCLE; | ||||||
|             } |             } | ||||||
|         } |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     # make a subroutine to remove lines from pointmap |  | ||||||
|     my $remove_line = sub { |  | ||||||
|         my $line = shift; |  | ||||||
|         foreach my $lines ($pointmap{$line->a->id}, $pointmap{$line->b->id}) { |  | ||||||
|             @$lines = grep $_ ne $line, @$lines; |  | ||||||
|         } |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     my $polylines = []; |  | ||||||
|      |  | ||||||
|     # loop while we have spare lines |  | ||||||
|     while (my ($first_line) = map @$_, values %pointmap) { |  | ||||||
|         # add first line to a new polyline |  | ||||||
|         my $points = [ $first_line->a, $first_line->b ]; |  | ||||||
|         $remove_line->($first_line); |  | ||||||
|         my $last_point = $first_line->b; |  | ||||||
|          |  | ||||||
|         # loop through connected lines until we return to the first point |  | ||||||
|         while (my $next_line = $pointmap{$last_point->id}->[0]) { |  | ||||||
|              |              | ||||||
|             # get next point |             $seen_points{$point_id} = $#points; | ||||||
|             ($last_point) = grep $_->id ne $last_point->id, @{$next_line->points}; |  | ||||||
|              |  | ||||||
|             # add point to polyline |  | ||||||
|             push @$points, $last_point; |  | ||||||
|             $remove_line->($next_line); |  | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         # remove last point as it coincides with first one |         if (@points < 4 || !points_coincide($points[0], $points[-1])) { | ||||||
|         pop @$points; |  | ||||||
|          |  | ||||||
|         if (@$points == 1 && $first_line->isa('Slic3r::Line::FacetEdge')) { |  | ||||||
|             Slic3r::debugf "Skipping spare facet edge"; |  | ||||||
|             next; |             next; | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         die sprintf "Invalid polyline with only %d points\n", scalar(@$points) if @$points < 3; |         pop @points; | ||||||
|          |         Slic3r::debugf "Discovered polyline of %d points\n", scalar(@points); | ||||||
|         Slic3r::debugf "Discovered polyline of %d points (%s)\n", scalar @$points, |         push @polylines, [@points]; | ||||||
|             join ' - ', map $_->id, @$points; |  | ||||||
|         push @$polylines, Slic3r::Polyline::Closed->new(points => $points); |  | ||||||
|          |  | ||||||
|         # actually this is not needed, as Math::Clipper used in make_surfaces() also cleans contours |  | ||||||
|         $polylines->[-1]->merge_continuous_lines; |  | ||||||
|         #$polylines->[-1]->cleanup;  # not proven to be actually useful |  | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     return $polylines; |     #Slic3r::SVG::output(undef, "polylines.svg", | ||||||
|  |     #    polylines => [ @polylines ], | ||||||
|  |     #); | ||||||
|  |      | ||||||
|  |     return [ map Slic3r::Polyline::Closed->cast($_), @polylines ]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub make_surfaces { | sub make_surfaces { | ||||||
|  | @ -336,7 +277,7 @@ sub merge_contiguous_surfaces { | ||||||
|         Slic3r::debugf "Initial surfaces (%d):\n", scalar @{ $self->surfaces }; |         Slic3r::debugf "Initial surfaces (%d):\n", scalar @{ $self->surfaces }; | ||||||
|         Slic3r::debugf "  [%s] %s (%s with %d holes)\n", $_->surface_type, $_->id,  |         Slic3r::debugf "  [%s] %s (%s with %d holes)\n", $_->surface_type, $_->id,  | ||||||
|             ($_->contour->is_counter_clockwise ? 'ccw' : 'cw'), scalar @{$_->holes} for @{ $self->surfaces }; |             ($_->contour->is_counter_clockwise ? 'ccw' : 'cw'), scalar @{$_->holes} for @{ $self->surfaces }; | ||||||
|         #Slic3r::SVG::output_polygons($main::print, "polygons-before.svg", [ map $_->contour->p, @{$self->surfaces} ]); |         #Slic3r::SVG::output_polygons(undef, "polygons-before.svg", [ map $_->contour->p, @{$self->surfaces} ]); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     my %resulting_surfaces = (); |     my %resulting_surfaces = (); | ||||||
|  | @ -487,12 +428,13 @@ sub process_bridges { | ||||||
|          |          | ||||||
|         # now connect the first point to the last of each polyline |         # now connect the first point to the last of each polyline | ||||||
|         @supported_polylines = map [ $_->[0]->[0], $_->[-1]->[-1] ], @supported_polylines; |         @supported_polylines = map [ $_->[0]->[0], $_->[-1]->[-1] ], @supported_polylines; | ||||||
|  |         # @supported_polylines becomes actually an array of lines | ||||||
|          |          | ||||||
|         # if we got more than two supports, get the longest two |         # if we got more than two supports, get the longest two | ||||||
|         if (@supported_polylines > 2) { |         if (@supported_polylines > 2) { | ||||||
|             my %lengths = map { "$_" => Slic3r::Geometry::line_length($_) }, @supported_polylines; |             my %lengths = map { $_ => Slic3r::Geometry::line_length($_) } @supported_polylines; | ||||||
|             @supported_polylines = sort { $lengths{"$a"} <=> $lengths{"$b"} } @supported_polylines; |             @supported_polylines = sort { $lengths{"$a"} <=> $lengths{"$b"} } @supported_polylines; | ||||||
|             @supported_polylines = @supported_polylines[0,1]; |             @supported_polylines = @supported_polylines[-2,-1]; | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         # connect the midpoints, that will give the the optimal infill direction |         # connect the midpoints, that will give the the optimal infill direction | ||||||
|  | @ -517,8 +459,8 @@ sub process_bridges { | ||||||
|          |          | ||||||
|         # now, extend our bridge by taking a portion of supporting surfaces |         # now, extend our bridge by taking a portion of supporting surfaces | ||||||
|         { |         { | ||||||
|             # offset the bridge by 5mm |             # offset the bridge by the specified amount of mm | ||||||
|             my $bridge_offset = ${ offset([$surface_p], 5 / $Slic3r::resolution, $Slic3r::resolution * 100, JT_MITER, 2) }[0]; |             my $bridge_offset = ${ offset([$surface_p], $Slic3r::bridge_overlap / $Slic3r::resolution, $Slic3r::resolution * 100, JT_MITER, 2) }[0]; | ||||||
|              |              | ||||||
|             # calculate the new bridge |             # calculate the new bridge | ||||||
|             my $clipper = Math::Clipper->new; |             my $clipper = Math::Clipper->new; | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ use Moo; | ||||||
| 
 | 
 | ||||||
| use CAD::Format::STL; | use CAD::Format::STL; | ||||||
| use Math::Clipper qw(integerize_coordinate_sets is_counter_clockwise); | use Math::Clipper qw(integerize_coordinate_sets is_counter_clockwise); | ||||||
|  | use Slic3r::Geometry qw(three_points_aligned longest_segment); | ||||||
| use XXX; | use XXX; | ||||||
| 
 | 
 | ||||||
| use constant X => 0; | use constant X => 0; | ||||||
|  | @ -82,7 +83,7 @@ sub parse_file { | ||||||
|              |              | ||||||
|             # round Z coordinates to the nearest multiple of layer height |             # round Z coordinates to the nearest multiple of layer height | ||||||
|             # XY will be rounded automatically to integers with coercion |             # XY will be rounded automatically to integers with coercion | ||||||
|             $vertex->[Z] = sprintf('%.0f', $vertex->[Z] * $Slic3r::resolution / $Slic3r::layer_height) |             $vertex->[Z] = int($vertex->[Z] * $Slic3r::resolution / $Slic3r::layer_height) | ||||||
|                 * $Slic3r::layer_height / $Slic3r::resolution; |                 * $Slic3r::layer_height / $Slic3r::resolution; | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  | @ -118,12 +119,38 @@ sub _facet { | ||||||
|      |      | ||||||
|     Slic3r::debugf "layers: min = %s, max = %s\n", $min_layer, $max_layer; |     Slic3r::debugf "layers: min = %s, max = %s\n", $min_layer, $max_layer; | ||||||
|      |      | ||||||
|  |     # reorder vertices so that the first one is the one with lowest Z | ||||||
|  |     # this is needed to get all intersection lines in a consistent order | ||||||
|  |     # (external on the right of the line) | ||||||
|  |     { | ||||||
|  |         my @z_order = sort { $vertices[$a][Z] <=> $vertices[$b][Z] } 0..2; | ||||||
|  |         @vertices = (splice(@vertices, $z_order[0]), splice(@vertices, 0, $z_order[0])); | ||||||
|  |     } | ||||||
|  |      | ||||||
|     # is the facet horizontal? |     # is the facet horizontal? | ||||||
|     # (note that we can have $min_z == $max_z && $min_layer != $max_layer |     # (note that we can have $min_z == $max_z && $min_layer != $max_layer | ||||||
|     # if $min_z % $layer_height != 0) |     # if $min_z % $layer_height != 0) | ||||||
|     if ($min_z == $max_z) { |     if ($min_z == $max_z) { | ||||||
|         Slic3r::debugf "Facet is horizontal\n"; |  | ||||||
|         my $layer = $print->layer($min_layer); |         my $layer = $print->layer($min_layer); | ||||||
|  |          | ||||||
|  |         # if all vertices are aligned, then facet is not horizontal but vertical | ||||||
|  |         # with a height less than layer height: that's why it was squashed on a | ||||||
|  |         # single layer | ||||||
|  |         ##local $Slic3r::Geometry::parallel_degrees_limit = 1; | ||||||
|  |         ##if (three_points_aligned(@vertices)) { | ||||||
|  |         if (0 && abs($normal->[Z]) == 0) { | ||||||
|  |             Slic3r::debugf "Facet is vertical with a height less than layer height\n"; | ||||||
|  |              | ||||||
|  |             my ($p1, $p2, $p3) = @vertices; | ||||||
|  |             $layer->add_line(Slic3r::Line::FacetEdge->cast( | ||||||
|  |                 $_, | ||||||
|  |                 edge_type => 'bottom', | ||||||
|  |             )) for ([$p1, $p2], [$p2, $p3], [$p1, $p3], [$p2, $p1], [$p3, $p2], [$p3, $p1]); | ||||||
|  |              | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         Slic3r::debugf "Facet is horizontal\n"; | ||||||
|         my $surface = $layer->add_surface(@vertices); |         my $surface = $layer->add_surface(@vertices); | ||||||
|          |          | ||||||
|         # to determine whether the surface is a top or bottom let's recompute |         # to determine whether the surface is a top or bottom let's recompute | ||||||
|  | @ -147,6 +174,7 @@ sub _facet { | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         if ($layer->id == 0 && !$clockwise) { |         if ($layer->id == 0 && !$clockwise) { | ||||||
|  |             YYY $normal; | ||||||
|             die "Right-hand rule gives bad result for facets on base layer!\n"; |             die "Right-hand rule gives bad result for facets on base layer!\n"; | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  | @ -180,11 +208,13 @@ sub intersect_facet { | ||||||
|          |          | ||||||
|         if ($a->[Z] == $b->[Z] && $a->[Z] == $z) { |         if ($a->[Z] == $b->[Z] && $a->[Z] == $z) { | ||||||
|             # edge is horizontal and belongs to the current layer |             # edge is horizontal and belongs to the current layer | ||||||
|  |             my $edge_type = (grep $_->[Z] > $z, @$vertices) ? 'bottom' : 'top'; | ||||||
|  |             ($a, $b) = ($b, $a) if $edge_type eq 'bottom'; | ||||||
|             push @lines, Slic3r::Line::FacetEdge->cast( |             push @lines, Slic3r::Line::FacetEdge->cast( | ||||||
|                 [ [$a->[X], $a->[Y]], [$b->[X], $b->[Y]] ], |                 [ [$a->[X], $a->[Y]], [$b->[X], $b->[Y]] ], | ||||||
|                 edge_type => (grep $_->[Z] > $z, @$vertices) ? 'bottom' : 'top', |                 edge_type => $edge_type, | ||||||
|             ); |             ); | ||||||
|             #print "Horizontal!\n"; |             #print "Horizontal edge!\n"; | ||||||
|              |              | ||||||
|         } elsif (($a->[Z] < $z && $b->[Z] > $z) || ($b->[Z] < $z && $a->[Z] > $z)) { |         } elsif (($a->[Z] < $z && $b->[Z] > $z) || ($b->[Z] < $z && $a->[Z] > $z)) { | ||||||
|             # edge intersects the current layer; calculate intersection |             # edge intersects the current layer; calculate intersection | ||||||
|  |  | ||||||
|  | @ -14,7 +14,24 @@ sub factor { | ||||||
| sub svg { | sub svg { | ||||||
|     my ($print) = @_; |     my ($print) = @_; | ||||||
|     $print ||= Slic3r::Print->new(x_length => 200 / $Slic3r::resolution, y_length => 200 / $Slic3r::resolution); |     $print ||= Slic3r::Print->new(x_length => 200 / $Slic3r::resolution, y_length => 200 / $Slic3r::resolution); | ||||||
|     return SVG->new(width => $print->max_length * factor(), height => $print->max_length * factor()); |     my $svg = SVG->new(width => $print->max_length * factor(), height => $print->max_length * factor()); | ||||||
|  |      | ||||||
|  |     my $marker_end = $svg->marker( | ||||||
|  |         id => "endArrow", | ||||||
|  |         viewBox => "0 0 10 10", | ||||||
|  |         refX => "1", | ||||||
|  |         refY => "5", | ||||||
|  |         markerUnits => "strokeWidth", | ||||||
|  |         orient => "auto", | ||||||
|  |         markerWidth => "10", | ||||||
|  |         markerHeight => "8", | ||||||
|  |     ); | ||||||
|  |     $marker_end->polyline( | ||||||
|  |         points => "0,0 10,5 0,10 1,5", | ||||||
|  |         fill => "darkblue", | ||||||
|  |     ); | ||||||
|  |      | ||||||
|  |     return $svg; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub output { | sub output { | ||||||
|  | @ -40,6 +57,7 @@ sub output { | ||||||
|                 ); |                 ); | ||||||
|                 $g->$method( |                 $g->$method( | ||||||
|                     %$path, |                     %$path, | ||||||
|  |                     'marker-end' => "url(#endArrow)", | ||||||
|                 ); |                 ); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -65,9 +83,9 @@ sub output { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     foreach my $type (qw(lines red_lines)) { |     foreach my $type (qw(lines red_lines green_lines)) { | ||||||
|         if ($things{$type}) { |         if ($things{$type}) { | ||||||
|             my ($colour) = $type eq 'lines' ? ('black') : ('red'); |             my ($colour) = $type =~ /^(red|green)_/; | ||||||
|             my $g = $svg->group( |             my $g = $svg->group( | ||||||
|                 style => { |                 style => { | ||||||
|                     'stroke-width' => 2, |                     'stroke-width' => 2, | ||||||
|  | @ -80,8 +98,9 @@ sub output { | ||||||
|                     x2 => $line->[1][X] * factor(), |                     x2 => $line->[1][X] * factor(), | ||||||
|                     y2 => $line->[1][Y] * factor(), |                     y2 => $line->[1][Y] * factor(), | ||||||
|                     style => { |                     style => { | ||||||
|                         'stroke' => $colour, |                         'stroke' => $colour || 'black', | ||||||
|                     }, |                     }, | ||||||
|  |                     'marker-end' => "url(#endArrow)", | ||||||
|                 ); |                 ); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
							
								
								
									
										47
									
								
								t/geometry.t
									
										
									
									
									
								
							
							
						
						
									
										47
									
								
								t/geometry.t
									
										
									
									
									
								
							|  | @ -2,7 +2,7 @@ use Test::More; | ||||||
| use strict; | use strict; | ||||||
| use warnings; | use warnings; | ||||||
| 
 | 
 | ||||||
| plan tests => 6; | plan tests => 15; | ||||||
| 
 | 
 | ||||||
| BEGIN { | BEGIN { | ||||||
|     use FindBin; |     use FindBin; | ||||||
|  | @ -10,6 +10,7 @@ BEGIN { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| use Slic3r; | use Slic3r; | ||||||
|  | use Slic3r::Geometry qw(PI); | ||||||
| 
 | 
 | ||||||
| #========================================================== | #========================================================== | ||||||
| 
 | 
 | ||||||
|  | @ -43,15 +44,19 @@ is_deeply Slic3r::Geometry::polygon_segment_having_point($polyline, $point), | ||||||
| 
 | 
 | ||||||
| #========================================================== | #========================================================== | ||||||
| 
 | 
 | ||||||
| $point = [ 736310778.185108, 5017423926.8924 ]; | { | ||||||
| my $line = [ [627484000, 3695776000], [750000000, 3720147000] ]; |     my $point = [ 736310778.185108, 5017423926.8924 ]; | ||||||
| is Slic3r::Geometry::point_in_segment($point, $line), 0, 'point_in_segment'; |     my $line = [ [627484000, 3695776000], [750000000, 3720147000] ]; | ||||||
|  |     is Slic3r::Geometry::point_in_segment($point, $line), 0, 'point_in_segment'; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| #========================================================== | #========================================================== | ||||||
| 
 | 
 | ||||||
| $point = [ 736310778.185108, 5017423926.8924 ]; | { | ||||||
| my $line = [ [627484000, 3695776000], [750000000, 3720147000] ]; |     my $point = [ 736310778.185108, 5017423926.8924 ]; | ||||||
| is Slic3r::Geometry::point_in_segment($point, $line), 0, 'point_in_segment'; |     my $line = [ [627484000, 3695776000], [750000000, 3720147000] ]; | ||||||
|  |     is Slic3r::Geometry::point_in_segment($point, $line), 0, 'point_in_segment'; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| #========================================================== | #========================================================== | ||||||
| 
 | 
 | ||||||
|  | @ -81,3 +86,31 @@ my $points = [ | ||||||
| is Slic3r::Geometry::can_connect_points(@$points, $polygons), 0, 'can_connect_points'; | is Slic3r::Geometry::can_connect_points(@$points, $polygons), 0, 'can_connect_points'; | ||||||
| 
 | 
 | ||||||
| #========================================================== | #========================================================== | ||||||
|  | 
 | ||||||
|  | { | ||||||
|  |     my $p1 = [10, 10]; | ||||||
|  |     my $p2 = [10, 20]; | ||||||
|  |     my $p3 = [10, 30]; | ||||||
|  |     my $p4 = [20, 20]; | ||||||
|  |     my $p5 = [0,  20]; | ||||||
|  |      | ||||||
|  |     is Slic3r::Geometry::angle3points($p2, $p3, $p1),  PI(),   'angle3points'; | ||||||
|  |     is Slic3r::Geometry::angle3points($p2, $p1, $p3),  PI(),   'angle3points'; | ||||||
|  |     is Slic3r::Geometry::angle3points($p2, $p3, $p4),  PI()/2*3, 'angle3points'; | ||||||
|  |     is Slic3r::Geometry::angle3points($p2, $p4, $p3),  PI()/2, 'angle3points'; | ||||||
|  |     is Slic3r::Geometry::angle3points($p2, $p1, $p4),  PI()/2, 'angle3points'; | ||||||
|  |     is Slic3r::Geometry::angle3points($p2, $p1, $p5),  PI()/2*3, 'angle3points'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | { | ||||||
|  |     my $p1 = [30, 30]; | ||||||
|  |     my $p2 = [20, 20]; | ||||||
|  |     my $p3 = [10, 10]; | ||||||
|  |     my $p4 = [30, 10]; | ||||||
|  |      | ||||||
|  |     is Slic3r::Geometry::angle3points($p2, $p1, $p3), PI(),       'angle3points'; | ||||||
|  |     is Slic3r::Geometry::angle3points($p2, $p1, $p4), PI()/2*3,   'angle3points'; | ||||||
|  |     is Slic3r::Geometry::angle3points($p2, $p1, $p1), 2*PI(),     'angle3points'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #========================================================== | ||||||
|  |  | ||||||
							
								
								
									
										6
									
								
								t/stl.t
									
										
									
									
									
								
							
							
						
						
									
										6
									
								
								t/stl.t
									
										
									
									
									
								
							|  | @ -21,12 +21,12 @@ is_deeply lines(20, 20, 20), [ | ||||||
|     [ $points[2], $points[0] ], |     [ $points[2], $points[0] ], | ||||||
| ], 'horizontal'; | ], 'horizontal'; | ||||||
| 
 | 
 | ||||||
| is_deeply lines(22, 20, 20), [ [ $points[1], $points[2] ] ], 'lower edge on layer'; | is_deeply lines(22, 20, 20), [ [ $points[2], $points[1] ] ], 'lower edge on layer'; | ||||||
| is_deeply lines(20, 20, 10), [ [ $points[0], $points[1] ] ], 'upper edge on layer'; | is_deeply lines(20, 20, 10), [ [ $points[0], $points[1] ] ], 'upper edge on layer'; | ||||||
| is_deeply lines(20, 15, 10), [                            ], 'upper vertex on layer'; | is_deeply lines(20, 15, 10), [                            ], 'upper vertex on layer'; | ||||||
| is_deeply lines(28, 20, 30), [                            ], 'lower vertex on layer'; | is_deeply lines(28, 20, 30), [                            ], 'lower vertex on layer'; | ||||||
| is_deeply lines(24, 10, 16), [ [ [4, 4],     [2, 6]     ] ], 'two edges intersect'; | is_deeply lines(24, 10, 16), [ [ [2, 6],     [4, 4]     ] ], 'two edges intersect'; | ||||||
| is_deeply lines(24, 10, 20), [ [ [4, 4],     [1, 9]     ] ], 'one vertex on plane and one edge intersects'; | is_deeply lines(24, 10, 20), [ [ [1, 9],     [4, 4]     ] ], 'one vertex on plane and one edge intersects'; | ||||||
| 
 | 
 | ||||||
| my @lower = $stl->intersect_facet(vertices(22, 20, 20), $z, $dz); | my @lower = $stl->intersect_facet(vertices(22, 20, 20), $z, $dz); | ||||||
| my @upper = $stl->intersect_facet(vertices(20, 20, 10), $z, $dz); | my @upper = $stl->intersect_facet(vertices(20, 20, 10), $z, $dz); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci