When using raft, validate first layer height against support material extruder only instead of taking other extruders into account, thus potentially allowing larger nozzles to be used for it. #2701

This commit is contained in:
Alessandro Ranellucci 2015-03-06 21:35:00 +01:00
parent 9332c21791
commit 095391d702
8 changed files with 85 additions and 29 deletions

View File

@ -49,9 +49,10 @@ sub make_fill {
Slic3r::debugf "Filling layer %d:\n", $layerm->id; Slic3r::debugf "Filling layer %d:\n", $layerm->id;
my $fill_density = $layerm->config->fill_density; my $fill_density = $layerm->config->fill_density;
my $infill_flow = $layerm->flow(FLOW_ROLE_INFILL); my $infill_flow = $layerm->flow(FLOW_ROLE_INFILL);
my $solid_infill_flow = $layerm->flow(FLOW_ROLE_SOLID_INFILL); my $solid_infill_flow = $layerm->flow(FLOW_ROLE_SOLID_INFILL);
my $top_solid_infill_flow = $layerm->flow(FLOW_ROLE_TOP_SOLID_INFILL);
my @surfaces = (); my @surfaces = ();
@ -75,7 +76,7 @@ sub make_fill {
if ($groups[$i][0]->is_solid && (!$groups[$i][0]->is_bridge || $layerm->id == 0)) { if ($groups[$i][0]->is_solid && (!$groups[$i][0]->is_bridge || $layerm->id == 0)) {
$is_solid[$i] = 1; $is_solid[$i] = 1;
$fw[$i] = ($groups[$i][0]->surface_type == S_TYPE_TOP) $fw[$i] = ($groups[$i][0]->surface_type == S_TYPE_TOP)
? $layerm->flow(FLOW_ROLE_TOP_SOLID_INFILL)->width ? $top_solid_infill_flow->width
: $solid_infill_flow->width; : $solid_infill_flow->width;
$pattern[$i] = $groups[$i][0]->is_external $pattern[$i] = $groups[$i][0]->is_external
? $layerm->config->external_fill_pattern ? $layerm->config->external_fill_pattern

View File

@ -745,11 +745,13 @@ sub _update {
perimeter_speed small_perimeter_speed external_perimeter_speed); perimeter_speed small_perimeter_speed external_perimeter_speed);
my $have_infill = $config->fill_density > 0; my $have_infill = $config->fill_density > 0;
# infill_extruder uses the same logic as in Print::extruders()
$self->get_field($_)->toggle($have_infill) $self->get_field($_)->toggle($have_infill)
for qw(fill_pattern infill_every_layers infill_only_where_needed solid_infill_every_layers for qw(fill_pattern infill_every_layers infill_only_where_needed solid_infill_every_layers
solid_infill_below_area infill_extruder); solid_infill_below_area infill_extruder);
my $have_solid_infill = ($config->top_solid_layers > 0) || ($config->bottom_solid_layers > 0); my $have_solid_infill = ($config->top_solid_layers > 0) || ($config->bottom_solid_layers > 0);
# solid_infill_extruder uses the same logic as in Print::extruders()
$self->get_field($_)->toggle($have_solid_infill) $self->get_field($_)->toggle($have_solid_infill)
for qw(external_fill_pattern infill_first solid_infill_extruder solid_infill_extrusion_width for qw(external_fill_pattern infill_first solid_infill_extruder solid_infill_extrusion_width
solid_infill_speed); solid_infill_speed);
@ -772,6 +774,7 @@ sub _update {
for qw(skirt_distance skirt_height); for qw(skirt_distance skirt_height);
my $have_brim = $config->brim_width > 0; my $have_brim = $config->brim_width > 0;
# perimeter_extruder uses the same logic as in Print::extruders()
$self->get_field('perimeter_extruder')->toggle($have_perimeters || $have_brim); $self->get_field('perimeter_extruder')->toggle($have_perimeters || $have_brim);
my $have_support_material = $config->support_material || $config->raft_layers > 0; my $have_support_material = $config->support_material || $config->raft_layers > 0;

View File

@ -12,7 +12,7 @@ BEGIN {
use List::Util qw(first sum); use List::Util qw(first sum);
use Slic3r; use Slic3r;
use Slic3r::Geometry qw(X Y scale unscale convex_hull); use Slic3r::Geometry qw(X Y scale unscale convex_hull);
use Slic3r::Geometry::Clipper qw(union diff_ex offset); use Slic3r::Geometry::Clipper qw(union diff diff_ex offset offset2_ex);
use Slic3r::Surface qw(:types); use Slic3r::Surface qw(:types);
use Slic3r::Test; use Slic3r::Test;
@ -248,18 +248,27 @@ for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
{ {
my $config = Slic3r::Config->new_from_defaults; my $config = Slic3r::Config->new_from_defaults;
$config->set('skirts', 0); $config->set('skirts', 0);
$config->set('perimeters', 0); $config->set('perimeters', 1);
$config->set('fill_density', 0); $config->set('fill_density', 0);
$config->set('top_solid_layers', 0); $config->set('top_solid_layers', 0);
$config->set('bottom_solid_layers', 0); $config->set('bottom_solid_layers', 0);
$config->set('solid_infill_below_area', 20000000); $config->set('solid_infill_below_area', 20000000);
$config->set('solid_infill_every_layers', 2); $config->set('solid_infill_every_layers', 2);
$config->set('perimeter_speed', 99);
$config->set('external_perimeter_speed', 99);
$config->set('cooling', 0);
$config->set('first_layer_speed', '100%');
my $print = Slic3r::Test::init_print('20mm_cube', config => $config); my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
my %layers_with_extrusion = (); my %layers_with_extrusion = ();
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
my ($self, $cmd, $args, $info) = @_; my ($self, $cmd, $args, $info) = @_;
$layers_with_extrusion{$self->Z} = 1 if $info->{extruding};
if ($cmd eq 'G1' && $info->{dist_XY} > 0 && $info->{extruding}) {
if (($args->{F} // $self->F) != $config->perimeter_speed*60) {
$layers_with_extrusion{$self->Z} = ($args->{F} // $self->F);
}
}
}); });
ok !%layers_with_extrusion, ok !%layers_with_extrusion,
@ -275,6 +284,7 @@ for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
$config->set('first_layer_height', 0.2); $config->set('first_layer_height', 0.2);
$config->set('nozzle_diameter', [0.35]); $config->set('nozzle_diameter', [0.35]);
$config->set('infill_extruder', 2); $config->set('infill_extruder', 2);
$config->set('solid_infill_extruder', 2);
$config->set('infill_extrusion_width', 0.52); $config->set('infill_extrusion_width', 0.52);
$config->set('solid_infill_extrusion_width', 0.52); $config->set('solid_infill_extrusion_width', 0.52);
$config->set('first_layer_extrusion_width', 0); $config->set('first_layer_extrusion_width', 0);
@ -301,7 +311,9 @@ for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
my $grow_d = scale($config->infill_extrusion_width)/2; my $grow_d = scale($config->infill_extrusion_width)/2;
my $layer0_infill = union([ map @{$_->grow($grow_d)}, @{ $infill{0.2} } ]); my $layer0_infill = union([ map @{$_->grow($grow_d)}, @{ $infill{0.2} } ]);
my $layer1_infill = union([ map @{$_->grow($grow_d)}, @{ $infill{0.4} } ]); my $layer1_infill = union([ map @{$_->grow($grow_d)}, @{ $infill{0.4} } ]);
my $diff = [ grep { $_->area > 2*(($grow_d*2)**2) } @{diff_ex($layer0_infill, $layer1_infill)} ]; my $diff = diff($layer0_infill, $layer1_infill);
$diff = offset2_ex($diff, -$grow_d, +$grow_d);
$diff = [ grep { $_->area > 2*(($grow_d*2)**2) } @$diff ];
is scalar(@$diff), 0, 'no missing parts in solid shell when fill_density is 0'; is scalar(@$diff), 0, 'no missing parts in solid shell when fill_density is 0';
} }

View File

@ -229,19 +229,19 @@ use Slic3r::Test;
my $test = sub { my $test = sub {
my ($print) = @_; my ($print) = @_;
my $has_bridges = 0; my %z_with_bridges = (); # z => 1
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
my ($self, $cmd, $args, $info) = @_; my ($self, $cmd, $args, $info) = @_;
if ($info->{extruding} && $info->{dist_XY} > 0) { if ($info->{extruding} && $info->{dist_XY} > 0) {
$has_bridges++ if ($args->{F} // $self->F) == $config->bridge_speed*60; $z_with_bridges{$self->Z} = 1 if ($args->{F} // $self->F) == $config->bridge_speed*60;
} }
}); });
return $has_bridges; return scalar keys %z_with_bridges;
}; };
ok !$test->(Slic3r::Test::init_print('V', config => $config)), ok $test->(Slic3r::Test::init_print('V', config => $config)) == 1,
'no overhangs printed with bridge speed'; 'no overhangs printed with bridge speed'; # except for the first internal solid layers above void
ok $test->(Slic3r::Test::init_print('V', config => $config, scale_xyz => [3,1,1])), ok $test->(Slic3r::Test::init_print('V', config => $config, scale_xyz => [3,1,1])) > 1,
'overhangs printed with bridge speed'; 'overhangs printed with bridge speed';
} }

View File

@ -72,6 +72,9 @@ use Slic3r::Test;
$config->set('bottom_solid_layers', 0); $config->set('bottom_solid_layers', 0);
ok $test->(), "no shells are applied when both top and bottom are set to zero"; ok $test->(), "no shells are applied when both top and bottom are set to zero";
$config->set('perimeters', 1);
$config->set('top_solid_layers', 3);
$config->set('bottom_solid_layers', 3);
$config->set('fill_density', 0); $config->set('fill_density', 0);
ok $test->(), "proper number of shells is applied even when fill density is none"; ok $test->(), "proper number of shells is applied even when fill density is none";
} }

View File

@ -1,4 +1,4 @@
use Test::More tests => 24; use Test::More tests => 25;
use strict; use strict;
use warnings; use warnings;
@ -179,7 +179,7 @@ use Slic3r::Test;
$test->(70); $test->(70);
} }
TTT: { {
my $config = Slic3r::Config->new_from_defaults; my $config = Slic3r::Config->new_from_defaults;
$config->set('brim_width', 0); $config->set('brim_width', 0);
$config->set('skirts', 0); $config->set('skirts', 0);
@ -219,4 +219,14 @@ TTT: {
ok !$test->(), 'bridge speed is not used when raft_layers > 0 and 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('raft_layers', 3);
$config->set('nozzle_diameter', [0.4, 1]);
$config->set('first_layer_height', 0.8);
$config->set('support_material_extruder', 2);
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
ok Slic3r::Test::gcode($print), 'first_layer_height is validated with support material extruder nozzle diameter when using raft layers';
}
__END__ __END__

View File

@ -305,9 +305,16 @@ Print::extruders() const
std::set<size_t> extruders; std::set<size_t> extruders;
FOREACH_REGION(this, region) { FOREACH_REGION(this, region) {
extruders.insert((*region)->config.perimeter_extruder - 1); // these checks reflect the same logic used in the GUI for enabling/disabling
extruders.insert((*region)->config.infill_extruder - 1); // extruder selection fields
extruders.insert((*region)->config.solid_infill_extruder - 1); if ((*region)->config.perimeters.value > 0 || this->config.brim_width.value > 0)
extruders.insert((*region)->config.perimeter_extruder - 1);
if ((*region)->config.fill_density.value > 0)
extruders.insert((*region)->config.infill_extruder - 1);
if ((*region)->config.top_solid_layers.value > 0 || (*region)->config.bottom_solid_layers.value > 0)
extruders.insert((*region)->config.solid_infill_extruder - 1);
} }
FOREACH_OBJECT(this, object) { FOREACH_OBJECT(this, object) {
if ((*object)->has_support_material()) { if ((*object)->has_support_material()) {
@ -619,17 +626,37 @@ Print::validate() const
} }
{ {
std::vector<double> layer_heights; // find the smallest nozzle diameter
std::set<size_t> extruders = this->extruders();
if (extruders.empty())
throw PrintValidationException("The supplied settings will cause an empty print.");
std::set<double> nozzle_diameters;
for (std::set<size_t>::iterator it = extruders.begin(); it != extruders.end(); ++it)
nozzle_diameters.insert(this->config.nozzle_diameter.get_at(*it));
double min_nozzle_diameter = *std::min_element(nozzle_diameters.begin(), nozzle_diameters.end());
FOREACH_OBJECT(this, i_object) { FOREACH_OBJECT(this, i_object) {
PrintObject* object = *i_object; PrintObject* object = *i_object;
layer_heights.push_back(object->config.layer_height);
layer_heights.push_back(object->config.get_abs_value("first_layer_height")); // validate first_layer_height
} double first_layer_height = object->config.get_abs_value("first_layer_height");
double max_layer_height = *std::max_element(layer_heights.begin(), layer_heights.end()); double first_layer_min_nozzle_diameter;
if (object->config.raft_layers > 0) {
std::set<size_t> extruders = this->extruders(); // if we have raft layers, only support material extruder is used on first layer
for (std::set<size_t>::iterator it = extruders.begin(); it != extruders.end(); ++it) { size_t first_layer_extruder = object->config.raft_layers == 1
if (max_layer_height > this->config.nozzle_diameter.get_at(*it)) ? object->config.support_material_interface_extruder-1
: object->config.support_material_extruder-1;
first_layer_min_nozzle_diameter = this->config.nozzle_diameter.get_at(first_layer_extruder);
} else {
// if we don't have raft layers, any nozzle diameter is potentially used in first layer
first_layer_min_nozzle_diameter = min_nozzle_diameter;
}
if (first_layer_height > first_layer_min_nozzle_diameter)
throw PrintValidationException("First layer height can't be greater than nozzle diameter");
// validate layer_height
if (object->config.layer_height.value > min_nozzle_diameter)
throw PrintValidationException("Layer height can't be greater than nozzle diameter"); throw PrintValidationException("Layer height can't be greater than nozzle diameter");
} }
} }

View File

@ -348,7 +348,7 @@ PrintObject::bridge_over_infill()
size_t region_id = region - this->_print->regions.begin(); size_t region_id = region - this->_print->regions.begin();
double fill_density = (*region)->config.fill_density.value; double fill_density = (*region)->config.fill_density.value;
if (fill_density == 100 || fill_density == 0) continue; if (fill_density == 100) continue;
FOREACH_LAYER(this, layer_it) { FOREACH_LAYER(this, layer_it) {
if (layer_it == this->layers.begin()) continue; if (layer_it == this->layers.begin()) continue;