mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -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 ($path, $description, $recursive) = @_; | ||||
|      | ||||
|     $path->merge_continuous_lines; | ||||
|      | ||||
|     # detect arcs | ||||
|     if ($Slic3r::gcode_arcs && !$recursive) { | ||||
|         my $gcode = ""; | ||||
|         $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 | ||||
|     $gcode .= sprintf " I%.${dec}f J%.${dec}f", | ||||
|         ($point->[X] - $self->last_pos->[X]) * $Slic3r::resolution + $self->shift_x, | ||||
|         ($point->[Y] - $self->last_pos->[Y]) * $Slic3r::resolution + $self->shift_y; | ||||
|         ($center->[X] - $self->last_pos->[X]) * $Slic3r::resolution, | ||||
|         ($center->[Y] - $self->last_pos->[Y]) * $Slic3r::resolution; | ||||
|      | ||||
|     $self->last_pos($point); | ||||
|     return $self->_Gx($gcode, $e, $comment); | ||||
|  |  | |||
|  | @ -76,9 +76,10 @@ sub split_at_acute_angles { | |||
| 
 | ||||
| sub detect_arcs { | ||||
|     my $self = shift; | ||||
|     my ($max_angle, $len_epsilon) = @_; | ||||
|      | ||||
|     my $max_angle = deg2rad(40); | ||||
|     my $len_epsilon = 1000000; | ||||
|     $max_angle = deg2rad($max_angle || 15); | ||||
|     $len_epsilon ||= 10 / $Slic3r::resolution; | ||||
|      | ||||
|     my @points = @{$self->points}; | ||||
|     my @paths = (); | ||||
|  | @ -111,34 +112,13 @@ sub detect_arcs { | |||
|             my $s1s2_angle = $s2_angle - $s1_angle; | ||||
|             my $s2s3_angle = $s3_angle - $s2_angle; | ||||
|             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 | ||||
|              | ||||
|             # 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]), | ||||
|             ); | ||||
|             my @arc_points = ($points[$i], $points[$i+3]),  # first and last points | ||||
|              | ||||
|             # now look for more points | ||||
|             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++) { | ||||
|                 my $line = Slic3r::Line->new($points[$j], $points[$j+1]); | ||||
|                 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; | ||||
|                  | ||||
|                 # point $j+1 belongs to the arc | ||||
|                 $arc->points->[-1] = $points[$j+1]; | ||||
|                 $arc_points[-1] = $points[$j+1]; | ||||
|                 $last_j = $j+1; | ||||
|                  | ||||
|                 $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 | ||||
|             push @paths, (ref $self)->new( | ||||
|                 points       => [ @points[0..$i] ], | ||||
|  | @ -162,7 +168,8 @@ sub detect_arcs { | |||
|              | ||||
|             # add our arc | ||||
|             push @paths, $arc; | ||||
|             print "ARC DETECTED\n"; | ||||
|             Slic3r::debugf "ARC DETECTED\n"; | ||||
|              | ||||
|             # remove arc points from path, leaving one | ||||
|             splice @points, 0, $last_j, (); | ||||
|              | ||||
|  | @ -175,7 +182,7 @@ sub detect_arcs { | |||
|     push @paths, (ref $self)->new( | ||||
|         points => [@points], | ||||
|         depth_layers => $self->depth_layers | ||||
|     ) if @points; | ||||
|     ) if @points > 1; | ||||
|      | ||||
|     return @paths; | ||||
| } | ||||
|  |  | |||
|  | @ -57,7 +57,7 @@ sub cleanup { | |||
| 
 | ||||
| sub detect_arcs { | ||||
|     my $self = shift; | ||||
|     @{$self->paths} = map $_->detect_arcs, @{$self->paths}; | ||||
|     @{$self->paths} = map $_->detect_arcs(@_), @{$self->paths}; | ||||
| } | ||||
| 
 | ||||
| 1; | ||||
|  |  | |||
							
								
								
									
										45
									
								
								t/arcs.t
									
										
									
									
									
								
							
							
						
						
									
										45
									
								
								t/arcs.t
									
										
									
									
									
								
							|  | @ -2,7 +2,7 @@ use Test::More; | |||
| use strict; | ||||
| use warnings; | ||||
| 
 | ||||
| plan tests => 2; | ||||
| plan tests => 6; | ||||
| 
 | ||||
| BEGIN { | ||||
|     use FindBin; | ||||
|  | @ -11,15 +11,46 @@ BEGIN { | |||
| 
 | ||||
| use Slic3r; | ||||
| 
 | ||||
| my $path = Slic3r::ExtrusionPath->cast([ | ||||
| { | ||||
|     my $path = Slic3r::ExtrusionPath->cast([ | ||||
|         [135322.42,26654.96], [187029.11,99546.23], [222515.14,92381.93], [258001.16,99546.23],  | ||||
|         [286979.42,119083.91], [306517.1,148062.17], [313681.4,183548.2], | ||||
|         [306517.1,219034.23], [286979.42,248012.49], [258001.16,267550.17], [222515.14,274714.47],  | ||||
|         [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'; | ||||
| isa_ok $collection->paths->[1], 'Slic3r::ExtrusionPath::Arc', 'second one'; | ||||
|     use Slic3r::SVG; | ||||
|     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