mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-07-31 20:31:59 +08:00
Merge pull request #3796 from platsch/slice_xs
Ported parts of Slice to xs
This commit is contained in:
commit
ff9bae79ca
@ -33,17 +33,6 @@ sub support_layers {
|
|||||||
return [ map $self->get_support_layer($_), 0..($self->support_layer_count - 1) ];
|
return [ map $self->get_support_layer($_), 0..($self->support_layer_count - 1) ];
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _adjust_layer_height {
|
|
||||||
my ($self, $lh) = @_;
|
|
||||||
|
|
||||||
if ($self->print->config->z_steps_per_mm > 0) {
|
|
||||||
my $min_dz = 1/$self->print->config->z_steps_per_mm * 4;
|
|
||||||
$lh = int($lh / $min_dz + 0.5) * $min_dz;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $lh;
|
|
||||||
}
|
|
||||||
|
|
||||||
# 1) Decides Z positions of the layers,
|
# 1) Decides Z positions of the layers,
|
||||||
# 2) Initializes layers and their regions
|
# 2) Initializes layers and their regions
|
||||||
# 3) Slices the object meshes
|
# 3) Slices the object meshes
|
||||||
@ -60,257 +49,7 @@ sub slice {
|
|||||||
$self->set_step_started(STEP_SLICE);
|
$self->set_step_started(STEP_SLICE);
|
||||||
$self->print->status_cb->(10, "Processing triangulated mesh");
|
$self->print->status_cb->(10, "Processing triangulated mesh");
|
||||||
|
|
||||||
my $min_nozzle_diameter;
|
$self->_slice;
|
||||||
{
|
|
||||||
my @nozzle_diameters = map $self->print->config->get_at('nozzle_diameter', $_),
|
|
||||||
@{$self->print->object_extruders};
|
|
||||||
|
|
||||||
$min_nozzle_diameter = min(@nozzle_diameters);
|
|
||||||
my $lh = min($min_nozzle_diameter, $self->config->layer_height);
|
|
||||||
|
|
||||||
$self->config->set('layer_height', $self->_adjust_layer_height($lh));
|
|
||||||
}
|
|
||||||
|
|
||||||
# init layers
|
|
||||||
{
|
|
||||||
$self->clear_layers;
|
|
||||||
|
|
||||||
# make layers taking custom heights into account
|
|
||||||
my $id = 0;
|
|
||||||
my $print_z = 0;
|
|
||||||
my $first_object_layer_height = -1;
|
|
||||||
my $first_object_layer_distance = -1;
|
|
||||||
|
|
||||||
# add raft layers
|
|
||||||
if ($self->config->raft_layers > 0) {
|
|
||||||
$id += $self->config->raft_layers;
|
|
||||||
|
|
||||||
# raise first object layer Z by the thickness of the raft itself
|
|
||||||
# plus the extra distance required by the support material logic
|
|
||||||
my $first_layer_height = $self->config->get_value('first_layer_height');
|
|
||||||
$print_z += $first_layer_height;
|
|
||||||
|
|
||||||
# use a large height
|
|
||||||
my $support_material_layer_height;
|
|
||||||
{
|
|
||||||
my @nozzle_diameters = (
|
|
||||||
map $self->print->config->get_at('nozzle_diameter', $_),
|
|
||||||
@{$self->support_material_extruders},
|
|
||||||
);
|
|
||||||
$support_material_layer_height = 0.75 * min(@nozzle_diameters);
|
|
||||||
}
|
|
||||||
$print_z += $support_material_layer_height * ($self->config->raft_layers - 1);
|
|
||||||
|
|
||||||
# compute the average of all nozzles used for printing the object
|
|
||||||
my $nozzle_diameter;
|
|
||||||
{
|
|
||||||
my @nozzle_diameters = (
|
|
||||||
map $self->print->config->get_at('nozzle_diameter', $_), @{$self->print->object_extruders}
|
|
||||||
);
|
|
||||||
$nozzle_diameter = sum(@nozzle_diameters)/@nozzle_diameters;
|
|
||||||
}
|
|
||||||
$first_object_layer_distance = $self->_support_material->contact_distance($self->config->layer_height, $nozzle_diameter);
|
|
||||||
|
|
||||||
# force first layer print_z according to the contact distance
|
|
||||||
# (the loop below will raise print_z by such height)
|
|
||||||
$first_object_layer_height = $first_object_layer_distance - $self->config->support_material_contact_distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
# loop until we have at least one layer and the max slice_z reaches the object height
|
|
||||||
my $slice_z = 0;
|
|
||||||
my $height = 0;
|
|
||||||
my $max_z = unscale($self->size->z);
|
|
||||||
while (($slice_z - $height) <= $max_z) {
|
|
||||||
# assign the default height to the layer according to the general settings
|
|
||||||
$height = ($id == 0)
|
|
||||||
? $self->config->get_value('first_layer_height')
|
|
||||||
: $self->config->layer_height;
|
|
||||||
|
|
||||||
# look for an applicable custom range
|
|
||||||
if (my $range = first { $_->[0] <= $slice_z && $_->[1] > $slice_z } @{$self->layer_height_ranges}) {
|
|
||||||
$height = $self->_adjust_layer_height($range->[2]);
|
|
||||||
|
|
||||||
# if user set custom height to zero we should just skip the range and resume slicing over it
|
|
||||||
if ($height == 0) {
|
|
||||||
$slice_z += $range->[1] - $range->[0];
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($first_object_layer_height != -1 && !@{$self->layers}) {
|
|
||||||
$height = $first_object_layer_height;
|
|
||||||
$print_z += ($first_object_layer_distance - $height);
|
|
||||||
}
|
|
||||||
|
|
||||||
$print_z += $height;
|
|
||||||
$slice_z += $height/2;
|
|
||||||
last if $slice_z > $max_z;
|
|
||||||
|
|
||||||
### Slic3r::debugf "Layer %d: height = %s; slice_z = %s; print_z = %s\n", $id, $height, $slice_z, $print_z;
|
|
||||||
|
|
||||||
$self->add_layer($id, $height, $print_z, $slice_z);
|
|
||||||
if ($self->layer_count >= 2) {
|
|
||||||
my $lc = $self->layer_count;
|
|
||||||
$self->get_layer($lc - 2)->set_upper_layer($self->get_layer($lc - 1));
|
|
||||||
$self->get_layer($lc - 1)->set_lower_layer($self->get_layer($lc - 2));
|
|
||||||
}
|
|
||||||
$id++;
|
|
||||||
|
|
||||||
$slice_z += $height/2; # add the other half layer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Reduce or thicken the top layer in order to match the original object size.
|
|
||||||
# This is not actually related to z_steps_per_mm but we only enable it in case
|
|
||||||
# user provided that value, as it means they really care about the layer height
|
|
||||||
# accuracy and we don't provide unexpected result for people noticing the last
|
|
||||||
# layer has a different layer height.
|
|
||||||
if ($self->print->config->z_steps_per_mm > 0) {
|
|
||||||
my $first_object_layer = $self->get_layer(0);
|
|
||||||
my $last_object_layer = $self->get_layer($self->layer_count-1);
|
|
||||||
my $print_height = $last_object_layer->print_z - $first_object_layer->print_z + $first_object_layer->height;
|
|
||||||
my $diff = $print_height - unscale($self->size->z);
|
|
||||||
if ($diff < 0) {
|
|
||||||
# we need to thicken last layer
|
|
||||||
$diff = min(abs($diff), $min_nozzle_diameter - $last_object_layer->height);
|
|
||||||
$last_object_layer->set_height($last_object_layer->height + $diff);
|
|
||||||
$last_object_layer->set_print_z($last_object_layer->print_z + $diff);
|
|
||||||
} else {
|
|
||||||
# we need to reduce last layer
|
|
||||||
# prevent generation of a too small layer
|
|
||||||
my $new_height = $last_object_layer->height - $diff;
|
|
||||||
if ($new_height < $min_nozzle_diameter/2) {
|
|
||||||
$last_object_layer->set_height($new_height);
|
|
||||||
$last_object_layer->set_print_z($last_object_layer->print_z - $diff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# make sure all layers contain layer region objects for all regions
|
|
||||||
my $regions_count = $self->print->region_count;
|
|
||||||
foreach my $layer (@{ $self->layers }) {
|
|
||||||
$layer->region($_) for 0 .. ($regions_count-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
# get array of Z coordinates for slicing
|
|
||||||
my @z = map $_->slice_z, @{$self->layers};
|
|
||||||
|
|
||||||
# slice all non-modifier volumes
|
|
||||||
for my $region_id (0..($self->region_count - 1)) {
|
|
||||||
my $expolygons_by_layer = $self->_slice_region($region_id, \@z, 0);
|
|
||||||
for my $layer_id (0..$#$expolygons_by_layer) {
|
|
||||||
my $layerm = $self->get_layer($layer_id)->regions->[$region_id];
|
|
||||||
$layerm->slices->clear;
|
|
||||||
foreach my $expolygon (@{ $expolygons_by_layer->[$layer_id] }) {
|
|
||||||
$layerm->slices->append(Slic3r::Surface->new(
|
|
||||||
expolygon => $expolygon,
|
|
||||||
surface_type => S_TYPE_INTERNAL,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# then slice all modifier volumes
|
|
||||||
if ($self->region_count > 1) {
|
|
||||||
for my $region_id (0..$self->region_count) {
|
|
||||||
my $expolygons_by_layer = $self->_slice_region($region_id, \@z, 1);
|
|
||||||
|
|
||||||
# loop through the other regions and 'steal' the slices belonging to this one
|
|
||||||
for my $other_region_id (0..$self->region_count) {
|
|
||||||
next if $other_region_id == $region_id;
|
|
||||||
|
|
||||||
for my $layer_id (0..$#$expolygons_by_layer) {
|
|
||||||
my $layerm = $self->get_layer($layer_id)->regions->[$region_id];
|
|
||||||
my $other_layerm = $self->get_layer($layer_id)->regions->[$other_region_id];
|
|
||||||
next if !defined $other_layerm;
|
|
||||||
|
|
||||||
my $other_slices = [ map $_->p, @{$other_layerm->slices} ]; # Polygons
|
|
||||||
my $my_parts = intersection_ex(
|
|
||||||
$other_slices,
|
|
||||||
[ map @$_, @{ $expolygons_by_layer->[$layer_id] } ],
|
|
||||||
);
|
|
||||||
next if !@$my_parts;
|
|
||||||
|
|
||||||
# append new parts to our region
|
|
||||||
foreach my $expolygon (@$my_parts) {
|
|
||||||
$layerm->slices->append(Slic3r::Surface->new(
|
|
||||||
expolygon => $expolygon,
|
|
||||||
surface_type => S_TYPE_INTERNAL,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
# remove such parts from original region
|
|
||||||
$other_layerm->slices->clear;
|
|
||||||
$other_layerm->slices->append(Slic3r::Surface->new(
|
|
||||||
expolygon => $_,
|
|
||||||
surface_type => S_TYPE_INTERNAL,
|
|
||||||
)) for @{ diff_ex($other_slices, [ map @$_, @$my_parts ]) };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# remove last layer(s) if empty
|
|
||||||
$self->delete_layer($self->layer_count - 1)
|
|
||||||
while $self->layer_count && (!map @{$_->slices}, @{$self->get_layer($self->layer_count - 1)->regions});
|
|
||||||
|
|
||||||
foreach my $layer (@{ $self->layers }) {
|
|
||||||
# apply size compensation
|
|
||||||
if ($self->config->xy_size_compensation != 0) {
|
|
||||||
my $delta = scale($self->config->xy_size_compensation);
|
|
||||||
if (@{$layer->regions} == 1) {
|
|
||||||
# single region
|
|
||||||
my $layerm = $layer->regions->[0];
|
|
||||||
my $slices = [ map $_->p, @{$layerm->slices} ];
|
|
||||||
$layerm->slices->clear;
|
|
||||||
$layerm->slices->append(Slic3r::Surface->new(
|
|
||||||
expolygon => $_,
|
|
||||||
surface_type => S_TYPE_INTERNAL,
|
|
||||||
)) for @{offset_ex($slices, $delta)};
|
|
||||||
} else {
|
|
||||||
if ($delta < 0) {
|
|
||||||
# multiple regions, shrinking
|
|
||||||
# we apply the offset to the combined shape, then intersect it
|
|
||||||
# with the original slices for each region
|
|
||||||
my $slices = union([ map $_->p, map @{$_->slices}, @{$layer->regions} ]);
|
|
||||||
$slices = offset($slices, $delta);
|
|
||||||
foreach my $layerm (@{$layer->regions}) {
|
|
||||||
my $this_slices = intersection_ex(
|
|
||||||
$slices,
|
|
||||||
[ map $_->p, @{$layerm->slices} ],
|
|
||||||
);
|
|
||||||
$layerm->slices->clear;
|
|
||||||
$layerm->slices->append(Slic3r::Surface->new(
|
|
||||||
expolygon => $_,
|
|
||||||
surface_type => S_TYPE_INTERNAL,
|
|
||||||
)) for @$this_slices;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
# multiple regions, growing
|
|
||||||
# this is an ambiguous case, since it's not clear how to grow regions where they are going to overlap
|
|
||||||
# so we give priority to the first one and so on
|
|
||||||
for my $i (0..$#{$layer->regions}) {
|
|
||||||
my $layerm = $layer->regions->[$i];
|
|
||||||
my $slices = offset_ex([ map $_->p, @{$layerm->slices} ], $delta);
|
|
||||||
if ($i > 0) {
|
|
||||||
$slices = diff_ex(
|
|
||||||
[ map @$_, @$slices ],
|
|
||||||
[ map $_->p, map @{$_->slices}, map $layer->regions->[$_], 0..($i-1) ], # slices of already processed regions
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$layerm->slices->clear;
|
|
||||||
$layerm->slices->append(Slic3r::Surface->new(
|
|
||||||
expolygon => $_,
|
|
||||||
surface_type => S_TYPE_INTERNAL,
|
|
||||||
)) for @$slices;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# merge all regions' slices to get islands
|
|
||||||
$layer->make_slices;
|
|
||||||
}
|
|
||||||
|
|
||||||
# detect slicing errors
|
# detect slicing errors
|
||||||
my $warning_thrown = 0;
|
my $warning_thrown = 0;
|
||||||
|
@ -140,6 +140,9 @@ class PrintObject
|
|||||||
void detect_surfaces_type();
|
void detect_surfaces_type();
|
||||||
void process_external_surfaces();
|
void process_external_surfaces();
|
||||||
void bridge_over_infill();
|
void bridge_over_infill();
|
||||||
|
coordf_t adjust_layer_height(coordf_t layer_height) const;
|
||||||
|
std::vector<coordf_t> generate_object_layers(coordf_t first_layer_height);
|
||||||
|
void _slice();
|
||||||
std::vector<ExPolygons> _slice_region(size_t region_id, std::vector<float> z, bool modifier);
|
std::vector<ExPolygons> _slice_region(size_t region_id, std::vector<float> z, bool modifier);
|
||||||
void _make_perimeters();
|
void _make_perimeters();
|
||||||
void _infill();
|
void _infill();
|
||||||
|
@ -549,6 +549,246 @@ PrintObject::bridge_over_infill()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// adjust the layer height to the next multiple of the z full-step resolution
|
||||||
|
coordf_t PrintObject::adjust_layer_height(coordf_t layer_height) const
|
||||||
|
{
|
||||||
|
coordf_t result = layer_height;
|
||||||
|
if(this->_print->config.z_steps_per_mm > 0) {
|
||||||
|
coordf_t min_dz = 1 / this->_print->config.z_steps_per_mm * 4;
|
||||||
|
result = int(layer_height / min_dz + 0.5) * min_dz;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result > 0 ? result : layer_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate a vector of print_z coordinates in object coordinate system (starting with 0) but including
|
||||||
|
// the first_layer_height if provided.
|
||||||
|
std::vector<coordf_t> PrintObject::generate_object_layers(coordf_t first_layer_height) {
|
||||||
|
|
||||||
|
std::vector<coordf_t> result;
|
||||||
|
|
||||||
|
coordf_t min_nozzle_diameter = 1.0;
|
||||||
|
std::set<size_t> object_extruders = this->_print->object_extruders();
|
||||||
|
for (std::set<size_t>::const_iterator it_extruder = object_extruders.begin(); it_extruder != object_extruders.end(); ++ it_extruder) {
|
||||||
|
min_nozzle_diameter = std::min(min_nozzle_diameter, this->_print->config.nozzle_diameter.get_at(*it_extruder));
|
||||||
|
}
|
||||||
|
coordf_t layer_height = std::min(min_nozzle_diameter, this->config.layer_height.getFloat());
|
||||||
|
layer_height = this->adjust_layer_height(layer_height);
|
||||||
|
this->config.layer_height.value = layer_height;
|
||||||
|
if(first_layer_height) {
|
||||||
|
result.push_back(first_layer_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
coordf_t print_z = first_layer_height;
|
||||||
|
coordf_t height = first_layer_height;
|
||||||
|
// loop until we have at least one layer and the max slice_z reaches the object height
|
||||||
|
while (print_z < unscale(this->size.z)) {
|
||||||
|
height = layer_height;
|
||||||
|
|
||||||
|
// look for an applicable custom range
|
||||||
|
for (t_layer_height_ranges::const_iterator it_range = this->layer_height_ranges.begin(); it_range != this->layer_height_ranges.end(); ++ it_range) {
|
||||||
|
if(print_z >= it_range->first.first && print_z <= it_range->first.second) {
|
||||||
|
if(it_range->second > 0) {
|
||||||
|
height = it_range->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print_z += height;
|
||||||
|
|
||||||
|
result.push_back(print_z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce or thicken the top layer in order to match the original object size.
|
||||||
|
// This is not actually related to z_steps_per_mm but we only enable it in case
|
||||||
|
// user provided that value, as it means they really care about the layer height
|
||||||
|
// accuracy and we don't provide unexpected result for people noticing the last
|
||||||
|
// layer has a different layer height.
|
||||||
|
if (this->_print->config.z_steps_per_mm > 0 && result.size() > 1) {
|
||||||
|
coordf_t diff = result.back() - unscale(this->size.z);
|
||||||
|
int last_layer = result.size()-1;
|
||||||
|
|
||||||
|
if (diff < 0) {
|
||||||
|
// we need to thicken last layer
|
||||||
|
coordf_t new_h = result[last_layer] - result[last_layer-1];
|
||||||
|
new_h = std::min(min_nozzle_diameter, new_h - diff); // add (negativ) diff value
|
||||||
|
std::cout << new_h << std::endl;
|
||||||
|
result[last_layer] = result[last_layer-1] + new_h;
|
||||||
|
} else {
|
||||||
|
// we need to reduce last layer
|
||||||
|
coordf_t new_h = result[last_layer] - result[last_layer-1];
|
||||||
|
if(min_nozzle_diameter/2 < new_h) { //prevent generation of a too small layer
|
||||||
|
new_h = std::max(min_nozzle_diameter/2, new_h - diff); // subtract (positive) diff value
|
||||||
|
std::cout << new_h << std::endl;
|
||||||
|
result[last_layer] = result[last_layer-1] + new_h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1) Decides Z positions of the layers,
|
||||||
|
// 2) Initializes layers and their regions
|
||||||
|
// 3) Slices the object meshes
|
||||||
|
// 4) Slices the modifier meshes and reclassifies the slices of the object meshes by the slices of the modifier meshes
|
||||||
|
// 5) Applies size compensation (offsets the slices in XY plane)
|
||||||
|
// 6) Replaces bad slices by the slices reconstructed from the upper/lower layer
|
||||||
|
// Resulting expolygons of layer regions are marked as Internal.
|
||||||
|
//
|
||||||
|
// this should be idempotent
|
||||||
|
void PrintObject::_slice()
|
||||||
|
{
|
||||||
|
|
||||||
|
coordf_t raft_height = 0;
|
||||||
|
coordf_t print_z = 0;
|
||||||
|
coordf_t height = 0;
|
||||||
|
coordf_t first_layer_height = this->config.first_layer_height.get_abs_value(this->config.layer_height.value);
|
||||||
|
|
||||||
|
|
||||||
|
// take raft layers into account
|
||||||
|
int id = 0;
|
||||||
|
|
||||||
|
if (this->config.raft_layers > 0) {
|
||||||
|
id = this->config.raft_layers;
|
||||||
|
|
||||||
|
coordf_t min_support_nozzle_diameter = 1.0;
|
||||||
|
std::set<size_t> support_material_extruders = this->_print->support_material_extruders();
|
||||||
|
for (std::set<size_t>::const_iterator it_extruder = support_material_extruders.begin(); it_extruder != support_material_extruders.end(); ++ it_extruder) {
|
||||||
|
min_support_nozzle_diameter = std::min(min_support_nozzle_diameter, this->_print->config.nozzle_diameter.get_at(*it_extruder));
|
||||||
|
}
|
||||||
|
coordf_t support_material_layer_height = 0.75 * min_support_nozzle_diameter;
|
||||||
|
|
||||||
|
// raise first object layer Z by the thickness of the raft itself
|
||||||
|
// plus the extra distance required by the support material logic
|
||||||
|
raft_height += first_layer_height;
|
||||||
|
raft_height += support_material_layer_height * (this->config.raft_layers - 1);
|
||||||
|
|
||||||
|
// reset for later layer generation
|
||||||
|
first_layer_height = 0;
|
||||||
|
|
||||||
|
// detachable support
|
||||||
|
if(this->config.support_material_contact_distance > 0) {
|
||||||
|
first_layer_height = min_support_nozzle_diameter;
|
||||||
|
raft_height += this->config.support_material_contact_distance;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize layers and their slice heights.
|
||||||
|
std::vector<float> slice_zs;
|
||||||
|
{
|
||||||
|
this->clear_layers();
|
||||||
|
// All print_z values for this object, without the raft.
|
||||||
|
std::vector<coordf_t> object_layers = this->generate_object_layers(first_layer_height);
|
||||||
|
// Reserve object layers for the raft. Last layer of the raft is the contact layer.
|
||||||
|
slice_zs.reserve(object_layers.size());
|
||||||
|
Layer *prev = nullptr;
|
||||||
|
coordf_t lo = raft_height;
|
||||||
|
coordf_t hi = lo;
|
||||||
|
for (size_t i_layer = 0; i_layer < object_layers.size(); i_layer++) {
|
||||||
|
lo = hi; // store old value
|
||||||
|
hi = object_layers[i_layer] + raft_height;
|
||||||
|
coordf_t slice_z = 0.5 * (lo + hi) - raft_height;
|
||||||
|
Layer *layer = this->add_layer(id++, hi - lo, hi, slice_z);
|
||||||
|
slice_zs.push_back(float(slice_z));
|
||||||
|
if (prev != nullptr) {
|
||||||
|
prev->upper_layer = layer;
|
||||||
|
layer->lower_layer = prev;
|
||||||
|
}
|
||||||
|
// Make sure all layers contain layer region objects for all regions.
|
||||||
|
for (size_t region_id = 0; region_id < this->_print->regions.size(); ++ region_id)
|
||||||
|
layer->add_region(this->print()->regions[region_id]);
|
||||||
|
prev = layer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->print()->regions.size() == 1) {
|
||||||
|
// Optimized for a single region. Slice the single non-modifier mesh.
|
||||||
|
std::vector<ExPolygons> expolygons_by_layer = this->_slice_region(0, slice_zs, false);
|
||||||
|
for (size_t layer_id = 0; layer_id < expolygons_by_layer.size(); ++ layer_id)
|
||||||
|
this->layers[layer_id]->regions.front()->slices.append(std::move(expolygons_by_layer[layer_id]), stInternal);
|
||||||
|
} else {
|
||||||
|
// Slice all non-modifier volumes.
|
||||||
|
for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) {
|
||||||
|
std::vector<ExPolygons> expolygons_by_layer = this->_slice_region(region_id, slice_zs, false);
|
||||||
|
for (size_t layer_id = 0; layer_id < expolygons_by_layer.size(); ++ layer_id)
|
||||||
|
this->layers[layer_id]->regions[region_id]->slices.append(std::move(expolygons_by_layer[layer_id]), stInternal);
|
||||||
|
}
|
||||||
|
// Slice all modifier volumes.
|
||||||
|
for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) {
|
||||||
|
std::vector<ExPolygons> expolygons_by_layer = this->_slice_region(region_id, slice_zs, true);
|
||||||
|
// loop through the other regions and 'steal' the slices belonging to this one
|
||||||
|
for (size_t other_region_id = 0; other_region_id < this->print()->regions.size(); ++ other_region_id) {
|
||||||
|
if (region_id == other_region_id)
|
||||||
|
continue;
|
||||||
|
for (size_t layer_id = 0; layer_id < expolygons_by_layer.size(); ++ layer_id) {
|
||||||
|
Layer *layer = layers[layer_id];
|
||||||
|
LayerRegion *layerm = layer->regions[region_id];
|
||||||
|
LayerRegion *other_layerm = layer->regions[other_region_id];
|
||||||
|
if (layerm == nullptr || other_layerm == nullptr)
|
||||||
|
continue;
|
||||||
|
Polygons other_slices = to_polygons(other_layerm->slices);
|
||||||
|
ExPolygons my_parts = intersection_ex(other_slices, to_polygons(expolygons_by_layer[layer_id]));
|
||||||
|
if (my_parts.empty())
|
||||||
|
continue;
|
||||||
|
// Remove such parts from original region.
|
||||||
|
other_layerm->slices.set(diff_ex(other_slices, to_polygons(my_parts)), stInternal);
|
||||||
|
// Append new parts to our region.
|
||||||
|
layerm->slices.append(std::move(my_parts), stInternal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove last layer(s) if empty
|
||||||
|
bool done = false;
|
||||||
|
while (! this->layers.empty()) {
|
||||||
|
const Layer *layer = this->layers.back();
|
||||||
|
for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id)
|
||||||
|
if (layer->regions[region_id] != nullptr && ! layer->regions[region_id]->slices.empty()) {
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(done) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->delete_layer(int(this->layers.size()) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t layer_id = 0; layer_id < layers.size(); ++ layer_id) {
|
||||||
|
Layer *layer = this->layers[layer_id];
|
||||||
|
// Apply size compensation and perform clipping of multi-part objects.
|
||||||
|
float delta = float(scale_(this->config.xy_size_compensation.value));
|
||||||
|
bool scale = delta != 0.f;
|
||||||
|
if (layer->regions.size() == 1) {
|
||||||
|
if (scale) {
|
||||||
|
// Single region, growing or shrinking.
|
||||||
|
LayerRegion *layerm = layer->regions.front();
|
||||||
|
layerm->slices.set(offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), delta), stInternal);
|
||||||
|
}
|
||||||
|
} else if (scale) {
|
||||||
|
// Multiple regions, growing, shrinking or just clipping one region by the other.
|
||||||
|
// When clipping the regions, priority is given to the first regions.
|
||||||
|
Polygons processed;
|
||||||
|
for (size_t region_id = 0; region_id < layer->regions.size(); ++ region_id) {
|
||||||
|
LayerRegion *layerm = layer->regions[region_id];
|
||||||
|
ExPolygons slices = to_expolygons(std::move(layerm->slices.surfaces));
|
||||||
|
if (scale)
|
||||||
|
slices = offset_ex(slices, delta);
|
||||||
|
if (region_id > 0)
|
||||||
|
// Trim by the slices of already processed regions.
|
||||||
|
slices = diff_ex(to_polygons(std::move(slices)), processed);
|
||||||
|
if (region_id + 1 < layer->regions.size())
|
||||||
|
// Collect the already processed regions to trim the to be processed regions.
|
||||||
|
processed += to_polygons(slices);
|
||||||
|
layerm->slices.set(std::move(slices), stInternal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Merge all regions' slices to get islands, chain them by a shortest path.
|
||||||
|
layer->make_slices();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// called from slice()
|
// called from slice()
|
||||||
std::vector<ExPolygons>
|
std::vector<ExPolygons>
|
||||||
PrintObject::_slice_region(size_t region_id, std::vector<float> z, bool modifier)
|
PrintObject::_slice_region(size_t region_id, std::vector<float> z, bool modifier)
|
||||||
|
@ -62,6 +62,93 @@ to_polygons(const SurfacesConstPtr &surfaces)
|
|||||||
return pp;
|
return pp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline ExPolygons to_expolygons(const Surfaces &src)
|
||||||
|
{
|
||||||
|
ExPolygons expolygons;
|
||||||
|
expolygons.reserve(src.size());
|
||||||
|
for (Surfaces::const_iterator it = src.begin(); it != src.end(); ++it)
|
||||||
|
expolygons.push_back(it->expolygon);
|
||||||
|
return expolygons;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ExPolygons to_expolygons(Surfaces &&src)
|
||||||
|
{
|
||||||
|
ExPolygons expolygons;
|
||||||
|
expolygons.reserve(src.size());
|
||||||
|
for (Surfaces::const_iterator it = src.begin(); it != src.end(); ++it)
|
||||||
|
expolygons.emplace_back(ExPolygon(std::move(it->expolygon)));
|
||||||
|
src.clear();
|
||||||
|
return expolygons;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ExPolygons to_expolygons(const SurfacesPtr &src)
|
||||||
|
{
|
||||||
|
ExPolygons expolygons;
|
||||||
|
expolygons.reserve(src.size());
|
||||||
|
for (SurfacesPtr::const_iterator it = src.begin(); it != src.end(); ++it)
|
||||||
|
expolygons.push_back((*it)->expolygon);
|
||||||
|
return expolygons;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Count a nuber of polygons stored inside the vector of expolygons.
|
||||||
|
// Useful for allocating space for polygons when converting expolygons to polygons.
|
||||||
|
inline size_t number_polygons(const Surfaces &surfaces)
|
||||||
|
{
|
||||||
|
size_t n_polygons = 0;
|
||||||
|
for (Surfaces::const_iterator it = surfaces.begin(); it != surfaces.end(); ++ it)
|
||||||
|
n_polygons += it->expolygon.holes.size() + 1;
|
||||||
|
return n_polygons;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t number_polygons(const SurfacesPtr &surfaces)
|
||||||
|
{
|
||||||
|
size_t n_polygons = 0;
|
||||||
|
for (SurfacesPtr::const_iterator it = surfaces.begin(); it != surfaces.end(); ++ it)
|
||||||
|
n_polygons += (*it)->expolygon.holes.size() + 1;
|
||||||
|
return n_polygons;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append a vector of Surfaces at the end of another vector of polygons.
|
||||||
|
inline void polygons_append(Polygons &dst, const Surfaces &src)
|
||||||
|
{
|
||||||
|
dst.reserve(dst.size() + number_polygons(src));
|
||||||
|
for (Surfaces::const_iterator it = src.begin(); it != src.end(); ++ it) {
|
||||||
|
dst.push_back(it->expolygon.contour);
|
||||||
|
dst.insert(dst.end(), it->expolygon.holes.begin(), it->expolygon.holes.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void polygons_append(Polygons &dst, Surfaces &&src)
|
||||||
|
{
|
||||||
|
dst.reserve(dst.size() + number_polygons(src));
|
||||||
|
for (Surfaces::iterator it = src.begin(); it != src.end(); ++ it) {
|
||||||
|
dst.push_back(std::move(it->expolygon.contour));
|
||||||
|
std::move(std::begin(it->expolygon.holes), std::end(it->expolygon.holes), std::back_inserter(dst));
|
||||||
|
it->expolygon.holes.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append a vector of Surfaces at the end of another vector of polygons.
|
||||||
|
inline void polygons_append(Polygons &dst, const SurfacesPtr &src)
|
||||||
|
{
|
||||||
|
dst.reserve(dst.size() + number_polygons(src));
|
||||||
|
for (SurfacesPtr::const_iterator it = src.begin(); it != src.end(); ++ it) {
|
||||||
|
dst.push_back((*it)->expolygon.contour);
|
||||||
|
dst.insert(dst.end(), (*it)->expolygon.holes.begin(), (*it)->expolygon.holes.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void polygons_append(Polygons &dst, SurfacesPtr &&src)
|
||||||
|
{
|
||||||
|
dst.reserve(dst.size() + number_polygons(src));
|
||||||
|
for (SurfacesPtr::const_iterator it = src.begin(); it != src.end(); ++ it) {
|
||||||
|
dst.push_back(std::move((*it)->expolygon.contour));
|
||||||
|
std::move(std::begin((*it)->expolygon.holes), std::end((*it)->expolygon.holes), std::back_inserter(dst));
|
||||||
|
(*it)->expolygon.holes.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -23,6 +23,16 @@ class SurfaceCollection
|
|||||||
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);
|
||||||
void filter_by_type(SurfaceType type, Polygons* polygons);
|
void filter_by_type(SurfaceType type, Polygons* polygons);
|
||||||
|
|
||||||
|
void set(const SurfaceCollection &coll) { surfaces = coll.surfaces; }
|
||||||
|
void set(SurfaceCollection &&coll) { surfaces = std::move(coll.surfaces); }
|
||||||
|
void set(const ExPolygons &src, SurfaceType surfaceType) { clear(); this->append(src, surfaceType); }
|
||||||
|
void set(const ExPolygons &src, const Surface &surfaceTempl) { clear(); this->append(src, surfaceTempl); }
|
||||||
|
void set(const Surfaces &src) { clear(); this->append(src); }
|
||||||
|
void set(ExPolygons &&src, SurfaceType surfaceType) { clear(); this->append(std::move(src), surfaceType); }
|
||||||
|
void set(ExPolygons &&src, const Surface &surfaceTempl) { clear(); this->append(std::move(src), surfaceTempl); }
|
||||||
|
void set(Surfaces &&src) { clear(); this->append(std::move(src)); }
|
||||||
|
|
||||||
void append(const SurfaceCollection &coll);
|
void append(const SurfaceCollection &coll);
|
||||||
void append(const Surfaces &surfaces);
|
void append(const Surfaces &surfaces);
|
||||||
void append(const ExPolygons &src, const Surface &templ);
|
void append(const ExPolygons &src, const Surface &templ);
|
||||||
|
@ -126,6 +126,7 @@ _constant()
|
|||||||
void detect_surfaces_type();
|
void detect_surfaces_type();
|
||||||
void process_external_surfaces();
|
void process_external_surfaces();
|
||||||
void bridge_over_infill();
|
void bridge_over_infill();
|
||||||
|
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%{
|
||||||
std::vector<float> z_f(z.begin(), z.end());
|
std::vector<float> z_f(z.begin(), z.end());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user