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:
parent
9332c21791
commit
095391d702
@ -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
|
||||||
|
@ -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;
|
||||||
|
20
t/fill.t
20
t/fill.t
@ -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';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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";
|
||||||
}
|
}
|
||||||
|
14
t/support.t
14
t/support.t
@ -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__
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user