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/t
diff options
context:
space:
mode:
authorVojtech Bubnik <bubnikv@gmail.com>2022-05-04 16:05:56 +0300
committerVojtech Bubnik <bubnikv@gmail.com>2022-05-04 16:06:04 +0300
commita627614b58bbc6bde9cb1afabaebfbd629492723 (patch)
treef1a349935e2433fd26c4c59712262d65cfcbc425 /t
parent7380787b3a53252beb4650ccd1edb8ce2027a1db (diff)
Perl unit tests for perimeters and multi-material were rewritten to C++.
Perl binding was slimmed down, namely Clipper is no more linked by Perl.
Diffstat (limited to 't')
-rw-r--r--t/dynamic.t93
-rw-r--r--t/geometry.t9
-rw-r--r--t/multi.t221
-rw-r--r--t/perimeters.t444
-rw-r--r--t/slice.t152
-rw-r--r--t/support.t272
6 files changed, 1 insertions, 1190 deletions
diff --git a/t/dynamic.t b/t/dynamic.t
deleted file mode 100644
index 5d4d3ceb4..000000000
--- a/t/dynamic.t
+++ /dev/null
@@ -1,93 +0,0 @@
-use Test::More;
-use strict;
-use warnings;
-
-plan skip_all => 'variable-width paths are currently disabled';
-plan tests => 20;
-
-BEGIN {
- use FindBin;
- use lib "$FindBin::Bin/../lib";
- use local::lib "$FindBin::Bin/../local-lib";
-}
-
-use List::Util qw(first);
-use Slic3r;
-use Slic3r::Geometry qw(X Y scale epsilon);
-use Slic3r::Surface ':types';
-
-sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ }
-
-{
- my $square = Slic3r::ExPolygon->new([
- scale_points [0,0], [10,0], [10,10], [0,10],
- ]);
-
- my @offsets = @{$square->noncollapsing_offset_ex(- scale 5)};
- is scalar @offsets, 1, 'non-collapsing offset';
-}
-
-{
- local $Slic3r::Config = Slic3r::Config->new(
- perimeters => 3,
- );
- my $w = 0.7;
- my $perimeter_flow = Slic3r::Flow->new(
- nozzle_diameter => 0.5,
- layer_height => 0.4,
- width => $w,
- );
-
- my $print = Slic3r::Print->new;
- my $region = Slic3r::Print::Region->new(
- print => $print,
- flows => { perimeter => $perimeter_flow },
- );
- push @{$print->regions}, $region;
- my $object = Slic3r::Print::Object->new(
- print => $print,
- size => [1,1],
- );
- my $make_layer = sub {
- my ($width) = @_;
- my $layer = Slic3r::Layer->new(
- object => $object,
- id => 1,
- slices => [
- Slic3r::Surface->new(
- surface_type => S_TYPE_INTERNAL,
- expolygon => Slic3r::ExPolygon->new([ scale_points [0,0], [50,0], [50,$width], [0,$width] ]),
- ),
- ],
- thin_walls => [],
- );
- my $layerm = $layer->region(0);
- $layer->make_perimeters;
- return $layerm;
- };
-
- my %widths = (
- 1 * $w => { perimeters => 1, gaps => 0 },
- 1.3 * $w => { perimeters => 1, gaps => 1, gap_flow_spacing => $perimeter_flow->clone(width => 0.2 * $w)->spacing },
- 1.5 * $w => { perimeters => 1, gaps => 1, gap_flow_spacing => $perimeter_flow->clone(width => 0.5 * $w)->spacing },
- 2 * $w => { perimeters => 1, gaps => 1, gap_flow_spacing => $perimeter_flow->spacing },
- 2.5 * $w => { perimeters => 1, gaps => 1, gap_flow_spacing => $perimeter_flow->clone(width => 1.5 * $w)->spacing },
- 3 * $w => { perimeters => 2, gaps => 0 },
- 4 * $w => { perimeters => 2, gaps => 1, gap_flow_spacing => $perimeter_flow->spacing },
- );
-
- foreach my $width (sort keys %widths) {
- my $layerm = $make_layer->($width);
- is scalar @{$layerm->perimeters}, $widths{$width}{perimeters}, 'right number of perimeters';
- is scalar @{$layerm->thin_fills} ? 1 : 0, $widths{$width}{gaps},
- ($widths{$width}{gaps} ? 'gaps were filled' : 'no gaps detected'); # TODO: we should check the exact number of gaps, but we need a better medial axis algorithm
-
- my @gaps = map $_, @{$layerm->thin_fills};
- if (@gaps) {
- ok +(!first { abs($_->flow_spacing - $widths{$width}{gap_flow_spacing}) > epsilon } @gaps),
- 'flow spacing was dynamically adjusted';
- }
- }
-}
-
-__END__
diff --git a/t/geometry.t b/t/geometry.t
index 874dab987..12a1ca743 100644
--- a/t/geometry.t
+++ b/t/geometry.t
@@ -2,7 +2,7 @@ use Test::More;
use strict;
use warnings;
-plan tests => 27;
+plan tests => 26;
BEGIN {
use FindBin;
@@ -126,13 +126,6 @@ my $polygons = [
#==========================================================
{
- my $line = Slic3r::Line->new([10,10], [20,10]);
- is $line->grow(5)->[0]->area, Slic3r::Polygon->new([10,5], [20,5], [20,15], [10,15])->area, 'grow line';
-}
-
-#==========================================================
-
-{
# if chained_path() works correctly, these points should be joined with no diagonal paths
# (thus 26 units long)
my @points = map Slic3r::Point->new_scale(@$_), [26,26],[52,26],[0,26],[26,52],[26,0],[0,52],[52,52],[52,0];
diff --git a/t/multi.t b/t/multi.t
deleted file mode 100644
index e74a7a1a8..000000000
--- a/t/multi.t
+++ /dev/null
@@ -1,221 +0,0 @@
-use Test::More tests => 13;
-use strict;
-use warnings;
-
-BEGIN {
- use FindBin;
- use lib "$FindBin::Bin/../lib";
- use local::lib "$FindBin::Bin/../local-lib";
-}
-
-use List::Util qw(first);
-use Slic3r;
-use Slic3r::Geometry qw(scale convex_hull);
-use Slic3r::Geometry::Clipper qw(offset);
-use Slic3r::Test;
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
- $config->set('raft_layers', 2);
- $config->set('infill_extruder', 2);
- $config->set('solid_infill_extruder', 3);
- $config->set('support_material_extruder', 4);
- $config->set('ooze_prevention', 1);
- $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]);
- $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.
-
- my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
-
- my $tool = undef;
- my @tool_temp = (0,0,0,0);
- my @toolchange_points = ();
- my @extrusion_points = ();
- Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($cmd =~ /^T(\d+)/) {
- # ignore initial toolchange
- 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;
-
- push @toolchange_points, my $point = Slic3r::Point->new_scale($self->X, $self->Y);
- }
- $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};
- } elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
- push @extrusion_points, my $point = Slic3r::Point->new_scale($args->{X}, $args->{Y});
- $point->translate(map +scale($_), @{ $config->extruder_offset->[$tool] });
- }
- });
- my $convex_hull = convex_hull(\@extrusion_points);
-
- 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(
- "ooze_prevention_test.svg",
- no_arrows => 1,
- polygons => [$convex_hull],
- red_points => \@t,
- points => \@toolchange_points,
- );
- }
-
- # 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';
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
- $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';
-}
-
-{
- my $config = Slic3r::Config->new;
- $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
- $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;
- $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
- $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';
-}
-
-{
- my $model = stacked_cubes();
- my $lower_config = $model->get_material('lower')->config;
- my $upper_config = $model->get_material('upper')->config;
-
- $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);
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
- $config->set('fill_density', 0);
- $config->set('solid_infill_speed', 99);
- $config->set('top_solid_infill_speed', 99);
- $config->set('cooling', [ 0 ]); # for preventing speeds from being altered
- $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
- 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 (($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';
- }
- {
- $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';
- }
-}
-
-{
- my $model = stacked_cubes();
- my $object = $model->objects->[0];
-
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
- $config->set('layer_height', 0.4);
- $config->set('first_layer_height', $config->layer_height);
- $config->set('skirts', 0);
- my $print = Slic3r::Test::init_print($model, config => $config);
-
- 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';
-
- 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');
- $object->add_instance(offset => Slic3r::Pointf->new(0,0));
-
- return $model;
-}
-
-__END__
diff --git a/t/perimeters.t b/t/perimeters.t
deleted file mode 100644
index c4aef6e7e..000000000
--- a/t/perimeters.t
+++ /dev/null
@@ -1,444 +0,0 @@
-use Test::More tests => 59;
-use strict;
-use warnings;
-
-BEGIN {
- use FindBin;
- use lib "$FindBin::Bin/../lib";
- use local::lib "$FindBin::Bin/../local-lib";
-}
-
-use Slic3r::ExtrusionLoop ':roles';
-use Slic3r::ExtrusionPath ':roles';
-use List::Util qw(first);
-use Slic3r;
-use Slic3r::Flow ':roles';
-use Slic3r::Geometry qw(PI scale unscale);
-use Slic3r::Geometry::Clipper qw(union_ex diff);
-use Slic3r::Surface ':types';
-use Slic3r::Test;
-
-{
- my $flow = Slic3r::Flow->new(
- width => 1,
- height => 1,
- nozzle_diameter => 1,
- );
-
- my $config = Slic3r::Config->new;
- my $test = sub {
- my ($expolygons, %expected) = @_;
-
- my $slices = Slic3r::Surface::Collection->new;
- $slices->append(Slic3r::Surface->new(
- surface_type => S_TYPE_INTERNAL,
- expolygon => $_,
- )) for @$expolygons;
-
- my ($region_config, $object_config, $print_config, $loops, $gap_fill, $fill_surfaces);
- my $g = Slic3r::Layer::PerimeterGenerator->new(
- # input:
- $slices,
- 1, # layer height
- $flow,
- ($region_config = Slic3r::Config::PrintRegion->new),
- ($object_config = Slic3r::Config::PrintObject->new),
- ($print_config = Slic3r::Config::Print->new),
-
- # output:
- ($loops = Slic3r::ExtrusionPath::Collection->new),
- ($gap_fill = Slic3r::ExtrusionPath::Collection->new),
- ($fill_surfaces = Slic3r::Surface::Collection->new),
- );
- $g->config->apply_dynamic($config);
- $g->process;
-
- is scalar(@$loops),
- scalar(@$expolygons), 'expected number of collections';
- ok !defined(first { !$_->isa('Slic3r::ExtrusionPath::Collection') } @$loops),
- 'everything is returned as collections';
-
- my $flattened_loops = $loops->flatten;
- my @loops = @$flattened_loops;
- is scalar(@loops),
- $expected{total}, 'expected number of loops';
- is scalar(grep $_->role == EXTR_ROLE_EXTERNAL_PERIMETER, map @$_, @loops),
- $expected{external}, 'expected number of external loops';
- is_deeply [ map { ($_->role == EXTR_ROLE_EXTERNAL_PERIMETER) || 0 } map @$_, @loops ],
- $expected{ext_order}, 'expected external order';
- is scalar(grep $_->loop_role == EXTRL_ROLE_CONTOUR_INTERNAL_PERIMETER, @loops),
- $expected{cinternal}, 'expected number of internal contour loops';
- is scalar(grep $_->polygon->is_counter_clockwise, @loops),
- $expected{ccw}, 'expected number of ccw loops';
- is_deeply [ map $_->polygon->is_counter_clockwise, @loops ],
- $expected{ccw_order}, 'expected ccw/cw order';
-
- if ($expected{nesting}) {
- foreach my $nesting (@{ $expected{nesting} }) {
- for my $i (1..$#$nesting) {
- ok $loops[$nesting->[$i-1]]->polygon->contains_point($loops[$nesting->[$i]]->first_point),
- 'expected nesting order';
- }
- }
- }
- };
-
- $config->set('perimeters', 3);
- $test->(
- [
- Slic3r::ExPolygon->new(
- Slic3r::Polygon->new_scale([0,0], [100,0], [100,100], [0,100]),
- ),
- ],
- total => 3,
- external => 1,
- ext_order => [0,0,1],
- cinternal => 1,
- ccw => 3,
- ccw_order => [1,1,1],
- nesting => [ [2,1,0] ],
- );
- $test->(
- [
- Slic3r::ExPolygon->new(
- Slic3r::Polygon->new_scale([0,0], [100,0], [100,100], [0,100]),
- Slic3r::Polygon->new_scale([40,40], [40,60], [60,60], [60,40]),
- ),
- ],
- total => 6,
- external => 2,
- ext_order => [0,0,1,0,0,1],
- cinternal => 1,
- ccw => 3,
- ccw_order => [0,0,0,1,1,1],
- nesting => [ [5,4,3,0,1,2] ],
- );
- $test->(
- [
- Slic3r::ExPolygon->new(
- Slic3r::Polygon->new_scale([0,0], [200,0], [200,200], [0,200]),
- Slic3r::Polygon->new_scale([20,20], [20,180], [180,180], [180,20]),
- ),
- # nested:
- Slic3r::ExPolygon->new(
- Slic3r::Polygon->new_scale([50,50], [150,50], [150,150], [50,150]),
- Slic3r::Polygon->new_scale([80,80], [80,120], [120,120], [120,80]),
- ),
- ],
- total => 4*3,
- external => 4,
- ext_order => [0,0,1,0,0,1,0,0,1,0,0,1],
- cinternal => 2,
- ccw => 2*3,
- ccw_order => [0,0,0,1,1,1,0,0,0,1,1,1],
- );
-
- $config->set('perimeters', 2);
- $test->(
- [
- Slic3r::ExPolygon->new(
- Slic3r::Polygon->new_scale([0,0], [50,0], [50,50], [0,50]),
- Slic3r::Polygon->new_scale([7.5,7.5], [7.5,12.5], [12.5,12.5], [12.5,7.5]),
- Slic3r::Polygon->new_scale([7.5,17.5], [7.5,22.5], [12.5,22.5], [12.5,17.5]),
- Slic3r::Polygon->new_scale([7.5,27.5], [7.5,32.5], [12.5,32.5], [12.5,27.5]),
- Slic3r::Polygon->new_scale([7.5,37.5], [7.5,42.5], [12.5,42.5], [12.5,37.5]),
- Slic3r::Polygon->new_scale([17.5,7.5], [17.5,12.5], [22.5,12.5], [22.5,7.5]),
- ),
- ],
- total => 12,
- external => 6,
- ext_order => [0,1,0,1,0,1,0,1,0,1,0,1],
- cinternal => 1,
- ccw => 2,
- ccw_order => [0,0,0,0,0,0,0,0,0,0,1,1],
- nesting => [ [0,1],[2,3],[4,5],[6,7],[8,9] ],
- );
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('skirts', 0);
- $config->set('fill_density', 0);
- $config->set('perimeters', 3);
- $config->set('top_solid_layers', 0);
- $config->set('bottom_solid_layers', 0);
- $config->set('cooling', [ 0 ]); # to prevent speeds from being altered
- $config->set('first_layer_speed', '100%'); # to prevent speeds from being altered
-
- {
- my $print = Slic3r::Test::init_print('overhang', config => $config);
- my $has_cw_loops = 0;
- my $cur_loop;
- Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($info->{extruding} && $info->{dist_XY} > 0) {
- $cur_loop ||= [ [$self->X, $self->Y] ];
- push @$cur_loop, [ @$info{qw(new_X new_Y)} ];
- } elsif ($cmd ne 'M73') { # skips remaining time lines (M73)
- if ($cur_loop) {
- $has_cw_loops = 1 if Slic3r::Polygon->new(@$cur_loop)->is_clockwise;
- $cur_loop = undef;
- }
- }
- });
- ok !$has_cw_loops, 'all perimeters extruded ccw';
- }
-
- foreach my $model (qw(cube_with_hole cube_with_concave_hole)) {
- $config->set('external_perimeter_speed', 68);
- my $print = Slic3r::Test::init_print(
- $model,
- config => $config,
- duplicate => 2, # we test two copies to make sure ExtrusionLoop objects are not modified in-place (the second object would not detect cw loops and thus would calculate wrong inwards moves)
- );
- my $has_cw_loops = my $has_outwards_move = my $starts_on_convex_point = 0;
- my $cur_loop;
- my %external_loops = (); # print_z => count of external loops
- Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($info->{extruding} && $info->{dist_XY} > 0) {
- $cur_loop ||= [ [$self->X, $self->Y] ];
- push @$cur_loop, [ @$info{qw(new_X new_Y)} ];
- } elsif ($cmd ne 'M73') { # skips remaining time lines (M73)
- if ($cur_loop) {
- $has_cw_loops = 1 if Slic3r::Polygon->new_scale(@$cur_loop)->is_clockwise;
- if ($self->F == $config->external_perimeter_speed*60) {
- my $move_dest = Slic3r::Point->new_scale(@$info{qw(new_X new_Y)});
-
- # reset counter for second object
- $external_loops{$self->Z} = 0
- if defined($external_loops{$self->Z}) && $external_loops{$self->Z} == 2;
-
- $external_loops{$self->Z}++;
- my $is_contour = $external_loops{$self->Z} == 2;
- my $is_hole = $external_loops{$self->Z} == 1;
-
- my $loop = Slic3r::Polygon->new_scale(@$cur_loop);
- my $loop_contains_point = $loop->contains_point($move_dest);
- $has_outwards_move = 1
- if (!$loop_contains_point && $is_contour) # contour should include destination
- || ($loop_contains_point && $is_hole); # hole should not
-
- if ($model eq 'cube_with_concave_hole') {
- # check that loop starts at a concave vertex
- my $ccw_angle = $loop->[-2]->ccw($loop->first_point, $loop->[1]);
- my $convex = ($ccw_angle > PI); # whether the angle on the *right* side is convex
- $starts_on_convex_point = 1
- if ($convex && $is_contour) || (!$convex && $is_hole);
- }
- }
- $cur_loop = undef;
- }
- }
- });
- ok !$has_cw_loops, 'all perimeters extruded ccw';
- ok !$has_outwards_move, 'move inwards after completing external loop';
- ok !$starts_on_convex_point, 'loops start on concave point if any';
- }
-
- {
- $config->set('perimeters', 1);
- $config->set('perimeter_speed', 77);
- $config->set('external_perimeter_speed', 66);
- $config->set('bridge_speed', 99);
- $config->set('cooling', [ 1 ]);
- $config->set('fan_below_layer_time', [ 0 ]);
- $config->set('slowdown_below_layer_time', [ 0 ]);
- $config->set('bridge_fan_speed', [ 100 ]);
- $config->set('bridge_flow_ratio', 33); # arbitrary value
- $config->set('overhangs', 1);
- my $print = Slic3r::Test::init_print('overhang', config => $config);
- my %layer_speeds = (); # print Z => [ speeds ]
- my $fan_speed = 0;
- my $bridge_mm_per_mm = ($config->nozzle_diameter->[0]**2) / ($config->filament_diameter->[0]**2) * $config->bridge_flow_ratio;
- Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- $fan_speed = 0 if $cmd eq 'M107';
- $fan_speed = $args->{S} if $cmd eq 'M106';
- if ($info->{extruding} && $info->{dist_XY} > 0) {
- $layer_speeds{$self->Z} ||= {};
- $layer_speeds{$self->Z}{my $feedrate = $args->{F} // $self->F} = 1;
-
- fail 'wrong speed found'
- if $feedrate != $config->perimeter_speed*60
- && $feedrate != $config->external_perimeter_speed*60
- && $feedrate != $config->bridge_speed*60;
-
- if ($feedrate == $config->bridge_speed*60) {
- fail 'printing overhang but fan is not enabled or running at wrong speed'
- if $fan_speed != 255;
- my $mm_per_mm = $info->{dist_E} / $info->{dist_XY};
- fail 'wrong bridge flow' if abs($mm_per_mm - $bridge_mm_per_mm) > 0.01;
- } else {
- fail 'fan is running when not supposed to'
- if $fan_speed > 0;
- }
- }
- });
- is scalar(grep { keys %$_ > 1 } values %layer_speeds), 1,
- 'only overhang layer has more than one speed';
- }
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('skirts', 0);
- $config->set('perimeters', 3);
- $config->set('layer_height', 0.4);
- $config->set('first_layer_height', 0.35);
- $config->set('extra_perimeters', 1);
- $config->set('cooling', [ 0 ]); # to prevent speeds from being altered
- $config->set('first_layer_speed', '100%'); # to prevent speeds from being altered
- $config->set('perimeter_speed', 99);
- $config->set('external_perimeter_speed', 99);
- $config->set('small_perimeter_speed', 99);
- $config->set('thin_walls', 0);
-
- my $print = Slic3r::Test::init_print('ipadstand', config => $config);
- my %perimeters = (); # z => number of loops
- my $in_loop = 0;
- Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($info->{extruding} && $info->{dist_XY} > 0 && ($args->{F} // $self->F) == $config->perimeter_speed*60) {
- $perimeters{$self->Z}++ if !$in_loop;
- $in_loop = 1;
- } elsif ($cmd ne 'M73') { # skips remaining time lines (M73)
- $in_loop = 0;
- }
- });
- ok !(grep { $_ % $config->perimeters } values %perimeters), 'no superfluous extra perimeters';
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('nozzle_diameter', [0.4]);
- $config->set('perimeters', 2);
- $config->set('perimeter_extrusion_width', 0.4);
- $config->set('external_perimeter_extrusion_width', 0.4);
- $config->set('infill_extrusion_width', 0.53);
- $config->set('solid_infill_extrusion_width', 0.53);
-
- # we just need a pre-filled Print object
- my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
-
- # override a layer's slices
- my $expolygon = Slic3r::ExPolygon->new([[-71974463,-139999376],[-71731792,-139987456],[-71706544,-139985616],[-71682119,-139982639],[-71441248,-139946912],[-71417487,-139942895],[-71379384,-139933984],[-71141800,-139874480],[-71105247,-139862895],[-70873544,-139779984],[-70838592,-139765856],[-70614943,-139660064],[-70581783,-139643567],[-70368368,-139515680],[-70323751,-139487872],[-70122160,-139338352],[-70082399,-139306639],[-69894800,-139136624],[-69878679,-139121327],[-69707992,-138933008],[-69668575,-138887343],[-69518775,-138685359],[-69484336,-138631632],[-69356423,-138418207],[-69250040,-138193296],[-69220920,-138128976],[-69137992,-137897168],[-69126095,-137860255],[-69066568,-137622608],[-69057104,-137582511],[-69053079,-137558751],[-69017352,-137317872],[-69014392,-137293456],[-69012543,-137268207],[-68999369,-137000000],[-63999999,-137000000],[-63705947,-136985551],[-63654984,-136977984],[-63414731,-136942351],[-63364756,-136929840],[-63129151,-136870815],[-62851950,-136771631],[-62585807,-136645743],[-62377483,-136520895],[-62333291,-136494415],[-62291908,-136463728],[-62096819,-136319023],[-62058644,-136284432],[-61878676,-136121328],[-61680968,-135903184],[-61650275,-135861807],[-61505591,-135666719],[-61354239,-135414191],[-61332211,-135367615],[-61228359,-135148063],[-61129179,-134870847],[-61057639,-134585262],[-61014451,-134294047],[-61000000,-134000000],[-61000000,-107999999],[-61014451,-107705944],[-61057639,-107414736],[-61129179,-107129152],[-61228359,-106851953],[-61354239,-106585808],[-61505591,-106333288],[-61680967,-106096816],[-61878675,-105878680],[-62096820,-105680967],[-62138204,-105650279],[-62333292,-105505591],[-62585808,-105354239],[-62632384,-105332207],[-62851951,-105228360],[-62900463,-105211008],[-63129152,-105129183],[-63414731,-105057640],[-63705947,-105014448],[-63999999,-105000000],[-68999369,-105000000],[-69012543,-104731792],[-69014392,-104706544],[-69017352,-104682119],[-69053079,-104441248],[-69057104,-104417487],[-69066008,-104379383],[-69125528,-104141799],[-69137111,-104105248],[-69220007,-103873544],[-69234136,-103838591],[-69339920,-103614943],[-69356415,-103581784],[-69484328,-103368367],[-69512143,-103323752],[-69661647,-103122160],[-69693352,-103082399],[-69863383,-102894800],[-69878680,-102878679],[-70066999,-102707992],[-70112656,-102668576],[-70314648,-102518775],[-70368367,-102484336],[-70581783,-102356424],[-70806711,-102250040],[-70871040,-102220919],[-71102823,-102137992],[-71139752,-102126095],[-71377383,-102066568],[-71417487,-102057104],[-71441248,-102053079],[-71682119,-102017352],[-71706535,-102014392],[-71731784,-102012543],[-71974456,-102000624],[-71999999,-102000000],[-104000000,-102000000],[-104025536,-102000624],[-104268207,-102012543],[-104293455,-102014392],[-104317880,-102017352],[-104558751,-102053079],[-104582512,-102057104],[-104620616,-102066008],[-104858200,-102125528],[-104894751,-102137111],[-105126455,-102220007],[-105161408,-102234136],[-105385056,-102339920],[-105418215,-102356415],[-105631632,-102484328],[-105676247,-102512143],[-105877839,-102661647],[-105917600,-102693352],[-106105199,-102863383],[-106121320,-102878680],[-106292007,-103066999],[-106331424,-103112656],[-106481224,-103314648],[-106515663,-103368367],[-106643575,-103581783],[-106749959,-103806711],[-106779080,-103871040],[-106862007,-104102823],[-106873904,-104139752],[-106933431,-104377383],[-106942896,-104417487],[-106946920,-104441248],[-106982648,-104682119],[-106985607,-104706535],[-106987456,-104731784],[-107000630,-105000000],[-112000000,-105000000],[-112294056,-105014448],[-112585264,-105057640],[-112870848,-105129184],[-112919359,-105146535],[-113148048,-105228360],[-113194624,-105250392],[-113414191,-105354239],[-113666711,-105505591],[-113708095,-105536279],[-113903183,-105680967],[-114121320,-105878679],[-114319032,-106096816],[-114349720,-106138200],[-114494408,-106333288],[-114645760,-106585808],[-114667792,-106632384],[-114771640,-106851952],[-114788991,-106900463],[-114870815,-107129151],[-114942359,-107414735],[-114985551,-107705943],[-115000000,-107999999],[-115000000,-134000000],[-114985551,-134294048],[-114942359,-134585263],[-114870816,-134870847],[-114853464,-134919359],[-114771639,-135148064],[-114645759,-135414192],[-114494407,-135666720],[-114319031,-135903184],[-114121320,-136121327],[-114083144,-136155919],[-113903184,-136319023],[-113861799,-136349712],[-113666711,-136494416],[-113458383,-136619264],[-113414192,-136645743],[-113148049,-136771631],[-112870848,-136870815],[-112820872,-136883327],[-112585264,-136942351],[-112534303,-136949920],[-112294056,-136985551],[-112000000,-137000000],[-107000630,-137000000],[-106987456,-137268207],[-106985608,-137293440],[-106982647,-137317872],[-106946920,-137558751],[-106942896,-137582511],[-106933991,-137620624],[-106874471,-137858208],[-106862888,-137894751],[-106779992,-138126463],[-106765863,-138161424],[-106660080,-138385055],[-106643584,-138418223],[-106515671,-138631648],[-106487855,-138676256],[-106338352,-138877839],[-106306647,-138917600],[-106136616,-139105199],[-106121320,-139121328],[-105933000,-139291999],[-105887344,-139331407],[-105685351,-139481232],[-105631632,-139515663],[-105418216,-139643567],[-105193288,-139749951],[-105128959,-139779072],[-104897175,-139862016],[-104860247,-139873904],[-104622616,-139933423],[-104582511,-139942896],[-104558751,-139946912],[-104317880,-139982656],[-104293463,-139985616],[-104268216,-139987456],[-104025544,-139999376],[-104000000,-140000000],[-71999999,-140000000]],[[-105000000,-138000000],[-105000000,-104000000],[-71000000,-104000000],[-71000000,-138000000]],[[-69000000,-132000000],[-69000000,-110000000],[-64991180,-110000000],[-64991180,-132000000]],[[-111008824,-132000000],[-111008824,-110000000],[-107000000,-110000000],[-107000000,-132000000]]);
- my $object = $print->print->objects->[0];
- $object->slice;
- my $layer = $object->get_layer(1);
- my $layerm = $layer->regions->[0];
- $layerm->slices->clear;
- $layerm->slices->append(Slic3r::Surface->new(surface_type => S_TYPE_INTERNAL, expolygon => $expolygon));
-
- # make perimeters
- $layer->make_perimeters;
-
- # compute the covered area
- my $pflow = $layerm->flow(FLOW_ROLE_PERIMETER);
- my $iflow = $layerm->flow(FLOW_ROLE_INFILL);
- my $covered_by_perimeters = union_ex([
- (map @{$_->polygon->split_at_first_point->grow($pflow->scaled_width/2)}, map @$_, @{$layerm->perimeters}),
- ]);
- my $covered_by_infill = union_ex([
- (map $_->p, @{$layerm->fill_surfaces}),
- (map @{$_->polyline->grow($iflow->scaled_width/2)}, @{$layerm->thin_fills}),
- ]);
-
- # compute the non covered area
- my $non_covered = diff(
- [ map @{$_->expolygon}, @{$layerm->slices} ],
- [ map @$_, (@$covered_by_perimeters, @$covered_by_infill) ],
- );
-
- if (0) {
- printf "max non covered = %f\n", List::Util::max(map unscale unscale $_->area, @$non_covered);
- require "Slic3r/SVG.pm";
- Slic3r::SVG::output(
- "gaps.svg",
- expolygons => [ map $_->expolygon, @{$layerm->slices} ],
- red_expolygons => union_ex([ map @$_, (@$covered_by_perimeters, @$covered_by_infill) ]),
- green_expolygons => union_ex($non_covered),
- no_arrows => 1,
- polylines => [
- map $_->polygon->split_at_first_point, map @$_, @{$layerm->perimeters},
- ],
- );
- }
- ok !(defined first { $_->area > ($iflow->scaled_width**2) } @$non_covered), 'no gap between perimeters and infill';
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('skirts', 0);
- $config->set('perimeters', 3);
- $config->set('layer_height', 0.4);
- $config->set('bridge_speed', 99);
- $config->set('fill_density', 0); # to prevent bridging over sparse infill
- $config->set('overhangs', 1);
- $config->set('cooling', [ 0 ]); # to prevent speeds from being altered
- $config->set('first_layer_speed', '100%'); # to prevent speeds from being altered
-
- my $test = sub {
- my ($print) = @_;
- my %z_with_bridges = (); # z => 1
- Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($info->{extruding} && $info->{dist_XY} > 0) {
- $z_with_bridges{$self->Z} = 1 if ($args->{F} // $self->F) == $config->bridge_speed*60;
- }
- });
- return scalar keys %z_with_bridges;
- };
- ok $test->(Slic3r::Test::init_print('V', config => $config)) == 1,
- 'no overhangs printed with bridge speed'; # except for the two internal solid layers above void
- ok $test->(Slic3r::Test::init_print('V', config => $config, scale_xyz => [3,1,1])) > 2,
- 'overhangs printed with bridge speed';
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('seam_position', 'random');
- my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
- ok Slic3r::Test::gcode($print), 'successful generation of G-code with seam_position = random';
-}
-
-{
- my $test = sub {
- my ($model_name) = @_;
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('seam_position', 'aligned');
- $config->set('skirts', 0);
- $config->set('perimeters', 1);
- $config->set('fill_density', 0);
- $config->set('top_solid_layers', 0);
- $config->set('bottom_solid_layers', 0);
- $config->set('retract_layer_change', [0]);
-
- my $was_extruding = 0;
- my @seam_points = ();
- my $print = Slic3r::Test::init_print($model_name, config => $config);
- Slic3r::GCode::Reader->new->parse(my $gcode = Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($info->{extruding}) {
- if (!$was_extruding) {
- push @seam_points, Slic3r::Point->new_scale($self->X, $self->Y);
- }
- $was_extruding = 1;
- } elsif ($cmd ne 'M73') { # skips remaining time lines (M73)
- $was_extruding = 0;
- }
- });
- my @dist = map unscale($_), map $seam_points[$_]->distance_to($seam_points[$_+1]), 0..($#seam_points-1);
- ok !(defined first { $_ > 3 } @dist), 'seam is aligned';
- };
- $test->('20mm_cube');
- $test->('small_dorito');
-}
-
-__END__
diff --git a/t/slice.t b/t/slice.t
deleted file mode 100644
index 2f193aae3..000000000
--- a/t/slice.t
+++ /dev/null
@@ -1,152 +0,0 @@
-use Test::More;
-use strict;
-use warnings;
-
-plan skip_all => 'temporarily disabled';
-plan tests => 16;
-
-BEGIN {
- use FindBin;
- use lib "$FindBin::Bin/../lib";
- use local::lib "$FindBin::Bin/../local-lib";
-}
-
-# temporarily disable compilation errors due to constant not being exported anymore
-sub Slic3r::TriangleMesh::I_B {}
-sub Slic3r::TriangleMesh::I_FACET_EDGE {}
-sub Slic3r::TriangleMesh::FE_BOTTOM {
-sub Slic3r::TriangleMesh::FE_TOP {}}
-
-use Slic3r;
-use Slic3r::Geometry qw(X Y Z);
-
-my @lines;
-my $z = 20;
-my @points = ([3, 4], [8, 5], [1, 9]); # XY coordinates of the facet vertices
-
-# NOTE:
-# the first point of the intersection lines is replaced by -1 because TriangleMesh.pm
-# is saving memory and doesn't store point A anymore since it's not actually needed.
-
-# We disable this test because intersect_facet() now assumes we never feed a horizontal
-# facet to it.
-# is_deeply lines(20, 20, 20), [
-# [ -1, $points[1] ], # $points[0]
-# [ -1, $points[2] ], # $points[1]
-# [ -1, $points[0] ], # $points[2]
-# ], 'horizontal';
-
-is_deeply lines(22, 20, 20), [ [ -1, $points[2] ] ], 'lower edge on layer'; # $points[1]
-is_deeply lines(20, 20, 22), [ [ -1, $points[1] ] ], 'lower edge on layer'; # $points[0]
-is_deeply lines(20, 22, 20), [ [ -1, $points[0] ] ], 'lower edge on layer'; # $points[2]
-
-is_deeply lines(20, 20, 10), [ [ -1, $points[0] ] ], 'upper edge on layer'; # $points[1]
-is_deeply lines(10, 20, 20), [ [ -1, $points[1] ] ], 'upper edge on layer'; # $points[2]
-is_deeply lines(20, 10, 20), [ [ -1, $points[2] ] ], 'upper edge on layer'; # $points[0]
-
-is_deeply lines(20, 15, 10), [ ], 'upper vertex on layer';
-is_deeply lines(28, 20, 30), [ ], 'lower vertex on layer';
-
-{
- my @z = (24, 10, 16);
- is_deeply lines(@z), [
- [
- -1, # line_plane_intersection([ vertices(@z)->[0], vertices(@z)->[1] ]),
- line_plane_intersection([ vertices(@z)->[2], vertices(@z)->[0] ]),
- ]
- ], 'two edges intersect';
-}
-
-{
- my @z = (16, 24, 10);
- is_deeply lines(@z), [
- [
- -1, # line_plane_intersection([ vertices(@z)->[1], vertices(@z)->[2] ]),
- line_plane_intersection([ vertices(@z)->[0], vertices(@z)->[1] ]),
- ]
- ], 'two edges intersect';
-}
-
-{
- my @z = (10, 16, 24);
- is_deeply lines(@z), [
- [
- -1, # line_plane_intersection([ vertices(@z)->[2], vertices(@z)->[0] ]),
- line_plane_intersection([ vertices(@z)->[1], vertices(@z)->[2] ]),
- ]
- ], 'two edges intersect';
-}
-
-{
- my @z = (24, 10, 20);
- is_deeply lines(@z), [
- [
- -1, # line_plane_intersection([ vertices(@z)->[0], vertices(@z)->[1] ]),
- $points[2],
- ]
- ], 'one vertex on plane and one edge intersects';
-}
-
-{
- my @z = (10, 20, 24);
- is_deeply lines(@z), [
- [
- -1, # line_plane_intersection([ vertices(@z)->[2], vertices(@z)->[0] ]),
- $points[1],
- ]
- ], 'one vertex on plane and one edge intersects';
-}
-
-{
- my @z = (20, 24, 10);
- is_deeply lines(@z), [
- [
- -1, # line_plane_intersection([ vertices(@z)->[1], vertices(@z)->[2] ]),
- $points[0],
- ]
- ], 'one vertex on plane and one edge intersects';
-}
-
-my @lower = intersect(22, 20, 20);
-my @upper = intersect(20, 20, 10);
-is $lower[0][Slic3r::TriangleMesh::I_FACET_EDGE], Slic3r::TriangleMesh::FE_BOTTOM, 'bottom edge on layer';
-is $upper[0][Slic3r::TriangleMesh::I_FACET_EDGE], Slic3r::TriangleMesh::FE_TOP, 'upper edge on layer';
-
-my $mesh;
-
-sub intersect {
- $mesh = Slic3r::TriangleMesh->new(
- facets => [],
- vertices => [],
- );
- push @{$mesh->facets}, [ [0,0,0], @{vertices(@_)} ];
- $mesh->analyze;
- return map Slic3r::TriangleMesh::unpack_line($_), $mesh->intersect_facet($#{$mesh->facets}, $z);
-}
-
-sub vertices {
- push @{$mesh->vertices}, map [ @{$points[$_]}, $_[$_] ], 0..2;
- [ ($#{$mesh->vertices}-2) .. $#{$mesh->vertices} ]
-}
-
-sub lines {
- my @lines = intersect(@_);
- #$_->a->[X] = sprintf('%.0f', $_->a->[X]) for @lines;
- #$_->a->[Y] = sprintf('%.0f', $_->a->[Y]) for @lines;
- $_->[Slic3r::TriangleMesh::I_B][X] = sprintf('%.0f', $_->[Slic3r::TriangleMesh::I_B][X]) for @lines;
- $_->[Slic3r::TriangleMesh::I_B][Y] = sprintf('%.0f', $_->[Slic3r::TriangleMesh::I_B][Y]) for @lines;
- return [ map [ -1, $_->[Slic3r::TriangleMesh::I_B] ], @lines ];
-}
-
-sub line_plane_intersection {
- my ($line) = @_;
- @$line = map $mesh->vertices->[$_], @$line;
-
- return [
- map sprintf('%.0f', $_),
- map +($line->[1][$_] + ($line->[0][$_] - $line->[1][$_]) * ($z - $line->[1][Z]) / ($line->[0][Z] - $line->[1][Z])),
- (X,Y)
- ];
-}
-
-__END__
diff --git a/t/support.t b/t/support.t
deleted file mode 100644
index 0283df22b..000000000
--- a/t/support.t
+++ /dev/null
@@ -1,272 +0,0 @@
-use Test::More;
-use strict;
-use warnings;
-
-plan skip_all => 'temporarily disabled';
-plan tests => 27;
-
-BEGIN {
- use FindBin;
- use lib "$FindBin::Bin/../lib";
- use local::lib "$FindBin::Bin/../local-lib";
-}
-
-use List::Util qw(first);
-use Slic3r;
-use Slic3r::Flow ':roles';
-use Slic3r::Geometry qw(epsilon scale);
-use Slic3r::Geometry::Clipper qw(diff);
-use Slic3r::Test;
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('support_material', 1);
- my @contact_z = my @top_z = ();
-
- my $test = sub {
- my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
- my $object_config = $print->print->objects->[0]->config;
- my $flow = Slic3r::Flow->new_from_width(
- width => $object_config->support_material_extrusion_width || $object_config->extrusion_width,
- role => FLOW_ROLE_SUPPORT_MATERIAL,
- nozzle_diameter => $print->config->nozzle_diameter->[$object_config->support_material_extruder-1] // $print->config->nozzle_diameter->[0],
- layer_height => $object_config->layer_height,
- );
- my $support = Slic3r::Print::SupportMaterial->new(
- object_config => $print->print->objects->[0]->config,
- print_config => $print->print->config,
- flow => $flow,
- interface_flow => $flow,
- first_layer_flow => $flow,
- );
- my $support_z = $support->support_layers_z($print->print->objects->[0], \@contact_z, \@top_z, $config->layer_height);
- my $expected_top_spacing = $support->contact_distance($config->layer_height, $config->nozzle_diameter->[0]);
-
- is $support_z->[0], $config->first_layer_height,
- 'first layer height is honored';
- is scalar(grep { $support_z->[$_]-$support_z->[$_-1] <= 0 } 1..$#$support_z), 0,
- 'no null or negative support layers';
- is scalar(grep { $support_z->[$_]-$support_z->[$_-1] > $config->nozzle_diameter->[0] + epsilon } 1..$#$support_z), 0,
- 'no layers thicker than nozzle diameter';
-
- my $wrong_top_spacing = 0;
- foreach my $top_z (@top_z) {
- # find layer index of this top surface
- my $layer_id = first { abs($support_z->[$_] - $top_z) < epsilon } 0..$#$support_z;
-
- # check that first support layer above this top surface (or the next one) is spaced with nozzle diameter
- $wrong_top_spacing = 1
- if ($support_z->[$layer_id+1] - $support_z->[$layer_id]) != $expected_top_spacing
- && ($support_z->[$layer_id+2] - $support_z->[$layer_id]) != $expected_top_spacing;
- }
- ok !$wrong_top_spacing, 'layers above top surfaces are spaced correctly';
- };
-
- $config->set('layer_height', 0.2);
- $config->set('first_layer_height', 0.3);
- @contact_z = (1.9);
- @top_z = (1.1);
- $test->();
-
- $config->set('first_layer_height', 0.4);
- $test->();
-
- $config->set('layer_height', $config->nozzle_diameter->[0]);
- $test->();
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('raft_layers', 3);
- $config->set('brim_width', 0);
- $config->set('skirts', 0);
- $config->set('support_material_extruder', 2);
- $config->set('support_material_interface_extruder', 2);
- $config->set('layer_height', 0.4);
- $config->set('first_layer_height', 0.4);
- my $print = Slic3r::Test::init_print('overhang', config => $config);
- ok my $gcode = Slic3r::Test::gcode($print), 'no conflict between raft/support and brim';
-
- my $tool = 0;
- Slic3r::GCode::Reader->new->parse($gcode, sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($cmd =~ /^T(\d+)/) {
- $tool = $1;
- } elsif ($info->{extruding}) {
- if ($self->Z <= ($config->raft_layers * $config->layer_height)) {
- fail 'not extruding raft with support material extruder'
- if $tool != ($config->support_material_extruder-1);
- } else {
- fail 'support material exceeds raft layers'
- if $tool == $config->support_material_extruder-1;
- # TODO: we should test that full support is generated when we use raft too
- }
- }
- });
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('skirts', 0);
- $config->set('raft_layers', 3);
- $config->set('support_material_pattern', 'honeycomb');
- $config->set('support_material_extrusion_width', 0.6);
- $config->set('first_layer_extrusion_width', '100%');
- $config->set('bridge_speed', 99);
- $config->set('cooling', [ 0 ]); # prevent speed alteration
- $config->set('first_layer_speed', '100%'); # prevent speed alteration
- $config->set('start_gcode', ''); # prevent any unexpected Z move
- my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
-
- my $layer_id = -1; # so that first Z move sets this to 0
- my @raft = my @first_object_layer = ();
- my %first_object_layer_speeds = (); # F => 1
- Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($info->{extruding} && $info->{dist_XY} > 0) {
- if ($layer_id <= $config->raft_layers) {
- # this is a raft layer or the first object layer
- my $line = Slic3r::Line->new_scale([ $self->X, $self->Y ], [ $info->{new_X}, $info->{new_Y} ]);
- my @path = @{$line->grow(scale($config->support_material_extrusion_width/2))};
- if ($layer_id < $config->raft_layers) {
- # this is a raft layer
- push @raft, @path;
- } else {
- push @first_object_layer, @path;
- $first_object_layer_speeds{ $args->{F} // $self->F } = 1;
- }
- }
- } elsif ($cmd eq 'G1' && $info->{dist_Z} > 0) {
- $layer_id++;
- }
- });
-
- ok !@{diff(\@first_object_layer, \@raft)},
- 'first object layer is completely supported by raft';
- is scalar(keys %first_object_layer_speeds), 1,
- 'only one speed used in first object layer';
- ok +(keys %first_object_layer_speeds)[0] == $config->bridge_speed*60,
- 'bridge speed used in first object layer';
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('skirts', 0);
- $config->set('layer_height', 0.35);
- $config->set('first_layer_height', 0.3);
- $config->set('nozzle_diameter', [0.5]);
- $config->set('support_material_extruder', 2);
- $config->set('support_material_interface_extruder', 2);
-
- my $test = sub {
- my ($raft_layers) = @_;
- $config->set('raft_layers', $raft_layers);
- my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
- my %raft_z = (); # z => 1
- my $tool = undef;
- Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($cmd =~ /^T(\d+)/) {
- $tool = $1;
- } elsif ($info->{extruding} && $info->{dist_XY} > 0) {
- if ($tool == $config->support_material_extruder-1) {
- $raft_z{$self->Z} = 1;
- }
- }
- });
-
- is scalar(keys %raft_z), $config->raft_layers, 'correct number of raft layers is generated';
- };
-
- $test->(2);
- $test->(70);
-
- $config->set('layer_height', 0.4);
- $config->set('first_layer_height', 0.35);
- $test->(3);
- $test->(70);
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('brim_width', 0);
- $config->set('skirts', 0);
- $config->set('support_material', 1);
- $config->set('top_solid_layers', 0); # so that we don't have the internal bridge over infill
- $config->set('bridge_speed', 99);
- $config->set('cooling', [ 0 ]);
- $config->set('first_layer_speed', '100%');
-
- my $test = sub {
- my $print = Slic3r::Test::init_print('overhang', config => $config);
-
- my $has_bridge_speed = 0;
- Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($info->{extruding}) {
- if (($args->{F} // $self->F) == $config->bridge_speed*60) {
- $has_bridge_speed = 1;
- }
- }
- });
- return $has_bridge_speed;
- };
-
- $config->set('support_material_contact_distance', 0.2);
- ok $test->(), 'bridge speed is used when support_material_contact_distance > 0';
-
- $config->set('support_material_contact_distance', 0);
- ok !$test->(), 'bridge speed is not used when support_material_contact_distance == 0';
-
- $config->set('raft_layers', 5);
- $config->set('support_material_contact_distance', 0.2);
- ok $test->(), 'bridge speed is used when raft_layers > 0 and support_material_contact_distance > 0';
-
- $config->set('support_material_contact_distance', 0);
- ok !$test->(), 'bridge speed is not used when raft_layers > 0 and support_material_contact_distance == 0';
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('skirts', 0);
- $config->set('start_gcode', '');
- $config->set('raft_layers', 8);
- $config->set('nozzle_diameter', [0.4, 1]);
- $config->set('layer_height', 0.1);
- $config->set('first_layer_height', 0.8);
- $config->set('support_material_extruder', 2);
- $config->set('support_material_interface_extruder', 2);
- $config->set('support_material_contact_distance', 0);
- my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
- ok my $gcode = Slic3r::Test::gcode($print), 'first_layer_height is validated with support material extruder nozzle diameter when using raft layers';
-
- my $tool = undef;
- my @z = (0);
- my %layer_heights_by_tool = (); # tool => [ lh, lh... ]
- Slic3r::GCode::Reader->new->parse($gcode, sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($cmd =~ /^T(\d+)/) {
- $tool = $1;
- } elsif ($cmd eq 'G1' && exists $args->{Z} && $args->{Z} != $self->Z) {
- push @z, $args->{Z};
- } elsif ($info->{extruding} && $info->{dist_XY} > 0) {
- $layer_heights_by_tool{$tool} ||= [];
- push @{ $layer_heights_by_tool{$tool} }, $z[-1] - $z[-2];
- }
- });
-
- ok !defined(first { $_ > $config->nozzle_diameter->[0] + epsilon }
- @{ $layer_heights_by_tool{$config->perimeter_extruder-1} }),
- 'no object layer is thicker than nozzle diameter';
-
- ok !defined(first { abs($_ - $config->layer_height) < epsilon }
- @{ $layer_heights_by_tool{$config->support_material_extruder-1} }),
- 'no support material layer is as thin as object layers';
-}
-
-__END__