mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 12:41:20 -06:00 
			
		
		
		
	Bugfix: arcs now work (some glitches in detecting their center, though). #30
This commit is contained in:
		
							parent
							
								
									8172bcb772
								
							
						
					
					
						commit
						d620b46beb
					
				
					 4 changed files with 85 additions and 44 deletions
				
			
		|  | @ -70,6 +70,9 @@ sub extrude { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|     my ($path, $description, $recursive) = @_; |     my ($path, $description, $recursive) = @_; | ||||||
|      |      | ||||||
|  |     $path->merge_continuous_lines; | ||||||
|  |      | ||||||
|  |     # detect arcs | ||||||
|     if ($Slic3r::gcode_arcs && !$recursive) { |     if ($Slic3r::gcode_arcs && !$recursive) { | ||||||
|         my $gcode = ""; |         my $gcode = ""; | ||||||
|         $gcode .= $self->extrude($_, $description, 1) for $path->detect_arcs; |         $gcode .= $self->extrude($_, $description, 1) for $path->detect_arcs; | ||||||
|  | @ -173,8 +176,8 @@ sub G2_G3 { | ||||||
|      |      | ||||||
|     # XY distance of the center from the start position |     # XY distance of the center from the start position | ||||||
|     $gcode .= sprintf " I%.${dec}f J%.${dec}f", |     $gcode .= sprintf " I%.${dec}f J%.${dec}f", | ||||||
|         ($point->[X] - $self->last_pos->[X]) * $Slic3r::resolution + $self->shift_x, |         ($center->[X] - $self->last_pos->[X]) * $Slic3r::resolution, | ||||||
|         ($point->[Y] - $self->last_pos->[Y]) * $Slic3r::resolution + $self->shift_y; |         ($center->[Y] - $self->last_pos->[Y]) * $Slic3r::resolution; | ||||||
|      |      | ||||||
|     $self->last_pos($point); |     $self->last_pos($point); | ||||||
|     return $self->_Gx($gcode, $e, $comment); |     return $self->_Gx($gcode, $e, $comment); | ||||||
|  |  | ||||||
|  | @ -76,9 +76,10 @@ sub split_at_acute_angles { | ||||||
| 
 | 
 | ||||||
| sub detect_arcs { | sub detect_arcs { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|  |     my ($max_angle, $len_epsilon) = @_; | ||||||
|      |      | ||||||
|     my $max_angle = deg2rad(40); |     $max_angle = deg2rad($max_angle || 15); | ||||||
|     my $len_epsilon = 1000000; |     $len_epsilon ||= 10 / $Slic3r::resolution; | ||||||
|      |      | ||||||
|     my @points = @{$self->points}; |     my @points = @{$self->points}; | ||||||
|     my @paths = (); |     my @paths = (); | ||||||
|  | @ -111,34 +112,13 @@ sub detect_arcs { | ||||||
|             my $s1s2_angle = $s2_angle - $s1_angle; |             my $s1s2_angle = $s2_angle - $s1_angle; | ||||||
|             my $s2s3_angle = $s3_angle - $s2_angle; |             my $s2s3_angle = $s3_angle - $s2_angle; | ||||||
|             next if abs($s1s2_angle - $s2s3_angle) > $Slic3r::Geometry::parallel_degrees_limit; |             next if abs($s1s2_angle - $s2s3_angle) > $Slic3r::Geometry::parallel_degrees_limit; | ||||||
|             next if $s1s2_angle < $Slic3r::Geometry::parallel_degrees_limit;     # ignore parallel lines |             next if abs($s1s2_angle) < $Slic3r::Geometry::parallel_degrees_limit;     # ignore parallel lines | ||||||
|             next if $s1s2_angle > $max_angle;  # ignore too sharp vertices |             next if $s1s2_angle > $max_angle;  # ignore too sharp vertices | ||||||
|              |             my @arc_points = ($points[$i], $points[$i+3]),  # first and last points | ||||||
|             # s1, s2, s3 form an arc |  | ||||||
|             my $orientation = $s1->point_on_left($points[$i+2]) ? 'ccw' : 'cw'; |  | ||||||
|              |  | ||||||
|             # to find the center, we intersect the perpendicular lines |  | ||||||
|             # passing by midpoints of $s1 and $s3 |  | ||||||
|             my $arc_center; |  | ||||||
|             { |  | ||||||
|                 my $s1_mid = $s1->midpoint; |  | ||||||
|                 my $s3_mid = $s2->midpoint; |  | ||||||
|                 my $rotation_angle = PI/2 * ($orientation eq 'ccw' ? -1 : 1); |  | ||||||
|                 my $ray1 = Slic3r::Line->new($s1_mid, rotate_points($rotation_angle, $s1_mid, $points[$i+1])); |  | ||||||
|                 my $ray3 = Slic3r::Line->new($s3_mid, rotate_points($rotation_angle, $s3_mid, $points[$i+3])); |  | ||||||
|                 $arc_center = $ray1->intersection($ray3, 0); |  | ||||||
|             } |  | ||||||
|              |  | ||||||
|             my $arc = Slic3r::ExtrusionPath::Arc->new( |  | ||||||
|                 points      => [$points[$i], $points[$i+3]],  # first and last points |  | ||||||
|                 orientation => $orientation, |  | ||||||
|                 center      => $arc_center, |  | ||||||
|                 radius      => $arc_center->distance_to($points[$i]), |  | ||||||
|             ); |  | ||||||
|              |              | ||||||
|             # now look for more points |             # now look for more points | ||||||
|             my $last_line_angle = $s3_angle; |             my $last_line_angle = $s3_angle; | ||||||
|             my $last_j = $points[$i+3]; |             my $last_j = $i+3; | ||||||
|             for (my $j = $i+3; $j < $#points; $j++) { |             for (my $j = $i+3; $j < $#points; $j++) { | ||||||
|                 my $line = Slic3r::Line->new($points[$j], $points[$j+1]); |                 my $line = Slic3r::Line->new($points[$j], $points[$j+1]); | ||||||
|                 last if abs($line->length - $s1_len) > $len_epsilon; |                 last if abs($line->length - $s1_len) > $len_epsilon; | ||||||
|  | @ -148,12 +128,38 @@ sub detect_arcs { | ||||||
|                 last if abs($s1s2_angle - $anglediff) > $Slic3r::Geometry::parallel_degrees_limit; |                 last if abs($s1s2_angle - $anglediff) > $Slic3r::Geometry::parallel_degrees_limit; | ||||||
|                  |                  | ||||||
|                 # point $j+1 belongs to the arc |                 # point $j+1 belongs to the arc | ||||||
|                 $arc->points->[-1] = $points[$j+1]; |                 $arc_points[-1] = $points[$j+1]; | ||||||
|                 $last_j = $j+1; |                 $last_j = $j+1; | ||||||
|                  |                  | ||||||
|                 $last_line_angle = $line_angle; |                 $last_line_angle = $line_angle; | ||||||
|             } |             } | ||||||
|              |              | ||||||
|  |             # s1, s2, s3 form an arc | ||||||
|  |             my $orientation = $s1->point_on_left($points[$i+2]) ? 'ccw' : 'cw'; | ||||||
|  |              | ||||||
|  |             # to find the center, we intersect the perpendicular lines | ||||||
|  |             # passing by midpoints of $s1 and last segment | ||||||
|  |             # a better method would be to draw all the perpendicular lines | ||||||
|  |             # and find the centroid of the enclosed polygon, or to | ||||||
|  |             # intersect multiple lines and find the centroid of the convex hull | ||||||
|  |             # around the intersections | ||||||
|  |             my $arc_center; | ||||||
|  |             { | ||||||
|  |                 my $s1_mid = $s1->midpoint; | ||||||
|  |                 my $last_mid = Slic3r::Line->new($points[$last_j-1], $points[$last_j])->midpoint; | ||||||
|  |                 my $rotation_angle = PI/2 * ($orientation eq 'ccw' ? -1 : 1); | ||||||
|  |                 my $ray1     = Slic3r::Line->new($s1_mid,   rotate_points($rotation_angle, $s1_mid,   $points[$i+1])); | ||||||
|  |                 my $last_ray = Slic3r::Line->new($last_mid, rotate_points($rotation_angle, $last_mid, $points[$last_j])); | ||||||
|  |                 $arc_center = $ray1->intersection($last_ray, 0); | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             my $arc = Slic3r::ExtrusionPath::Arc->new( | ||||||
|  |                 points      => [@arc_points], | ||||||
|  |                 orientation => $orientation, | ||||||
|  |                 center      => $arc_center, | ||||||
|  |                 radius      => $arc_center->distance_to($points[$i]), | ||||||
|  |             ); | ||||||
|  |              | ||||||
|             # points 0..$i form a linear path |             # points 0..$i form a linear path | ||||||
|             push @paths, (ref $self)->new( |             push @paths, (ref $self)->new( | ||||||
|                 points       => [ @points[0..$i] ], |                 points       => [ @points[0..$i] ], | ||||||
|  | @ -162,7 +168,8 @@ sub detect_arcs { | ||||||
|              |              | ||||||
|             # add our arc |             # add our arc | ||||||
|             push @paths, $arc; |             push @paths, $arc; | ||||||
|             print "ARC DETECTED\n"; |             Slic3r::debugf "ARC DETECTED\n"; | ||||||
|  |              | ||||||
|             # remove arc points from path, leaving one |             # remove arc points from path, leaving one | ||||||
|             splice @points, 0, $last_j, (); |             splice @points, 0, $last_j, (); | ||||||
|              |              | ||||||
|  | @ -175,7 +182,7 @@ sub detect_arcs { | ||||||
|     push @paths, (ref $self)->new( |     push @paths, (ref $self)->new( | ||||||
|         points => [@points], |         points => [@points], | ||||||
|         depth_layers => $self->depth_layers |         depth_layers => $self->depth_layers | ||||||
|     ) if @points; |     ) if @points > 1; | ||||||
|      |      | ||||||
|     return @paths; |     return @paths; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -57,7 +57,7 @@ sub cleanup { | ||||||
| 
 | 
 | ||||||
| sub detect_arcs { | sub detect_arcs { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|     @{$self->paths} = map $_->detect_arcs, @{$self->paths}; |     @{$self->paths} = map $_->detect_arcs(@_), @{$self->paths}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 1; | 1; | ||||||
|  |  | ||||||
							
								
								
									
										55
									
								
								t/arcs.t
									
										
									
									
									
								
							
							
						
						
									
										55
									
								
								t/arcs.t
									
										
									
									
									
								
							|  | @ -2,7 +2,7 @@ use Test::More; | ||||||
| use strict; | use strict; | ||||||
| use warnings; | use warnings; | ||||||
| 
 | 
 | ||||||
| plan tests => 2; | plan tests => 6; | ||||||
| 
 | 
 | ||||||
| BEGIN { | BEGIN { | ||||||
|     use FindBin; |     use FindBin; | ||||||
|  | @ -11,15 +11,46 @@ BEGIN { | ||||||
| 
 | 
 | ||||||
| use Slic3r; | use Slic3r; | ||||||
| 
 | 
 | ||||||
| my $path = Slic3r::ExtrusionPath->cast([ | { | ||||||
|     [135322.42,26654.96], [187029.11,99546.23], [222515.14,92381.93], [258001.16,99546.23],  |     my $path = Slic3r::ExtrusionPath->cast([ | ||||||
|     [286979.42,119083.91], [306517.1,148062.17], [313681.4,183548.2], |         [135322.42,26654.96], [187029.11,99546.23], [222515.14,92381.93], [258001.16,99546.23],  | ||||||
|     [306517.1,219034.23], [286979.42,248012.49], [258001.16,267550.17], [222515.14,274714.47],  |         [286979.42,119083.91], [306517.1,148062.17], [313681.4,183548.2], | ||||||
|     [187029.11,267550.17], [158050.85,248012.49], [138513.17,219034.23], [131348.87,183548.2],  |         [306517.1,219034.23], [286979.42,248012.49], [258001.16,267550.17], [222515.14,274714.47],  | ||||||
|     [86948.77,175149.09], [119825.35,100585], |         [187029.11,267550.17], [158050.85,248012.49], [138513.17,219034.23], [131348.87,183548.2],  | ||||||
| ]); |         [86948.77,175149.09], [119825.35,100585], | ||||||
| my $collection = Slic3r::ExtrusionPath::Collection->new(paths => [$path]); |     ]); | ||||||
| $collection->detect_arcs; |  | ||||||
|      |      | ||||||
| is scalar(@{$collection->paths}), 3, 'path collection now contains three paths'; |     use Slic3r::SVG; | ||||||
| isa_ok $collection->paths->[1], 'Slic3r::ExtrusionPath::Arc', 'second one'; |     local $Slic3r::resolution = 0.0001; | ||||||
|  |     Slic3r::SVG::output(undef, "arc.svg", | ||||||
|  |         polylines => [ $path->points ], | ||||||
|  |     ); | ||||||
|  |      | ||||||
|  |     my $collection = Slic3r::ExtrusionPath::Collection->new(paths => [$path]); | ||||||
|  |     $collection->detect_arcs(30); | ||||||
|  |      | ||||||
|  |     is scalar(@{$collection->paths}), 3, 'path collection now contains three paths'; | ||||||
|  |     isa_ok $collection->paths->[1], 'Slic3r::ExtrusionPath::Arc', 'second one'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #========================================================== | ||||||
|  | 
 | ||||||
|  | { | ||||||
|  |     my $path = Slic3r::ExtrusionPath->cast([ | ||||||
|  |         [10,20], [10.7845909572784,19.9691733373313], [11.5643446504023,19.8768834059514],  | ||||||
|  |         [12.3344536385591,19.7236992039768], [13.0901699437495,19.5105651629515],  | ||||||
|  |         [13.8268343236509,19.2387953251129], [14.5399049973955,18.9100652418837],  | ||||||
|  |         [15.2249856471595,18.5264016435409], [15.8778525229247,18.0901699437495],  | ||||||
|  |         [16.4944804833018,17.6040596560003], | ||||||
|  |     ]); | ||||||
|  |     my $collection = Slic3r::ExtrusionPath::Collection->new(paths => [$path]); | ||||||
|  |     $collection->detect_arcs(10, 1); | ||||||
|  |      | ||||||
|  |     is scalar(@{$collection->paths}), 1, 'path collection now contains one path'; | ||||||
|  |     isa_ok $collection->paths->[0], 'Slic3r::ExtrusionPath::Arc', 'path'; | ||||||
|  |     is $collection->paths->[0]->orientation, 'cw', 'orientation was correctly detected'; | ||||||
|  |     my $center = [ map sprintf('%.0f', $_), @{ $collection->paths->[0]->center } ]; | ||||||
|  |     is_deeply $center, [10,10], 'center was correctly detected'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #========================================================== | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci