Bugfix: arcs now work (some glitches in detecting their center, though). #30
This commit is contained in:
parent
8172bcb772
commit
d620b46beb
@ -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;
|
||||||
|
45
t/arcs.t
45
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([
|
{
|
||||||
|
my $path = Slic3r::ExtrusionPath->cast([
|
||||||
[135322.42,26654.96], [187029.11,99546.23], [222515.14,92381.93], [258001.16,99546.23],
|
[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],
|
[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],
|
[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],
|
[187029.11,267550.17], [158050.85,248012.49], [138513.17,219034.23], [131348.87,183548.2],
|
||||||
[86948.77,175149.09], [119825.35,100585],
|
[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…
Reference in New Issue
Block a user