Support for user definable variable layer thickness, the C++ backend.

This commit is contained in:
bubnikv 2016-12-12 17:53:38 +01:00
parent 2ab86a4895
commit 1ea958158a
7 changed files with 924 additions and 44 deletions

View file

@ -2,12 +2,23 @@
#include "BoundingBox.hpp"
#include "ClipperUtils.hpp"
#include "Geometry.hpp"
#include "SVG.hpp"
#include <boost/log/trivial.hpp>
#include <Shiny/Shiny.h>
// #define SLIC3R_DEBUG
// Make assert active if SLIC3R_DEBUG
#ifdef SLIC3R_DEBUG
#undef NDEBUG
#define DEBUG
#define _DEBUG
#include "SVG.hpp"
#undef assert
#include <cassert>
#endif
namespace Slic3r {
PrintObject::PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox)
@ -760,9 +771,9 @@ PrintObject::discover_vertical_shells()
// Assign resulting internal surfaces to layer.
const SurfaceType surfaceTypesKeep[] = { stTop, stBottom, stBottomBridge };
layerm->fill_surfaces.keep_types(surfaceTypesKeep, sizeof(surfaceTypesKeep)/sizeof(SurfaceType));
layerm->fill_surfaces.append(stInternal , new_internal);
layerm->fill_surfaces.append(stInternalVoid , new_internal_void);
layerm->fill_surfaces.append(stInternalSolid, new_internal_solid);
layerm->fill_surfaces.append(new_internal, stInternal);
layerm->fill_surfaces.append(new_internal_void, stInternalVoid);
layerm->fill_surfaces.append(new_internal_solid, stInternalSolid);
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
layerm->export_region_slices_to_svg_debug("4_discover_vertical_shells");
@ -910,6 +921,194 @@ PrintObject::bridge_over_infill()
}
}
SlicingParameters PrintObject::slicing_parameters() const
{
return SlicingParameters::create_from_config(
this->print()->config, this->config,
unscale(this->size.z), this->print()->object_extruders());
}
void PrintObject::update_layer_height_profile()
{
if (this->layer_height_profile.empty()) {
if (0)
// if (this->layer_height_profile.empty())
this->layer_height_profile = layer_height_profile_adaptive(this->slicing_parameters(), this->layer_height_ranges,
this->model_object()->volumes);
else
this->layer_height_profile = layer_height_profile_from_ranges(this->slicing_parameters(), this->layer_height_ranges);
}
}
// 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()
{
SlicingParameters slicing_params = this->slicing_parameters();
// 1) Initialize layers and their slice heights.
std::vector<float> slice_zs;
{
this->clear_layers();
// Object layers (pairs of bottom/top Z coordinate), without the raft.
this->update_layer_height_profile();
std::vector<coordf_t> object_layers = generate_object_layers(slicing_params, this->layer_height_profile);
// Reserve object layers for the raft. Last layer of the raft is the contact layer.
int id = int(slicing_params.raft_layers());
slice_zs.reserve(object_layers.size());
Layer *prev = nullptr;
for (size_t i_layer = 0; i_layer < object_layers.size(); i_layer += 2) {
coordf_t lo = object_layers[i_layer];
coordf_t hi = object_layers[i_layer + 1];
coordf_t slice_z = 0.5 * (lo + hi);
Layer *layer = this->add_layer(id ++, hi - lo, hi + slicing_params.object_print_z_min, 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, my_parts), stInternal);
// Append new parts to our region.
layerm->slices.append(std::move(my_parts), stInternal);
}
}
}
}
// remove last layer(s) if empty
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())
// Non empty layer.
goto end;
this->delete_layer(int(this->layers.size()) - 1);
}
end:
;
for (size_t layer_id = 0; layer_id < layers.size(); ++ layer_id) {
Layer *layer = this->layers[layer_id];
// apply size compensation
if (this->config.xy_size_compensation.value != 0.) {
float delta = float(scale_(this->config.xy_size_compensation.value));
if (layer->regions.size() == 1) {
// single region
LayerRegion *layerm = layer->regions.front();
layerm->slices.set(offset_ex(to_polygons(std::move(layerm->slices.surfaces)), delta), stInternal);
} 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
Polygons region_slices;
for (size_t region_id = 0; region_id < layer->regions.size(); ++ region_id)
polygons_append(region_slices, layer->regions[region_id]->slices.surfaces);
Polygons slices = offset(union_(region_slices), delta);
for (size_t region_id = 0; region_id < layer->regions.size(); ++ region_id) {
LayerRegion *layerm = layer->regions[region_id];
layerm->slices.set(std::move(intersection_ex(slices, to_polygons(std::move(layerm->slices.surfaces)))), stInternal);
}
} 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
Polygons processed;
for (size_t region_id = 0;; ++ region_id) {
LayerRegion *layerm = layer->regions[region_id];
ExPolygons slices = offset_ex(to_polygons(layerm->slices.surfaces), 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()) {
layerm->slices.set(std::move(slices), stInternal);
break;
}
polygons_append(processed, slices);
layerm->slices.set(std::move(slices), stInternal);
}
}
}
}
// Merge all regions' slices to get islands, chain them by a shortest path.
layer->make_slices();
}
}
std::vector<ExPolygons> PrintObject::_slice_region(size_t region_id, const std::vector<float> &z, bool modifier)
{
std::vector<ExPolygons> layers;
assert(region_id < this->region_volumes.size());
std::vector<int> &volumes = this->region_volumes[region_id];
if (! volumes.empty()) {
// Compose mesh.
//FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
TriangleMesh mesh;
for (std::vector<int>::const_iterator it_volume = volumes.begin(); it_volume != volumes.end(); ++ it_volume) {
ModelVolume *volume = this->model_object()->volumes[*it_volume];
if (volume->modifier == modifier)
mesh.merge(volume->mesh);
}
if (mesh.stl.stats.number_of_facets > 0) {
// transform mesh
// we ignore the per-instance transformations currently and only
// consider the first one
this->model_object()->instances.front()->transform_mesh(&mesh, true);
// align mesh to Z = 0 (it should be already aligned actually) and apply XY shift
mesh.translate(- unscale(this->_copies_shift.x), - unscale(this->_copies_shift.y), -this->model_object()->bounding_box().min.z);
// perform actual slicing
TriangleMeshSlicer mslicer(&mesh);
mslicer.slice(z, &layers);
}
}
return layers;
}
void
PrintObject::_make_perimeters()
{
@ -930,7 +1129,7 @@ PrintObject::_make_perimeters()
// this algorithm makes sure that at least one perimeter is overlapping
// but we don't generate any extra perimeter if fill density is zero, as they would be floating
// inside the object - infill_only_where_needed should be the method of choice for printing
// hollow objects
// hollow objects
FOREACH_REGION(this->_print, region_it) {
size_t region_id = region_it - this->_print->regions.begin();
const PrintRegion &region = **region_it;
@ -941,7 +1140,7 @@ PrintObject::_make_perimeters()
|| region.config.fill_density == 0
|| this->layer_count() < 2) continue;
for (size_t i = 0; i <= (this->layer_count()-2); ++i) {
for (int i = 0; i < int(this->layer_count()) - 1; ++i) {
LayerRegion &layerm = *this->get_layer(i)->get_region(region_id);
const LayerRegion &upper_layerm = *this->get_layer(i+1)->get_region(region_id);
const Polygons upper_layerm_polygons = upper_layerm.slices;
@ -1044,4 +1243,4 @@ PrintObject::_infill()
this->state.set_done(posInfill);
}
}
} // namespace Slic3r