Better and more robust implementation of infill_only_where_needed

This commit is contained in:
Alessandro Ranellucci 2015-02-23 00:44:51 +01:00
parent 69ea88473d
commit 2655f3f816
2 changed files with 71 additions and 36 deletions

View file

@ -711,61 +711,91 @@ sub clip_fill_surfaces {
# We only want infill under ceilings; this is almost like an # We only want infill under ceilings; this is almost like an
# internal support material. # internal support material.
my $additional_margin = scale 3*0; # proceed top-down skipping bottom layer
my $upper_internal = [];
for my $layer_id (reverse 1..($self->layer_count - 1)) {
my $layer = $self->get_layer($layer_id);
my $lower_layer = $self->get_layer($layer_id-1);
my $overhangs = []; # arrayref of polygons # detect things that we need to support
for my $layer_id (reverse 0..($self->layer_count - 1)) { my $overhangs = []; # Polygons
my $layer = $self->get_layer($layer_id);
my @layer_internal = (); # arrayref of Surface objects
my @new_internal = (); # arrayref of Surface objects
# clip this layer's internal surfaces to @overhangs # we need to support any solid surface
foreach my $layerm (@{$layer->regions}) { push @$overhangs, map $_->p,
grep $_->is_solid, map @{$_->fill_surfaces}, @{$layer->regions};
# we also need to support perimeters when there's at least one full
# unsupported loop
{
# get perimeters area as the difference between slices and fill_surfaces
my $perimeters = diff(
[ map @$_, @{$layer->slices} ],
[ map $_->p, map @{$_->fill_surfaces}, @{$layer->regions} ],
);
# only consider the area that is not supported by lower perimeters
$perimeters = intersection(
$perimeters,
[ map $_->p, map @{$_->fill_surfaces}, @{$lower_layer->regions} ],
1,
);
# only consider perimeter areas that are at least one extrusion width thick
my $pw = min(map $_->flow(FLOW_ROLE_PERIMETER)->scaled_width, @{$layer->regions});
$perimeters = offset2($perimeters, -$pw, +$pw);
# append such thick perimeters to the areas that need support
push @$overhangs, @$perimeters;
}
# find new internal infill
$upper_internal = my $new_internal = intersection(
[
@$overhangs,
@$upper_internal,
],
[
# our current internal fill boundaries
map $_->p,
grep $_->surface_type == S_TYPE_INTERNAL || $_->surface_type == S_TYPE_INTERNALVOID,
map @{$_->fill_surfaces}, @{$lower_layer->regions}
],
);
# apply new internal infill to regions
foreach my $layerm (@{$lower_layer->regions}) {
my (@internal, @other) = (); my (@internal, @other) = ();
foreach my $surface (map $_->clone, @{$layerm->fill_surfaces}) { foreach my $surface (map $_->clone, @{$layerm->fill_surfaces}) {
if ($surface->surface_type == S_TYPE_INTERNAL) { if ($surface->surface_type == S_TYPE_INTERNAL || $surface->surface_type == S_TYPE_INTERNALVOID) {
push @internal, $surface; push @internal, $surface;
} else { } else {
push @other, $surface; push @other, $surface;
} }
} }
# keep all the original internal surfaces to detect overhangs in this layer my @new = map Slic3r::Surface->new(
push @layer_internal, @internal;
push @new_internal, my @new = map Slic3r::Surface->new(
expolygon => $_, expolygon => $_,
surface_type => S_TYPE_INTERNAL, surface_type => S_TYPE_INTERNAL,
), ),
@{intersection_ex( @{intersection_ex(
[ map $_->p, @internal ], [ map $_->p, @internal ],
$overhangs, $new_internal,
1,
)}; )};
push @new, map Slic3r::Surface->new( push @other, map Slic3r::Surface->new(
expolygon => $_, expolygon => $_,
surface_type => S_TYPE_INTERNALVOID, surface_type => S_TYPE_INTERNALVOID,
), ),
@{diff_ex( @{diff_ex(
[ map $_->p, @internal ], [ map $_->p, @internal ],
$overhangs, $new_internal,
1,
)}; )};
$layerm->fill_surfaces->clear; $layerm->fill_surfaces->clear;
$layerm->fill_surfaces->append($_) for (@new, @other); $layerm->fill_surfaces->append($_) for (@new, @other);
} }
# get this layer's overhangs defined as the full slice minus the internal infill
# (thus we also consider perimeters)
if ($layer_id > 0) {
my $solid = diff(
[ map $_->p, map @{$_->fill_surfaces}, @{$layer->regions} ],
[ map $_->p, @layer_internal ],
);
$overhangs = offset($solid, +$additional_margin);
push @$overhangs, map $_->p, @new_internal; # propagate upper overhangs
}
} }
} }

View file

@ -61,13 +61,18 @@ LayerRegion::prepare_fill_surfaces()
the only meaningful information returned by psPerimeters. */ the only meaningful information returned by psPerimeters. */
// if no solid layers are requested, turn top/bottom surfaces to internal // if no solid layers are requested, turn top/bottom surfaces to internal
if (this->_region->config.top_solid_layers == 0) { if (this->region()->config.top_solid_layers == 0) {
for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) { for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) {
if (surface->surface_type == stTop) if (surface->surface_type == stTop) {
surface->surface_type = stInternal; if (this->layer()->object()->config.infill_only_where_needed) {
surface->surface_type = stInternalVoid;
} else {
surface->surface_type = stInternal;
}
}
} }
} }
if (this->_region->config.bottom_solid_layers == 0) { if (this->region()->config.bottom_solid_layers == 0) {
for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) { for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) {
if (surface->surface_type == stBottom || surface->surface_type == stBottomBridge) if (surface->surface_type == stBottom || surface->surface_type == stBottomBridge)
surface->surface_type = stInternal; surface->surface_type = stInternal;
@ -75,9 +80,9 @@ LayerRegion::prepare_fill_surfaces()
} }
// turn too small internal regions into solid regions according to the user setting // turn too small internal regions into solid regions according to the user setting
if (this->_region->config.fill_density.value > 0) { if (this->region()->config.fill_density.value > 0) {
// scaling an area requires two calls! // scaling an area requires two calls!
double min_area = scale_(scale_(this->_region->config.solid_infill_below_area.value)); double min_area = scale_(scale_(this->region()->config.solid_infill_below_area.value));
for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) { for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) {
if (surface->surface_type == stInternal && surface->area() <= min_area) if (surface->surface_type == stInternal && surface->area() <= min_area)
surface->surface_type = stInternalSolid; surface->surface_type = stInternalSolid;