mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-15 16:45:55 +08:00
Ported PrintObject::combine_infill() to C++
This commit is contained in:
parent
450042a60c
commit
2bbb089a4f
@ -252,135 +252,4 @@ sub _support_material {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
# combine fill surfaces across layers
|
|
||||||
# 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 combine_infill {
|
|
||||||
my $self = shift;
|
|
||||||
|
|
||||||
# define the type used for voids
|
|
||||||
my %voidtype = (
|
|
||||||
&S_TYPE_INTERNAL() => S_TYPE_INTERNALVOID,
|
|
||||||
);
|
|
||||||
|
|
||||||
# work on each region separately
|
|
||||||
for my $region_id (0 .. ($self->print->region_count-1)) {
|
|
||||||
my $region = $self->print->get_region($region_id);
|
|
||||||
my $every = $region->config->infill_every_layers;
|
|
||||||
next unless $every > 1 && $region->config->fill_density > 0;
|
|
||||||
|
|
||||||
# limit the number of combined layers to the maximum height allowed by this regions' nozzle
|
|
||||||
my $nozzle_diameter = min(
|
|
||||||
$self->print->config->get_at('nozzle_diameter', $region->config->infill_extruder-1),
|
|
||||||
$self->print->config->get_at('nozzle_diameter', $region->config->solid_infill_extruder-1),
|
|
||||||
);
|
|
||||||
|
|
||||||
# define the combinations
|
|
||||||
my %combine = (); # layer_idx => number of additional combined lower layers
|
|
||||||
{
|
|
||||||
my $current_height = my $layers = 0;
|
|
||||||
for my $layer_idx (0 .. ($self->layer_count-1)) {
|
|
||||||
my $layer = $self->get_layer($layer_idx);
|
|
||||||
next if $layer->id == 0; # skip first print layer (which may not be first layer in array because of raft)
|
|
||||||
my $height = $layer->height;
|
|
||||||
|
|
||||||
# check whether the combination of this layer with the lower layers' buffer
|
|
||||||
# would exceed max layer height or max combined layer count
|
|
||||||
if ($current_height + $height >= $nozzle_diameter + epsilon || $layers >= $every) {
|
|
||||||
# append combination to lower layer
|
|
||||||
$combine{$layer_idx-1} = $layers;
|
|
||||||
$current_height = $layers = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$current_height += $height;
|
|
||||||
$layers++;
|
|
||||||
}
|
|
||||||
|
|
||||||
# append lower layers (if any) to uppermost layer
|
|
||||||
$combine{$self->layer_count-1} = $layers;
|
|
||||||
}
|
|
||||||
|
|
||||||
# loop through layers to which we have assigned layers to combine
|
|
||||||
for my $layer_idx (sort keys %combine) {
|
|
||||||
next unless $combine{$layer_idx} > 1;
|
|
||||||
|
|
||||||
# get all the LayerRegion objects to be combined
|
|
||||||
my @layerms = map $self->get_layer($_)->get_region($region_id),
|
|
||||||
($layer_idx - ($combine{$layer_idx}-1) .. $layer_idx);
|
|
||||||
|
|
||||||
# only combine internal infill
|
|
||||||
for my $type (S_TYPE_INTERNAL) {
|
|
||||||
# we need to perform a multi-layer intersection, so let's split it in pairs
|
|
||||||
|
|
||||||
# initialize the intersection with the candidates of the lowest layer
|
|
||||||
my $intersection = [ map $_->expolygon, @{$layerms[0]->fill_surfaces->filter_by_type($type)} ];
|
|
||||||
|
|
||||||
# start looping from the second layer and intersect the current intersection with it
|
|
||||||
for my $layerm (@layerms[1 .. $#layerms]) {
|
|
||||||
$intersection = intersection_ex(
|
|
||||||
[ map @$_, @$intersection ],
|
|
||||||
[ map @{$_->expolygon}, @{$layerm->fill_surfaces->filter_by_type($type)} ],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
my $area_threshold = $layerms[0]->infill_area_threshold;
|
|
||||||
@$intersection = grep $_->area > $area_threshold, @$intersection;
|
|
||||||
next if !@$intersection;
|
|
||||||
Slic3r::debugf " combining %d %s regions from layers %d-%d\n",
|
|
||||||
scalar(@$intersection),
|
|
||||||
($type == S_TYPE_INTERNAL ? 'internal' : 'internal-solid'),
|
|
||||||
$layer_idx-($every-1), $layer_idx;
|
|
||||||
|
|
||||||
# $intersection now contains the regions that can be combined across the full amount of layers
|
|
||||||
# so let's remove those areas from all layers
|
|
||||||
|
|
||||||
my @intersection_with_clearance = map @{$_->offset(
|
|
||||||
$layerms[-1]->flow(FLOW_ROLE_SOLID_INFILL)->scaled_width / 2
|
|
||||||
+ $layerms[-1]->flow(FLOW_ROLE_PERIMETER)->scaled_width / 2
|
|
||||||
# Because fill areas for rectilinear and honeycomb are grown
|
|
||||||
# later to overlap perimeters, we need to counteract that too.
|
|
||||||
+ (($type == S_TYPE_INTERNALSOLID || $region->config->fill_pattern =~ /(rectilinear|grid|line|honeycomb)/)
|
|
||||||
? $layerms[-1]->flow(FLOW_ROLE_SOLID_INFILL)->scaled_width
|
|
||||||
: 0)
|
|
||||||
)}, @$intersection;
|
|
||||||
|
|
||||||
|
|
||||||
foreach my $layerm (@layerms) {
|
|
||||||
my @this_type = @{$layerm->fill_surfaces->filter_by_type($type)};
|
|
||||||
my @other_types = map $_->clone, grep $_->surface_type != $type, @{$layerm->fill_surfaces};
|
|
||||||
|
|
||||||
my @new_this_type = map Slic3r::Surface->new(expolygon => $_, surface_type => $type),
|
|
||||||
@{diff_ex(
|
|
||||||
[ map $_->p, @this_type ],
|
|
||||||
[ @intersection_with_clearance ],
|
|
||||||
)};
|
|
||||||
|
|
||||||
# apply surfaces back with adjusted depth to the uppermost layer
|
|
||||||
if ($layerm->layer->id == $self->get_layer($layer_idx)->id) {
|
|
||||||
push @new_this_type,
|
|
||||||
map Slic3r::Surface->new(
|
|
||||||
expolygon => $_,
|
|
||||||
surface_type => $type,
|
|
||||||
thickness => sum(map $_->layer->height, @layerms),
|
|
||||||
thickness_layers => scalar(@layerms),
|
|
||||||
),
|
|
||||||
@$intersection;
|
|
||||||
} else {
|
|
||||||
# save void surfaces
|
|
||||||
push @new_this_type,
|
|
||||||
map Slic3r::Surface->new(expolygon => $_, surface_type => $voidtype{$type}),
|
|
||||||
@{intersection_ex(
|
|
||||||
[ map @{$_->expolygon}, @this_type ],
|
|
||||||
[ @intersection_with_clearance ],
|
|
||||||
)};
|
|
||||||
}
|
|
||||||
|
|
||||||
$layerm->fill_surfaces->clear;
|
|
||||||
$layerm->fill_surfaces->append($_) for (@new_this_type, @other_types);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -34,6 +34,7 @@ Pointf circle_taubin_newton(const Pointfs& input, size_t cycles = 20);
|
|||||||
Pointf circle_taubin_newton(const Pointfs::const_iterator& input_start, const Pointfs::const_iterator& input_end, size_t cycles = 20);
|
Pointf circle_taubin_newton(const Pointfs::const_iterator& input_start, const Pointfs::const_iterator& input_end, size_t cycles = 20);
|
||||||
|
|
||||||
/// Epsilon value
|
/// Epsilon value
|
||||||
|
// FIXME: this is a duplicate from libslic3r.h
|
||||||
constexpr double epsilon { 1e-4 };
|
constexpr double epsilon { 1e-4 };
|
||||||
constexpr coord_t scaled_epsilon { static_cast<coord_t>(epsilon / SCALING_FACTOR) };
|
constexpr coord_t scaled_epsilon { static_cast<coord_t>(epsilon / SCALING_FACTOR) };
|
||||||
|
|
||||||
|
@ -1175,33 +1175,41 @@ PrintObject::prepare_infill()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// combine fill surfaces across layers
|
||||||
|
// 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::combine_infill()
|
PrintObject::combine_infill()
|
||||||
{
|
{
|
||||||
// Work on each region separately.
|
// Work on each region separately.
|
||||||
for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) {
|
for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) {
|
||||||
const PrintRegion *region = this->print()->regions[region_id];
|
const PrintRegion *region = this->print()->regions[region_id];
|
||||||
const int every = region->config.infill_every_layers.value;
|
const int every = region->config.infill_every_layers();
|
||||||
if (every < 2 || region->config.fill_density == 0.)
|
if (every < 2 || region->config.fill_density == 0.)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Limit the number of combined layers to the maximum height allowed by this regions' nozzle.
|
// Limit the number of combined layers to the maximum height allowed by this regions' nozzle.
|
||||||
//FIXME limit the layer height to max_layer_height
|
// FIXME: limit the layer height to max_layer_height
|
||||||
double nozzle_diameter = std::min(
|
const double nozzle_diameter = std::min(
|
||||||
this->print()->config.nozzle_diameter.get_at(region->config.infill_extruder.value - 1),
|
this->_print->config.nozzle_diameter.get_at(region->config.infill_extruder.value - 1),
|
||||||
this->print()->config.nozzle_diameter.get_at(region->config.solid_infill_extruder.value - 1));
|
this->_print->config.nozzle_diameter.get_at(region->config.solid_infill_extruder.value - 1)
|
||||||
|
);
|
||||||
|
|
||||||
// define the combinations
|
// define the combinations
|
||||||
std::vector<size_t> combine(this->layers.size(), 0);
|
std::vector<size_t> combine(this->layers.size(), 0); // layer_idx => number of additional combined lower layers
|
||||||
{
|
{
|
||||||
double current_height = 0.;
|
double current_height = 0.;
|
||||||
size_t num_layers = 0;
|
size_t num_layers = 0;
|
||||||
for (size_t layer_idx = 0; layer_idx < this->layers.size(); ++layer_idx) {
|
for (size_t layer_idx = 0; layer_idx < this->layers.size(); ++layer_idx) {
|
||||||
const Layer *layer = this->layers[layer_idx];
|
const Layer *layer = this->layers[layer_idx];
|
||||||
if (layer->id() == 0)
|
|
||||||
// Skip first print layer (which may not be first layer in array because of raft).
|
// Skip first print layer (which may not be first layer in array because of raft).
|
||||||
|
if (layer->id() == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Check whether the combination of this layer with the lower layers' buffer
|
// Check whether the combination of this layer with the lower layers' buffer
|
||||||
// would exceed max layer height or max combined layer count.
|
// would exceed max layer height or max combined layer count.
|
||||||
if (current_height + layer->height >= nozzle_diameter + EPSILON || (every < 0 || num_layers >= static_cast<size_t>(every)) ) {
|
if (current_height + layer->height >= nozzle_diameter + EPSILON || num_layers >= static_cast<size_t>(every) ) {
|
||||||
// Append combination to lower layer.
|
// Append combination to lower layer.
|
||||||
combine[layer_idx - 1] = num_layers;
|
combine[layer_idx - 1] = num_layers;
|
||||||
current_height = 0.;
|
current_height = 0.;
|
||||||
@ -1216,66 +1224,84 @@ PrintObject::combine_infill()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// loop through layers to which we have assigned layers to combine
|
// loop through layers to which we have assigned layers to combine
|
||||||
for (size_t layer_idx = 0; layer_idx < this->layers.size(); ++ layer_idx) {
|
for (size_t layer_idx = 0; layer_idx < combine.size(); ++layer_idx) {
|
||||||
size_t num_layers = combine[layer_idx];
|
const size_t& num_layers = combine[layer_idx];
|
||||||
if (num_layers <= 1)
|
if (num_layers <= 1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Get all the LayerRegion objects to be combined.
|
// Get all the LayerRegion objects to be combined.
|
||||||
std::vector<LayerRegion*> layerms;
|
std::vector<LayerRegion*> layerms;
|
||||||
layerms.reserve(num_layers);
|
layerms.reserve(num_layers);
|
||||||
for (size_t i = layer_idx + 1 - num_layers; i <= layer_idx; ++i)
|
for (size_t i = layer_idx + 1 - num_layers; i <= layer_idx; ++i)
|
||||||
layerms.emplace_back(this->layers[i]->regions[region_id]);
|
layerms.push_back(this->layers[i]->regions[region_id]);
|
||||||
|
|
||||||
// We need to perform a multi-layer intersection, so let's split it in pairs.
|
// We need to perform a multi-layer intersection, so let's split it in pairs.
|
||||||
|
|
||||||
// Initialize the intersection with the candidates of the lowest layer.
|
// Initialize the intersection with the candidates of the lowest layer.
|
||||||
ExPolygons intersection = to_expolygons(layerms.front()->fill_surfaces.filter_by_type(stInternal));
|
ExPolygons intersection = to_expolygons(layerms.front()->fill_surfaces.filter_by_type(stInternal));
|
||||||
|
|
||||||
// Start looping from the second layer and intersect the current intersection with it.
|
// Start looping from the second layer and intersect the current intersection with it.
|
||||||
for (size_t i = 1; i < layerms.size(); ++i)
|
for (size_t i = 1; i < layerms.size(); ++i)
|
||||||
intersection = intersection_ex(
|
intersection = intersection_ex(
|
||||||
to_polygons(intersection),
|
to_polygons(intersection),
|
||||||
to_polygons(layerms[i]->fill_surfaces.filter_by_type(stInternal)),
|
to_polygons(layerms[i]->fill_surfaces.filter_by_type(stInternal))
|
||||||
false);
|
);
|
||||||
double area_threshold = layerms.front()->infill_area_threshold();
|
|
||||||
if (! intersection.empty() && area_threshold > 0.)
|
// Remove ExPolygons whose area is <= infill_area_threshold()
|
||||||
|
const double area_threshold = layerms.front()->infill_area_threshold();
|
||||||
intersection.erase(std::remove_if(intersection.begin(), intersection.end(),
|
intersection.erase(std::remove_if(intersection.begin(), intersection.end(),
|
||||||
[area_threshold](const ExPolygon &expoly) { return expoly.area() <= area_threshold; }),
|
[area_threshold](const ExPolygon &expoly) { return expoly.area() <= area_threshold; }),
|
||||||
intersection.end());
|
intersection.end());
|
||||||
|
|
||||||
if (intersection.empty())
|
if (intersection.empty())
|
||||||
continue;
|
continue;
|
||||||
// Slic3r::debugf " combining %d %s regions from layers %d-%d\n",
|
|
||||||
// scalar(@$intersection),
|
#ifdef SLIC3R_DEBUG
|
||||||
// ($type == S_TYPE_INTERNAL ? 'internal' : 'internal-solid'),
|
std::cout << " combining " << intersection.size()
|
||||||
// $layer_idx-($every-1), $layer_idx;
|
<< " internal regions from layers " << (layer_idx-(every-1))
|
||||||
|
<< "-" << layer_idx << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
// intersection now contains the regions that can be combined across the full amount of layers,
|
// intersection now contains the regions that can be combined across the full amount of layers,
|
||||||
// so let's remove those areas from all layers.
|
// so let's remove those areas from all layers.
|
||||||
Polygons intersection_with_clearance;
|
|
||||||
intersection_with_clearance.reserve(intersection.size());
|
const float clearance_offset =
|
||||||
float clearance_offset =
|
|
||||||
0.5f * layerms.back()->flow(frPerimeter).scaled_width() +
|
0.5f * layerms.back()->flow(frPerimeter).scaled_width() +
|
||||||
// Because fill areas for rectilinear and honeycomb are grown
|
// Because fill areas for rectilinear and honeycomb are grown
|
||||||
// later to overlap perimeters, we need to counteract that too.
|
// later to overlap perimeters, we need to counteract that too.
|
||||||
((region->config.fill_pattern == ipRectilinear ||
|
((region->config.fill_pattern == ipRectilinear ||
|
||||||
region->config.fill_pattern == ipGrid ||
|
region->config.fill_pattern == ipGrid ||
|
||||||
region->config.fill_pattern == ipHoneycomb) ? 1.5f : 0.5f) *
|
region->config.fill_pattern == ipHoneycomb) ? 1.5f : 0.5f)
|
||||||
layerms.back()->flow(frSolidInfill).scaled_width();
|
* layerms.back()->flow(frSolidInfill).scaled_width();
|
||||||
for (ExPolygon &expoly : intersection)
|
|
||||||
|
Polygons intersection_with_clearance;
|
||||||
|
intersection_with_clearance.reserve(intersection.size());
|
||||||
|
for (const ExPolygon &expoly : intersection)
|
||||||
polygons_append(intersection_with_clearance, offset(expoly, clearance_offset));
|
polygons_append(intersection_with_clearance, offset(expoly, clearance_offset));
|
||||||
|
|
||||||
for (LayerRegion *layerm : layerms) {
|
for (LayerRegion *layerm : layerms) {
|
||||||
Polygons internal = to_polygons(layerm->fill_surfaces.filter_by_type(stInternal));
|
const Polygons internal = to_polygons(layerm->fill_surfaces.filter_by_type(stInternal));
|
||||||
layerm->fill_surfaces.remove_type(stInternal);
|
layerm->fill_surfaces.remove_type(stInternal);
|
||||||
layerm->fill_surfaces.append(diff_ex(internal, intersection_with_clearance, false), stInternal);
|
|
||||||
|
layerm->fill_surfaces.append(
|
||||||
|
diff_ex(internal, intersection_with_clearance),
|
||||||
|
stInternal
|
||||||
|
);
|
||||||
|
|
||||||
if (layerm == layerms.back()) {
|
if (layerm == layerms.back()) {
|
||||||
// Apply surfaces back with adjusted depth to the uppermost layer.
|
// Apply surfaces back with adjusted depth to the uppermost layer.
|
||||||
Surface templ(stInternal, ExPolygon());
|
Surface templ(stInternal, ExPolygon());
|
||||||
templ.thickness = 0.;
|
templ.thickness = 0.;
|
||||||
for (LayerRegion *layerm2 : layerms)
|
for (const LayerRegion *layerm2 : layerms)
|
||||||
templ.thickness += layerm2->layer()->height;
|
templ.thickness += layerm2->layer()->height;
|
||||||
templ.thickness_layers = (unsigned short)layerms.size();
|
templ.thickness_layers = (unsigned short)layerms.size();
|
||||||
layerm->fill_surfaces.append(intersection, templ);
|
layerm->fill_surfaces.append(intersection, templ);
|
||||||
} else {
|
} else {
|
||||||
// Save void surfaces.
|
// Save void surfaces.
|
||||||
layerm->fill_surfaces.append(
|
layerm->fill_surfaces.append(
|
||||||
intersection_ex(internal, intersection_with_clearance, false),
|
intersection_ex(internal, intersection_with_clearance),
|
||||||
stInternalVoid);
|
stInternalVoid
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1624,8 +1650,9 @@ PrintObject::clip_fill_surfaces()
|
|||||||
// get our current internal fill boundaries
|
// get our current internal fill boundaries
|
||||||
Polygons lower_layer_internal_surfaces;
|
Polygons lower_layer_internal_surfaces;
|
||||||
for (const auto* layerm : lower_layer->regions)
|
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, to_polygons(
|
||||||
polygons_append(lower_layer_internal_surfaces, *s);
|
layerm->fill_surfaces.filter_by_type({ stInternal, stInternalVoid })
|
||||||
|
));
|
||||||
upper_internal = intersection(overhangs, lower_layer_internal_surfaces);
|
upper_internal = intersection(overhangs, lower_layer_internal_surfaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1634,10 +1661,7 @@ PrintObject::clip_fill_surfaces()
|
|||||||
if (layerm->region()->config.fill_density.value == 0)
|
if (layerm->region()->config.fill_density.value == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Polygons internal;
|
Polygons internal{ to_polygons(layerm->fill_surfaces.filter_by_type({ stInternal, stInternalVoid })) };
|
||||||
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.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);
|
||||||
|
@ -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 combine_infill();
|
||||||
void discover_horizontal_shells();
|
void discover_horizontal_shells();
|
||||||
void clip_fill_surfaces();
|
void clip_fill_surfaces();
|
||||||
void _slice();
|
void _slice();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user