Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAlessandro Ranellucci <aar@cpan.org>2011-10-20 20:11:59 +0400
committerAlessandro Ranellucci <aar@cpan.org>2011-10-28 16:13:44 +0400
commit6d6533831ea63a256389a55afcca522a9db66c4b (patch)
tree144e2ff4c014679801f9fe0d461c28418c44b8a2 /lib
parent7f341cfcd36527d7ace1af6702bbca29f46fb2a3 (diff)
New experimental --gcode-arcs options to generate G2/G3 commands. #23
Diffstat (limited to 'lib')
-rw-r--r--lib/Slic3r.pm4
-rw-r--r--lib/Slic3r/Extruder.pm70
-rw-r--r--lib/Slic3r/ExtrusionPath.pm112
-rw-r--r--lib/Slic3r/ExtrusionPath/Arc.pm23
-rw-r--r--lib/Slic3r/ExtrusionPath/Collection.pm5
-rw-r--r--lib/Slic3r/Geometry.pm4
-rw-r--r--lib/Slic3r/Line.pm30
-rw-r--r--lib/Slic3r/Point.pm2
8 files changed, 230 insertions, 20 deletions
diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm
index 03deb859e..e5b2126a7 100644
--- a/lib/Slic3r.pm
+++ b/lib/Slic3r.pm
@@ -13,6 +13,7 @@ use Slic3r::ExPolygon;
use Slic3r::Extruder;
use Slic3r::ExtrusionLoop;
use Slic3r::ExtrusionPath;
+use Slic3r::ExtrusionPath::Arc;
use Slic3r::ExtrusionPath::Collection;
use Slic3r::Fill;
use Slic3r::Geometry;
@@ -34,7 +35,8 @@ use Slic3r::Surface::Bridge;
our $nozzle_diameter = 0.5;
our $print_center = [100,100]; # object will be centered around this point
our $use_relative_e_distances = 0;
-our $z_offset = 0;
+our $z_offset = 0;
+our $gcode_arcs = 0;
# filament options
our $filament_diameter = 3; # mm
diff --git a/lib/Slic3r/Extruder.pm b/lib/Slic3r/Extruder.pm
index a03880f04..c58eab823 100644
--- a/lib/Slic3r/Extruder.pm
+++ b/lib/Slic3r/Extruder.pm
@@ -30,6 +30,7 @@ has 'retract_speed' => (
default => sub { $Slic3r::retract_speed * 60 }, # mm/min
);
+use Slic3r::Geometry qw(points_coincide);
use XXX;
use constant PI => 4 * atan2(1, 1);
@@ -67,7 +68,13 @@ sub extrude_loop {
sub extrude {
my $self = shift;
- my ($path, $description) = @_;
+ my ($path, $description, $recursive) = @_;
+
+ if ($Slic3r::gcode_arcs && !$recursive) {
+ my $gcode = "";
+ $gcode .= $self->extrude($_, $description, 1) for $path->detect_arcs;
+ return $gcode;
+ }
my $gcode = "";
@@ -80,23 +87,28 @@ sub extrude {
}
# go to first point of extrusion path
- $gcode .= $self->G1($path->points->[0], undef, 0, "move to first $description point");
+ $gcode .= $self->G1($path->points->[0], undef, 0, "move to first $description point")
+ if !points_coincide($self->last_pos, $path->points->[0]);
# compensate retraction
$gcode .= $self->unretract if $self->retracted;
- XXX "yes!\n" if $path->depth_layers > 1;
- # extrude while going to next points
- foreach my $line ($path->lines) {
- # calculate how much filament to drive into the extruder
- # to get the desired amount of extruded plastic
- my $e = $line->a->distance_to($line->b) * $Slic3r::resolution
- * (($Slic3r::nozzle_diameter**2) / ($Slic3r::filament_diameter ** 2))
- * $Slic3r::thickness_ratio
- * $self->flow_ratio
- * $Slic3r::filament_packing_density
- * $path->depth_layers;
-
- $gcode .= $self->G1($line->b, undef, $e, $description);
+
+ # calculate extrusion length per distance unit
+ my $e = $Slic3r::resolution
+ * (($Slic3r::nozzle_diameter**2) / ($Slic3r::filament_diameter ** 2))
+ * $Slic3r::thickness_ratio
+ * $self->flow_ratio
+ * $Slic3r::filament_packing_density
+ * $path->depth_layers;
+
+ # extrude arc or line
+ if ($path->isa('Slic3r::ExtrusionPath::Arc')) {
+ $gcode .= $self->G2_G3($path->points->[-1], $path->orientation,
+ $path->center, $e * $path->length, $description);
+ } else {
+ foreach my $line ($path->lines) {
+ $gcode .= $self->G1($line->b, undef, $e * $line->length, $description);
+ }
}
return $gcode;
@@ -145,6 +157,34 @@ sub G1 {
$gcode .= sprintf " Z%.${dec}f", $z;
}
+ return $self->_Gx($gcode, $e, $comment);
+}
+
+sub G2_G3 {
+ my $self = shift;
+ my ($point, $orientation, $center, $e, $comment) = @_;
+ my $dec = $self->dec;
+
+ my $gcode = $orientation eq 'cw' ? "G2" : "G3";
+
+ $gcode .= sprintf " X%.${dec}f Y%.${dec}f",
+ ($point->x * $Slic3r::resolution) + $self->shift_x,
+ ($point->y * $Slic3r::resolution) + $self->shift_y; #**
+ $self->last_pos($point);
+
+ # 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;
+
+ return $self->_Gx($gcode, $e, $comment);
+}
+
+sub _Gx {
+ my $self = shift;
+ my ($gcode, $e, $comment) = @_;
+ my $dec = $self->dec;
+
# apply the speed reduction for print moves on bottom layer
my $speed_multiplier = $e && $self->z == $Slic3r::z_offset
? $Slic3r::bottom_layer_speed_ratio
diff --git a/lib/Slic3r/ExtrusionPath.pm b/lib/Slic3r/ExtrusionPath.pm
index dfc5a83f2..67c32807d 100644
--- a/lib/Slic3r/ExtrusionPath.pm
+++ b/lib/Slic3r/ExtrusionPath.pm
@@ -7,7 +7,11 @@ extends 'Slic3r::Polyline';
# expressed in layers
has 'depth_layers' => (is => 'ro', default => sub {1});
-use constant PI => 4 * atan2(1, 1);
+use constant X => 0;
+use constant Y => 1;
+
+use Slic3r::Geometry qw(PI epsilon deg2rad rotate_points);
+use XXX;
sub clip_end {
my $self = shift;
@@ -70,4 +74,110 @@ sub split_at_acute_angles {
return @paths;
}
+sub detect_arcs {
+ my $self = shift;
+
+ my $max_angle = deg2rad(40);
+ my $len_epsilon = 1000000;
+
+ my @points = @{$self->points};
+ my @paths = ();
+
+ # we require at least 3 consecutive segments to form an arc
+ CYCLE: while (@points >= 4) {
+ 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) > $Slic3r::Geometry::parallel_degrees_limit;
+ next if $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]),
+ );
+
+ # now look for more points
+ my $last_line_angle = $s3_angle;
+ my $last_j = $points[$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) > $Slic3r::Geometry::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;
+ }
+
+ # points 0..$i form a linear path
+ push @paths, (ref $self)->new(
+ points => [ @points[0..$i] ],
+ depth_layers => $self->depth_layers,
+ ) if $i > 0;
+
+ # add our arc
+ push @paths, $arc;
+ print "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, (ref $self)->new(
+ points => [@points],
+ depth_layers => $self->depth_layers
+ ) if @points;
+
+ return @paths;
+}
+
1;
diff --git a/lib/Slic3r/ExtrusionPath/Arc.pm b/lib/Slic3r/ExtrusionPath/Arc.pm
new file mode 100644
index 000000000..59c65c75c
--- /dev/null
+++ b/lib/Slic3r/ExtrusionPath/Arc.pm
@@ -0,0 +1,23 @@
+package Slic3r::ExtrusionPath::Arc;
+use Moo;
+
+extends 'Slic3r::ExtrusionPath';
+
+has 'center' => (is => 'ro', required => 1);
+has 'radius' => (is => 'ro', required => 1);
+has 'orientation' => (is => 'ro', required => 1); # cw/ccw
+
+use Slic3r::Geometry qw(PI angle3points);
+
+sub angle {
+ my $self = shift;
+ return angle3points($self->center, @{$self->points});
+}
+
+sub length {
+ my $self = shift;
+
+ return $self->radius * $self->angle;
+}
+
+1;
diff --git a/lib/Slic3r/ExtrusionPath/Collection.pm b/lib/Slic3r/ExtrusionPath/Collection.pm
index 1601bcdbc..4a4358617 100644
--- a/lib/Slic3r/ExtrusionPath/Collection.pm
+++ b/lib/Slic3r/ExtrusionPath/Collection.pm
@@ -55,4 +55,9 @@ sub cleanup {
@{$self->paths} = map $_->split_at_acute_angles, @{$self->paths};
}
+sub detect_arcs {
+ my $self = shift;
+ @{$self->paths} = map $_->detect_arcs, @{$self->paths};
+}
+
1;
diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm
index ac33a2197..fa7180c72 100644
--- a/lib/Slic3r/Geometry.pm
+++ b/lib/Slic3r/Geometry.pm
@@ -429,7 +429,7 @@ sub _line_intersection {
# Take this test away and the line segments are
# turned into lines going from infinite to another.
# bounding_box_intersect() defined later in this chapter.
- return "out of bounding box" unless bounding_box_intersect( 2, @box_a, @box_b );
+ ###return "out of bounding box" unless bounding_box_intersect( 2, @box_a, @box_b );
}
elsif ( @_ == 4 ) { # The parametric form.
$x0 = $x2 = 0;
@@ -509,7 +509,7 @@ sub _line_intersection {
my $h10 = $dx10 ? ($x - $x0) / $dx10 : ($dy10 ? ($y - $y0) / $dy10 : 1);
my $h32 = $dx32 ? ($x - $x2) / $dx32 : ($dy32 ? ($y - $y2) / $dy32 : 1);
- return [[$x, $y], $h10 >= 0 && $h10 <= 1 && $h32 >= 0 && $h32 <= 1];
+ return [Slic3r::Point->new($x, $y), $h10 >= 0 && $h10 <= 1 && $h32 >= 0 && $h32 <= 1];
}
# 2D
diff --git a/lib/Slic3r/Line.pm b/lib/Slic3r/Line.pm
index 9f0dc21d0..3f218f80c 100644
--- a/lib/Slic3r/Line.pm
+++ b/lib/Slic3r/Line.pm
@@ -2,6 +2,11 @@ package Slic3r::Line;
use strict;
use warnings;
+use constant A => 0;
+use constant B => 1;
+use constant X => 0;
+use constant Y => 1;
+
sub new {
my $class = shift;
my $self;
@@ -70,4 +75,29 @@ sub length {
return Slic3r::Geometry::line_length($self);
}
+sub atan {
+ my $self = shift;
+ return Slic3r::Geometry::line_atan($self);
+}
+
+sub intersection {
+ my $self = shift;
+ my ($line, $require_crossing) = @_;
+ return Slic3r::Geometry::line_intersection($self, $line, $require_crossing);
+}
+
+sub point_on_left {
+ my $self = shift;
+ my ($point) = @_;
+ return Slic3r::Geometry::point_is_on_left_of_segment($point, $self);
+}
+
+sub midpoint {
+ my $self = shift;
+ return Slic3r::Point->new(
+ ($self->[A][X] + $self->[B][X]) / 2,
+ ($self->[A][Y] + $self->[B][Y]) / 2,
+ );
+}
+
1;
diff --git a/lib/Slic3r/Point.pm b/lib/Slic3r/Point.pm
index 5ddb4f495..e8570ef8a 100644
--- a/lib/Slic3r/Point.pm
+++ b/lib/Slic3r/Point.pm
@@ -4,7 +4,7 @@ use warnings;
sub new {
my $class = shift;
- my $self;
+ my $self;use XXX; ZZZ if !defined $_[0];
if (@_ == 2) {
$self = [@_];
} elsif (ref $_[0] eq 'ARRAY') {