From 7fbacc5885548363186df3bd9b5cf17c172c39e9 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Wed, 28 Aug 2013 15:29:18 +0200 Subject: [PATCH 1/7] Minor optimizations in GCode.pm --- lib/Slic3r/GCode.pm | 55 ++++++++++++++++----------------------------- 1 file changed, 19 insertions(+), 36 deletions(-) diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index bace58030..1aafb60c1 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -78,8 +78,7 @@ sub _build_enable_wipe { } sub set_shift { - my $self = shift; - my @shift = @_; + my ($self, @shift) = @_; # if shift increases (goes towards right), last_pos decreases because it goes towards left my @translate = ( @@ -94,8 +93,7 @@ sub set_shift { } sub change_layer { - my $self = shift; - my ($layer) = @_; + my ($self, $layer) = @_; $self->layer($layer); @@ -138,8 +136,7 @@ sub change_layer { # this method accepts Z in unscaled coordinates sub move_z { - my $self = shift; - my ($z, $comment) = @_; + my ($self, $z, $comment) = @_; $z += $self->config->z_offset; @@ -174,8 +171,7 @@ sub extrude { } sub extrude_loop { - my $self = shift; - my ($loop, $description) = @_; + my ($self, $loop, $description) = @_; # extrude all loops ccw $loop = $loop->unpack if $loop->isa('Slic3r::ExtrusionLoop::Packed'); @@ -280,8 +276,7 @@ sub extrude_loop { } sub extrude_path { - my $self = shift; - my ($path, $description, %params) = @_; + my ($self, $path, $description, %params) = @_; $path = $path->unpack if $path->isa('Slic3r::ExtrusionPath::Packed'); $path->simplify(&Slic3r::SCALED_RESOLUTION); @@ -367,8 +362,7 @@ sub extrude_path { } sub travel_to { - my $self = shift; - my ($point, $role, $comment) = @_; + my ($self, $point, $role, $comment) = @_; my $gcode = ""; @@ -417,8 +411,7 @@ sub travel_to { } sub _plan { - my $self = shift; - my ($mp, $point, $comment) = @_; + my ($self, $mp, $point, $comment) = @_; my $gcode = ""; my @travel = $mp->shortest_path($self->last_pos, $point)->lines; @@ -447,8 +440,7 @@ sub _plan { } sub retract { - my $self = shift; - my %params = @_; + my ($self, %params) = @_; # get the retraction length and abort if none my ($length, $restart_extra, $comment) = $params{toolchange} @@ -535,7 +527,7 @@ sub retract { } sub unretract { - my $self = shift; + my ($self) = @_; my $gcode = ""; $gcode .= "M101 ; extruder on\n" if $self->config->gcode_flavor eq 'makerware'; @@ -560,7 +552,7 @@ sub unretract { } sub reset_e { - my $self = shift; + my ($self) = @_; return "" if $self->config->gcode_flavor =~ /^(?:mach3|makerware|sailfish)$/; $self->extruder->e(0) if $self->extruder; @@ -569,8 +561,7 @@ sub reset_e { } sub set_acceleration { - my $self = shift; - my ($acceleration) = @_; + my ($self, $acceleration) = @_; return "" if !$acceleration; return sprintf "M204 S%s%s\n", @@ -589,8 +580,7 @@ sub G1 { } sub _G0_G1 { - my $self = shift; - my ($gcode, $point, $z, $e, $comment) = @_; + my ($self, $gcode, $point, $z, $e, $comment) = @_; my $dec = $self->dec; if ($point) { @@ -609,8 +599,7 @@ sub _G0_G1 { } sub G2_G3 { - my $self = shift; - my ($point, $orientation, $center, $e, $comment) = @_; + my ($self, $point, $orientation, $center, $e, $comment) = @_; my $dec = $self->dec; my $gcode = $orientation eq 'cw' ? "G2" : "G3"; @@ -629,8 +618,7 @@ sub G2_G3 { } sub _Gx { - my $self = shift; - my ($gcode, $e, $comment) = @_; + my ($self, $gcode, $e, $comment) = @_; my $dec = $self->dec; # output speed if it's different from last one used @@ -674,8 +662,7 @@ sub _Gx { } sub set_extruder { - my $self = shift; - my ($extruder) = @_; + my ($self, $extruder) = @_; # return nothing if this extruder was already selected return "" if (defined $self->extruder) && ($self->extruder->id == $extruder->id); @@ -715,8 +702,7 @@ sub set_extruder { } sub set_fan { - my $self = shift; - my ($speed, $dont_save) = @_; + my ($self, $speed, $dont_save) = @_; if ($self->last_fan_speed != $speed || $dont_save) { $self->last_fan_speed($speed) if !$dont_save; @@ -740,8 +726,7 @@ sub set_fan { } sub set_temperature { - my $self = shift; - my ($temperature, $wait, $tool) = @_; + my ($self, $temperature, $wait, $tool) = @_; return "" if $wait && $self->config->gcode_flavor =~ /^(?:makerware|sailfish)$/; @@ -759,8 +744,7 @@ sub set_temperature { } sub set_bed_temperature { - my $self = shift; - my ($temperature, $wait) = @_; + my ($self, $temperature, $wait) = @_; my ($code, $comment) = ($wait && $self->config->gcode_flavor ne 'teacup') ? (($self->config->gcode_flavor =~ /^(?:makerware|sailfish)$/ ? 'M109' : 'M190'), 'wait for bed temperature to be reached') @@ -776,8 +760,7 @@ sub set_bed_temperature { # http://hydraraptor.blogspot.it/2010/12/frequency-limit.html sub _limit_frequency { - my $self = shift; - my ($point) = @_; + my ($self, $point) = @_; return '' if $self->config->vibration_limit == 0; my $min_time = 1 / ($self->config->vibration_limit * 60); # in minutes From 36e5e1f93322edfbd49829dc1cc8c9bf0326ee90 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Wed, 28 Aug 2013 16:51:58 +0200 Subject: [PATCH 2/7] Moved vibration limit to its own G-code filter --- MANIFEST | 1 + lib/Slic3r.pm | 1 + lib/Slic3r/GCode.pm | 43 +------------------- lib/Slic3r/GCode/Layer.pm | 13 ++++++ lib/Slic3r/GCode/Reader.pm | 11 +++-- lib/Slic3r/GCode/SpiralVase.pm | 4 +- lib/Slic3r/GCode/VibrationLimit.pm | 64 ++++++++++++++++++++++++++++++ lib/Slic3r/Line.pm | 5 --- t/custom_gcode.t | 2 +- t/fill.t | 2 +- t/layers.t | 2 +- t/perimeters.t | 8 ++-- t/retraction.t | 2 +- t/shells.t | 8 ++-- t/skirt_brim.t | 2 +- t/support.t | 2 +- t/vibrationlimit.t | 2 +- utils/gcode_sectioncut.pl | 2 +- 18 files changed, 103 insertions(+), 71 deletions(-) create mode 100644 lib/Slic3r/GCode/VibrationLimit.pm diff --git a/MANIFEST b/MANIFEST index 62df31da1..7923aee40 100644 --- a/MANIFEST +++ b/MANIFEST @@ -29,6 +29,7 @@ lib/Slic3r/GCode/Layer.pm lib/Slic3r/GCode/MotionPlanner.pm lib/Slic3r/GCode/Reader.pm lib/Slic3r/GCode/SpiralVase.pm +lib/Slic3r/GCode/VibrationLimit.pm lib/Slic3r/Geometry.pm lib/Slic3r/Geometry/BoundingBox.pm lib/Slic3r/Geometry/Clipper.pm diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index 30654bed7..e4287090f 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -54,6 +54,7 @@ use Slic3r::GCode::Layer; use Slic3r::GCode::MotionPlanner; use Slic3r::GCode::Reader; use Slic3r::GCode::SpiralVase; +use Slic3r::GCode::VibrationLimit; use Slic3r::Geometry qw(PI); use Slic3r::Geometry::BoundingBox; use Slic3r::Geometry::Clipper; diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 1aafb60c1..85f6fe3e7 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -1,7 +1,7 @@ package Slic3r::GCode; use Moo; -use List::Util qw(min max first); +use List::Util qw(min first); use Slic3r::ExtrusionPath ':roles'; use Slic3r::Geometry qw(epsilon scale unscale scaled_epsilon points_coincide PI X Y B); use Slic3r::Geometry::Clipper qw(union_ex); @@ -38,10 +38,6 @@ has 'last_fan_speed' => (is => 'rw', default => sub {0}); has 'wipe_path' => (is => 'rw'); has 'dec' => (is => 'ro', default => sub { 3 } ); -# used for vibration limit: -has 'last_dir' => (is => 'ro', default => sub { [0,0] }); -has 'dir_time' => (is => 'ro', default => sub { [0,0] }); - sub _build_speeds { my $self = shift; return { @@ -587,7 +583,6 @@ sub _G0_G1 { $gcode .= sprintf " X%.${dec}f Y%.${dec}f", ($point->x * &Slic3r::SCALING_FACTOR) + $self->shift_x - $self->extruder->extruder_offset->[X], ($point->y * &Slic3r::SCALING_FACTOR) + $self->shift_y - $self->extruder->extruder_offset->[Y]; #** - $gcode = $self->_limit_frequency($point) . $gcode; $self->last_pos($point->clone); } if (defined $z && (!defined $self->z || $z != $self->z)) { @@ -758,40 +753,4 @@ sub set_bed_temperature { return $gcode; } -# http://hydraraptor.blogspot.it/2010/12/frequency-limit.html -sub _limit_frequency { - my ($self, $point) = @_; - - return '' if $self->config->vibration_limit == 0; - my $min_time = 1 / ($self->config->vibration_limit * 60); # in minutes - - # calculate the move vector and move direction - my $vector = Slic3r::Line->new($self->last_pos, $point)->vector; - my @dir = map { $vector->[B][$_] <=> 0 } X,Y; - - my $time = (unscale $vector->length) / $self->speeds->{$self->speed}; # in minutes - if ($time > 0) { - my @pause = (); - foreach my $axis (X,Y) { - if ($dir[$axis] != 0 && $self->last_dir->[$axis] != $dir[$axis]) { - if ($self->last_dir->[$axis] != 0) { - # this axis is changing direction: check whether we need to pause - if ($self->dir_time->[$axis] < $min_time) { - push @pause, ($min_time - $self->dir_time->[$axis]); - } - } - $self->last_dir->[$axis] = $dir[$axis]; - $self->dir_time->[$axis] = 0; - } - $self->dir_time->[$axis] += $time; - } - - if (@pause) { - return sprintf "G4 P%d\n", max(@pause) * 60 * 1000; - } - } - - return ''; -} - 1; diff --git a/lib/Slic3r/GCode/Layer.pm b/lib/Slic3r/GCode/Layer.pm index 1b21b3fca..387ba750a 100644 --- a/lib/Slic3r/GCode/Layer.pm +++ b/lib/Slic3r/GCode/Layer.pm @@ -9,6 +9,7 @@ has 'gcodegen' => (is => 'ro', required => 1); has 'shift' => (is => 'ro', required => 1); has 'spiralvase' => (is => 'lazy'); +has 'vibration_limit' => (is => 'lazy'); has 'skirt_done' => (is => 'rw', default => sub { {} }); # print_z => 1 has 'brim_done' => (is => 'rw'); has 'second_layer_things_done' => (is => 'rw'); @@ -22,6 +23,14 @@ sub _build_spiralvase { : undef; } +sub _build_vibration_limit { + my $self = shift; + + return $Slic3r::Config->vibration_limit + ? Slic3r::GCode::VibrationLimit->new(config => $self->gcodegen->config) + : undef; +} + sub process_layer { my $self = shift; my ($layer, $object_copies) = @_; @@ -164,6 +173,10 @@ sub process_layer { $gcode = $self->spiralvase->process_layer($gcode, $layer) if $spiralvase; + # apply vibration limit if enabled + $gcode = $self->vibration_limit->process($gcode) + if $Slic3r::Config->vibration_limit != 0; + return $gcode; } diff --git a/lib/Slic3r/GCode/Reader.pm b/lib/Slic3r/GCode/Reader.pm index 20a1313b0..76f3bf005 100644 --- a/lib/Slic3r/GCode/Reader.pm +++ b/lib/Slic3r/GCode/Reader.pm @@ -1,7 +1,6 @@ package Slic3r::GCode::Reader; use Moo; -has 'gcode' => (is => 'ro', required => 1); has 'X' => (is => 'rw', default => sub {0}); has 'Y' => (is => 'rw', default => sub {0}); has 'Z' => (is => 'rw', default => sub {0}); @@ -13,9 +12,9 @@ my @AXES = qw(X Y Z E); sub parse { my $self = shift; - my ($cb) = @_; + my ($gcode, $cb) = @_; - foreach my $raw_line (split /\R+/, $self->gcode) { + foreach my $raw_line (split /\R+/, $gcode) { print "$raw_line\n" if $Verbose || $ENV{SLIC3R_TESTS_GCODE}; my $line = $raw_line; $line =~ s/\s*;(.*)//; # strip comment @@ -50,12 +49,12 @@ sub parse { } # run callback - $cb->($self, $command, \%args, \%info); + #$cb->($self, $command, \%args, \%info); # update coordinates if ($command =~ /^(?:G[01]|G92)$/) { - for (@AXES, 'F') { - $self->$_($args{$_}) if exists $args{$_}; + for my $axis (@AXES, 'F') { + $self->$axis($args{$axis}) if exists $args{$axis}; } } diff --git a/lib/Slic3r/GCode/SpiralVase.pm b/lib/Slic3r/GCode/SpiralVase.pm index 1094e728e..e9f36ba70 100644 --- a/lib/Slic3r/GCode/SpiralVase.pm +++ b/lib/Slic3r/GCode/SpiralVase.pm @@ -10,7 +10,7 @@ sub process_layer { my ($gcode, $layer) = @_; my $total_layer_length = 0; - Slic3r::GCode::Reader->new(gcode => $gcode)->parse(sub { + Slic3r::GCode::Reader->new->parse($gcode, sub { my ($reader, $cmd, $args, $info) = @_; $total_layer_length += $info->{dist_XY} if $cmd eq 'G1' && $info->{extruding}; @@ -20,7 +20,7 @@ sub process_layer { my $layer_height = $layer->height; my $z = $layer->print_z + $self->config->z_offset - $layer_height; my $newlayer = 0; - Slic3r::GCode::Reader->new(gcode => $gcode)->parse(sub { + Slic3r::GCode::Reader->new->parse($gcode, sub { my ($reader, $cmd, $args, $info) = @_; if ($cmd eq 'G1' && exists $args->{Z}) { diff --git a/lib/Slic3r/GCode/VibrationLimit.pm b/lib/Slic3r/GCode/VibrationLimit.pm new file mode 100644 index 000000000..0680a3b82 --- /dev/null +++ b/lib/Slic3r/GCode/VibrationLimit.pm @@ -0,0 +1,64 @@ +package Slic3r::GCode::VibrationLimit; +use Moo; + +extends 'Slic3r::GCode::Reader'; + +has 'config' => (is => 'ro', required => 1); +has '_min_time' => (is => 'lazy'); +has '_last_dir' => (is => 'ro', default => sub { [0,0] }); +has '_dir_time' => (is => 'ro', default => sub { [0,0] }); + +# inspired by http://hydraraptor.blogspot.it/2010/12/frequency-limit.html + +use List::Util qw(max); +use Slic3r::Geometry qw(X Y); + +sub _build__min_time { + my ($self) = @_; + return 1 / ($self->config->vibration_limit * 60); # in minutes +} + +sub process { + my $self = shift; + my ($gcode) = @_; + + my $new_gcode = ""; + $self->parse($gcode, sub { + my ($reader, $cmd, $args, $info) = @_; + + if ($cmd eq 'G1' && $info->{dist_XY} > 0) { + my $point = Slic3r::Point->new($args->{X} // $reader->X, $args->{Y} // $reader->Y); + my @dir = ( + ($point->x <=> $reader->X), + ($point->y <=> $reader->Y), #$ + ); + my $time = $info->{dist_XY} / ($args->{F} // $reader->F); # in minutes + if ($time > 0) { + my @pause = (); + foreach my $axis (X,Y) { + if ($dir[$axis] != 0 && $self->_last_dir->[$axis] != $dir[$axis]) { + if ($self->_last_dir->[$axis] != 0) { + # this axis is changing direction: check whether we need to pause + if ($self->_dir_time->[$axis] < $self->_min_time) { + push @pause, ($self->_min_time - $self->_dir_time->[$axis]); + } + } + $self->_last_dir->[$axis] = $dir[$axis]; + $self->_dir_time->[$axis] = 0; + } + $self->_dir_time->[$axis] += $time; + } + + if (@pause) { + $new_gcode .= sprintf "G4 P%d\n", max(@pause) * 60 * 1000; + } + } + } + + $new_gcode .= $info->{raw} . "\n"; + }); + + return $new_gcode; +} + +1; diff --git a/lib/Slic3r/Line.pm b/lib/Slic3r/Line.pm index 968ec1b6a..cdc47e005 100644 --- a/lib/Slic3r/Line.pm +++ b/lib/Slic3r/Line.pm @@ -24,11 +24,6 @@ sub coincides_with { || ($self->a->coincides_with($line->b) && $self->b->coincides_with($line->a)); } -sub vector { - my $self = shift; - return (ref $self)->new([0,0], [map $self->[B][$_] - $self->[A][$_], X,Y]); -} - sub atan { my $self = shift; return Slic3r::Geometry::line_atan($self); diff --git a/t/custom_gcode.t b/t/custom_gcode.t index 9c5fbdcc4..765946f36 100644 --- a/t/custom_gcode.t +++ b/t/custom_gcode.t @@ -20,7 +20,7 @@ use Slic3r::Test; my $print = Slic3r::Test::init_print('2x20x10', config => $conf); my $last_move_was_z_change = 0; - Slic3r::GCode::Reader->new(gcode => Slic3r::Test::gcode($print))->parse(sub { + Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { my ($self, $cmd, $args, $info) = @_; if ($last_move_was_z_change && $cmd ne $config->layer_gcode) { diff --git a/t/fill.t b/t/fill.t index 3f7bb227c..54be555b0 100644 --- a/t/fill.t +++ b/t/fill.t @@ -174,7 +174,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ } my $print = Slic3r::Test::init_print('20mm_cube', config => $config); my %layers_with_extrusion = (); - Slic3r::GCode::Reader->new(gcode => Slic3r::Test::gcode($print))->parse(sub { + Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { my ($self, $cmd, $args, $info) = @_; $layers_with_extrusion{$self->Z} = 1 if $info->{extruding}; }); diff --git a/t/layers.t b/t/layers.t index 6ee92cf2e..2da409747 100644 --- a/t/layers.t +++ b/t/layers.t @@ -21,7 +21,7 @@ my $test = sub { my @z = (); my @increments = (); - Slic3r::GCode::Reader->new(gcode => Slic3r::Test::gcode($print))->parse(sub { + Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { my ($self, $cmd, $args, $info) = @_; if ($info->{dist_Z}) { diff --git a/t/perimeters.t b/t/perimeters.t index 1dacd31c0..0f877e082 100644 --- a/t/perimeters.t +++ b/t/perimeters.t @@ -25,7 +25,7 @@ use Slic3r::Test; my $print = Slic3r::Test::init_print('overhang', config => $config); my $has_cw_loops = 0; my $cur_loop; - Slic3r::GCode::Reader->new(gcode => Slic3r::Test::gcode($print))->parse(sub { + Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { my ($self, $cmd, $args, $info) = @_; if ($info->{extruding} && $info->{dist_XY} > 0) { @@ -47,7 +47,7 @@ use Slic3r::Test; my $has_cw_loops = my $has_outwards_move = 0; my $cur_loop; my %external_loops = (); # print_z => count of external loops - Slic3r::GCode::Reader->new(gcode => Slic3r::Test::gcode($print))->parse(sub { + Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { my ($self, $cmd, $args, $info) = @_; if ($info->{extruding} && $info->{dist_XY} > 0) { @@ -77,7 +77,7 @@ use Slic3r::Test; my $print = Slic3r::Test::init_print('L', config => $config); my $loop_starts_from_convex_point = 0; my $cur_loop; - Slic3r::GCode::Reader->new(gcode => Slic3r::Test::gcode($print))->parse(sub { + Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { my ($self, $cmd, $args, $info) = @_; if ($info->{extruding} && $info->{dist_XY} > 0) { @@ -107,7 +107,7 @@ use Slic3r::Test; my $print = Slic3r::Test::init_print('overhang', config => $config); my %layer_speeds = (); # print Z => [ speeds ] my $fan_speed = 0; - Slic3r::GCode::Reader->new(gcode => Slic3r::Test::gcode($print))->parse(sub { + Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { my ($self, $cmd, $args, $info) = @_; $fan_speed = 0 if $cmd eq 'M107'; diff --git a/t/retraction.t b/t/retraction.t index 08276ad6e..8221c4deb 100644 --- a/t/retraction.t +++ b/t/retraction.t @@ -25,7 +25,7 @@ my $test = sub { my $lifted = 0; my $changed_tool = 0; my $wait_for_toolchange = 0; - Slic3r::GCode::Reader->new(gcode => Slic3r::Test::gcode($print))->parse(sub { + Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { my ($self, $cmd, $args, $info) = @_; if ($cmd =~ /^T(\d+)/) { diff --git a/t/shells.t b/t/shells.t index 175260be6..32372144b 100644 --- a/t/shells.t +++ b/t/shells.t @@ -23,7 +23,7 @@ use Slic3r::Test; my $print = Slic3r::Test::init_print('20mm_cube', config => $config); my %layers_with_shells = (); # Z => $count - Slic3r::GCode::Reader->new(gcode => Slic3r::Test::gcode($print))->parse(sub { + Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { my ($self, $cmd, $args, $info) = @_; if ($self->Z > 0) { @@ -58,7 +58,7 @@ use Slic3r::Test; my $print = Slic3r::Test::init_print('V', config => $config); my %layers_with_solid_infill = (); # Z => 1 - Slic3r::GCode::Reader->new(gcode => Slic3r::Test::gcode($print))->parse(sub { + Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { my ($self, $cmd, $args, $info) = @_; $layers_with_solid_infill{$self->Z} = 1 @@ -90,7 +90,7 @@ use Slic3r::Test; my $print = Slic3r::Test::init_print('V', config => $config); my %layers = (); # Z => 1 - Slic3r::GCode::Reader->new(gcode => Slic3r::Test::gcode($print))->parse(sub { + Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { my ($self, $cmd, $args, $info) = @_; $layers{$self->Z} = 1 if $info->{extruding} && ($args->{F} // $self->F) == $config->solid_infill_speed*60; @@ -116,7 +116,7 @@ use Slic3r::Test; my $travel_moves_after_first_extrusion = 0; my $started_extruding = 0; my @z_steps = (); - Slic3r::GCode::Reader->new(gcode => Slic3r::Test::gcode($print))->parse(sub { + Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { my ($self, $cmd, $args, $info) = @_; $started_extruding = 1 if $info->{extruding}; diff --git a/t/skirt_brim.t b/t/skirt_brim.t index c78bf41e0..e73ccc620 100644 --- a/t/skirt_brim.t +++ b/t/skirt_brim.t @@ -27,7 +27,7 @@ use Slic3r::Test; my $print = Slic3r::Test::init_print(['20mm_cube','20mm_cube'], config => $config); my %layers_with_skirt = (); # Z => $count - Slic3r::GCode::Reader->new(gcode => Slic3r::Test::gcode($print))->parse(sub { + Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { my ($self, $cmd, $args, $info) = @_; if (defined $self->Z) { diff --git a/t/support.t b/t/support.t index 9ed16395a..4cda5bff4 100644 --- a/t/support.t +++ b/t/support.t @@ -65,7 +65,7 @@ use Slic3r::Test; ok my $gcode = Slic3r::Test::gcode($print), 'no conflict between raft/support and brim'; my $tool = 0; - Slic3r::GCode::Reader->new(gcode => $gcode)->parse(sub { + Slic3r::GCode::Reader->new->parse($gcode, sub { my ($self, $cmd, $args, $info) = @_; if ($cmd =~ /^T(\d+)/) { diff --git a/t/vibrationlimit.t b/t/vibrationlimit.t index a903b6b82..ff39073e9 100644 --- a/t/vibrationlimit.t +++ b/t/vibrationlimit.t @@ -28,7 +28,7 @@ my $test = sub { my %dir_time = (X => 0, Y => 0); my %dir_sleep_time = (X => 0, Y => 0); my $last_cmd_pause = 0; - Slic3r::GCode::Reader->new(gcode => Slic3r::Test::gcode($print))->parse(sub { + Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { my ($self, $cmd, $args, $info) = @_; if ($cmd !~ /^G[01]$/) { diff --git a/utils/gcode_sectioncut.pl b/utils/gcode_sectioncut.pl index 4304f4aba..733208a3e 100644 --- a/utils/gcode_sectioncut.pl +++ b/utils/gcode_sectioncut.pl @@ -41,7 +41,7 @@ my %opt = ( # read paths my %paths = (); # z => [ path, path ... ] - Slic3r::GCode::Reader->new(gcode => io($input_file)->all)->parse(sub { + Slic3r::GCode::Reader->new->parse(io($input_file)->all, sub { my ($self, $cmd, $args, $info) = @_; if ($cmd eq 'G1' && $info->{extruding}) { From 0049b02bed497b95b41fdabc52bb396746fbcd29 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Wed, 28 Aug 2013 18:12:20 +0200 Subject: [PATCH 3/7] Huge speed boost by reducing the number of method calls in GCode.pm --- lib/Slic3r/ExtrusionPath.pm | 5 ++ lib/Slic3r/GCode.pm | 133 +++++++++++++++++------------- lib/Slic3r/GCode/CoolingBuffer.pm | 3 +- lib/Slic3r/GCode/Reader.pm | 2 +- t/vibrationlimit.t | 2 +- 5 files changed, 83 insertions(+), 62 deletions(-) diff --git a/lib/Slic3r/ExtrusionPath.pm b/lib/Slic3r/ExtrusionPath.pm index 3409a5975..06b7d0959 100644 --- a/lib/Slic3r/ExtrusionPath.pm +++ b/lib/Slic3r/ExtrusionPath.pm @@ -117,6 +117,11 @@ sub first_point { return $self->polyline->[0]; } +sub last_point { + my $self = shift; + return $self->polyline->[-1]; +} + sub is_perimeter { my $self = shift; return $self->role == EXTR_ROLE_PERIMETER diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 85f6fe3e7..73d8a62fe 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -36,7 +36,6 @@ has 'last_speed' => (is => 'rw', default => sub {""}); has 'last_f' => (is => 'rw', default => sub {""}); has 'last_fan_speed' => (is => 'rw', default => sub {0}); has 'wipe_path' => (is => 'rw'); -has 'dec' => (is => 'ro', default => sub { 3 } ); sub _build_speeds { my $self = shift; @@ -319,29 +318,89 @@ sub extrude_path { # calculate extrusion length per distance unit my $e = $self->extruder->e_per_mm3 * $area; + $e = 0 if !$self->config->extrusion_axis; # set speed $self->speed( $params{speed} || $role_speeds{$path->role} || die "Unknown role: " . $path->role ); + my $F = $self->speeds->{$self->speed} // $self->speed; + if ($self->layer->id == 0) { + $F = $self->config->first_layer_speed =~ /^(\d+(?:\.\d+)?)%$/ + ? sprintf("%.3f", $F * $1/100) + : $self->config->first_layer_speed * 60; + } # extrude arc or line + $gcode .= ";_BRIDGE_FAN_START\n" if $path->is_bridge; my $path_length = 0; if ($path->isa('Slic3r::ExtrusionPath::Arc')) { $path_length = unscale $path->length; - $gcode .= $self->G2_G3($path->points->[-1], $path->orientation, - $path->center, $e * unscale $path_length, $description); + + # calculate extrusion length for this arc + my $E = 0; + if ($e) { + $E = $e * $path_length; + $self->extruder->e(0) if $self->config->use_relative_e_distances; + $self->total_extrusion_length($self->total_extrusion_length + $E); + $E = $self->extruder->e($self->extruder->e + $E); + } + + # compose G-code line + my $point = $path->points->[-1]; + $gcode .= $path->orientation eq 'cw' ? "G2" : "G3"; + $gcode .= sprintf " X%.3f Y%.3f", + ($point->x * &Slic3r::SCALING_FACTOR) + $self->shift_x - $self->extruder->extruder_offset->[X], + ($point->y * &Slic3r::SCALING_FACTOR) + $self->shift_y - $self->extruder->extruder_offset->[Y]; #** + + # XY distance of the center from the start position + $gcode .= sprintf " I%.3f J%.3f", + ($path->center->[X] - $self->last_pos->[X]) * &Slic3r::SCALING_FACTOR, + ($path->center->[Y] - $self->last_pos->[Y]) * &Slic3r::SCALING_FACTOR; + + $gcode .= sprintf(" %s%.5f", $self->config->extrusion_axis, $E) + if $E; + $gcode .= " F$F"; + $gcode .= " ; $description" + if $self->config->gcode_comments; + $gcode .= "\n"; + $self->wipe_path(undef); } else { + my $local_F = $F; foreach my $line ($path->lines) { - my $line_length = unscale $line->length; - $path_length += $line_length; - $gcode .= $self->G1($line->[B], undef, $e * $line_length, $description); + $path_length += my $line_length = unscale $line->length; + + # calculate extrusion length for this line + my $E = 0; + if ($e) { + $E = $e * $line_length; + $self->extruder->e(0) if $self->config->use_relative_e_distances; + $self->total_extrusion_length($self->total_extrusion_length + $E); + $E = $self->extruder->e($self->extruder->e + $E); + } + + # compose G-code line + $gcode .= sprintf "G1 X%.3f Y%.3f", + ($line->[B]->x * &Slic3r::SCALING_FACTOR) + $self->shift_x - $self->extruder->extruder_offset->[X], + ($line->[B]->y * &Slic3r::SCALING_FACTOR) + $self->shift_y - $self->extruder->extruder_offset->[Y]; #** + $gcode .= sprintf(" %s%.5f", $self->config->extrusion_axis, $E) + if $E; + $gcode .= " F$local_F" + if $local_F; + $gcode .= " ; $description" + if $self->config->gcode_comments; + $gcode .= "\n"; + + # only include F in the first line + $local_F = 0; } $self->wipe_path(Slic3r::Polyline->new(reverse @{$path->points})) if $self->enable_wipe; } + $gcode .= ";_BRIDGE_FAN_END\n" if $path->is_bridge; + $self->last_pos($path->last_point); if ($self->config->cooling) { - my $path_time = $path_length / $self->speeds->{$self->last_speed} * 60; + my $path_time = $path_length / $F * 60; if ($self->layer->id == 0) { $path_time = $self->config->first_layer_speed =~ /^(\d+(?:\.\d+)?)%$/ ? $path_time / ($1/100) @@ -577,69 +636,30 @@ sub G1 { sub _G0_G1 { my ($self, $gcode, $point, $z, $e, $comment) = @_; - my $dec = $self->dec; if ($point) { - $gcode .= sprintf " X%.${dec}f Y%.${dec}f", + $gcode .= sprintf " X%.3f Y%.3f", ($point->x * &Slic3r::SCALING_FACTOR) + $self->shift_x - $self->extruder->extruder_offset->[X], ($point->y * &Slic3r::SCALING_FACTOR) + $self->shift_y - $self->extruder->extruder_offset->[Y]; #** $self->last_pos($point->clone); } if (defined $z && (!defined $self->z || $z != $self->z)) { $self->z($z); - $gcode .= sprintf " Z%.${dec}f", $z; + $gcode .= sprintf " Z%.3f", $z; } return $self->_Gx($gcode, $e, $comment); } -sub G2_G3 { - my ($self, $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::SCALING_FACTOR) + $self->shift_x - $self->extruder->extruder_offset->[X], - ($point->y * &Slic3r::SCALING_FACTOR) + $self->shift_y - $self->extruder->extruder_offset->[Y]; #** - - # XY distance of the center from the start position - $gcode .= sprintf " I%.${dec}f J%.${dec}f", - ($center->[X] - $self->last_pos->[X]) * &Slic3r::SCALING_FACTOR, - ($center->[Y] - $self->last_pos->[Y]) * &Slic3r::SCALING_FACTOR; - - $self->last_pos($point); - return $self->_Gx($gcode, $e, $comment); -} - sub _Gx { my ($self, $gcode, $e, $comment) = @_; - my $dec = $self->dec; - # output speed if it's different from last one used - # (goal: reduce gcode size) - my $append_bridge_off = 0; - my $F; - if ($self->speed ne $self->last_speed) { - if ($self->speed eq 'bridge') { - $gcode = ";_BRIDGE_FAN_START\n$gcode"; - } elsif ($self->last_speed eq 'bridge') { - $append_bridge_off = 1; - } - - # apply the speed reduction for print moves on bottom layer - $F = $self->speed eq 'retract' - ? ($self->extruder->retract_speed_mm_min) - : $self->speeds->{$self->speed} // $self->speed; - if ($e && $self->layer && $self->layer->id == 0 && $comment !~ /retract/) { - $F = $self->config->first_layer_speed =~ /^(\d+(?:\.\d+)?)%$/ - ? ($F * $1/100) - : $self->config->first_layer_speed * 60; - } - $self->last_speed($self->speed); - $self->last_f($F); - } - $gcode .= sprintf " F%.${dec}f", $F if defined $F; + my $F = $self->speed eq 'retract' + ? ($self->extruder->retract_speed_mm_min) + : $self->speeds->{$self->speed} // $self->speed; + $self->last_speed($self->speed); + $self->last_f($F); + $gcode .= sprintf " F%.3f", $F; # output extrusion distance if ($e && $self->config->extrusion_axis) { @@ -649,10 +669,7 @@ sub _Gx { $gcode .= sprintf " %s%.5f", $self->config->extrusion_axis, $self->extruder->e; } - $gcode .= sprintf " ; %s", $comment if $comment && $self->config->gcode_comments; - if ($append_bridge_off) { - $gcode = ";_BRIDGE_FAN_END\n$gcode"; - } + $gcode .= " ; $comment" if $comment && $self->config->gcode_comments; return "$gcode\n"; } diff --git a/lib/Slic3r/GCode/CoolingBuffer.pm b/lib/Slic3r/GCode/CoolingBuffer.pm index 45283bef6..d95b5fec1 100644 --- a/lib/Slic3r/GCode/CoolingBuffer.pm +++ b/lib/Slic3r/GCode/CoolingBuffer.pm @@ -56,10 +56,9 @@ sub flush { Slic3r::debugf " fan = %d%%, speed = %d%%\n", $fan_speed, $speed_factor * 100; if ($speed_factor < 1) { - my $dec = $self->gcodegen->dec; $gcode =~ s/^(?=.*? [XY])(?=.*? E)(?!;_WIPE)(?min_print_speed ? $self->min_print_speed : $new_speed) + $1 . sprintf("%.3f", $new_speed < $self->min_print_speed ? $self->min_print_speed : $new_speed) /gexm; } } diff --git a/lib/Slic3r/GCode/Reader.pm b/lib/Slic3r/GCode/Reader.pm index 76f3bf005..11e04f6a8 100644 --- a/lib/Slic3r/GCode/Reader.pm +++ b/lib/Slic3r/GCode/Reader.pm @@ -49,7 +49,7 @@ sub parse { } # run callback - #$cb->($self, $command, \%args, \%info); + $cb->($self, $command, \%args, \%info); # update coordinates if ($command =~ /^(?:G[01]|G92)$/) { diff --git a/t/vibrationlimit.t b/t/vibrationlimit.t index ff39073e9..2553e2260 100644 --- a/t/vibrationlimit.t +++ b/t/vibrationlimit.t @@ -58,7 +58,7 @@ my $test = sub { my $one_axis_would_trigger_limit_without_pause = 0; foreach my $axis (qw(X Y)) { # are we changing direction on this axis? - my $dir = $info->{"dist_$axis"} <=> 0; + my $dir = $info->{"dist_$axis"} <=> ($args->{$axis} // $self->$axis); if ($dir != 0 && $dir{$axis} != $dir) { # this move changes direction on this axis if ($dir{$axis} != 0) { From b70027890452e796dad5d105e1d5604d085bdc20 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Wed, 28 Aug 2013 19:50:16 +0200 Subject: [PATCH 4/7] Move arc fitting code to its own post-processing filter and remove the built-in ExtrusionPath::Arc class --- MANIFEST | 1 - lib/Slic3r.pm | 2 +- lib/Slic3r/ExtrusionPath.pm | 112 --------------------- lib/Slic3r/ExtrusionPath/Arc.pm | 27 ----- lib/Slic3r/ExtrusionPath/Collection.pm | 5 - lib/Slic3r/GCode.pm | 43 +------- lib/Slic3r/GCode/ArcFitting.pm | 133 +++++++++++++++++++++++++ lib/Slic3r/GCode/Layer.pm | 13 +++ lib/Slic3r/Point.pm | 5 + t/arcs.t | 1 + 10 files changed, 154 insertions(+), 188 deletions(-) delete mode 100644 lib/Slic3r/ExtrusionPath/Arc.pm create mode 100644 lib/Slic3r/GCode/ArcFitting.pm diff --git a/MANIFEST b/MANIFEST index 7923aee40..aa795023e 100644 --- a/MANIFEST +++ b/MANIFEST @@ -5,7 +5,6 @@ lib/Slic3r/ExPolygon.pm lib/Slic3r/Extruder.pm lib/Slic3r/ExtrusionLoop.pm lib/Slic3r/ExtrusionPath.pm -lib/Slic3r/ExtrusionPath/Arc.pm lib/Slic3r/ExtrusionPath/Collection.pm lib/Slic3r/Fill.pm lib/Slic3r/Fill/ArchimedeanChords.pm diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index e4287090f..1ee54f551 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -41,7 +41,6 @@ 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::Flow; @@ -49,6 +48,7 @@ use Slic3r::Format::AMF; use Slic3r::Format::OBJ; use Slic3r::Format::STL; use Slic3r::GCode; +use Slic3r::GCode::ArcFitting; use Slic3r::GCode::CoolingBuffer; use Slic3r::GCode::Layer; use Slic3r::GCode::MotionPlanner; diff --git a/lib/Slic3r/ExtrusionPath.pm b/lib/Slic3r/ExtrusionPath.pm index 06b7d0959..5b818d92e 100644 --- a/lib/Slic3r/ExtrusionPath.pm +++ b/lib/Slic3r/ExtrusionPath.pm @@ -178,118 +178,6 @@ 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) or 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; -} - package Slic3r::ExtrusionPath::Packed; sub unpack { my $self = shift; diff --git a/lib/Slic3r/ExtrusionPath/Arc.pm b/lib/Slic3r/ExtrusionPath/Arc.pm deleted file mode 100644 index 05596f185..000000000 --- a/lib/Slic3r/ExtrusionPath/Arc.pm +++ /dev/null @@ -1,27 +0,0 @@ -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; - - if($self->orientation eq 'ccw') { - return $self->radius * $self->angle; - } else { - return $self->radius * (2*PI() - $self->angle); - } -} - -1; diff --git a/lib/Slic3r/ExtrusionPath/Collection.pm b/lib/Slic3r/ExtrusionPath/Collection.pm index 88cc12528..d0bf14ab9 100644 --- a/lib/Slic3r/ExtrusionPath/Collection.pm +++ b/lib/Slic3r/ExtrusionPath/Collection.pm @@ -36,9 +36,4 @@ 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/GCode.pm b/lib/Slic3r/GCode.pm index 73d8a62fe..3d5cb28f7 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -276,15 +276,6 @@ sub extrude_path { $path = $path->unpack if $path->isa('Slic3r::ExtrusionPath::Packed'); $path->simplify(&Slic3r::SCALED_RESOLUTION); - # detect arcs - if ($self->config->gcode_arcs && !$params{dont_detect_arcs}) { - my $gcode = ""; - foreach my $arc_path ($path->detect_arcs) { - $gcode .= $self->extrude_path($arc_path, $description, %params, dont_detect_arcs => 1); - } - return $gcode; - } - # go to first point of extrusion path my $gcode = ""; $gcode .= $self->travel_to($path->points->[0], $path->role, "move to first $description point") @@ -332,39 +323,7 @@ sub extrude_path { # extrude arc or line $gcode .= ";_BRIDGE_FAN_START\n" if $path->is_bridge; my $path_length = 0; - if ($path->isa('Slic3r::ExtrusionPath::Arc')) { - $path_length = unscale $path->length; - - # calculate extrusion length for this arc - my $E = 0; - if ($e) { - $E = $e * $path_length; - $self->extruder->e(0) if $self->config->use_relative_e_distances; - $self->total_extrusion_length($self->total_extrusion_length + $E); - $E = $self->extruder->e($self->extruder->e + $E); - } - - # compose G-code line - my $point = $path->points->[-1]; - $gcode .= $path->orientation eq 'cw' ? "G2" : "G3"; - $gcode .= sprintf " X%.3f Y%.3f", - ($point->x * &Slic3r::SCALING_FACTOR) + $self->shift_x - $self->extruder->extruder_offset->[X], - ($point->y * &Slic3r::SCALING_FACTOR) + $self->shift_y - $self->extruder->extruder_offset->[Y]; #** - - # XY distance of the center from the start position - $gcode .= sprintf " I%.3f J%.3f", - ($path->center->[X] - $self->last_pos->[X]) * &Slic3r::SCALING_FACTOR, - ($path->center->[Y] - $self->last_pos->[Y]) * &Slic3r::SCALING_FACTOR; - - $gcode .= sprintf(" %s%.5f", $self->config->extrusion_axis, $E) - if $E; - $gcode .= " F$F"; - $gcode .= " ; $description" - if $self->config->gcode_comments; - $gcode .= "\n"; - - $self->wipe_path(undef); - } else { + { my $local_F = $F; foreach my $line ($path->lines) { $path_length += my $line_length = unscale $line->length; diff --git a/lib/Slic3r/GCode/ArcFitting.pm b/lib/Slic3r/GCode/ArcFitting.pm new file mode 100644 index 000000000..019ebc859 --- /dev/null +++ b/lib/Slic3r/GCode/ArcFitting.pm @@ -0,0 +1,133 @@ +package Slic3r::GCode::ArcFitting; +use Moo; + +use Slic3r::Geometry qw(X Y PI scale unscale deg2rad); + +extends 'Slic3r::GCode::Reader'; +has 'config' => (is => 'ro', required => 1); +has 'max_angle' => (is => 'rw', default => sub { deg2rad(15) }); +has 'len_epsilon' => (is => 'rw', default => sub { scale 10 }); +has 'parallel_degrees_limit' => (is => 'rw', default => sub { abs(deg2rad(3)) }); + +sub process { + my $self = shift; + my ($gcode) = @_; + + my $new_gcode = ""; + my $buffer = ""; + my @cur_path = (); + my $cur_len = 0; + my $cur_relative_angle = 0; + + $self->parse($gcode, sub { + my ($reader, $cmd, $args, $info) = @_; + + if ($info->{extruding} && $info->{dist_XY} > 0) { + my $point = Slic3r::Point->new_scale($args->{X}, $args->{Y}); + + if (@cur_path >= 2) { + if ($cur_path[-1]->distance_to($point) > $self->len_epsilon) { + # if the last distance is not compatible with the current arc, flush it + $new_gcode .= $self->flush_path(\@cur_path, \$buffer); + } elsif (@cur_path >= 3) { + my $rel_angle = relative_angle(@cur_path[-2,-1], $point); + if (($cur_relative_angle != 0 && abs($rel_angle - $cur_relative_angle) > $self->parallel_degrees_limit) # relative angle is too different from the previous one + || abs($rel_angle) < $self->parallel_degrees_limit # relative angle is almost parallel + || $rel_angle > $self->max_angle) { # relative angle is excessive (too sharp) + # in these cases, $point does not really look like an additional point of the current arc + $new_gcode .= $self->flush_path(\@cur_path, \$buffer); + } + } + } + + if (@cur_path == 0) { + # we're starting a path, so let's prepend the previous position + push @cur_path, Slic3r::Point->new_scale($self->X, $self->Y), $point; + $buffer .= $info->{raw} . "\n"; + $cur_len = $cur_path[0]->distance_to($cur_path[1]); + } else { + push @cur_path, $point; + $buffer .= $info->{raw} . "\n"; + if (@cur_path == 3) { + # we have two segments, time to compute a reference angle + $cur_relative_angle = relative_angle(@cur_path[0,1,2]); + } + } + } else { + $new_gcode .= $self->flush_path(\@cur_path, \$buffer); + $new_gcode .= $info->{raw} . "\n"; + } + }); + + $new_gcode .= $self->flush_path(\@cur_path, \$buffer); + return $new_gcode; +} + +sub flush_path { + my ($self, $cur_path, $buffer) = @_; + + my $gcode = ""; + + if (@$cur_path >= 3) { + # if we have enough points, then we have an arc + $$buffer =~ s/^/;/mg; + $gcode = "; these moves were replaced by an arc:\n" . $$buffer; + + my $orientation = Slic3r::Geometry::point_is_on_left_of_segment($cur_path->[2], [ @$cur_path[0,1] ]) ? '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 = Slic3r::Line->new(@$cur_path[0,1])->midpoint; + my $last_mid = Slic3r::Line->new(@$cur_path[-2,-1])->midpoint; + my $rotation_angle = PI/2 * ($orientation eq 'ccw' ? -1 : 1); + my $ray1 = Slic3r::Line->new($s1_mid, $cur_path->[1]->clone->rotate($rotation_angle, $s1_mid)); + my $last_ray = Slic3r::Line->new($last_mid, $cur_path->[-1]->clone->rotate($rotation_angle, $last_mid)); + $arc_center = $ray1->intersection($last_ray, 0) or next POINT; + } + my $radius = $arc_center->distance_to($cur_path->[0]); + my $total_angle = Slic3r::Geometry::angle3points($arc_center, @$cur_path[0,-1]); + my $length = $orientation eq 'ccw' + ? $radius * $total_angle + : $radius * (2*PI - $total_angle); + + # compose G-code line + $gcode .= $orientation eq 'cw' ? "G2" : "G3"; + $gcode .= sprintf " X%.3f Y%.3f", map unscale($_), @{$cur_path->[-1]}; # destination point + + # XY distance of the center from the start position + $gcode .= sprintf " I%.3f J%.3f", map { unscale($arc_center->[$_] - $cur_path->[0][$_]) } (X,Y); + + my $E = 0; # TODO: compute E using $length + $gcode .= sprintf(" %s%.5f", $self->config->extrusion_axis, $E) + if $E; + + my $F = 0; # TODO: extract F from original moves + $gcode .= " F$F\n"; + } else { + $gcode = $$buffer; + } + + $$buffer = ""; + splice @$cur_path, 0, $#$cur_path; # keep last point as starting position for next path + return $gcode; +} + +sub relative_angle { + my ($p1, $p2, $p3) = @_; + + my $s1 = Slic3r::Line->new($p1, $p2); + my $s2 = Slic3r::Line->new($p2, $p3); + my $s1_angle = $s1->atan; + my $s2_angle = $s2->atan; + $s1_angle += 2*PI if $s1_angle < 0; + $s2_angle += 2*PI if $s2_angle < 0; + return $s2_angle - $s1_angle; +} + +1; diff --git a/lib/Slic3r/GCode/Layer.pm b/lib/Slic3r/GCode/Layer.pm index 387ba750a..cfce61695 100644 --- a/lib/Slic3r/GCode/Layer.pm +++ b/lib/Slic3r/GCode/Layer.pm @@ -10,6 +10,7 @@ has 'shift' => (is => 'ro', required => 1); has 'spiralvase' => (is => 'lazy'); has 'vibration_limit' => (is => 'lazy'); +has 'arc_fitting' => (is => 'lazy'); has 'skirt_done' => (is => 'rw', default => sub { {} }); # print_z => 1 has 'brim_done' => (is => 'rw'); has 'second_layer_things_done' => (is => 'rw'); @@ -31,6 +32,14 @@ sub _build_vibration_limit { : undef; } +sub _build_arc_fitting { + my $self = shift; + + return $Slic3r::Config->gcode_arcs + ? Slic3r::GCode::ArcFitting->new(config => $self->gcodegen->config) + : undef; +} + sub process_layer { my $self = shift; my ($layer, $object_copies) = @_; @@ -177,6 +186,10 @@ sub process_layer { $gcode = $self->vibration_limit->process($gcode) if $Slic3r::Config->vibration_limit != 0; + # apply arc fitting if enabled + $gcode = $self->arc_fitting->process($gcode) + if $Slic3r::Config->gcode_arcs; + return $gcode; } diff --git a/lib/Slic3r/Point.pm b/lib/Slic3r/Point.pm index 4e86995e1..532c74dd0 100644 --- a/lib/Slic3r/Point.pm +++ b/lib/Slic3r/Point.pm @@ -20,6 +20,11 @@ sub new { return $self; } +sub new_scale { + my $class = shift; + return $class->new(map Slic3r::Geometry::scale($_), @_); +} + sub clone { Storable::dclone($_[0]) } diff --git a/t/arcs.t b/t/arcs.t index 3b14903c8..80d7f2ec5 100644 --- a/t/arcs.t +++ b/t/arcs.t @@ -2,6 +2,7 @@ use Test::More; use strict; use warnings; +plan skip_all => 'arcs are currently disabled'; plan tests => 13; BEGIN { From c49330f0499a2701ef0cc4eb8216d06dc2c24521 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Wed, 28 Aug 2013 20:01:17 +0200 Subject: [PATCH 5/7] One minor optimization in GCode.pm --- lib/Slic3r/GCode.pm | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 3d5cb28f7..3093d1439 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -556,8 +556,16 @@ sub unretract { my $to_unretract = $self->extruder->retracted + $self->extruder->restart_extra; if ($to_unretract) { $self->speed('retract'); - # use G1 instead of G0 because G0 will blend the restart with the previous travel move - $gcode .= $self->G1(undef, undef, $to_unretract, "compensate retraction"); + if ($self->config->extrusion_axis) { + $self->extruder->e(0) if $self->config->use_relative_e_distances; + $self->total_extrusion_length($self->total_extrusion_length + $to_unretract); + # use G1 instead of G0 because G0 will blend the restart with the previous travel move + $gcode .= sprintf "G1 E%.5f F%.3f", + $self->extruder->e($self->extruder->e + $to_unretract), + $self->extruder->retract_speed_mm_min; + $gcode .= " ; compensate retraction" if $self->config->gcode_comments; + $gcode .= "\n"; + } $self->extruder->retracted(0); $self->extruder->restart_extra(0); } From 2d366c4852db38ea021f021a12e634f1eeb0854d Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Wed, 28 Aug 2013 20:13:18 +0200 Subject: [PATCH 6/7] Refactor E code and keep track of per-extruder consumend filament --- lib/Slic3r/Extruder.pm | 17 ++++++++++++++++- lib/Slic3r/GCode.pm | 19 ++++--------------- lib/Slic3r/GUI/Plater.pm | 1 + lib/Slic3r/Print.pm | 21 ++++++++------------- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/lib/Slic3r/Extruder.pm b/lib/Slic3r/Extruder.pm index 91c6314cb..1171b766f 100644 --- a/lib/Slic3r/Extruder.pm +++ b/lib/Slic3r/Extruder.pm @@ -12,9 +12,11 @@ use constant OPTIONS => [qw( has 'id' => (is => 'rw', required => 1); has $_ => (is => 'ro', required => 1) for @{&OPTIONS}; +has 'config'=> (is => 'ro', required => 1); has 'bridge_flow' => (is => 'lazy'); -has 'e' => (is => 'rw', default => sub {0} ); +has 'E' => (is => 'rw', default => sub {0} ); +has 'absolute_E' => (is => 'rw', default => sub {0} ); has 'retracted' => (is => 'rw', default => sub {0} ); has 'restart_extra' => (is => 'rw', default => sub {0} ); has 'e_per_mm3' => (is => 'lazy'); @@ -44,6 +46,19 @@ sub _build_scaled_wipe_distance { return scale($self->retract_length / $self->retract_speed * $Slic3r::Config->travel_speed * 0.8); } +sub extrude { + my ($self, $E) = @_; + + $self->E(0) if $self->config->use_relative_e_distances; + $self->absolute_E($self->absolute_E + $E); + return $self->E($self->E + $E); +} + +sub extruded_volume { + my ($self) = @_; + return $self->absolute_E * ($self->filament_diameter**2) * PI/4; +} + sub make_flow { my $self = shift; return Slic3r::Flow->new(nozzle_diameter => $self->nozzle_diameter, @_); diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 3093d1439..f01013fd7 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -29,7 +29,6 @@ has 'new_object' => (is => 'rw', default => sub {0}); has 'straight_once' => (is => 'rw', default => sub {1}); has 'extruder' => (is => 'rw'); has 'elapsed_time' => (is => 'rw', default => sub {0} ); # seconds -has 'total_extrusion_length' => (is => 'rw', default => sub {0} ); has 'lifted' => (is => 'rw', default => sub {0} ); has 'last_pos' => (is => 'rw', default => sub { Slic3r::Point->new(0,0) } ); has 'last_speed' => (is => 'rw', default => sub {""}); @@ -330,12 +329,7 @@ sub extrude_path { # calculate extrusion length for this line my $E = 0; - if ($e) { - $E = $e * $line_length; - $self->extruder->e(0) if $self->config->use_relative_e_distances; - $self->total_extrusion_length($self->total_extrusion_length + $E); - $E = $self->extruder->e($self->extruder->e + $E); - } + $E = $self->extruder->extrude($e * $line_length) if $e; # compose G-code line $gcode .= sprintf "G1 X%.3f Y%.3f", @@ -557,11 +551,9 @@ sub unretract { if ($to_unretract) { $self->speed('retract'); if ($self->config->extrusion_axis) { - $self->extruder->e(0) if $self->config->use_relative_e_distances; - $self->total_extrusion_length($self->total_extrusion_length + $to_unretract); # use G1 instead of G0 because G0 will blend the restart with the previous travel move $gcode .= sprintf "G1 E%.5f F%.3f", - $self->extruder->e($self->extruder->e + $to_unretract), + $self->extruder->extrude($to_unretract), $self->extruder->retract_speed_mm_min; $gcode .= " ; compensate retraction" if $self->config->gcode_comments; $gcode .= "\n"; @@ -577,7 +569,7 @@ sub reset_e { my ($self) = @_; return "" if $self->config->gcode_flavor =~ /^(?:mach3|makerware|sailfish)$/; - $self->extruder->e(0) if $self->extruder; + $self->extruder->E(0) if $self->extruder; return sprintf "G92 %s0%s\n", $self->config->extrusion_axis, ($self->config->gcode_comments ? ' ; reset extrusion distance' : '') if $self->config->extrusion_axis && !$self->config->use_relative_e_distances; } @@ -630,10 +622,7 @@ sub _Gx { # output extrusion distance if ($e && $self->config->extrusion_axis) { - $self->extruder->e(0) if $self->config->use_relative_e_distances; - $self->extruder->e($self->extruder->e + $e); - $self->total_extrusion_length($self->total_extrusion_length + $e); - $gcode .= sprintf " %s%.5f", $self->config->extrusion_axis, $self->extruder->e; + $gcode .= sprintf " %s%.5f", $self->config->extrusion_axis, $self->extruder->extrude($e); } $gcode .= " ; $comment" if $comment && $self->config->gcode_comments; diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index c58590193..ad9843fd3 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -696,6 +696,7 @@ sub export_gcode2 { my %params = ( output_file => $output_file, status_cb => sub { $params{progressbar}->(@_) }, + quiet => 1, ); if ($params{export_svg}) { $print->export_svg(%params); diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 390823727..122053091 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -15,7 +15,6 @@ use Time::HiRes qw(gettimeofday tv_interval); has 'config' => (is => 'rw', default => sub { Slic3r::Config->new_from_defaults }, trigger => 1); has 'extra_variables' => (is => 'rw', default => sub {{}}); has 'objects' => (is => 'rw', default => sub {[]}); -has 'total_extrusion_length' => (is => 'rw'); has 'processing_time' => (is => 'rw'); has 'extruders' => (is => 'rw', default => sub {[]}); has 'regions' => (is => 'rw', default => sub {[]}); @@ -236,6 +235,7 @@ sub init_extruders { ); for my $extruder_id (keys %{{ map {$_ => 1} @used_extruders }}) { $self->extruders->[$extruder_id] = Slic3r::Extruder->new( + config => $self->config, id => $extruder_id, map { $_ => $self->config->get($_)->[$extruder_id] // $self->config->get($_)->[0] } #/ @{&Slic3r::Extruder::OPTIONS} @@ -484,8 +484,9 @@ sub export_gcode { $self->processing_time - int($self->processing_time/60)*60; # TODO: more statistics! - printf "Filament required: %.1fmm (%.1fcm3)\n", - $self->total_extrusion_length, $self->total_extrusion_volume; + print map sprintf("Filament required: %.1fmm (%.1fcm3)\n", + $_->absolute_E, $_->extruded_volume/1000), + @{$self->extruders}; } } @@ -895,16 +896,15 @@ sub write_gcode { print $fh $buffer->flush; } - # save statistic data - $self->total_extrusion_length($gcodegen->total_extrusion_length); - # write end commands to file print $fh $gcodegen->retract if $gcodegen->extruder; # empty prints don't even set an extruder print $fh $gcodegen->set_fan(0); printf $fh "%s\n", $Slic3r::Config->replace_options($Slic3r::Config->end_gcode); - printf $fh "; filament used = %.1fmm (%.1fcm3)\n", - $self->total_extrusion_length, $self->total_extrusion_volume; + foreach my $extruder (@{$self->extruders}) { + printf $fh "; filament used = %.1fmm (%.1fcm3)\n", + $extruder->absolute_E, $extruder->extruded_volume/1000; + } if ($Slic3r::Config->gcode_comments) { # append full config @@ -920,11 +920,6 @@ sub write_gcode { close $fh; } -sub total_extrusion_volume { - my $self = shift; - return $self->total_extrusion_length * ($self->extruders->[0]->filament_diameter**2) * PI/4 / 1000; -} - # this method will return the supplied input file path after expanding its # format variables with their values sub expanded_output_filepath { From 2abda4753d2c93a447dafd8735ad602651ec60b3 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Fri, 30 Aug 2013 23:18:02 +0200 Subject: [PATCH 7/7] Removed MANIFEST since it's not used by Build.PL anymore --- MANIFEST | 140 -------------------------------------------------- MANIFEST.SKIP | 72 -------------------------- 2 files changed, 212 deletions(-) delete mode 100644 MANIFEST delete mode 100644 MANIFEST.SKIP diff --git a/MANIFEST b/MANIFEST deleted file mode 100644 index aa795023e..000000000 --- a/MANIFEST +++ /dev/null @@ -1,140 +0,0 @@ -Build.PL -lib/Slic3r.pm -lib/Slic3r/Config.pm -lib/Slic3r/ExPolygon.pm -lib/Slic3r/Extruder.pm -lib/Slic3r/ExtrusionLoop.pm -lib/Slic3r/ExtrusionPath.pm -lib/Slic3r/ExtrusionPath/Collection.pm -lib/Slic3r/Fill.pm -lib/Slic3r/Fill/ArchimedeanChords.pm -lib/Slic3r/Fill/Base.pm -lib/Slic3r/Fill/Concentric.pm -lib/Slic3r/Fill/Flowsnake.pm -lib/Slic3r/Fill/HilbertCurve.pm -lib/Slic3r/Fill/Honeycomb.pm -lib/Slic3r/Fill/Line.pm -lib/Slic3r/Fill/OctagramSpiral.pm -lib/Slic3r/Fill/PlanePath.pm -lib/Slic3r/Fill/Rectilinear.pm -lib/Slic3r/Flow.pm -lib/Slic3r/Format/AMF.pm -lib/Slic3r/Format/AMF/Parser.pm -lib/Slic3r/Format/OBJ.pm -lib/Slic3r/Format/STL.pm -lib/Slic3r/GCode.pm -lib/Slic3r/GCode/CoolingBuffer.pm -lib/Slic3r/GCode/Layer.pm -lib/Slic3r/GCode/MotionPlanner.pm -lib/Slic3r/GCode/Reader.pm -lib/Slic3r/GCode/SpiralVase.pm -lib/Slic3r/GCode/VibrationLimit.pm -lib/Slic3r/Geometry.pm -lib/Slic3r/Geometry/BoundingBox.pm -lib/Slic3r/Geometry/Clipper.pm -lib/Slic3r/GUI.pm -lib/Slic3r/GUI/AboutDialog.pm -lib/Slic3r/GUI/ConfigWizard.pm -lib/Slic3r/GUI/OptionsGroup.pm -lib/Slic3r/GUI/Plater.pm -lib/Slic3r/GUI/Plater/ObjectPreviewDialog.pm -lib/Slic3r/GUI/Plater/ObjectSettingsDialog.pm -lib/Slic3r/GUI/Preferences.pm -lib/Slic3r/GUI/PreviewCanvas.pm -lib/Slic3r/GUI/SkeinPanel.pm -lib/Slic3r/GUI/SimpleTab.pm -lib/Slic3r/GUI/Tab.pm -lib/Slic3r/Layer.pm -lib/Slic3r/Layer/Region.pm -lib/Slic3r/Line.pm -lib/Slic3r/Model.pm -lib/Slic3r/Point.pm -lib/Slic3r/Polygon.pm -lib/Slic3r/Polyline.pm -lib/Slic3r/Print.pm -lib/Slic3r/Print/Region.pm -lib/Slic3r/Print/Object.pm -lib/Slic3r/Surface.pm -lib/Slic3r/SVG.pm -lib/Slic3r/Test.pm -lib/Slic3r/Test/SectionCut.pm -lib/Slic3r/TriangleMesh.pm -MANIFEST This list of files -README.markdown -slic3r.pl -t/angles.t -t/arcs.t -t/clean_polylines.t -t/clipper.t -t/collinear.t -t/combineinfill.t -t/cooling.t -t/custom_gcode.t -t/dynamic.t -t/fill.t -t/freeze.t -t/gcode.t -t/geometry.t -t/layers.t -t/loops.t -t/perimeters.t -t/polyclip.t -t/print.t -t/retraction.t -t/serialize.t -t/shells.t -t/slice.t -t/skirt_brim.t -t/support.t -t/svg.t -t/vibrationlimit.t -utils/amf-to-stl.pl -utils/gcode_sectioncut.pl -utils/post-processing/filament-weight.pl -utils/post-processing/prowl-notification.pl -utils/post-processing/z-every-line.pl -utils/post-processing/decimate.pl -utils/post-processing/flowrate.pl -utils/split_stl.pl -utils/stl-to-amf.pl -utils/view-mesh.pl -utils/zsh/functions/_slic3r -utils/zsh/README.markdown -var/add.png -var/arrow_out.png -var/arrow_rotate_anticlockwise.png -var/arrow_rotate_clockwise.png -var/arrow_up.png -var/box.png -var/brick_add.png -var/brick_delete.png -var/brick_go.png -var/bricks.png -var/building.png -var/bullet_black.png -var/bullet_blue.png -var/bullet_white.png -var/cog.png -var/cog_go.png -var/cross.png -var/delete.png -var/disk.png -var/error.png -var/funnel.png -var/hourglass.png -var/layers.png -var/note.png -var/package.png -var/page_white_go.png -var/printer_empty.png -var/shading.png -var/shape_ungroup.png -var/Slic3r.icns -var/Slic3r.ico -var/Slic3r.png -var/Slic3r_128px.png -var/Slic3r_192px.png -var/Slic3r_192px_transparent.png -var/spool.png -var/time.png -var/wrench.png diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP deleted file mode 100644 index fae34e019..000000000 --- a/MANIFEST.SKIP +++ /dev/null @@ -1,72 +0,0 @@ - -#!start included /opt/local/lib/perl5/5.12.3/ExtUtils/MANIFEST.SKIP -# Avoid version control files. -\bRCS\b -\bCVS\b -\bSCCS\b -,v$ -\B\.svn\b -\B\.git\b -\B\.gitignore\b -\b_darcs\b -\B\.cvsignore$ - -# Avoid VMS specific MakeMaker generated files -\bDescrip.MMS$ -\bDESCRIP.MMS$ -\bdescrip.mms$ - -# Avoid Makemaker generated and utility files. -\bMANIFEST\.bak -\bMakefile$ -\bblib/ -\bMakeMaker-\d -\bpm_to_blib\.ts$ -\bpm_to_blib$ -\bblibdirs\.ts$ # 6.18 through 6.25 generated this - -# Avoid Module::Build generated and utility files. -\bBuild$ -\b_build/ -\bBuild.bat$ -\bBuild.COM$ -\bBUILD.COM$ -\bbuild.com$ - -# Avoid temp and backup files. -~$ -\.old$ -\#$ -\b\.# -\.bak$ -\.tmp$ -\.# -\.rej$ - -# Avoid OS-specific files/dirs -# Mac OSX metadata -\B\.DS_Store -# Mac OSX SMB mount metadata files -\B\._ - -# Avoid Devel::Cover files. -\bcover_db\b -#!end included /opt/local/lib/perl5/5.12.3/ExtUtils/MANIFEST.SKIP - -# Avoid configuration metadata file -^MYMETA\. - -# Avoid Module::Build generated and utility files. -\bBuild$ -\bBuild.bat$ -\b_build -\bBuild.COM$ -\bBUILD.COM$ -\bbuild.com$ -^MANIFEST\.SKIP - -# Avoid archives of this distribution -\bSlic3r-[\d\.\_]+ - -\.git$ -^\.DS_Store$