Bugfix: infill was not correctly generated when infill_every_layers was used along with raft_layers. Includes regression test. #2396

This commit is contained in:
Alessandro Ranellucci 2014-12-08 20:14:04 +01:00
parent f7026c41c5
commit 9a9ba02d85
2 changed files with 69 additions and 34 deletions

View File

@ -991,39 +991,47 @@ sub discover_horizontal_shells {
sub combine_infill { sub combine_infill {
my $self = shift; my $self = shift;
return unless defined first { $_->config->infill_every_layers > 1 && $_->config->fill_density > 0 } @{$self->print->regions}; # work on each region separately
my @layer_heights = map $_->height, @{$self->layers};
for my $region_id (0 .. ($self->print->region_count-1)) { for my $region_id (0 .. ($self->print->region_count-1)) {
my $region = $self->print->regions->[$region_id]; my $region = $self->print->regions->[$region_id];
my $every = $region->config->infill_every_layers; my $every = $region->config->infill_every_layers;
next unless $every > 1 && $region->config->fill_density > 0;
# limit the number of combined layers to the maximum height allowed by this regions' nozzle # limit the number of combined layers to the maximum height allowed by this regions' nozzle
my $nozzle_diameter = $self->print->config->get_at('nozzle_diameter', $region->config->infill_extruder-1); my $nozzle_diameter = $self->print->config->get_at('nozzle_diameter', $region->config->infill_extruder-1);
# define the combinations # define the combinations
my @combine = (); # layer_id => thickness in layers my %combine = (); # layer_idx => number of additional combined lower layers
{ {
my $current_height = my $layers = 0; my $current_height = my $layers = 0;
for my $layer_id (1 .. $#layer_heights) { for my $layer_idx (0 .. ($self->layer_count-1)) {
my $height = $self->get_layer($layer_id)->height; my $layer = $self->get_layer($layer_idx);
next if $layer->id == 0; # skip first print layer (which may not be first layer in array because of raft)
my $height = $layer->height;
# check whether the combination of this layer with the lower layers' buffer
# would exceed max layer height or max combined layer count
if ($current_height + $height >= $nozzle_diameter || $layers >= $every) { if ($current_height + $height >= $nozzle_diameter || $layers >= $every) {
$combine[$layer_id-1] = $layers; # append combination to lower layer
$combine{$layer_idx-1} = $layers;
$current_height = $layers = 0; $current_height = $layers = 0;
} }
$current_height += $height; $current_height += $height;
$layers++; $layers++;
} }
# append lower layers (if any) to uppermost layer
$combine{$self->layer_count-1} = $layers;
} }
# skip bottom layer # loop through layers to which we have assigned layers to combine
for my $layer_id (1 .. $#combine) { for my $layer_idx (sort keys %combine) {
next unless ($combine[$layer_id] // 1) > 1; next unless $combine{$layer_idx} > 1;
# get all the LayerRegion objects to be combined
my @layerms = map $self->get_layer($_)->regions->[$region_id], my @layerms = map $self->get_layer($_)->regions->[$region_id],
($layer_id - ($combine[$layer_id]-1) .. $layer_id); ($layer_idx - ($combine{$layer_idx}-1) .. $layer_idx);
# only combine internal infill # only combine internal infill
for my $type (S_TYPE_INTERNAL) { for my $type (S_TYPE_INTERNAL) {
@ -1046,7 +1054,7 @@ sub combine_infill {
Slic3r::debugf " combining %d %s regions from layers %d-%d\n", Slic3r::debugf " combining %d %s regions from layers %d-%d\n",
scalar(@$intersection), scalar(@$intersection),
($type == S_TYPE_INTERNAL ? 'internal' : 'internal-solid'), ($type == S_TYPE_INTERNAL ? 'internal' : 'internal-solid'),
$layer_id-($every-1), $layer_id; $layer_idx-($every-1), $layer_idx;
# $intersection now contains the regions that can be combined across the full amount of layers # $intersection now contains the regions that can be combined across the full amount of layers
# so let's remove those areas from all layers # so let's remove those areas from all layers
@ -1073,7 +1081,7 @@ sub combine_infill {
)}; )};
# apply surfaces back with adjusted depth to the uppermost layer # apply surfaces back with adjusted depth to the uppermost layer
if ($layerm->id == $layer_id) { if ($layerm->id == $self->get_layer($layer_idx)->id) {
push @new_this_type, push @new_this_type,
map Slic3r::Surface->new( map Slic3r::Surface->new(
expolygon => $_, expolygon => $_,

View File

@ -11,37 +11,64 @@ use List::Util qw(first);
use Slic3r; use Slic3r;
use Slic3r::Test; use Slic3r::Test;
plan tests => 2; plan tests => 6;
{ {
my $test = sub {
my ($config) = @_;
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
ok my $gcode = Slic3r::Test::gcode($print), "infill_every_layers does not crash";
my $tool = undef;
my %layers = (); # layer_z => 1
my %layer_infill = (); # layer_z => has_infill
Slic3r::GCode::Reader->new->parse($gcode, sub {
my ($self, $cmd, $args, $info) = @_;
if ($cmd =~ /^T(\d+)/) {
$tool = $1;
} elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0 && $tool != $config->support_material_extruder-1) {
$layer_infill{$self->Z} //= 0;
if ($tool == $config->infill_extruder-1) {
$layer_infill{$self->Z} = 1;
}
}
$layers{$args->{Z}} = 1 if $cmd eq 'G1' && $info->{dist_Z} > 0;
});
my $layers_with_perimeters = scalar(keys %layer_infill);
my $layers_with_infill = grep $_ > 0, values %layer_infill;
is scalar(keys %layers), $layers_with_perimeters+$config->raft_layers, 'expected number of layers';
# first infill layer is never combined, so we don't consider it
$layers_with_infill--;
$layers_with_perimeters--;
# we expect that infill is generated for half the number of combined layers
# plus for each single layer that was not combined (remainder)
is $layers_with_infill,
int($layers_with_perimeters/$config->infill_every_layers) + ($layers_with_perimeters % $config->infill_every_layers),
'infill is only present in correct number of layers';
};
my $config = Slic3r::Config->new_from_defaults; my $config = Slic3r::Config->new_from_defaults;
$config->set('gcode_comments', 1);
$config->set('layer_height', 0.2); $config->set('layer_height', 0.2);
$config->set('first_layer_height', 0.2); $config->set('first_layer_height', 0.2);
$config->set('nozzle_diameter', [0.5]); $config->set('nozzle_diameter', [0.5]);
$config->set('infill_every_layers', 2); $config->set('infill_every_layers', 2);
$config->set('perimeter_extruder', 1);
$config->set('infill_extruder', 2); $config->set('infill_extruder', 2);
$config->set('support_material_extruder', 3);
$config->set('support_material_interface_extruder', 3);
$config->set('top_solid_layers', 0); $config->set('top_solid_layers', 0);
$config->set('bottom_solid_layers', 0); $config->set('bottom_solid_layers', 0);
my $print = Slic3r::Test::init_print('20mm_cube', config => $config); $test->($config);
ok my $gcode = Slic3r::Test::gcode($print), "infill_every_layers does not crash";
my $tool = undef; $config->set('skirts', 0); # prevent usage of perimeter_extruder in raft layers
my %layer_infill = (); # layer_z => has_infill $config->set('raft_layers', 5);
Slic3r::GCode::Reader->new->parse($gcode, sub { $test->($config);
my ($self, $cmd, $args, $info) = @_;
if ($cmd =~ /^T(\d+)/) {
$tool = $1;
} elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
$layer_infill{$self->Z} //= 0;
if ($tool == $config->infill_extruder-1) {
$layer_infill{$self->Z} = 1;
}
}
});
my $layers_with_infill = grep $_, values %layer_infill;
$layers_with_infill--; # first layer is never combined
is $layers_with_infill, scalar(keys %layer_infill)/2, 'infill is only present in correct number of layers';
} }
# the following needs to be adapted to the new API # the following needs to be adapted to the new API