2014-05-15 17:22:41 +00:00
|
|
|
use Test::More tests => 13;
|
2013-09-18 23:29:34 +00:00
|
|
|
use strict;
|
|
|
|
use warnings;
|
|
|
|
|
|
|
|
BEGIN {
|
|
|
|
use FindBin;
|
|
|
|
use lib "$FindBin::Bin/../lib";
|
2017-08-18 07:58:50 +00:00
|
|
|
use local::lib "$FindBin::Bin/../local-lib";
|
2013-09-18 23:29:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
use List::Util qw(first);
|
|
|
|
use Slic3r;
|
2013-11-22 20:43:35 +00:00
|
|
|
use Slic3r::Geometry qw(scale convex_hull);
|
2014-05-15 17:22:41 +00:00
|
|
|
use Slic3r::Geometry::Clipper qw(offset);
|
2013-09-18 23:29:34 +00:00
|
|
|
use Slic3r::Test;
|
|
|
|
|
|
|
|
{
|
2017-10-27 16:52:35 +00:00
|
|
|
my $config = Slic3r::Config::new_from_defaults;
|
2018-03-28 08:16:04 +00:00
|
|
|
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
2013-11-15 14:52:11 +00:00
|
|
|
$config->set('raft_layers', 2);
|
2013-09-18 23:29:34 +00:00
|
|
|
$config->set('infill_extruder', 2);
|
2014-12-29 00:37:34 +00:00
|
|
|
$config->set('solid_infill_extruder', 3);
|
|
|
|
$config->set('support_material_extruder', 4);
|
2013-11-15 15:01:15 +00:00
|
|
|
$config->set('ooze_prevention', 1);
|
2014-12-29 00:37:34 +00:00
|
|
|
$config->set('extruder_offset', [ [0,0], [20,0], [0,20], [20,20] ]);
|
|
|
|
$config->set('temperature', [200, 180, 170, 160]);
|
|
|
|
$config->set('first_layer_temperature', [206, 186, 166, 156]);
|
2019-07-16 11:06:58 +00:00
|
|
|
$config->set('toolchange_gcode', 'T[next_extruder] ;toolchange'); # test that it doesn't crash when this is supplied
|
|
|
|
# Since July 2019, PrusaSlicer only emits automatic Tn command in case that the toolchange_gcode is empty
|
|
|
|
# The "T[next_extruder]" is therefore needed in this test.
|
2013-09-18 23:29:34 +00:00
|
|
|
|
|
|
|
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
|
|
|
|
|
|
|
my $tool = undef;
|
2014-12-29 00:37:34 +00:00
|
|
|
my @tool_temp = (0,0,0,0);
|
2013-09-19 08:44:29 +00:00
|
|
|
my @toolchange_points = ();
|
|
|
|
my @extrusion_points = ();
|
2013-09-18 23:29:34 +00:00
|
|
|
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
|
|
|
|
my ($self, $cmd, $args, $info) = @_;
|
|
|
|
|
|
|
|
if ($cmd =~ /^T(\d+)/) {
|
2014-12-29 00:37:34 +00:00
|
|
|
# ignore initial toolchange
|
2013-09-18 23:29:34 +00:00
|
|
|
if (defined $tool) {
|
|
|
|
my $expected_temp = $self->Z == ($config->get_value('first_layer_height') + $config->z_offset)
|
|
|
|
? $config->first_layer_temperature->[$tool]
|
|
|
|
: $config->temperature->[$tool];
|
|
|
|
die 'standby temperature was not set before toolchange'
|
|
|
|
if $tool_temp[$tool] != $expected_temp + $config->standby_temperature_delta;
|
2014-05-15 17:22:41 +00:00
|
|
|
|
2014-12-29 00:37:34 +00:00
|
|
|
push @toolchange_points, my $point = Slic3r::Point->new_scale($self->X, $self->Y);
|
2013-09-18 23:29:34 +00:00
|
|
|
}
|
|
|
|
$tool = $1;
|
|
|
|
} elsif ($cmd eq 'M104' || $cmd eq 'M109') {
|
|
|
|
my $t = $args->{T} // $tool;
|
|
|
|
if ($tool_temp[$t] == 0) {
|
|
|
|
fail 'initial temperature is not equal to first layer temperature + standby delta'
|
|
|
|
unless $args->{S} == $config->first_layer_temperature->[$t] + $config->standby_temperature_delta;
|
|
|
|
}
|
|
|
|
$tool_temp[$t] = $args->{S};
|
2013-09-19 08:44:29 +00:00
|
|
|
} elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
|
2013-11-15 14:52:11 +00:00
|
|
|
push @extrusion_points, my $point = Slic3r::Point->new_scale($args->{X}, $args->{Y});
|
2014-12-29 00:37:34 +00:00
|
|
|
$point->translate(map +scale($_), @{ $config->extruder_offset->[$tool] });
|
2013-09-18 23:29:34 +00:00
|
|
|
}
|
|
|
|
});
|
2013-11-22 20:43:35 +00:00
|
|
|
my $convex_hull = convex_hull(\@extrusion_points);
|
2014-12-29 00:37:34 +00:00
|
|
|
|
|
|
|
my @t = ();
|
|
|
|
foreach my $point (@toolchange_points) {
|
|
|
|
foreach my $offset (@{$config->extruder_offset}) {
|
|
|
|
push @t, my $p = $point->clone;
|
|
|
|
$p->translate(map +scale($_), @$offset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ok !(defined first { $convex_hull->contains_point($_) } @t), 'all nozzles are outside skirt at toolchange';
|
|
|
|
|
|
|
|
if (0) {
|
|
|
|
require "Slic3r/SVG.pm";
|
|
|
|
Slic3r::SVG::output(
|
2015-01-19 14:30:34 +00:00
|
|
|
"ooze_prevention_test.svg",
|
2014-12-29 00:37:34 +00:00
|
|
|
no_arrows => 1,
|
|
|
|
polygons => [$convex_hull],
|
|
|
|
red_points => \@t,
|
2015-01-19 14:30:34 +00:00
|
|
|
points => \@toolchange_points,
|
2014-12-29 00:37:34 +00:00
|
|
|
);
|
|
|
|
}
|
2014-05-15 17:22:41 +00:00
|
|
|
|
|
|
|
# offset the skirt by the maximum displacement between extruders plus a safety extra margin
|
|
|
|
my $delta = scale(20 * sqrt(2) + 1);
|
|
|
|
my $outer_convex_hull = offset([$convex_hull], +$delta)->[0];
|
|
|
|
ok !(defined first { !$outer_convex_hull->contains_point($_) } @toolchange_points), 'all toolchanges happen within expected area';
|
2013-09-18 23:29:34 +00:00
|
|
|
}
|
|
|
|
|
2014-02-26 10:55:36 +00:00
|
|
|
{
|
2017-10-27 16:52:35 +00:00
|
|
|
my $config = Slic3r::Config::new_from_defaults;
|
2018-03-28 08:16:04 +00:00
|
|
|
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
2014-02-26 10:55:36 +00:00
|
|
|
$config->set('support_material_extruder', 3);
|
|
|
|
|
|
|
|
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
|
|
|
ok Slic3r::Test::gcode($print), 'no errors when using non-consecutive extruders';
|
|
|
|
}
|
|
|
|
|
2014-04-05 08:09:05 +00:00
|
|
|
{
|
2014-04-05 08:18:00 +00:00
|
|
|
my $config = Slic3r::Config->new;
|
2018-03-28 08:16:04 +00:00
|
|
|
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
2014-04-05 08:18:00 +00:00
|
|
|
$config->set('extruder', 2);
|
|
|
|
|
|
|
|
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
|
|
|
like Slic3r::Test::gcode($print), qr/ T1/, 'extruder shortcut';
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
my $config = Slic3r::Config->new;
|
2018-03-28 08:16:04 +00:00
|
|
|
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
2014-04-05 08:09:05 +00:00
|
|
|
$config->set('perimeter_extruder', 2);
|
|
|
|
$config->set('infill_extruder', 2);
|
|
|
|
$config->set('support_material_extruder', 2);
|
|
|
|
$config->set('support_material_interface_extruder', 2);
|
|
|
|
|
|
|
|
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
|
|
|
ok Slic3r::Test::gcode($print), 'no errors when using multiple skirts with a single, non-zero, extruder';
|
|
|
|
}
|
|
|
|
|
2014-03-24 22:44:47 +00:00
|
|
|
{
|
2014-04-19 09:43:41 +00:00
|
|
|
my $model = stacked_cubes();
|
|
|
|
my $lower_config = $model->get_material('lower')->config;
|
|
|
|
my $upper_config = $model->get_material('upper')->config;
|
2014-03-24 22:44:47 +00:00
|
|
|
|
|
|
|
$lower_config->set('extruder', 1);
|
|
|
|
$lower_config->set('bottom_solid_layers', 0);
|
|
|
|
$lower_config->set('top_solid_layers', 1);
|
|
|
|
$upper_config->set('extruder', 2);
|
|
|
|
$upper_config->set('bottom_solid_layers', 1);
|
|
|
|
$upper_config->set('top_solid_layers', 0);
|
2017-10-27 16:52:35 +00:00
|
|
|
my $config = Slic3r::Config::new_from_defaults;
|
2018-03-28 08:16:04 +00:00
|
|
|
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
2014-03-24 22:44:47 +00:00
|
|
|
$config->set('fill_density', 0);
|
|
|
|
$config->set('solid_infill_speed', 99);
|
|
|
|
$config->set('top_solid_infill_speed', 99);
|
2017-06-21 14:15:39 +00:00
|
|
|
$config->set('cooling', [ 0 ]); # for preventing speeds from being altered
|
2014-03-24 22:44:47 +00:00
|
|
|
$config->set('first_layer_speed', '100%'); # for preventing speeds from being altered
|
|
|
|
|
|
|
|
my $test = sub {
|
|
|
|
my $print = Slic3r::Test::init_print($model, config => $config);
|
|
|
|
my $tool = undef;
|
|
|
|
my %T0_shells = my %T1_shells = (); # Z => 1
|
2014-03-25 00:11:28 +00:00
|
|
|
Slic3r::GCode::Reader->new->parse(my $gcode = Slic3r::Test::gcode($print), sub {
|
2014-03-24 22:44:47 +00:00
|
|
|
my ($self, $cmd, $args, $info) = @_;
|
|
|
|
|
|
|
|
if ($cmd =~ /^T(\d+)/) {
|
|
|
|
$tool = $1;
|
|
|
|
} elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
|
|
|
|
if (($args->{F} // $self->F) == $config->solid_infill_speed*60) {
|
|
|
|
if ($tool == 0) {
|
|
|
|
$T0_shells{$self->Z} = 1;
|
|
|
|
} elsif ($tool == 1) {
|
|
|
|
$T1_shells{$self->Z} = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return [ sort keys %T0_shells ], [ sort keys %T1_shells ];
|
|
|
|
};
|
|
|
|
|
|
|
|
{
|
|
|
|
my ($t0, $t1) = $test->();
|
|
|
|
is scalar(@$t0), 0, 'no interface shells';
|
|
|
|
is scalar(@$t1), 0, 'no interface shells';
|
|
|
|
}
|
2014-03-25 00:11:28 +00:00
|
|
|
{
|
|
|
|
$config->set('interface_shells', 1);
|
|
|
|
my ($t0, $t1) = $test->();
|
|
|
|
is scalar(@$t0), $lower_config->top_solid_layers, 'top interface shells';
|
|
|
|
is scalar(@$t1), $upper_config->bottom_solid_layers, 'bottom interface shells';
|
|
|
|
}
|
2014-03-24 22:44:47 +00:00
|
|
|
}
|
|
|
|
|
2014-04-19 09:43:41 +00:00
|
|
|
{
|
|
|
|
my $model = stacked_cubes();
|
2015-01-17 09:36:42 +00:00
|
|
|
my $object = $model->objects->[0];
|
2014-04-19 09:43:41 +00:00
|
|
|
|
2017-10-27 16:52:35 +00:00
|
|
|
my $config = Slic3r::Config::new_from_defaults;
|
2018-03-28 08:16:04 +00:00
|
|
|
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
2014-07-26 12:15:53 +00:00
|
|
|
$config->set('layer_height', 0.4);
|
2021-04-21 13:38:00 +00:00
|
|
|
$config->set('first_layer_height', $config->layer_height);
|
2014-04-19 09:43:41 +00:00
|
|
|
$config->set('skirts', 0);
|
|
|
|
my $print = Slic3r::Test::init_print($model, config => $config);
|
|
|
|
|
2015-01-17 09:36:42 +00:00
|
|
|
is $object->volumes->[0]->config->extruder, 1, 'auto_assign_extruders() assigned correct extruder to first volume';
|
|
|
|
is $object->volumes->[1]->config->extruder, 2, 'auto_assign_extruders() assigned correct extruder to second volume';
|
2014-04-19 09:43:41 +00:00
|
|
|
|
|
|
|
my $tool = undef;
|
|
|
|
my %T0 = my %T1 = (); # Z => 1
|
|
|
|
Slic3r::GCode::Reader->new->parse(my $gcode = Slic3r::Test::gcode($print), sub {
|
|
|
|
my ($self, $cmd, $args, $info) = @_;
|
|
|
|
|
|
|
|
if ($cmd =~ /^T(\d+)/) {
|
|
|
|
$tool = $1;
|
|
|
|
} elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
|
|
|
|
if ($tool == 0) {
|
|
|
|
$T0{$self->Z} = 1;
|
|
|
|
} elsif ($tool == 1) {
|
|
|
|
$T1{$self->Z} = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
ok !(defined first { $_ > 20 } keys %T0), 'T0 is never used for upper object';
|
|
|
|
ok !(defined first { $_ < 20 } keys %T1), 'T1 is never used for lower object';
|
|
|
|
}
|
|
|
|
|
|
|
|
sub stacked_cubes {
|
|
|
|
my $model = Slic3r::Model->new;
|
|
|
|
my $object = $model->add_object;
|
|
|
|
$object->add_volume(mesh => Slic3r::Test::mesh('20mm_cube'), material_id => 'lower');
|
|
|
|
$object->add_volume(mesh => Slic3r::Test::mesh('20mm_cube', translate => [0,0,20]), material_id => 'upper');
|
2014-05-09 12:24:35 +00:00
|
|
|
$object->add_instance(offset => Slic3r::Pointf->new(0,0));
|
2014-04-19 09:43:41 +00:00
|
|
|
|
|
|
|
return $model;
|
|
|
|
}
|
|
|
|
|
2013-09-18 23:29:34 +00:00
|
|
|
__END__
|