mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-12 09:17:52 -06:00
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
|
# 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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue