Make combine_infill() completely idempotent. Includes unit testing

This commit is contained in:
Alessandro Ranellucci 2014-12-08 21:23:42 +01:00
parent 9a9ba02d85
commit d350241da3
3 changed files with 41 additions and 9 deletions

View File

@ -678,7 +678,8 @@ sub detect_surfaces_type {
# Note: this method should be idempotent, but fill_surfaces gets modified # Note: this method should be idempotent, but fill_surfaces gets modified
# in place. However we're now only using its boundaries (which are invariant) # in place. However we're now only using its boundaries (which are invariant)
# so we're safe # so we're safe. This guarantees idempotence of prepare_infill() also in case
# that combine_infill() turns some fill_surface into VOID surfaces.
my $fill_boundaries = [ map $_->clone->p, @{$layerm->fill_surfaces} ]; my $fill_boundaries = [ map $_->clone->p, @{$layerm->fill_surfaces} ];
$layerm->fill_surfaces->clear; $layerm->fill_surfaces->clear;
foreach my $surface (@{$layerm->slices}) { foreach my $surface (@{$layerm->slices}) {
@ -988,12 +989,19 @@ sub discover_horizontal_shells {
} }
# combine fill surfaces across layers # combine fill surfaces across layers
# Idempotence of this method is guaranteed by the fact that we don't remove things from
# fill_surfaces but we only turn them into VOID surfaces, thus preserving the boundaries.
sub combine_infill { sub combine_infill {
my $self = shift; my $self = shift;
# define the type used for voids
my %voidtype = (
&S_TYPE_INTERNAL() => S_TYPE_INTERNALVOID,
);
# work on each region separately # work on each region separately
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->get_region($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; next unless $every > 1 && $region->config->fill_density > 0;
@ -1030,7 +1038,7 @@ sub combine_infill {
next unless $combine{$layer_idx} > 1; next unless $combine{$layer_idx} > 1;
# get all the LayerRegion objects to be combined # get all the LayerRegion objects to be combined
my @layerms = map $self->get_layer($_)->regions->[$region_id], my @layerms = map $self->get_layer($_)->get_region($region_id),
($layer_idx - ($combine{$layer_idx}-1) .. $layer_idx); ($layer_idx - ($combine{$layer_idx}-1) .. $layer_idx);
# only combine internal infill # only combine internal infill
@ -1092,8 +1100,8 @@ sub combine_infill {
@$intersection; @$intersection;
} else { } else {
# save void surfaces # save void surfaces
push @this_type, push @new_this_type,
map Slic3r::Surface->new(expolygon => $_, surface_type => S_TYPE_INTERNALVOID), map Slic3r::Surface->new(expolygon => $_, surface_type => $voidtype{$type}),
@{intersection_ex( @{intersection_ex(
[ map @{$_->expolygon}, @this_type ], [ map @{$_->expolygon}, @this_type ],
[ @intersection_with_clearance ], [ @intersection_with_clearance ],

View File

@ -9,9 +9,10 @@ BEGIN {
use List::Util qw(first); use List::Util qw(first);
use Slic3r; use Slic3r;
use Slic3r::Surface ':types';
use Slic3r::Test; use Slic3r::Test;
plan tests => 6; plan tests => 8;
{ {
my $test = sub { my $test = sub {
@ -53,7 +54,6 @@ plan tests => 6;
}; };
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]);
@ -71,6 +71,30 @@ plan tests => 6;
$test->($config); $test->($config);
} }
{
my $config = Slic3r::Config->new_from_defaults;
$config->set('layer_height', 0.2);
$config->set('first_layer_height', 0.2);
$config->set('nozzle_diameter', [0.5]);
$config->set('infill_every_layers', 2);
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
$print->process;
ok defined(first { @{$_->get_region(0)->fill_surfaces->filter_by_type(S_TYPE_INTERNALVOID)} > 0 }
@{$print->print->get_object(0)->layers}),
'infill combination produces internal void surfaces';
# we disable combination after infill has been generated
$config->set('infill_every_layers', 1);
$print->apply_config($config);
$print->process;
ok !(defined first { @{$_->get_region(0)->fill_surfaces} == 0 }
@{$print->print->get_object(0)->layers}),
'infill combination is idempotent';
}
# the following needs to be adapted to the new API # the following needs to be adapted to the new API
if (0) { if (0) {
my $config = Slic3r::Config->new_from_defaults; my $config = Slic3r::Config->new_from_defaults;

View File

@ -249,6 +249,8 @@ PrintObject::invalidate_state_by_config_options(const std::vector<t_config_optio
steps.insert(posSupportMaterial); steps.insert(posSupportMaterial);
} else if (*opt_key == "interface_shells" } else if (*opt_key == "interface_shells"
|| *opt_key == "infill_only_where_needed" || *opt_key == "infill_only_where_needed"
|| *opt_key == "infill_every_layers"
|| *opt_key == "solid_infill_every_layers"
|| *opt_key == "bottom_solid_layers" || *opt_key == "bottom_solid_layers"
|| *opt_key == "top_solid_layers" || *opt_key == "top_solid_layers"
|| *opt_key == "solid_infill_below_area" || *opt_key == "solid_infill_below_area"
@ -258,8 +260,6 @@ PrintObject::invalidate_state_by_config_options(const std::vector<t_config_optio
} else if (*opt_key == "external_fill_pattern" } else if (*opt_key == "external_fill_pattern"
|| *opt_key == "fill_angle" || *opt_key == "fill_angle"
|| *opt_key == "fill_pattern" || *opt_key == "fill_pattern"
|| *opt_key == "infill_every_layers"
|| *opt_key == "solid_infill_every_layers"
|| *opt_key == "top_infill_extrusion_width" || *opt_key == "top_infill_extrusion_width"
|| *opt_key == "first_layer_extrusion_width") { || *opt_key == "first_layer_extrusion_width") {
steps.insert(posInfill); steps.insert(posInfill);