mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-07-29 15:31:59 +08:00
Ported PrintObject::clip_fill_surfaces() to C++
This commit is contained in:
parent
a4d8d20c7a
commit
e5bd2ef801
@ -252,111 +252,6 @@ sub _support_material {
|
||||
);
|
||||
}
|
||||
|
||||
# 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 clip_fill_surfaces {
|
||||
my $self = shift;
|
||||
|
||||
return unless $self->config->infill_only_where_needed
|
||||
&& any { $_->config->fill_density > 0 } @{$self->print->regions};
|
||||
|
||||
# We only want infill under ceilings; this is almost like an
|
||||
# internal support material.
|
||||
|
||||
# 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);
|
||||
|
||||
# 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}) {
|
||||
next if $layerm->region->config->fill_density == 0;
|
||||
|
||||
my (@internal, @other) = ();
|
||||
foreach my $surface (map $_->clone, @{$layerm->fill_surfaces}) {
|
||||
if ($surface->surface_type == S_TYPE_INTERNAL || $surface->surface_type == S_TYPE_INTERNALVOID) {
|
||||
push @internal, $surface;
|
||||
} else {
|
||||
push @other, $surface;
|
||||
}
|
||||
}
|
||||
|
||||
my @new = map Slic3r::Surface->new(
|
||||
expolygon => $_,
|
||||
surface_type => S_TYPE_INTERNAL,
|
||||
),
|
||||
@{intersection_ex(
|
||||
[ map $_->p, @internal ],
|
||||
$new_internal,
|
||||
1,
|
||||
)};
|
||||
|
||||
push @other, map Slic3r::Surface->new(
|
||||
expolygon => $_,
|
||||
surface_type => S_TYPE_INTERNALVOID,
|
||||
),
|
||||
@{diff_ex(
|
||||
[ map $_->p, @internal ],
|
||||
$new_internal,
|
||||
1,
|
||||
)};
|
||||
|
||||
# If there are voids it means that our internal infill is not adjacent to
|
||||
# perimeters. In this case it would be nice to add a loop around infill to
|
||||
# make it more robust and nicer. TODO.
|
||||
|
||||
$layerm->fill_surfaces->clear;
|
||||
$layerm->fill_surfaces->append($_) for (@new, @other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub discover_horizontal_shells {
|
||||
my $self = shift;
|
||||
|
||||
|
@ -1550,6 +1550,8 @@ PrintObject::_discover_neighbor_horizontal_shells(LayerRegion* layerm, const siz
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
void
|
||||
PrintObject::clip_fill_surfaces()
|
||||
{
|
||||
@ -1562,62 +1564,73 @@ PrintObject::clip_fill_surfaces()
|
||||
// internal support material.
|
||||
// Proceed top-down, skipping the bottom layer.
|
||||
Polygons upper_internal;
|
||||
for (int layer_id = int(this->layers.size()) - 1; layer_id > 0; -- layer_id) {
|
||||
Layer *layer = this->layers[layer_id];
|
||||
for (int layer_id = int(this->layers.size()) - 1; layer_id > 0; --layer_id) {
|
||||
const Layer *layer = this->layers[layer_id];
|
||||
Layer *lower_layer = this->layers[layer_id - 1];
|
||||
|
||||
// Detect things that we need to support.
|
||||
// Cummulative slices.
|
||||
Polygons slices;
|
||||
for (const ExPolygon &expoly : layer->slices.expolygons)
|
||||
polygons_append(slices, to_polygons(expoly));
|
||||
// Cummulative fill surfaces.
|
||||
Polygons fill_surfaces;
|
||||
// Solid surfaces to be supported.
|
||||
Polygons overhangs;
|
||||
for (const LayerRegion *layerm : layer->regions)
|
||||
for (const LayerRegion *layerm : layer->regions) {
|
||||
for (const Surface &surface : layerm->fill_surfaces.surfaces) {
|
||||
Polygons polygons = to_polygons(surface.expolygon);
|
||||
if (surface.is_solid())
|
||||
polygons_append(overhangs, polygons);
|
||||
polygons_append(fill_surfaces, std::move(polygons));
|
||||
}
|
||||
Polygons lower_layer_fill_surfaces;
|
||||
Polygons lower_layer_internal_surfaces;
|
||||
for (const LayerRegion *layerm : lower_layer->regions)
|
||||
for (const Surface &surface : layerm->fill_surfaces.surfaces) {
|
||||
Polygons polygons = to_polygons(surface.expolygon);
|
||||
if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid)
|
||||
polygons_append(lower_layer_internal_surfaces, polygons);
|
||||
polygons_append(lower_layer_fill_surfaces, std::move(polygons));
|
||||
//polygons_append(fill_surfaces, std::move(polygons));
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
Polygons fill_surfaces;
|
||||
for (const LayerRegion *layerm : layer->regions)
|
||||
polygons_append(fill_surfaces, (Polygons)layerm->fill_surfaces);
|
||||
Polygons perimeters = diff(layer->slices, fill_surfaces);
|
||||
|
||||
// Only consider the area that is not supported by lower perimeters
|
||||
Polygons perimeters = intersection(diff(slices, fill_surfaces), lower_layer_fill_surfaces);
|
||||
Polygons lower_layer_fill_surfaces;
|
||||
for (const LayerRegion *layerm : lower_layer->regions)
|
||||
polygons_append(lower_layer_fill_surfaces, (Polygons)layerm->fill_surfaces);
|
||||
perimeters = intersection(perimeters, lower_layer_fill_surfaces, true);
|
||||
|
||||
// Only consider perimeter areas that are at least one extrusion width thick.
|
||||
//FIXME Offset2 eats out from both sides, while the perimeters are create outside in.
|
||||
//Should the pw not be half of the current value?
|
||||
float pw = FLT_MAX;
|
||||
for (const LayerRegion *layerm : layer->regions)
|
||||
pw = std::min<float>(pw, layerm->flow(frPerimeter).scaled_width());
|
||||
perimeters = offset2(perimeters, -pw, +pw);
|
||||
|
||||
// Append such thick perimeters to the areas that need support
|
||||
polygons_append(overhangs, offset2(perimeters, -pw, +pw));
|
||||
polygons_append(overhangs, perimeters);
|
||||
}
|
||||
|
||||
// Find new internal infill.
|
||||
polygons_append(overhangs, std::move(upper_internal));
|
||||
upper_internal = intersection(overhangs, lower_layer_internal_surfaces);
|
||||
{
|
||||
polygons_append(overhangs, std::move(upper_internal));
|
||||
|
||||
// get our current internal fill boundaries
|
||||
Polygons lower_layer_internal_surfaces;
|
||||
for (const auto* layerm : lower_layer->regions)
|
||||
for (const auto* s : layerm->fill_surfaces.filter_by_type({ stInternal, stInternalVoid }))
|
||||
polygons_append(lower_layer_internal_surfaces, *s);
|
||||
upper_internal = intersection(overhangs, lower_layer_internal_surfaces);
|
||||
}
|
||||
|
||||
// Apply new internal infill to regions.
|
||||
for (LayerRegion *layerm : lower_layer->regions) {
|
||||
for (auto* layerm : lower_layer->regions) {
|
||||
if (layerm->region()->config.fill_density.value == 0)
|
||||
continue;
|
||||
|
||||
Polygons internal;
|
||||
for (Surface &surface : layerm->fill_surfaces.surfaces)
|
||||
if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid)
|
||||
polygons_append(internal, std::move(surface.expolygon));
|
||||
for (const auto* s : layerm->fill_surfaces.filter_by_type({ stInternal, stInternalVoid }))
|
||||
polygons_append(internal, *s);
|
||||
|
||||
layerm->fill_surfaces.remove_types({ stInternal, stInternalVoid });
|
||||
layerm->fill_surfaces.append(intersection_ex(internal, upper_internal, true), stInternal);
|
||||
layerm->fill_surfaces.append(diff_ex (internal, upper_internal, true), stInternalVoid);
|
||||
|
||||
// If there are voids it means that our internal infill is not adjacent to
|
||||
// perimeters. In this case it would be nice to add a loop around infill to
|
||||
// make it more robust and nicer. TODO.
|
||||
|
@ -90,29 +90,30 @@ SurfaceCollection::any_bottom_contains(const T &item) const
|
||||
}
|
||||
template bool SurfaceCollection::any_bottom_contains<Polyline>(const Polyline &item) const;
|
||||
|
||||
SurfacesPtr
|
||||
SurfaceCollection::filter_by_type(SurfaceType type)
|
||||
{
|
||||
SurfacesPtr ss;
|
||||
for (Surfaces::iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) {
|
||||
if (surface->surface_type == type) ss.push_back(&*surface);
|
||||
}
|
||||
return ss;
|
||||
}
|
||||
|
||||
SurfacesPtr
|
||||
SurfaceCollection::filter_by_type(std::initializer_list<SurfaceType> types)
|
||||
{
|
||||
size_t n {0};
|
||||
SurfacesPtr ss;
|
||||
for (const auto& t : types) {
|
||||
for (const auto& t : types)
|
||||
n |= t;
|
||||
}
|
||||
for (Surfaces::iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) {
|
||||
if ((surface->surface_type & n) == surface->surface_type) ss.push_back(&*surface);
|
||||
}
|
||||
SurfacesPtr ss;
|
||||
for (auto& s : this->surfaces)
|
||||
if ((s.surface_type & n) == s.surface_type) ss.push_back(&s);
|
||||
return ss;
|
||||
}
|
||||
|
||||
SurfacesConstPtr
|
||||
SurfaceCollection::filter_by_type(std::initializer_list<SurfaceType> types) const
|
||||
{
|
||||
size_t n {0};
|
||||
for (const auto& t : types)
|
||||
n |= t;
|
||||
SurfacesConstPtr ss;
|
||||
for (auto& s : this->surfaces)
|
||||
if ((s.surface_type & n) == s.surface_type) ss.push_back(&s);
|
||||
return ss;
|
||||
}
|
||||
|
||||
void
|
||||
SurfaceCollection::filter_by_type(SurfaceType type, Polygons* polygons)
|
||||
{
|
||||
|
@ -21,9 +21,15 @@ class SurfaceCollection
|
||||
void group(std::vector<SurfacesConstPtr> *retval) const;
|
||||
template <class T> bool any_internal_contains(const T &item) const;
|
||||
template <class T> bool any_bottom_contains(const T &item) const;
|
||||
SurfacesPtr filter_by_type(SurfaceType type);
|
||||
SurfacesPtr filter_by_type(SurfaceType type) {
|
||||
return this->filter_by_type({ type });
|
||||
};
|
||||
SurfacesPtr filter_by_type(std::initializer_list<SurfaceType> types);
|
||||
void filter_by_type(SurfaceType type, Polygons* polygons);
|
||||
SurfacesConstPtr filter_by_type(SurfaceType type) const {
|
||||
return this->filter_by_type({ type });
|
||||
};
|
||||
SurfacesConstPtr filter_by_type(std::initializer_list<SurfaceType> types) const;
|
||||
|
||||
/// deletes all surfaces that match the supplied type.
|
||||
void remove_type(const SurfaceType type);
|
||||
|
@ -129,6 +129,7 @@ _constant()
|
||||
%name{_detect_surfaces_type} void detect_surfaces_type();
|
||||
void process_external_surfaces();
|
||||
void bridge_over_infill();
|
||||
void clip_fill_surfaces();
|
||||
void _slice();
|
||||
SV* _slice_region(size_t region_id, std::vector<double> z, bool modifier)
|
||||
%code%{
|
||||
|
Loading…
x
Reference in New Issue
Block a user