Merge pull request #3796 from platsch/slice_xs

Ported parts of Slice to xs
This commit is contained in:
Alessandro Ranellucci 2017-03-28 10:37:52 +02:00 committed by GitHub
commit ff9bae79ca
6 changed files with 342 additions and 262 deletions

View File

@ -33,17 +33,6 @@ sub support_layers {
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,
# 2) Initializes layers and their regions
# 3) Slices the object meshes
@ -60,257 +49,7 @@ sub slice {
$self->set_step_started(STEP_SLICE);
$self->print->status_cb->(10, "Processing triangulated mesh");
my $min_nozzle_diameter;
{
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;
}
$self->_slice;
# detect slicing errors
my $warning_thrown = 0;

View File

@ -140,6 +140,9 @@ class PrintObject
void detect_surfaces_type();
void process_external_surfaces();
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);
void _make_perimeters();
void _infill();

View File

@ -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()
std::vector<ExPolygons>
PrintObject::_slice_region(size_t region_id, std::vector<float> z, bool modifier)

View File

@ -62,6 +62,93 @@ to_polygons(const SurfacesConstPtr &surfaces)
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

View File

@ -23,6 +23,16 @@ class SurfaceCollection
template <class T> bool any_bottom_contains(const T &item) const;
SurfacesPtr filter_by_type(SurfaceType type);
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 Surfaces &surfaces);
void append(const ExPolygons &src, const Surface &templ);

View File

@ -126,6 +126,7 @@ _constant()
void detect_surfaces_type();
void process_external_surfaces();
void bridge_over_infill();
void _slice();
SV* _slice_region(size_t region_id, std::vector<double> z, bool modifier)
%code%{
std::vector<float> z_f(z.begin(), z.end());