From 49fbe989109843ad3a2cbc25bcd32a65ec4dfcd3 Mon Sep 17 00:00:00 2001 From: Samir55 Date: Sun, 15 Jul 2018 03:42:50 +0200 Subject: [PATCH] Fixing bugs. --- src/test/libslic3r/test_support_material.cpp | 209 +++++-- t/support.t | 560 +++++++++---------- xs/src/libslic3r/SupportMaterial.cpp | 62 +- xs/src/libslic3r/SupportMaterial.hpp | 1 - 4 files changed, 463 insertions(+), 369 deletions(-) diff --git a/src/test/libslic3r/test_support_material.cpp b/src/test/libslic3r/test_support_material.cpp index 13fbd6d3e..0222ffa07 100644 --- a/src/test/libslic3r/test_support_material.cpp +++ b/src/test/libslic3r/test_support_material.cpp @@ -10,6 +10,8 @@ using namespace std; using namespace Slic3r; +void test_1_check(Print &print, bool &a, bool &b, bool &c, bool &d); + // Testing supports material member functions. TEST_CASE("", "") { @@ -42,6 +44,41 @@ TEST_CASE("", "") } +TEST_CASE("SupportMaterial: forced support is generated", "") +{ + // Create a mesh & modelObject. + TriangleMesh mesh = TriangleMesh::make_cube(20, 20, 20); + + Model model = Model(); + ModelObject *object = model.add_object(); + object->add_volume(mesh); + model.add_default_instances(); + model.align_instances_to_origin(); + + Print print = Print(); + + vector contact_z = {1.9}; + vector top_z = {1.1}; + print.default_object_config.support_material_enforce_layers = 100; + print.default_object_config.support_material = 0; + print.default_object_config.layer_height = 0.2; + print.default_object_config.set_deserialize("first_layer_height", "0.3"); + + print.add_model_object(model.objects[0]); + print.objects.front()->_slice(); + + SupportMaterial *support = print.objects.front()->_support_material(); + auto support_z = support->support_layers_z(contact_z, top_z, print.default_object_config.layer_height); + + bool check = true; + for (int i = 1; i < support_z.size(); i++) { + if (support_z[i] - support_z[i - 1] <= 0) + check = false; + } + + REQUIRE(check == true); +} + SCENARIO("SupportMaterial: support_layers_z and contact_distance") { GIVEN("A print object having one modelObject") { @@ -57,76 +94,136 @@ SCENARIO("SupportMaterial: support_layers_z and contact_distance") // Align to origin. model.align_instances_to_origin(); - // Create Print. - Print print = Print(); - print.default_object_config.set_deserialize("support_material", "1"); - - vector contact_z = {1.9}; - vector top_z = {1.1}; - - WHEN("Layer height = 0.2 and, first layer height = 0.3") { - + WHEN("First layer height = 0.4") { + // Create Print. + Print print = Print(); + print.default_object_config.set_deserialize("support_material", "1"); print.default_object_config.set_deserialize("layer_height", "0.2"); - print.default_object_config.set_deserialize("first_layer_height", "0.3"); + print.default_object_config.set_deserialize("first_layer_height", "0.4"); print.add_model_object(model.objects[0]); print.objects.front()->_slice(); + bool a, b, c, d; - SupportMaterial *support = print.objects.front()->_support_material(); - - vector - support_z = support->support_layers_z(contact_z, top_z, print.default_object_config.layer_height.value); - + test_1_check(print, a, b, c, d); THEN("First layer height is honored") { - REQUIRE((support_z[0] == print.default_object_config.first_layer_height.value)); + REQUIRE(a == true); } - THEN("No null or negative support layers") { - bool check = true; - for (size_t i = 1; i < support_z.size(); ++i) - if (support_z[i] - support_z[i - 1] <= 0) check = false; - REQUIRE(check == true); + REQUIRE(b == true); } - THEN("No layers thicker than nozzle diameter") { - bool check = true; - for (size_t i = 1; i < support_z.size(); ++i) - if (support_z[i] - support_z[i - 1] > print.config.nozzle_diameter.get_at(0) + EPSILON) - check = false; - REQUIRE(check == true); + REQUIRE(c == true); } - THEN("Layers above top surfaces are spaced correctly") { - coordf_t expected_top_spacing = support - ->contact_distance(print.default_object_config.layer_height, - print.config.nozzle_diameter.get_at(0)); - - bool wrong_top_spacing = 0; - for (coordf_t top_z_el : top_z) { - // find layer index of this top surface. - size_t layer_id = -1; - for (size_t i = 0; i < support_z.size(); i++) { - if (abs(support_z[i] - top_z_el) < EPSILON) { - layer_id = i; - i = static_cast(support_z.size()); - } - } - - // check that first support layer above this top surface (or the next one) is spaced with nozzle diameter - if (abs(support_z[layer_id + 1] - support_z[layer_id] - expected_top_spacing) > EPSILON - && abs(support_z[layer_id + 2] - support_z[layer_id] - expected_top_spacing) > EPSILON) { - wrong_top_spacing = 1; - } - REQUIRE(!wrong_top_spacing); - } + REQUIRE(d == true); } } -// /* Test Also with this -// $config->set('first_layer_height', 0.4); -// $test->(); +// WHEN("Layer height = 0.2 and, first layer height = 0.3") { +// print.default_object_config.set_deserialize("layer_height", "0.2"); +// print.default_object_config.set_deserialize("first_layer_height", "0.3"); +// print.add_model_object(model.objects[0]); +// print.objects.front()->_slice(); +// bool a, b, c, d; // -// $config->set('layer_height', $config->nozzle_diameter->[0]); -// $test->(); -// */ +// test_1_check(print, a, b, c, d); +// THEN("First layer height is honored") { +// REQUIRE(a == true); +// } +// THEN("No null or negative support layers") { +// REQUIRE(b == true); +// } +// THEN("No layers thicker than nozzle diameter") { +// REQUIRE(c == true); +// } +// THEN("Layers above top surfaces are spaced correctly") { +// REQUIRE(d == true); +// } +// } +// +// +// WHEN("Layer height = nozzle_diameter[0]") { +// print.default_object_config.set_deserialize("layer_height", "0.2"); +// print.default_object_config.set_deserialize("first_layer_height", "0.3"); +// print.add_model_object(model.objects[0]); +// print.objects.front()->_slice(); +// bool a, b, c, d; +// +// test_1_check(print, a, b, c, d); +// THEN("First layer height is honored") { +// REQUIRE(a == true); +// } +// THEN("No null or negative support layers") { +// REQUIRE(b == true); +// } +// THEN("No layers thicker than nozzle diameter") { +// REQUIRE(c == true); +// } +// THEN("Layers above top surfaces are spaced correctly") { +// REQUIRE(d == true); +// } +// } } } + +SCENARIO("SupportMaterial: Checking bridge speed") { + // Create a mesh & modelObject. + TriangleMesh mesh = TriangleMesh::make_cube(20, 20, 20); + + Model model = Model(); + ModelObject *object = model.add_object(); + object->add_volume(mesh); + model.add_default_instances(); + model.align_instances_to_origin(); + + Print print = Print(); +} + +void test_1_check(Print &print, bool &a, bool &b, bool &c, bool &d) +{ + vector contact_z = {1.9}; + vector top_z = {1.1}; + + SupportMaterial *support = print.objects.front()->_support_material(); + + vector + support_z = support->support_layers_z(contact_z, top_z, print.default_object_config.layer_height); +for(auto el: support_z) + cout << el << endl; + cout << endl; + + a = (support_z[0] == print.default_object_config.first_layer_height.value); + + b = true; + for (size_t i = 1; i < support_z.size(); ++i) + if (support_z[i] - support_z[i - 1] <= 0) b = false; + + + c = true; + for (size_t i = 1; i < support_z.size(); ++i) + if (support_z[i] - support_z[i - 1] > print.config.nozzle_diameter.get_at(0) + EPSILON) + c = false; + + coordf_t expected_top_spacing = support + ->contact_distance(print.default_object_config.layer_height, + print.config.nozzle_diameter.get_at(0)); + + bool wrong_top_spacing = 0; + for (coordf_t top_z_el : top_z) { + // find layer index of this top surface. + size_t layer_id = -1; + for (size_t i = 0; i < support_z.size(); i++) { + if (abs(support_z[i] - top_z_el) < EPSILON) { + layer_id = i; + i = static_cast(support_z.size()); + } + } + + // check that first support layer above this top surface (or the next one) is spaced with nozzle diameter + if (abs(support_z[layer_id + 1] - support_z[layer_id] - expected_top_spacing) > EPSILON + && abs(support_z[layer_id + 2] - support_z[layer_id] - expected_top_spacing) > EPSILON) { + wrong_top_spacing = 1; + } + } + d = !wrong_top_spacing; +} diff --git a/t/support.t b/t/support.t index 50f4d53fa..61d1416fa 100644 --- a/t/support.t +++ b/t/support.t @@ -1,4 +1,4 @@ -use Test::More tests => 29; +use Test::More tests => 12; use strict; use warnings; @@ -7,7 +7,7 @@ BEGIN { use lib "$FindBin::Bin/../lib"; use local::lib "$FindBin::Bin/../local-lib"; } - +use Data::Dumper; use List::Util qw(first); use Slic3r; use Slic3r::Geometry qw(epsilon scale PI); @@ -31,7 +31,7 @@ use Slic3r::Test; ); my $support_z = $support->support_layers_z(\@contact_z, \@top_z, $config->layer_height); my $expected_top_spacing = $support->contact_distance($config->layer_height, $config->nozzle_diameter->[0]); - + diag(Dumper($support_z)); 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, @@ -64,281 +64,281 @@ use Slic3r::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('layer_height', 0.2); - $config->set('skirts', 0); - $config->set('raft_layers', 5); - $config->set('support_material_pattern', 'rectilinear'); - $config->set('support_material_extrusion_width', 0.4); - $config->set('support_material_interface_extrusion_width', 0.6); - $config->set('support_material_interface_layers', 2); - $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; - my $success = 1; - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - if ($info->{extruding} && $info->{dist_XY} > 0) { - # this is a raft layer - if (($layer_id < $config->raft_layers) && ($layer_id > 0)) { - my $width; - my $support_layer_height = $config->nozzle_diameter->[0] * 0.75; - - # support layer - if ($config->raft_layers - $config->support_material_interface_layers > $layer_id) { - $width = $config->support_material_extrusion_width; - } - # interface layer - else { - $width = $config->support_material_interface_extrusion_width; - } - my $expected_E_per_mm3 = 4 / (($config->filament_diameter->[0]**2) * PI); - my $expected_mm3_per_mm = $width * $support_layer_height + ($support_layer_height**2) / 4.0 * (PI-4.0); - my $expected_e_per_mm = $expected_E_per_mm3 * $expected_mm3_per_mm; - - my $e_per_mm = ($info->{dist_E} / $info->{dist_XY});; - - my $diff = abs($e_per_mm - $expected_e_per_mm); - - if ($diff > 0.001) { - $success = 0; - } - } - } elsif ($cmd eq 'G1' && $info->{dist_Z} > 0) { - $layer_id++; - } - }); - - ok $success, - 'support material interface extrusion width is used for interfaces'; -} - -{ - 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'; -} - -{ - my $config = Slic3r::Config->new_from_defaults; - $config->set('support_material_enforce_layers', 100); - $config->set('support_material', 0); - my @contact_z = my @top_z = (); - - my $test = sub { - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $flow = $print->print->objects->[0]->support_material_flow; - 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(\@contact_z, \@top_z, $config->layer_height); - - is scalar(grep { $support_z->[$_]-$support_z->[$_-1] <= 0 } 1..$#$support_z), 0, - 'forced support is generated'; - - }; - $config->set('layer_height', 0.2); - $config->set('first_layer_height', 0.3); - @contact_z = (1.9); - @top_z = (1.1); - $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('layer_height', 0.2); +# $config->set('skirts', 0); +# $config->set('raft_layers', 5); +# $config->set('support_material_pattern', 'rectilinear'); +# $config->set('support_material_extrusion_width', 0.4); +# $config->set('support_material_interface_extrusion_width', 0.6); +# $config->set('support_material_interface_layers', 2); +# $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; +# my $success = 1; +# Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { +# my ($self, $cmd, $args, $info) = @_; +# if ($info->{extruding} && $info->{dist_XY} > 0) { +# # this is a raft layer +# if (($layer_id < $config->raft_layers) && ($layer_id > 0)) { +# my $width; +# my $support_layer_height = $config->nozzle_diameter->[0] * 0.75; +# +# # support layer +# if ($config->raft_layers - $config->support_material_interface_layers > $layer_id) { +# $width = $config->support_material_extrusion_width; +# } +# # interface layer +# else { +# $width = $config->support_material_interface_extrusion_width; +# } +# my $expected_E_per_mm3 = 4 / (($config->filament_diameter->[0]**2) * PI); +# my $expected_mm3_per_mm = $width * $support_layer_height + ($support_layer_height**2) / 4.0 * (PI-4.0); +# my $expected_e_per_mm = $expected_E_per_mm3 * $expected_mm3_per_mm; +# +# my $e_per_mm = ($info->{dist_E} / $info->{dist_XY});; +# +# my $diff = abs($e_per_mm - $expected_e_per_mm); +# +# if ($diff > 0.001) { +# $success = 0; +# } +# } +# } elsif ($cmd eq 'G1' && $info->{dist_Z} > 0) { +# $layer_id++; +# } +# }); +# +# ok $success, +# 'support material interface extrusion width is used for interfaces'; +#} +# +#{ +# 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'; +#} +# +#{ +# my $config = Slic3r::Config->new_from_defaults; +# $config->set('support_material_enforce_layers', 100); +# $config->set('support_material', 0); +# my @contact_z = my @top_z = (); +# +# my $test = sub { +# my $print = Slic3r::Test::init_print('20mm_cube', config => $config); +# my $flow = $print->print->objects->[0]->support_material_flow; +# 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(\@contact_z, \@top_z, $config->layer_height); +# +# is scalar(grep { $support_z->[$_]-$support_z->[$_-1] <= 0 } 1..$#$support_z), 0, +# 'forced support is generated'; +# +# }; +# $config->set('layer_height', 0.2); +# $config->set('first_layer_height', 0.3); +# @contact_z = (1.9); +# @top_z = (1.1); +# $test->(); +#} __END__ diff --git a/xs/src/libslic3r/SupportMaterial.cpp b/xs/src/libslic3r/SupportMaterial.cpp index b29c9030e..11aef4124 100644 --- a/xs/src/libslic3r/SupportMaterial.cpp +++ b/xs/src/libslic3r/SupportMaterial.cpp @@ -74,36 +74,36 @@ SupportMaterial::generate(PrintObject *object) // that it will be effective, regardless of how it's built below. pair, map> contact_overhang = contact_area(object); map &contact = contact_overhang.first; - cout << "Contact size " << contact.size() << endl; + //cout << "Contact size " << contact.size() << endl; map &overhang = contact_overhang.second; int ppp = 0; - cout << "Samir " << ppp++ << endl; + //cout << "Samir " << ppp++ << endl; // Determine the top surfaces of the object. We need these to determine // the layer heights of support material and to clip support to the object // silhouette. map top = object_top(object, &contact); - cout << "Samir " << ppp++ << endl; + //cout << "Samir " << ppp++ << endl; // We now know the upper and lower boundaries for our support material object // (@$contact_z and @$top_z), so we can generate intermediate layers. vector support_z = support_layers_z(get_keys_sorted(contact), get_keys_sorted(top), get_max_layer_height(object)); - cout << "Samir " << ppp++ << endl; + //cout << "Samir " << ppp++ << endl; // If we wanted to apply some special logic to the first support layers lying on // object's top surfaces this is the place to detect them. map shape; if (object_config->support_material_pattern.value == smpPillars) this->generate_pillars_shape(contact, support_z, shape); - cout << "Samir " << ppp++ << endl; + //cout << "Samir " << ppp++ << endl; // Propagate contact layers downwards to generate interface layers. map interface = generate_interface_layers(support_z, contact, top); clip_with_object(interface, support_z, *object); if (!shape.empty()) clip_with_shape(interface, shape); - cout << "Samir " << ppp++ << endl; + //cout << "Samir " << ppp++ << endl; // Propagate contact layers and interface layers downwards to generate // the main support layers. map base = generate_base_layers(support_z, contact, interface, top); @@ -111,11 +111,11 @@ SupportMaterial::generate(PrintObject *object) if (!shape.empty()) clip_with_shape(base, shape); - cout << "Samir " << ppp++ << endl; + //cout << "Samir " << ppp++ << endl; // Detect what part of base support layers are "reverse interfaces" because they // lie above object's top surfaces. generate_bottom_interface_layers(support_z, base, top, interface); - cout << "Samir " << ppp++ << endl; + //cout << "Samir " << ppp++ << endl; // Install support layers into object. for (int i = 0; i < int(support_z.size()); i++) { object->add_support_layer( @@ -129,11 +129,11 @@ SupportMaterial::generate(PrintObject *object) object->support_layers.end()[-1]->lower_layer = object->support_layers.end()[-2]; } } - cout << "Supports z count is " << support_z.size() << endl; - cout << "Samir " << ppp++ << endl; + //cout << "Supports z count is " << support_z.size() << endl; + //cout << "Samir " << ppp++ << endl; // Generate the actual toolpaths and save them into each layer. generate_toolpaths(object, overhang, contact, interface, base); - cout << "Samir " << ppp++ << endl; + //cout << "Samir " << ppp++ << endl; } vector @@ -142,7 +142,7 @@ SupportMaterial::support_layers_z(vector contact_z, coordf_t max_object_layer_height) { // Quick table to check whether a given Z is a top surface. - map is_top; + map is_top; for (auto z : top_z) is_top[z] = true; // determine layer height for any non-contact layer @@ -150,9 +150,8 @@ SupportMaterial::support_layers_z(vector contact_z, // layer_height > nozzle_diameter * 0.75. auto nozzle_diameter = config->nozzle_diameter.get_at(static_cast( object_config->support_material_extruder - 1)); - auto support_material_height = (max_object_layer_height, (nozzle_diameter * 0.75)); + auto support_material_height = max(max_object_layer_height, (nozzle_diameter * 0.75)); coordf_t _contact_distance = this->contact_distance(support_material_height, nozzle_diameter); - // Initialize known, fixed, support layers. vector z; for (auto c_z : contact_z) z.push_back(c_z); @@ -176,7 +175,7 @@ SupportMaterial::support_layers_z(vector contact_z, // since we already have two raft layers ($z[0] and $z[1]) we need to insert // raft_layers-2 more int idx = 1; - for (int j = 0; j < object_config->raft_layers - 2; j++) { + for (int j = 1; j <= object_config->raft_layers - 2; j++) { float z_new = roundf(static_cast((z[0] + height * idx) * 100)) / 100; // round it to 2 decimal places. z.insert(z.begin() + idx, z_new); @@ -185,14 +184,14 @@ SupportMaterial::support_layers_z(vector contact_z, } // Create other layers (skip raft layers as they're already done and use thicker layers). - for (int i = static_cast(z.size()); i >= object_config->raft_layers.value; i--) { + for (auto i = static_cast(z.size()) - 1; i >= object_config->raft_layers; i--) { coordf_t target_height = support_material_height; - if (i > 0 && is_top[z[i - 1]]) { + if (i > 0 && is_top.count(z[i - 1]) > 0 && is_top[z[i - 1]]) { target_height = nozzle_diameter; } // Enforce first layer height. if ((i == 0 && z[i] > target_height + first_layer_height) - || (z[i] - z[i - 1] > target_height + EPSILON)) { + || (i > 0 && z[i] - z[i - 1] > target_height + EPSILON)) { z.insert(z.begin() + i, (z[i] - target_height)); i++; } @@ -248,7 +247,7 @@ SupportMaterial::contact_area(PrintObject *object) // and $layer->id == 0 means first print layer (including raft). // If no raft, and we're at layer 0, skip to layer 1 - cout << "LAYER ID " << layer_id << endl; + //cout << "LAYER ID " << layer_id << endl; if (conf.raft_layers == 0 && layer_id == 0) { continue; } @@ -601,12 +600,12 @@ SupportMaterial::generate_pillars_shape(const map &contact, if (contact.empty()) return; int u = 0; - cout << "Pillars generation " << contact.size() << endl; + //cout << "Pillars generation " << contact.size() << endl; coord_t pillar_size = scale_(object_config->support_material_pillar_size.value); coord_t pillar_spacing = scale_(object_config->support_material_pillar_spacing.value); - cout << "Samir U " << u++ << endl; + //cout << "Samir U " << u++ << endl; Polygons grid; { auto pillar = Polygon({ @@ -635,28 +634,28 @@ SupportMaterial::generate_pillars_shape(const map &contact, grid = union_(pillars); } - cout << "Samir U " << u++ << endl; //1 - cout << "Support z size " << support_z.size() << endl; + //cout << "Samir U " << u++ << endl; //1 + //cout << "Support z size " << support_z.size() << endl; // Add pillars to every layer. for (auto i = 0; i < support_z.size(); i++) { shape[i] = grid; } - cout << "Samir U " << u++ << endl; + //cout << "Samir U " << u++ << endl; // Build capitals. - cout << "contacts START " << endl; + //cout << "contacts START " << endl; for (auto el : contact) { - cout << el.first << endl; + //cout << el.first << endl; } - cout << "contacts END" << endl; + //cout << "contacts END" << endl; for (auto i = 0; i < support_z.size(); i++) { coordf_t z = support_z[i]; - cout << z << endl; + //cout << z << endl; auto capitals = intersection( grid, contact.count(z) > 0 ? contact.at(z) : Polygons() ); - cout << "Samir U " << u++ << endl; + //cout << "Samir U " << u++ << endl; // Work on one pillar at time (if any) to prevent the capitals from being merged // but store the contact area supported by the capital because we need to make // sure nothing is left. @@ -673,7 +672,7 @@ SupportMaterial::generate_pillars_shape(const map &contact, append_to(shape[i], capital_polygons); } } - cout << "Samir U " << u++ << endl; + //cout << "Samir U " << u++ << endl; // Work on one pillar at time (if any) to prevent the capitals from being merged // but store the contact area supported by the capital because we need to make // sure nothing is left. @@ -688,7 +687,7 @@ SupportMaterial::generate_pillars_shape(const map &contact, } } } - cout << "Samir U " << u++ << endl; + //cout << "Samir U " << u++ << endl; } map @@ -749,7 +748,6 @@ SupportMaterial::generate_interface_layers(vector support_z, auto interface_layers_num = object_config->support_material_interface_layers.value; for (int layer_id = 0; layer_id < support_z.size(); layer_id++) { - // Todo Ask about how to port this line. "my $this = $contact->{$z} // next;" auto z = support_z[layer_id]; if (contact.count(z) <= 0) diff --git a/xs/src/libslic3r/SupportMaterial.hpp b/xs/src/libslic3r/SupportMaterial.hpp index 15c2fc1e6..4b1eda2f0 100644 --- a/xs/src/libslic3r/SupportMaterial.hpp +++ b/xs/src/libslic3r/SupportMaterial.hpp @@ -88,7 +88,6 @@ public: pair, map> contact_area(PrintObject *object); - // TODO Is this expolygons or polygons? map object_top(PrintObject *object, map *contact); void generate_pillars_shape(const map &contact,