Better and more robust implementation of infill_only_where_needed
This commit is contained in:
parent
69ea88473d
commit
2655f3f816
2 changed files with 71 additions and 36 deletions
|
@ -711,61 +711,91 @@ sub clip_fill_surfaces {
|
|||
# We only want infill under ceilings; this is almost like an
|
||||
# internal support material.
|
||||
|
||||
my $additional_margin = scale 3*0;
|
||||
|
||||
my $overhangs = []; # arrayref of polygons
|
||||
for my $layer_id (reverse 0..($self->layer_count - 1)) {
|
||||
my $layer = $self->get_layer($layer_id);
|
||||
my @layer_internal = (); # arrayref of Surface objects
|
||||
my @new_internal = (); # arrayref of Surface objects
|
||||
# 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);
|
||||
|
||||
# clip this layer's internal surfaces to @overhangs
|
||||
foreach my $layerm (@{$layer->regions}) {
|
||||
# detect things that we need to support
|
||||
my $overhangs = []; # Polygons
|
||||
|
||||
# we need to support any solid surface
|
||||
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) = ();
|
||||
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;
|
||||
} else {
|
||||
push @other, $surface;
|
||||
}
|
||||
}
|
||||
|
||||
# keep all the original internal surfaces to detect overhangs in this layer
|
||||
push @layer_internal, @internal;
|
||||
|
||||
push @new_internal, my @new = map Slic3r::Surface->new(
|
||||
my @new = map Slic3r::Surface->new(
|
||||
expolygon => $_,
|
||||
surface_type => S_TYPE_INTERNAL,
|
||||
),
|
||||
@{intersection_ex(
|
||||
[ map $_->p, @internal ],
|
||||
$overhangs,
|
||||
$new_internal,
|
||||
1,
|
||||
)};
|
||||
|
||||
push @new, map Slic3r::Surface->new(
|
||||
push @other, map Slic3r::Surface->new(
|
||||
expolygon => $_,
|
||||
surface_type => S_TYPE_INTERNALVOID,
|
||||
),
|
||||
@{diff_ex(
|
||||
[ map $_->p, @internal ],
|
||||
$overhangs,
|
||||
$new_internal,
|
||||
1,
|
||||
)};
|
||||
|
||||
|
||||
$layerm->fill_surfaces->clear;
|
||||
$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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,13 +61,18 @@ LayerRegion::prepare_fill_surfaces()
|
|||
the only meaningful information returned by psPerimeters. */
|
||||
|
||||
// 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) {
|
||||
if (surface->surface_type == stTop)
|
||||
surface->surface_type = stInternal;
|
||||
if (surface->surface_type == stTop) {
|
||||
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) {
|
||||
if (surface->surface_type == stBottom || surface->surface_type == stBottomBridge)
|
||||
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
|
||||
if (this->_region->config.fill_density.value > 0) {
|
||||
if (this->region()->config.fill_density.value > 0) {
|
||||
// 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) {
|
||||
if (surface->surface_type == stInternal && surface->area() <= min_area)
|
||||
surface->surface_type = stInternalSolid;
|
||||
|
|
Loading…
Add table
Reference in a new issue