Moved vibration limit to its own G-code filter
This commit is contained in:
parent
fb763b0187
commit
73c05a6092
18 changed files with 103 additions and 70 deletions
1
MANIFEST
1
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
|
||||
|
|
|
@ -55,6 +55,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;
|
||||
|
|
|
@ -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 {
|
||||
|
@ -584,7 +580,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 if $self->config->vibration_limit != 0;
|
||||
$self->last_pos($point->clone);
|
||||
}
|
||||
if (defined $z && (!defined $self->z || $z != $self->z)) {
|
||||
|
@ -755,39 +750,4 @@ sub set_bed_temperature {
|
|||
return $gcode;
|
||||
}
|
||||
|
||||
# http://hydraraptor.blogspot.it/2010/12/frequency-limit.html
|
||||
sub _limit_frequency {
|
||||
my ($self, $point) = @_;
|
||||
|
||||
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;
|
||||
|
|
|
@ -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) = @_;
|
||||
|
@ -162,6 +171,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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}) {
|
||||
|
|
64
lib/Slic3r/GCode/VibrationLimit.pm
Normal file
64
lib/Slic3r/GCode/VibrationLimit.pm
Normal file
|
@ -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;
|
|
@ -15,11 +15,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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
2
t/fill.t
2
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};
|
||||
});
|
||||
|
|
|
@ -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}) {
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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+)/) {
|
||||
|
|
|
@ -27,7 +27,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) {
|
||||
|
@ -74,7 +74,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
|
||||
|
@ -106,7 +106,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;
|
||||
|
@ -132,7 +132,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};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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+)/) {
|
||||
|
|
|
@ -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]$/) {
|
||||
|
|
|
@ -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}) {
|
||||
|
|
Loading…
Reference in a new issue