mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-15 10:47:50 -06:00
Move arc fitting code to its own post-processing filter and remove the built-in ExtrusionPath::Arc class
This commit is contained in:
parent
055273fbc8
commit
5f17fa342b
9 changed files with 149 additions and 196 deletions
|
@ -126,116 +126,4 @@ sub split_at_acute_angles {
|
|||
return @paths;
|
||||
}
|
||||
|
||||
sub detect_arcs {
|
||||
my $self = shift;
|
||||
my ($max_angle, $len_epsilon) = @_;
|
||||
|
||||
$max_angle = deg2rad($max_angle || 15);
|
||||
$len_epsilon ||= 10 / &Slic3r::SCALING_FACTOR;
|
||||
my $parallel_degrees_limit = abs(Slic3r::Geometry::deg2rad(3));
|
||||
|
||||
my @points = @{$self->points};
|
||||
my @paths = ();
|
||||
|
||||
# we require at least 3 consecutive segments to form an arc
|
||||
CYCLE: while (@points >= 4) {
|
||||
POINT: for (my $i = 0; $i <= $#points - 3; $i++) {
|
||||
my $s1 = Slic3r::Line->new($points[$i], $points[$i+1]);
|
||||
my $s2 = Slic3r::Line->new($points[$i+1], $points[$i+2]);
|
||||
my $s3 = Slic3r::Line->new($points[$i+2], $points[$i+3]);
|
||||
my $s1_len = $s1->length;
|
||||
my $s2_len = $s2->length;
|
||||
my $s3_len = $s3->length;
|
||||
|
||||
# segments must have the same length
|
||||
if (abs($s3_len - $s2_len) > $len_epsilon) {
|
||||
# optimization: skip a cycle
|
||||
$i++;
|
||||
next;
|
||||
}
|
||||
next if abs($s2_len - $s1_len) > $len_epsilon;
|
||||
|
||||
# segments must have the same relative angle
|
||||
my $s1_angle = $s1->atan;
|
||||
my $s2_angle = $s2->atan;
|
||||
my $s3_angle = $s3->atan;
|
||||
$s1_angle += 2*PI if $s1_angle < 0;
|
||||
$s2_angle += 2*PI if $s2_angle < 0;
|
||||
$s3_angle += 2*PI if $s3_angle < 0;
|
||||
my $s1s2_angle = $s2_angle - $s1_angle;
|
||||
my $s2s3_angle = $s3_angle - $s2_angle;
|
||||
next if abs($s1s2_angle - $s2s3_angle) > $parallel_degrees_limit;
|
||||
next if abs($s1s2_angle) < $parallel_degrees_limit; # ignore parallel lines
|
||||
next if $s1s2_angle > $max_angle; # ignore too sharp vertices
|
||||
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 = $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;
|
||||
my $line_angle = $line->atan;
|
||||
$line_angle += 2*PI if $line_angle < 0;
|
||||
my $anglediff = $line_angle - $last_line_angle;
|
||||
last if abs($s1s2_angle - $anglediff) > $parallel_degrees_limit;
|
||||
|
||||
# point $j+1 belongs to the arc
|
||||
$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) // next POINT;
|
||||
}
|
||||
|
||||
my $arc = Slic3r::ExtrusionPath::Arc->new(
|
||||
polyline => Slic3r::Polyline->new(@arc_points),
|
||||
role => $self->role,
|
||||
flow_spacing => $self->flow_spacing,
|
||||
orientation => $orientation,
|
||||
center => $arc_center,
|
||||
radius => $arc_center->distance_to($points[$i]),
|
||||
);
|
||||
|
||||
# points 0..$i form a linear path
|
||||
push @paths, $self->clone(polyline => Slic3r::Polyline->new(@points[0..$i]))
|
||||
if $i > 0;
|
||||
|
||||
# add our arc
|
||||
push @paths, $arc;
|
||||
Slic3r::debugf "ARC DETECTED\n";
|
||||
|
||||
# remove arc points from path, leaving one
|
||||
splice @points, 0, $last_j, ();
|
||||
|
||||
next CYCLE;
|
||||
}
|
||||
last;
|
||||
}
|
||||
|
||||
# remaining points form a linear path
|
||||
push @paths, $self->clone(polyline => Slic3r::Polyline->new(@points))
|
||||
if @points > 1;
|
||||
|
||||
return @paths;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue