mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-10-04 03:06:34 +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 {
|
sub discover_horizontal_shells {
|
||||||
my $self = shift;
|
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
|
void
|
||||||
PrintObject::clip_fill_surfaces()
|
PrintObject::clip_fill_surfaces()
|
||||||
{
|
{
|
||||||
@ -1563,61 +1565,72 @@ PrintObject::clip_fill_surfaces()
|
|||||||
// Proceed top-down, skipping the bottom layer.
|
// Proceed top-down, skipping the bottom layer.
|
||||||
Polygons upper_internal;
|
Polygons upper_internal;
|
||||||
for (int layer_id = int(this->layers.size()) - 1; layer_id > 0; --layer_id) {
|
for (int layer_id = int(this->layers.size()) - 1; layer_id > 0; --layer_id) {
|
||||||
Layer *layer = this->layers[layer_id];
|
const Layer *layer = this->layers[layer_id];
|
||||||
Layer *lower_layer = this->layers[layer_id - 1];
|
Layer *lower_layer = this->layers[layer_id - 1];
|
||||||
|
|
||||||
// Detect things that we need to support.
|
// 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.
|
// Solid surfaces to be supported.
|
||||||
Polygons overhangs;
|
Polygons overhangs;
|
||||||
for (const LayerRegion *layerm : layer->regions)
|
for (const LayerRegion *layerm : layer->regions) {
|
||||||
for (const Surface &surface : layerm->fill_surfaces.surfaces) {
|
for (const Surface &surface : layerm->fill_surfaces.surfaces) {
|
||||||
Polygons polygons = to_polygons(surface.expolygon);
|
Polygons polygons = to_polygons(surface.expolygon);
|
||||||
if (surface.is_solid())
|
if (surface.is_solid())
|
||||||
polygons_append(overhangs, polygons);
|
polygons_append(overhangs, polygons);
|
||||||
polygons_append(fill_surfaces, std::move(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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We also need to support perimeters when there's at least one full unsupported loop
|
// 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
|
// 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
|
// 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.
|
// 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.
|
//FIXME Offset2 eats out from both sides, while the perimeters are create outside in.
|
||||||
//Should the pw not be half of the current value?
|
//Should the pw not be half of the current value?
|
||||||
float pw = FLT_MAX;
|
float pw = FLT_MAX;
|
||||||
for (const LayerRegion *layerm : layer->regions)
|
for (const LayerRegion *layerm : layer->regions)
|
||||||
pw = std::min<float>(pw, layerm->flow(frPerimeter).scaled_width());
|
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
|
// 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.
|
// Find new internal infill.
|
||||||
|
{
|
||||||
polygons_append(overhangs, std::move(upper_internal));
|
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);
|
upper_internal = intersection(overhangs, lower_layer_internal_surfaces);
|
||||||
|
}
|
||||||
|
|
||||||
// Apply new internal infill to regions.
|
// 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)
|
if (layerm->region()->config.fill_density.value == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Polygons internal;
|
Polygons internal;
|
||||||
for (Surface &surface : layerm->fill_surfaces.surfaces)
|
for (const auto* s : layerm->fill_surfaces.filter_by_type({ stInternal, stInternalVoid }))
|
||||||
if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid)
|
polygons_append(internal, *s);
|
||||||
polygons_append(internal, std::move(surface.expolygon));
|
|
||||||
layerm->fill_surfaces.remove_types({ stInternal, stInternalVoid });
|
layerm->fill_surfaces.remove_types({ stInternal, stInternalVoid });
|
||||||
layerm->fill_surfaces.append(intersection_ex(internal, upper_internal, true), stInternal);
|
layerm->fill_surfaces.append(intersection_ex(internal, upper_internal, true), stInternal);
|
||||||
layerm->fill_surfaces.append(diff_ex (internal, upper_internal, true), stInternalVoid);
|
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
|
// 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
|
// perimeters. In this case it would be nice to add a loop around infill to
|
||||||
// make it more robust and nicer. TODO.
|
// 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;
|
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
|
SurfacesPtr
|
||||||
SurfaceCollection::filter_by_type(std::initializer_list<SurfaceType> types)
|
SurfaceCollection::filter_by_type(std::initializer_list<SurfaceType> types)
|
||||||
{
|
{
|
||||||
size_t n {0};
|
size_t n {0};
|
||||||
SurfacesPtr ss;
|
for (const auto& t : types)
|
||||||
for (const auto& t : types) {
|
|
||||||
n |= t;
|
n |= t;
|
||||||
}
|
SurfacesPtr ss;
|
||||||
for (Surfaces::iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) {
|
for (auto& s : this->surfaces)
|
||||||
if ((surface->surface_type & n) == surface->surface_type) ss.push_back(&*surface);
|
if ((s.surface_type & n) == s.surface_type) ss.push_back(&s);
|
||||||
}
|
|
||||||
return ss;
|
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
|
void
|
||||||
SurfaceCollection::filter_by_type(SurfaceType type, Polygons* polygons)
|
SurfaceCollection::filter_by_type(SurfaceType type, Polygons* polygons)
|
||||||
{
|
{
|
||||||
|
@ -21,9 +21,15 @@ class SurfaceCollection
|
|||||||
void group(std::vector<SurfacesConstPtr> *retval) const;
|
void group(std::vector<SurfacesConstPtr> *retval) const;
|
||||||
template <class T> bool any_internal_contains(const T &item) const;
|
template <class T> bool any_internal_contains(const T &item) const;
|
||||||
template <class T> bool any_bottom_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);
|
SurfacesPtr filter_by_type(std::initializer_list<SurfaceType> types);
|
||||||
void filter_by_type(SurfaceType type, Polygons* polygons);
|
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.
|
/// deletes all surfaces that match the supplied type.
|
||||||
void remove_type(const SurfaceType type);
|
void remove_type(const SurfaceType type);
|
||||||
|
@ -129,6 +129,7 @@ _constant()
|
|||||||
%name{_detect_surfaces_type} void detect_surfaces_type();
|
%name{_detect_surfaces_type} void detect_surfaces_type();
|
||||||
void process_external_surfaces();
|
void process_external_surfaces();
|
||||||
void bridge_over_infill();
|
void bridge_over_infill();
|
||||||
|
void clip_fill_surfaces();
|
||||||
void _slice();
|
void _slice();
|
||||||
SV* _slice_region(size_t region_id, std::vector<double> z, bool modifier)
|
SV* _slice_region(size_t region_id, std::vector<double> z, bool modifier)
|
||||||
%code%{
|
%code%{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user