Support for user definable variable layer thickness, the C++ backend.
This commit is contained in:
parent
2ab86a4895
commit
1ea958158a
7 changed files with 924 additions and 44 deletions
|
@ -3,9 +3,8 @@
|
||||||
|
|
||||||
#include "libslic3r.h"
|
#include "libslic3r.h"
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <boost/thread.hpp>
|
#include <string>
|
||||||
#include "BoundingBox.hpp"
|
#include "BoundingBox.hpp"
|
||||||
#include "Flow.hpp"
|
#include "Flow.hpp"
|
||||||
#include "PrintConfig.hpp"
|
#include "PrintConfig.hpp"
|
||||||
|
@ -13,7 +12,7 @@
|
||||||
#include "Layer.hpp"
|
#include "Layer.hpp"
|
||||||
#include "Model.hpp"
|
#include "Model.hpp"
|
||||||
#include "PlaceholderParser.hpp"
|
#include "PlaceholderParser.hpp"
|
||||||
|
#include "Slicing.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
@ -80,6 +79,10 @@ public:
|
||||||
PrintObjectConfig config;
|
PrintObjectConfig config;
|
||||||
t_layer_height_ranges layer_height_ranges;
|
t_layer_height_ranges layer_height_ranges;
|
||||||
|
|
||||||
|
// Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers.
|
||||||
|
// The pairs of <z, layer_height> are packed into a 1D array to simplify handling by the Perl XS.
|
||||||
|
std::vector<coordf_t> layer_height_profile;
|
||||||
|
|
||||||
// this is set to true when LayerRegion->slices is split in top/internal/bottom
|
// this is set to true when LayerRegion->slices is split in top/internal/bottom
|
||||||
// so that next call to make_perimeters() performs a union() before computing loops
|
// so that next call to make_perimeters() performs a union() before computing loops
|
||||||
bool typed_slices;
|
bool typed_slices;
|
||||||
|
@ -138,6 +141,17 @@ public:
|
||||||
bool invalidate_step(PrintObjectStep step);
|
bool invalidate_step(PrintObjectStep step);
|
||||||
bool invalidate_all_steps();
|
bool invalidate_all_steps();
|
||||||
|
|
||||||
|
// Process layer_height_ranges, the raft layers and first layer thickness into layer_height_profile.
|
||||||
|
// The layer_height_profile may be later modified interactively by the user to refine layers at sloping surfaces.
|
||||||
|
void update_layer_height_profile();
|
||||||
|
|
||||||
|
// Collect the slicing parameters, to be used by variable layer thickness algorithm,
|
||||||
|
// by the interactive layer height editor and by the printing process itself.
|
||||||
|
// The slicing parameters are dependent on various configuration values
|
||||||
|
// (layer height, first layer height, raft settings, print nozzle diameter etc).
|
||||||
|
SlicingParameters slicing_parameters() const;
|
||||||
|
|
||||||
|
void _slice();
|
||||||
bool has_support_material() const;
|
bool has_support_material() const;
|
||||||
void detect_surfaces_type();
|
void detect_surfaces_type();
|
||||||
void process_external_surfaces();
|
void process_external_surfaces();
|
||||||
|
@ -155,6 +169,8 @@ private:
|
||||||
// parameter
|
// parameter
|
||||||
PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox);
|
PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox);
|
||||||
~PrintObject() {}
|
~PrintObject() {}
|
||||||
|
|
||||||
|
std::vector<ExPolygons> _slice_region(size_t region_id, const std::vector<float> &z, bool modifier);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<PrintObject*> PrintObjectPtrs;
|
typedef std::vector<PrintObject*> PrintObjectPtrs;
|
||||||
|
|
|
@ -2,12 +2,23 @@
|
||||||
#include "BoundingBox.hpp"
|
#include "BoundingBox.hpp"
|
||||||
#include "ClipperUtils.hpp"
|
#include "ClipperUtils.hpp"
|
||||||
#include "Geometry.hpp"
|
#include "Geometry.hpp"
|
||||||
#include "SVG.hpp"
|
|
||||||
|
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
#include <Shiny/Shiny.h>
|
#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 {
|
namespace Slic3r {
|
||||||
|
|
||||||
PrintObject::PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox)
|
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.
|
// Assign resulting internal surfaces to layer.
|
||||||
const SurfaceType surfaceTypesKeep[] = { stTop, stBottom, stBottomBridge };
|
const SurfaceType surfaceTypesKeep[] = { stTop, stBottom, stBottomBridge };
|
||||||
layerm->fill_surfaces.keep_types(surfaceTypesKeep, sizeof(surfaceTypesKeep)/sizeof(SurfaceType));
|
layerm->fill_surfaces.keep_types(surfaceTypesKeep, sizeof(surfaceTypesKeep)/sizeof(SurfaceType));
|
||||||
layerm->fill_surfaces.append(stInternal , new_internal);
|
layerm->fill_surfaces.append(new_internal, stInternal);
|
||||||
layerm->fill_surfaces.append(stInternalVoid , new_internal_void);
|
layerm->fill_surfaces.append(new_internal_void, stInternalVoid);
|
||||||
layerm->fill_surfaces.append(stInternalSolid, new_internal_solid);
|
layerm->fill_surfaces.append(new_internal_solid, stInternalSolid);
|
||||||
|
|
||||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||||
layerm->export_region_slices_to_svg_debug("4_discover_vertical_shells");
|
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
|
void
|
||||||
PrintObject::_make_perimeters()
|
PrintObject::_make_perimeters()
|
||||||
{
|
{
|
||||||
|
@ -930,7 +1129,7 @@ PrintObject::_make_perimeters()
|
||||||
// this algorithm makes sure that at least one perimeter is overlapping
|
// 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
|
// 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
|
// 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) {
|
FOREACH_REGION(this->_print, region_it) {
|
||||||
size_t region_id = region_it - this->_print->regions.begin();
|
size_t region_id = region_it - this->_print->regions.begin();
|
||||||
const PrintRegion ®ion = **region_it;
|
const PrintRegion ®ion = **region_it;
|
||||||
|
@ -941,7 +1140,7 @@ PrintObject::_make_perimeters()
|
||||||
|| region.config.fill_density == 0
|
|| region.config.fill_density == 0
|
||||||
|| this->layer_count() < 2) continue;
|
|| 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);
|
LayerRegion &layerm = *this->get_layer(i)->get_region(region_id);
|
||||||
const LayerRegion &upper_layerm = *this->get_layer(i+1)->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;
|
const Polygons upper_layerm_polygons = upper_layerm.slices;
|
||||||
|
@ -1044,4 +1243,4 @@ PrintObject::_infill()
|
||||||
this->state.set_done(posInfill);
|
this->state.set_done(posInfill);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace Slic3r
|
||||||
|
|
585
xs/src/libslic3r/Slicing.cpp
Normal file
585
xs/src/libslic3r/Slicing.cpp
Normal file
|
@ -0,0 +1,585 @@
|
||||||
|
#include "Slicing.hpp"
|
||||||
|
#include "SlicingAdaptive.hpp"
|
||||||
|
#include "PrintConfig.hpp"
|
||||||
|
#include "Model.hpp"
|
||||||
|
|
||||||
|
// #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
|
||||||
|
{
|
||||||
|
|
||||||
|
SlicingParameters create_from_config(
|
||||||
|
const PrintConfig &print_config,
|
||||||
|
const PrintObjectConfig &object_config,
|
||||||
|
coordf_t object_height,
|
||||||
|
const std::set<size_t> &object_extruders)
|
||||||
|
{
|
||||||
|
coordf_t first_layer_height = (object_config.first_layer_height.value <= 0) ?
|
||||||
|
object_config.layer_height.value :
|
||||||
|
object_config.first_layer_height.get_abs_value(object_config.layer_height.value);
|
||||||
|
coordf_t support_material_extruder_dmr = print_config.nozzle_diameter.get_at(object_config.support_material_extruder.value - 1);
|
||||||
|
coordf_t support_material_interface_extruder_dmr = print_config.nozzle_diameter.get_at(object_config.support_material_interface_extruder.value - 1);
|
||||||
|
bool soluble_interface = object_config.support_material_contact_distance.value == 0.;
|
||||||
|
|
||||||
|
SlicingParameters params;
|
||||||
|
params.layer_height = object_config.layer_height.value;
|
||||||
|
params.first_object_layer_height = first_layer_height;
|
||||||
|
params.object_print_z_min = 0.;
|
||||||
|
params.object_print_z_max = object_height;
|
||||||
|
params.base_raft_layers = object_config.raft_layers.value;
|
||||||
|
|
||||||
|
if (params.base_raft_layers > 0) {
|
||||||
|
params.interface_raft_layers = (params.base_raft_layers + 1) / 2;
|
||||||
|
params.base_raft_layers -= params.interface_raft_layers;
|
||||||
|
// Use as large as possible layer height for the intermediate raft layers.
|
||||||
|
params.base_raft_layer_height = std::max(params.layer_height, 0.75 * support_material_extruder_dmr);
|
||||||
|
params.interface_raft_layer_height = std::max(params.layer_height, 0.75 * support_material_interface_extruder_dmr);
|
||||||
|
params.contact_raft_layer_height_bridging = false;
|
||||||
|
params.first_object_layer_bridging = false;
|
||||||
|
#if 1
|
||||||
|
params.contact_raft_layer_height = std::max(params.layer_height, 0.75 * support_material_interface_extruder_dmr);
|
||||||
|
if (! soluble_interface) {
|
||||||
|
// Compute the average of all nozzles used for printing the object over a raft.
|
||||||
|
//FIXME It is expected, that the 1st layer of the object is printed with a bridging flow over a full raft. Shall it not be vice versa?
|
||||||
|
coordf_t average_object_extruder_dmr = 0.;
|
||||||
|
if (! object_extruders.empty()) {
|
||||||
|
for (std::set<size_t>::const_iterator it_extruder = object_extruders.begin(); it_extruder != object_extruders.end(); ++ it_extruder)
|
||||||
|
average_object_extruder_dmr += print_config.nozzle_diameter.get_at(*it_extruder);
|
||||||
|
average_object_extruder_dmr /= coordf_t(object_extruders.size());
|
||||||
|
}
|
||||||
|
params.first_object_layer_height = average_object_extruder_dmr;
|
||||||
|
params.first_object_layer_bridging = true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
params.contact_raft_layer_height = soluble_interface ? support_material_interface_extruder_dmr : 0.75 * support_material_interface_extruder_dmr;
|
||||||
|
params.contact_raft_layer_height_bridging = ! soluble_interface;
|
||||||
|
...
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.has_raft()) {
|
||||||
|
// Raise first object layer Z by the thickness of the raft itself plus the extra distance required by the support material logic.
|
||||||
|
//FIXME The last raft layer is the contact layer, which shall be printed with a bridging flow for ease of separation. Currently it is not the case.
|
||||||
|
coordf_t print_z = first_layer_height + object_config.support_material_contact_distance.value;
|
||||||
|
if (params.raft_layers() == 1) {
|
||||||
|
params.contact_raft_layer_height = first_layer_height;
|
||||||
|
} else {
|
||||||
|
print_z +=
|
||||||
|
// Number of the base raft layers is decreased by the first layer, which has already been added to print_z.
|
||||||
|
coordf_t(params.base_raft_layers - 1) * params.base_raft_layer_height +
|
||||||
|
// Number of the interface raft layers is decreased by the contact layer.
|
||||||
|
coordf_t(params.interface_raft_layers - 1) * params.interface_raft_layer_height +
|
||||||
|
params.contact_raft_layer_height;
|
||||||
|
}
|
||||||
|
params.object_print_z_min = print_z;
|
||||||
|
params.object_print_z_max += print_z;
|
||||||
|
}
|
||||||
|
|
||||||
|
params.min_layer_height = std::min(params.layer_height, first_layer_height);
|
||||||
|
params.max_layer_height = std::max(params.layer_height, first_layer_height);
|
||||||
|
|
||||||
|
//FIXME add it to the print configuration
|
||||||
|
params.min_layer_height = 0.05;
|
||||||
|
|
||||||
|
// Calculate the maximum layer height as 0.75 from the minimum nozzle diameter.
|
||||||
|
if (! object_extruders.empty()) {
|
||||||
|
coordf_t min_object_extruder_dmr = 1000000.;
|
||||||
|
for (std::set<size_t>::const_iterator it_extruder = object_extruders.begin(); it_extruder != object_extruders.end(); ++ it_extruder)
|
||||||
|
min_object_extruder_dmr = std::min(min_object_extruder_dmr, print_config.nozzle_diameter.get_at(*it_extruder));
|
||||||
|
// Allow excessive maximum layer height higher than 0.75 * min_object_extruder_dmr
|
||||||
|
params.max_layer_height = std::max(std::max(params.layer_height, first_layer_height), 0.75 * min_object_extruder_dmr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert layer_height_ranges to layer_height_profile. Both are referenced to z=0, meaning the raft layers are not accounted for
|
||||||
|
// in the height profile and the printed object may be lifted by the raft thickness at the time of the G-code generation.
|
||||||
|
std::vector<coordf_t> layer_height_profile_from_ranges(
|
||||||
|
const SlicingParameters &slicing_params,
|
||||||
|
const t_layer_height_ranges &layer_height_ranges)
|
||||||
|
{
|
||||||
|
// 1) If there are any height ranges, trim one by the other to make them non-overlapping. Insert the 1st layer if fixed.
|
||||||
|
std::vector<std::pair<t_layer_height_range,coordf_t>> ranges_non_overlapping;
|
||||||
|
ranges_non_overlapping.reserve(layer_height_ranges.size() * 4);
|
||||||
|
if (slicing_params.first_object_layer_height_fixed())
|
||||||
|
ranges_non_overlapping.push_back(std::pair<t_layer_height_range,coordf_t>(
|
||||||
|
t_layer_height_range(0., slicing_params.first_object_layer_height),
|
||||||
|
slicing_params.first_object_layer_height));
|
||||||
|
// The height ranges are sorted lexicographically by low / high layer boundaries.
|
||||||
|
for (t_layer_height_ranges::const_iterator it_range = layer_height_ranges.begin(); it_range != layer_height_ranges.end(); ++ it_range) {
|
||||||
|
coordf_t lo = it_range->first.first;
|
||||||
|
coordf_t hi = std::min(it_range->first.second, slicing_params.object_print_z_height());
|
||||||
|
coordf_t height = it_range->second;
|
||||||
|
if (! ranges_non_overlapping.empty())
|
||||||
|
// Trim current low with the last high.
|
||||||
|
lo = std::max(lo, ranges_non_overlapping.back().first.second);
|
||||||
|
if (lo + EPSILON < hi)
|
||||||
|
// Ignore too narrow ranges.
|
||||||
|
ranges_non_overlapping.push_back(std::pair<t_layer_height_range,coordf_t>(t_layer_height_range(lo, hi), height));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Convert the trimmed ranges to a height profile, fill in the undefined intervals between z=0 and z=slicing_params.object_print_z_max()
|
||||||
|
// with slicing_params.layer_height
|
||||||
|
std::vector<coordf_t> layer_height_profile;
|
||||||
|
for (std::vector<std::pair<t_layer_height_range,coordf_t>>::const_iterator it_range = ranges_non_overlapping.begin(); it_range != ranges_non_overlapping.end(); ++ it_range) {
|
||||||
|
coordf_t lo = it_range->first.first;
|
||||||
|
coordf_t hi = it_range->first.second;
|
||||||
|
coordf_t height = it_range->second;
|
||||||
|
coordf_t last_z = layer_height_profile.empty() ? 0. : layer_height_profile[layer_height_profile.size() - 2];
|
||||||
|
coordf_t last_height = layer_height_profile.empty() ? 0. : layer_height_profile[layer_height_profile.size() - 1];
|
||||||
|
if (lo > last_z + EPSILON) {
|
||||||
|
// Insert a step of normal layer height.
|
||||||
|
layer_height_profile.push_back(last_z);
|
||||||
|
layer_height_profile.push_back(slicing_params.layer_height);
|
||||||
|
layer_height_profile.push_back(lo);
|
||||||
|
layer_height_profile.push_back(slicing_params.layer_height);
|
||||||
|
}
|
||||||
|
// Insert a step of the overriden layer height.
|
||||||
|
layer_height_profile.push_back(lo);
|
||||||
|
layer_height_profile.push_back(height);
|
||||||
|
layer_height_profile.push_back(hi);
|
||||||
|
layer_height_profile.push_back(height);
|
||||||
|
}
|
||||||
|
|
||||||
|
coordf_t last_z = layer_height_profile.empty() ? 0. : layer_height_profile[layer_height_profile.size() - 2];
|
||||||
|
coordf_t last_height = layer_height_profile.empty() ? 0. : layer_height_profile[layer_height_profile.size() - 1];
|
||||||
|
if (last_z < slicing_params.object_print_z_height()) {
|
||||||
|
// Insert a step of normal layer height up to the object top.
|
||||||
|
layer_height_profile.push_back(last_z);
|
||||||
|
layer_height_profile.push_back(slicing_params.layer_height);
|
||||||
|
layer_height_profile.push_back(slicing_params.object_print_z_height());
|
||||||
|
layer_height_profile.push_back(slicing_params.layer_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
return layer_height_profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Based on the work of @platsch
|
||||||
|
// Fill layer_height_profile by heights ensuring a prescribed maximum cusp height.
|
||||||
|
std::vector<coordf_t> layer_height_profile_adaptive(
|
||||||
|
const SlicingParameters &slicing_params,
|
||||||
|
const t_layer_height_ranges &layer_height_ranges,
|
||||||
|
const ModelVolumePtrs &volumes)
|
||||||
|
{
|
||||||
|
// 1) Initialize the SlicingAdaptive class with the object meshes.
|
||||||
|
SlicingAdaptive as;
|
||||||
|
as.set_slicing_parameters(slicing_params);
|
||||||
|
for (ModelVolumePtrs::const_iterator it = volumes.begin(); it != volumes.end(); ++ it)
|
||||||
|
if (! (*it)->modifier)
|
||||||
|
as.add_mesh(&(*it)->mesh);
|
||||||
|
as.prepare();
|
||||||
|
|
||||||
|
// 2) Generate layers using the algorithm of @platsch
|
||||||
|
// loop until we have at least one layer and the max slice_z reaches the object height
|
||||||
|
//FIXME make it configurable
|
||||||
|
// Cusp value: A maximum allowed distance from a corner of a rectangular extrusion to a chrodal line, in mm.
|
||||||
|
const coordf_t cusp_value = 0.2; // $self->config->get_value('cusp_value');
|
||||||
|
|
||||||
|
std::vector<coordf_t> layer_height_profile;
|
||||||
|
layer_height_profile.push_back(0.);
|
||||||
|
layer_height_profile.push_back(slicing_params.first_object_layer_height);
|
||||||
|
if (slicing_params.first_object_layer_height_fixed()) {
|
||||||
|
layer_height_profile.push_back(slicing_params.first_object_layer_height);
|
||||||
|
layer_height_profile.push_back(slicing_params.first_object_layer_height);
|
||||||
|
}
|
||||||
|
coordf_t slice_z = slicing_params.first_object_layer_height;
|
||||||
|
coordf_t height = slicing_params.first_object_layer_height;
|
||||||
|
coordf_t cusp_height = 0.;
|
||||||
|
int current_facet = 0;
|
||||||
|
while ((slice_z - height) <= slicing_params.object_print_z_height()) {
|
||||||
|
height = 999;
|
||||||
|
// Slic3r::debugf "\n Slice layer: %d\n", $id;
|
||||||
|
// determine next layer height
|
||||||
|
coordf_t cusp_height = as.cusp_height(slice_z, cusp_value, current_facet);
|
||||||
|
// check for horizontal features and object size
|
||||||
|
/*
|
||||||
|
if($self->config->get_value('match_horizontal_surfaces')) {
|
||||||
|
my $horizontal_dist = $adaptive_slicing[$region_id]->horizontal_facet_distance(scale $slice_z+$cusp_height, $min_height);
|
||||||
|
if(($horizontal_dist < $min_height) && ($horizontal_dist > 0)) {
|
||||||
|
Slic3r::debugf "Horizontal feature ahead, distance: %f\n", $horizontal_dist;
|
||||||
|
# can we shrink the current layer a bit?
|
||||||
|
if($cusp_height-($min_height-$horizontal_dist) > $min_height) {
|
||||||
|
# yes we can
|
||||||
|
$cusp_height = $cusp_height-($min_height-$horizontal_dist);
|
||||||
|
Slic3r::debugf "Shrink layer height to %f\n", $cusp_height;
|
||||||
|
}else{
|
||||||
|
# no, current layer would become too thin
|
||||||
|
$cusp_height = $cusp_height+$horizontal_dist;
|
||||||
|
Slic3r::debugf "Widen layer height to %f\n", $cusp_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
height = std::min(cusp_height, height);
|
||||||
|
|
||||||
|
// apply z-gradation
|
||||||
|
/*
|
||||||
|
my $gradation = $self->config->get_value('adaptive_slicing_z_gradation');
|
||||||
|
if($gradation > 0) {
|
||||||
|
$height = $height - unscale((scale($height)) % (scale($gradation)));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// look for an applicable custom range
|
||||||
|
/*
|
||||||
|
if (my $range = first { $_->[0] <= $slice_z && $_->[1] > $slice_z } @{$self->layer_height_ranges}) {
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
layer_height_profile.push_back(slice_z);
|
||||||
|
layer_height_profile.push_back(height);
|
||||||
|
slice_z += height;
|
||||||
|
layer_height_profile.push_back(slice_z);
|
||||||
|
layer_height_profile.push_back(height);
|
||||||
|
}
|
||||||
|
|
||||||
|
coordf_t last = std::max(slicing_params.first_object_layer_height, layer_height_profile[layer_height_profile.size() - 2]);
|
||||||
|
layer_height_profile.push_back(last);
|
||||||
|
layer_height_profile.push_back(slicing_params.first_object_layer_height);
|
||||||
|
layer_height_profile.push_back(slicing_params.object_print_z_height());
|
||||||
|
layer_height_profile.push_back(slicing_params.first_object_layer_height);
|
||||||
|
|
||||||
|
return layer_height_profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline T clamp(const T low, const T high, const T value)
|
||||||
|
{
|
||||||
|
return std::max(low, std::min(high, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline T lerp(const T a, const T b, const T t)
|
||||||
|
{
|
||||||
|
assert(t >= T(-EPSILON) && t <= T(1.+EPSILON));
|
||||||
|
return (1. - t) * a + t * b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void adjust_layer_height_profile(
|
||||||
|
const SlicingParameters &slicing_params,
|
||||||
|
std::vector<coordf_t> &layer_height_profile,
|
||||||
|
coordf_t z,
|
||||||
|
coordf_t layer_thickness_delta,
|
||||||
|
coordf_t band_width,
|
||||||
|
int action)
|
||||||
|
{
|
||||||
|
// Constrain the profile variability by the 1st layer height.
|
||||||
|
std::pair<coordf_t, coordf_t> z_span_variable =
|
||||||
|
std::pair<coordf_t, coordf_t>(
|
||||||
|
slicing_params.first_object_layer_height_fixed() ? slicing_params.first_object_layer_height : 0.,
|
||||||
|
slicing_params.object_print_z_height());
|
||||||
|
if (z < z_span_variable.first || z > z_span_variable.second)
|
||||||
|
return;
|
||||||
|
|
||||||
|
assert(layer_height_profile.size() >= 2);
|
||||||
|
|
||||||
|
// 1) Get the current layer thickness at z.
|
||||||
|
coordf_t current_layer_height = slicing_params.layer_height;
|
||||||
|
for (size_t i = 0; i < layer_height_profile.size(); i += 2) {
|
||||||
|
if (i + 2 == layer_height_profile.size()) {
|
||||||
|
current_layer_height = layer_height_profile[i + 1];
|
||||||
|
break;
|
||||||
|
} else if (layer_height_profile[i + 2] > z) {
|
||||||
|
coordf_t z1 = layer_height_profile[i];
|
||||||
|
coordf_t h1 = layer_height_profile[i + 1];
|
||||||
|
coordf_t z2 = layer_height_profile[i + 2];
|
||||||
|
coordf_t h2 = layer_height_profile[i + 3];
|
||||||
|
current_layer_height = lerp(h1, h2, (z - z1) / (z2 - z1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Is it possible to apply the delta?
|
||||||
|
switch (action) {
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
if (layer_thickness_delta > 0) {
|
||||||
|
if (current_layer_height >= slicing_params.max_layer_height - EPSILON)
|
||||||
|
return;
|
||||||
|
layer_thickness_delta = std::min(layer_thickness_delta, slicing_params.max_layer_height - current_layer_height);
|
||||||
|
} else {
|
||||||
|
if (current_layer_height <= slicing_params.min_layer_height + EPSILON)
|
||||||
|
return;
|
||||||
|
layer_thickness_delta = std::max(layer_thickness_delta, slicing_params.min_layer_height - current_layer_height);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
layer_thickness_delta = std::abs(layer_thickness_delta);
|
||||||
|
layer_thickness_delta = std::min(layer_thickness_delta, std::abs(slicing_params.layer_height - current_layer_height));
|
||||||
|
if (layer_thickness_delta < EPSILON)
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) Densify the profile inside z +- band_width/2, remove duplicate Zs from the height profile inside the band.
|
||||||
|
coordf_t lo = std::max(z_span_variable.first, z - 0.5 * band_width);
|
||||||
|
coordf_t hi = std::min(z_span_variable.second, z + 0.5 * band_width);
|
||||||
|
coordf_t z_step = 0.1;
|
||||||
|
size_t i = 0;
|
||||||
|
while (i < layer_height_profile.size() && layer_height_profile[i] < lo)
|
||||||
|
i += 2;
|
||||||
|
i -= 2;
|
||||||
|
|
||||||
|
std::vector<double> profile_new;
|
||||||
|
profile_new.reserve(layer_height_profile.size());
|
||||||
|
assert(i >= 0 && i + 1 < layer_height_profile.size());
|
||||||
|
profile_new.insert(profile_new.end(), layer_height_profile.begin(), layer_height_profile.begin() + i + 2);
|
||||||
|
coordf_t zz = lo;
|
||||||
|
while (zz < hi) {
|
||||||
|
size_t next = i + 2;
|
||||||
|
coordf_t z1 = layer_height_profile[i];
|
||||||
|
coordf_t h1 = layer_height_profile[i + 1];
|
||||||
|
coordf_t height = h1;
|
||||||
|
if (next < layer_height_profile.size()) {
|
||||||
|
coordf_t z2 = layer_height_profile[next];
|
||||||
|
coordf_t h2 = layer_height_profile[next + 1];
|
||||||
|
height = lerp(h1, h2, (zz - z1) / (z2 - z1));
|
||||||
|
}
|
||||||
|
// Adjust height by layer_thickness_delta.
|
||||||
|
coordf_t weight = std::abs(zz - z) < 0.5 * band_width ? (0.5 + 0.5 * cos(2. * M_PI * (zz - z) / band_width)) : 0.;
|
||||||
|
coordf_t height_new = height;
|
||||||
|
switch (action) {
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
height += weight * layer_thickness_delta;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
coordf_t delta = height - slicing_params.layer_height;
|
||||||
|
coordf_t step = weight * layer_thickness_delta;
|
||||||
|
step = (std::abs(delta) > step) ?
|
||||||
|
(delta > 0) ? -step : step :
|
||||||
|
-delta;
|
||||||
|
height += step;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Avoid entering a too short segment.
|
||||||
|
if (profile_new[profile_new.size() - 2] + EPSILON < zz) {
|
||||||
|
profile_new.push_back(zz);
|
||||||
|
profile_new.push_back(clamp(slicing_params.min_layer_height, slicing_params.max_layer_height, height));
|
||||||
|
}
|
||||||
|
zz += z_step;
|
||||||
|
i = next;
|
||||||
|
while (i < layer_height_profile.size() && layer_height_profile[i] < zz)
|
||||||
|
i += 2;
|
||||||
|
i -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 2;
|
||||||
|
if (i < layer_height_profile.size()) {
|
||||||
|
if (profile_new[profile_new.size() - 2] + z_step < layer_height_profile[i]) {
|
||||||
|
profile_new.push_back(profile_new[profile_new.size() - 2] + z_step);
|
||||||
|
profile_new.push_back(layer_height_profile[i + 1]);
|
||||||
|
}
|
||||||
|
profile_new.insert(profile_new.end(), layer_height_profile.begin() + i, layer_height_profile.end());
|
||||||
|
}
|
||||||
|
layer_height_profile = std::move(profile_new);
|
||||||
|
|
||||||
|
assert(layer_height_profile.size() > 2);
|
||||||
|
assert(layer_height_profile.size() % 2 == 0);
|
||||||
|
assert(layer_height_profile[0] == 0.);
|
||||||
|
#ifdef _DEBUG
|
||||||
|
for (size_t i = 2; i < layer_height_profile.size(); i += 2)
|
||||||
|
assert(layer_height_profile[i - 2] <= layer_height_profile[i]);
|
||||||
|
for (size_t i = 1; i < layer_height_profile.size(); i += 2) {
|
||||||
|
assert(layer_height_profile[i] > slicing_params.min_layer_height - EPSILON);
|
||||||
|
assert(layer_height_profile[i] < slicing_params.max_layer_height + EPSILON);
|
||||||
|
}
|
||||||
|
#endif /* _DEBUG */
|
||||||
|
}
|
||||||
|
|
||||||
|
// Produce object layers as pairs of low / high layer boundaries, stored into a linear vector.
|
||||||
|
std::vector<coordf_t> generate_object_layers(
|
||||||
|
const SlicingParameters &slicing_params,
|
||||||
|
const std::vector<coordf_t> &layer_height_profile)
|
||||||
|
{
|
||||||
|
coordf_t print_z = 0;
|
||||||
|
coordf_t height = 0;
|
||||||
|
|
||||||
|
std::vector<coordf_t> out;
|
||||||
|
|
||||||
|
if (slicing_params.first_object_layer_height_fixed()) {
|
||||||
|
out.push_back(0);
|
||||||
|
print_z = slicing_params.first_object_layer_height;
|
||||||
|
out.push_back(print_z);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t idx_layer_height_profile = 0;
|
||||||
|
// loop until we have at least one layer and the max slice_z reaches the object height
|
||||||
|
coordf_t slice_z = print_z + 0.5 * slicing_params.min_layer_height;
|
||||||
|
while (slice_z < slicing_params.object_print_z_height()) {
|
||||||
|
height = slicing_params.min_layer_height;
|
||||||
|
if (idx_layer_height_profile < layer_height_profile.size()) {
|
||||||
|
size_t next = idx_layer_height_profile + 2;
|
||||||
|
for (;;) {
|
||||||
|
if (next >= layer_height_profile.size() || slice_z < layer_height_profile[next])
|
||||||
|
break;
|
||||||
|
idx_layer_height_profile = next;
|
||||||
|
next += 2;
|
||||||
|
}
|
||||||
|
coordf_t z1 = layer_height_profile[idx_layer_height_profile];
|
||||||
|
coordf_t h1 = layer_height_profile[idx_layer_height_profile + 1];
|
||||||
|
height = h1;
|
||||||
|
if (next < layer_height_profile.size()) {
|
||||||
|
coordf_t z2 = layer_height_profile[next];
|
||||||
|
coordf_t h2 = layer_height_profile[next + 1];
|
||||||
|
height = lerp(h1, h2, (slice_z - z1) / (z2 - z1));
|
||||||
|
assert(height >= slicing_params.min_layer_height - EPSILON && height <= slicing_params.max_layer_height + EPSILON);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slice_z = print_z + 0.5 * height;
|
||||||
|
if (slice_z >= slicing_params.object_print_z_height())
|
||||||
|
break;
|
||||||
|
assert(height > slicing_params.min_layer_height - EPSILON);
|
||||||
|
assert(height < slicing_params.max_layer_height + EPSILON);
|
||||||
|
out.push_back(print_z);
|
||||||
|
print_z += height;
|
||||||
|
slice_z = print_z + 0.5 * slicing_params.min_layer_height;
|
||||||
|
out.push_back(print_z);
|
||||||
|
}
|
||||||
|
|
||||||
|
//FIXME Adjust the last layer to align with the top object layer exactly?
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
int generate_layer_height_texture(
|
||||||
|
const SlicingParameters &slicing_params,
|
||||||
|
const std::vector<coordf_t> &layers,
|
||||||
|
void *data, int rows, int cols, bool level_of_detail_2nd_level)
|
||||||
|
{
|
||||||
|
// https://github.com/aschn/gnuplot-colorbrewer
|
||||||
|
std::vector<Point3> palette_raw;
|
||||||
|
palette_raw.push_back(Point3(0x0B2, 0x018, 0x02B));
|
||||||
|
palette_raw.push_back(Point3(0x0D6, 0x060, 0x04D));
|
||||||
|
palette_raw.push_back(Point3(0x0F4, 0x0A5, 0x082));
|
||||||
|
palette_raw.push_back(Point3(0x0FD, 0x0DB, 0x0C7));
|
||||||
|
palette_raw.push_back(Point3(0x0D1, 0x0E5, 0x0F0));
|
||||||
|
palette_raw.push_back(Point3(0x092, 0x0C5, 0x0DE));
|
||||||
|
palette_raw.push_back(Point3(0x043, 0x093, 0x0C3));
|
||||||
|
palette_raw.push_back(Point3(0x021, 0x066, 0x0AC));
|
||||||
|
|
||||||
|
// Clear the main texture and the 2nd LOD level.
|
||||||
|
memset(data, 0, rows * cols * 5);
|
||||||
|
// 2nd LOD level data start
|
||||||
|
unsigned char *data1 = reinterpret_cast<unsigned char*>(data) + rows * cols * 4;
|
||||||
|
int ncells = std::min((cols-1) * rows, int(ceil(16. * (slicing_params.object_print_z_height() / slicing_params.min_layer_height))));
|
||||||
|
int ncells1 = ncells / 2;
|
||||||
|
int cols1 = cols / 2;
|
||||||
|
coordf_t z_to_cell = coordf_t(ncells-1) / slicing_params.object_print_z_height();
|
||||||
|
coordf_t cell_to_z = slicing_params.object_print_z_height() / coordf_t(ncells-1);
|
||||||
|
coordf_t z_to_cell1 = coordf_t(ncells1-1) / slicing_params.object_print_z_height();
|
||||||
|
coordf_t cell_to_z1 = slicing_params.object_print_z_height() / coordf_t(ncells1-1);
|
||||||
|
// for color scaling
|
||||||
|
coordf_t hscale = 2.f * std::max(slicing_params.max_layer_height - slicing_params.layer_height, slicing_params.layer_height - slicing_params.min_layer_height);
|
||||||
|
if (hscale == 0)
|
||||||
|
// All layers have the same height. Provide some height scale to avoid division by zero.
|
||||||
|
hscale = slicing_params.layer_height;
|
||||||
|
for (size_t idx_layer = 0; idx_layer < layers.size(); idx_layer += 2) {
|
||||||
|
coordf_t lo = layers[idx_layer];
|
||||||
|
coordf_t hi = layers[idx_layer + 1];
|
||||||
|
coordf_t mid = 0.5f * (lo + hi);
|
||||||
|
assert(mid <= slicing_params.object_print_z_height());
|
||||||
|
coordf_t h = hi - lo;
|
||||||
|
hi = std::min(hi, slicing_params.object_print_z_height());
|
||||||
|
int cell_first = clamp(0, ncells-1, int(ceil(lo * z_to_cell)));
|
||||||
|
int cell_last = clamp(0, ncells-1, int(floor(hi * z_to_cell)));
|
||||||
|
for (int cell = cell_first; cell <= cell_last; ++ cell) {
|
||||||
|
coordf_t idxf = (0.5 * hscale + (h - slicing_params.layer_height)) * coordf_t(palette_raw.size()) / hscale;
|
||||||
|
int idx1 = clamp(0, int(palette_raw.size() - 1), int(floor(idxf)));
|
||||||
|
int idx2 = std::min(int(palette_raw.size() - 1), idx1 + 1);
|
||||||
|
coordf_t t = idxf - coordf_t(idx1);
|
||||||
|
const Point3 &color1 = palette_raw[idx1];
|
||||||
|
const Point3 &color2 = palette_raw[idx2];
|
||||||
|
|
||||||
|
coordf_t z = cell_to_z * coordf_t(cell);
|
||||||
|
assert(z >= lo && z <= hi);
|
||||||
|
// Intensity profile to visualize the layers.
|
||||||
|
coordf_t intensity = cos(M_PI * 0.7 * (mid - z) / h);
|
||||||
|
|
||||||
|
// Color mapping from layer height to RGB.
|
||||||
|
Pointf3 color(
|
||||||
|
intensity * lerp(coordf_t(color1.x), coordf_t(color2.x), t),
|
||||||
|
intensity * lerp(coordf_t(color1.y), coordf_t(color2.y), t),
|
||||||
|
intensity * lerp(coordf_t(color1.z), coordf_t(color2.z), t));
|
||||||
|
|
||||||
|
int row = cell / (cols - 1);
|
||||||
|
int col = cell - row * (cols - 1);
|
||||||
|
assert(row >= 0 && row < rows);
|
||||||
|
assert(col >= 0 && col < cols);
|
||||||
|
unsigned char *ptr = (unsigned char*)data + (row * cols + col) * 4;
|
||||||
|
ptr[0] = clamp<int>(0, 255, int(floor(color.x + 0.5)));
|
||||||
|
ptr[1] = clamp<int>(0, 255, int(floor(color.y + 0.5)));
|
||||||
|
ptr[2] = clamp<int>(0, 255, int(floor(color.z + 0.5)));
|
||||||
|
ptr[3] = 255;
|
||||||
|
if (col == 0 && row > 0) {
|
||||||
|
// Duplicate the first value in a row as a last value of the preceding row.
|
||||||
|
ptr[-4] = ptr[0];
|
||||||
|
ptr[-3] = ptr[1];
|
||||||
|
ptr[-2] = ptr[2];
|
||||||
|
ptr[-1] = ptr[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (level_of_detail_2nd_level) {
|
||||||
|
cell_first = clamp(0, ncells1-1, int(ceil(lo * z_to_cell1)));
|
||||||
|
cell_last = clamp(0, ncells1-1, int(floor(hi * z_to_cell1)));
|
||||||
|
for (int cell = cell_first; cell <= cell_last; ++ cell) {
|
||||||
|
coordf_t idxf = (0.5 * hscale + (h - slicing_params.layer_height)) * coordf_t(palette_raw.size()) / hscale;
|
||||||
|
int idx1 = clamp(0, int(palette_raw.size() - 1), int(floor(idxf)));
|
||||||
|
int idx2 = std::min(int(palette_raw.size() - 1), idx1 + 1);
|
||||||
|
coordf_t t = idxf - coordf_t(idx1);
|
||||||
|
const Point3 &color1 = palette_raw[idx1];
|
||||||
|
const Point3 &color2 = palette_raw[idx2];
|
||||||
|
|
||||||
|
coordf_t z = cell_to_z1 * coordf_t(cell);
|
||||||
|
assert(z >= lo && z <= hi);
|
||||||
|
|
||||||
|
// Color mapping from layer height to RGB.
|
||||||
|
Pointf3 color(
|
||||||
|
lerp(coordf_t(color1.x), coordf_t(color2.x), t),
|
||||||
|
lerp(coordf_t(color1.y), coordf_t(color2.y), t),
|
||||||
|
lerp(coordf_t(color1.z), coordf_t(color2.z), t));
|
||||||
|
|
||||||
|
int row = cell / (cols1 - 1);
|
||||||
|
int col = cell - row * (cols1 - 1);
|
||||||
|
assert(row >= 0 && row < rows/2);
|
||||||
|
assert(col >= 0 && col < cols/2);
|
||||||
|
unsigned char *ptr = data1 + (row * cols1 + col) * 4;
|
||||||
|
ptr[0] = clamp<int>(0, 255, int(floor(color.x + 0.5)));
|
||||||
|
ptr[1] = clamp<int>(0, 255, int(floor(color.y + 0.5)));
|
||||||
|
ptr[2] = clamp<int>(0, 255, int(floor(color.z + 0.5)));
|
||||||
|
ptr[3] = 255;
|
||||||
|
if (col == 0 && row > 0) {
|
||||||
|
// Duplicate the first value in a row as a last value of the preceding row.
|
||||||
|
ptr[-4] = ptr[0];
|
||||||
|
ptr[-3] = ptr[1];
|
||||||
|
ptr[-2] = ptr[2];
|
||||||
|
ptr[-1] = ptr[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns number of cells of the 0th LOD level.
|
||||||
|
return ncells;
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace Slic3r
|
|
@ -3,15 +3,52 @@
|
||||||
#ifndef slic3r_Slicing_hpp_
|
#ifndef slic3r_Slicing_hpp_
|
||||||
#define slic3r_Slicing_hpp_
|
#define slic3r_Slicing_hpp_
|
||||||
|
|
||||||
#include "libslic3r.h"
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "libslic3r.h"
|
||||||
namespace Slic3r
|
namespace Slic3r
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class PrintConfig;
|
||||||
|
class PrintObjectConfig;
|
||||||
|
class ModelVolume;
|
||||||
|
typedef std::vector<ModelVolume*> ModelVolumePtrs;
|
||||||
|
|
||||||
|
// Parameters to guide object slicing and support generation.
|
||||||
|
// The slicing parameters account for a raft and whether the 1st object layer is printed with a normal or a bridging flow
|
||||||
|
// (using a normal flow over a soluble support, using a bridging flow over a non-soluble support).
|
||||||
struct SlicingParameters
|
struct SlicingParameters
|
||||||
{
|
{
|
||||||
SlicingParameters() { memset(this, 0, sizeof(SlicingParameters)); }
|
SlicingParameters() { memset(this, 0, sizeof(SlicingParameters)); }
|
||||||
|
|
||||||
|
static SlicingParameters create_from_config(
|
||||||
|
const PrintConfig &print_config,
|
||||||
|
const PrintObjectConfig &object_config,
|
||||||
|
coordf_t object_height,
|
||||||
|
const std::set<size_t> &object_extruders);
|
||||||
|
|
||||||
|
// Has any raft layers?
|
||||||
|
bool has_raft() const { return raft_layers() > 0; }
|
||||||
|
size_t raft_layers() const { return base_raft_layers + interface_raft_layers; }
|
||||||
|
|
||||||
|
// Is the 1st object layer height fixed, or could it be varied?
|
||||||
|
bool first_object_layer_height_fixed() const { return ! has_raft() || first_object_layer_bridging; }
|
||||||
|
|
||||||
|
// Height of the object to be printed. This value does not contain the raft height.
|
||||||
|
coordf_t object_print_z_height() const { return object_print_z_max - object_print_z_min; }
|
||||||
|
|
||||||
|
// Number of raft layers.
|
||||||
|
size_t base_raft_layers;
|
||||||
|
// Number of interface layers including the contact layer.
|
||||||
|
size_t interface_raft_layers;
|
||||||
|
|
||||||
|
// Layer heights of the raft (base, interface and a contact layer).
|
||||||
|
coordf_t base_raft_layer_height;
|
||||||
|
coordf_t interface_raft_layer_height;
|
||||||
|
coordf_t contact_raft_layer_height;
|
||||||
|
bool contact_raft_layer_height_bridging;
|
||||||
|
|
||||||
// The regular layer height, applied for all but the first layer, if not overridden by layer ranges
|
// The regular layer height, applied for all but the first layer, if not overridden by layer ranges
|
||||||
// or by the variable layer thickness table.
|
// or by the variable layer thickness table.
|
||||||
coordf_t layer_height;
|
coordf_t layer_height;
|
||||||
|
@ -19,10 +56,10 @@ struct SlicingParameters
|
||||||
// Thickness of the first layer. This is either the first print layer thickness if printed without a raft,
|
// Thickness of the first layer. This is either the first print layer thickness if printed without a raft,
|
||||||
// or a bridging flow thickness if printed over a non-soluble raft,
|
// or a bridging flow thickness if printed over a non-soluble raft,
|
||||||
// or a normal layer height if printed over a soluble raft.
|
// or a normal layer height if printed over a soluble raft.
|
||||||
coordf_t first_layer_height;
|
coordf_t first_object_layer_height;
|
||||||
|
|
||||||
// If the object is printed over a non-soluble raft, the first layer may be printed with a briding flow.
|
// If the object is printed over a non-soluble raft, the first layer may be printed with a briding flow.
|
||||||
bool first_layer_bridging;
|
bool first_object_layer_bridging;
|
||||||
|
|
||||||
// Minimum / maximum layer height, to be used for the automatic adaptive layer height algorithm,
|
// Minimum / maximum layer height, to be used for the automatic adaptive layer height algorithm,
|
||||||
// or by an interactive layer height editor.
|
// or by an interactive layer height editor.
|
||||||
|
@ -39,6 +76,37 @@ struct SlicingParameters
|
||||||
typedef std::pair<coordf_t,coordf_t> t_layer_height_range;
|
typedef std::pair<coordf_t,coordf_t> t_layer_height_range;
|
||||||
typedef std::map<t_layer_height_range,coordf_t> t_layer_height_ranges;
|
typedef std::map<t_layer_height_range,coordf_t> t_layer_height_ranges;
|
||||||
|
|
||||||
|
extern std::vector<coordf_t> layer_height_profile_from_ranges(
|
||||||
|
const SlicingParameters &slicing_params,
|
||||||
|
const t_layer_height_ranges &layer_height_ranges);
|
||||||
|
|
||||||
|
extern std::vector<coordf_t> layer_height_profile_adaptive(
|
||||||
|
const SlicingParameters &slicing_params,
|
||||||
|
const t_layer_height_ranges &layer_height_ranges,
|
||||||
|
const ModelVolumePtrs &volumes);
|
||||||
|
|
||||||
|
extern void adjust_layer_height_profile(
|
||||||
|
const SlicingParameters &slicing_params,
|
||||||
|
std::vector<coordf_t> &layer_height_profile,
|
||||||
|
coordf_t z,
|
||||||
|
coordf_t layer_thickness_delta,
|
||||||
|
coordf_t band_width,
|
||||||
|
int action);
|
||||||
|
|
||||||
|
// Produce object layers as pairs of low / high layer boundaries, stored into a linear vector.
|
||||||
|
// The object layers are based at z=0, ignoring the raft layers.
|
||||||
|
extern std::vector<coordf_t> generate_object_layers(
|
||||||
|
const SlicingParameters &slicing_params,
|
||||||
|
const std::vector<coordf_t> &layer_height_profile);
|
||||||
|
|
||||||
|
// Produce a 1D texture packed into a 2D texture describing in the RGBA format
|
||||||
|
// the planned object layers.
|
||||||
|
// Returns number of cells used by the texture of the 0th LOD level.
|
||||||
|
extern int generate_layer_height_texture(
|
||||||
|
const SlicingParameters &slicing_params,
|
||||||
|
const std::vector<coordf_t> &layers,
|
||||||
|
void *data, int rows, int cols, bool level_of_detail_2nd_level);
|
||||||
|
|
||||||
}; // namespace Slic3r
|
}; // namespace Slic3r
|
||||||
|
|
||||||
#endif /* slic3r_Slicing_hpp_ */
|
#endif /* slic3r_Slicing_hpp_ */
|
||||||
|
|
|
@ -22,22 +22,13 @@ std::pair<float, float> face_z_span(const stl_facet *f)
|
||||||
void SlicingAdaptive::prepare()
|
void SlicingAdaptive::prepare()
|
||||||
{
|
{
|
||||||
// 1) Collect faces of all meshes.
|
// 1) Collect faces of all meshes.
|
||||||
{
|
int nfaces_total = 0;
|
||||||
int nfaces_total = 0;
|
for (std::vector<const TriangleMesh*>::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh)
|
||||||
for (std::vector<const TriangleMesh*>::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh)
|
nfaces_total += (*it_mesh)->stl.stats.number_of_facets;
|
||||||
nfaces_total += (*it_mesh)->stl.stats.number_of_facets;
|
m_faces.reserve(nfaces_total);
|
||||||
m_faces.reserve(nfaces_total);
|
for (std::vector<const TriangleMesh*>::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh)
|
||||||
}
|
for (int i = 0; i < (*it_mesh)->stl.stats.number_of_facets; ++ i)
|
||||||
m_max_z = 0;
|
m_faces.push_back((*it_mesh)->stl.facet_start + i);
|
||||||
for (std::vector<const TriangleMesh*>::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh) {
|
|
||||||
const stl_facet *faces = (*it_mesh)->stl.facet_start;
|
|
||||||
int nfaces = (*it_mesh)->stl.stats.number_of_facets;
|
|
||||||
for (int i = 0; i < nfaces; ++ i) {
|
|
||||||
const stl_facet *facet = faces + i;
|
|
||||||
m_faces.push_back(facet);
|
|
||||||
m_max_z = std::max(std::max(m_max_z, facet->vertex[0].z), std::max(facet->vertex[1].z, facet->vertex[2].z));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2) Sort faces lexicographically by their Z span.
|
// 2) Sort faces lexicographically by their Z span.
|
||||||
std::sort(m_faces.begin(), m_faces.end(), [](const stl_facet *f1, const stl_facet *f2) {
|
std::sort(m_faces.begin(), m_faces.end(), [](const stl_facet *f1, const stl_facet *f2) {
|
||||||
|
@ -54,7 +45,7 @@ void SlicingAdaptive::prepare()
|
||||||
|
|
||||||
float SlicingAdaptive::cusp_height(float z, float cusp_value, int ¤t_facet)
|
float SlicingAdaptive::cusp_height(float z, float cusp_value, int ¤t_facet)
|
||||||
{
|
{
|
||||||
float height = m_layer_height_max;
|
float height = m_slicing_params.max_layer_height;
|
||||||
bool first_hit = false;
|
bool first_hit = false;
|
||||||
|
|
||||||
// find all facets intersecting the slice-layer
|
// find all facets intersecting the slice-layer
|
||||||
|
@ -81,10 +72,10 @@ float SlicingAdaptive::cusp_height(float z, float cusp_value, int ¤t_facet
|
||||||
}
|
}
|
||||||
|
|
||||||
// lower height limit due to printer capabilities
|
// lower height limit due to printer capabilities
|
||||||
height = std::max(height, m_layer_height_min);
|
height = std::max(height, float(m_slicing_params.min_layer_height));
|
||||||
|
|
||||||
// check for sloped facets inside the determined layer and correct height if necessary
|
// check for sloped facets inside the determined layer and correct height if necessary
|
||||||
if (height > m_layer_height_min) {
|
if (height > m_slicing_params.min_layer_height) {
|
||||||
for (; ordered_id < int(m_faces.size()); ++ ordered_id) {
|
for (; ordered_id < int(m_faces.size()); ++ ordered_id) {
|
||||||
std::pair<float, float> zspan = face_z_span(m_faces[ordered_id]);
|
std::pair<float, float> zspan = face_z_span(m_faces[ordered_id]);
|
||||||
// facet's minimum is higher than slice_z + height -> end loop
|
// facet's minimum is higher than slice_z + height -> end loop
|
||||||
|
@ -119,7 +110,7 @@ float SlicingAdaptive::cusp_height(float z, float cusp_value, int ¤t_facet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// lower height limit due to printer capabilities again
|
// lower height limit due to printer capabilities again
|
||||||
height = std::max(height, m_layer_height_min);
|
height = std::max(height, float(m_slicing_params.min_layer_height));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slic3r::debugf "cusp computation, layer-bottom at z:%f, cusp_value:%f, resulting layer height:%f\n", unscale $z, $cusp_value, $height;
|
// Slic3r::debugf "cusp computation, layer-bottom at z:%f, cusp_value:%f, resulting layer height:%f\n", unscale $z, $cusp_value, $height;
|
||||||
|
@ -133,7 +124,7 @@ float SlicingAdaptive::horizontal_facet_distance(float z)
|
||||||
for (size_t i = 0; i < m_faces.size(); ++ i) {
|
for (size_t i = 0; i < m_faces.size(); ++ i) {
|
||||||
std::pair<float, float> zspan = face_z_span(m_faces[i]);
|
std::pair<float, float> zspan = face_z_span(m_faces[i]);
|
||||||
// facet's minimum is higher than max forward distance -> end loop
|
// facet's minimum is higher than max forward distance -> end loop
|
||||||
if (zspan.first > z + m_layer_height_max)
|
if (zspan.first > z + m_slicing_params.max_layer_height)
|
||||||
break;
|
break;
|
||||||
// min_z == max_z -> horizontal facet
|
// min_z == max_z -> horizontal facet
|
||||||
if (zspan.first > z && zspan.first == zspan.second)
|
if (zspan.first > z && zspan.first == zspan.second)
|
||||||
|
@ -141,9 +132,9 @@ float SlicingAdaptive::horizontal_facet_distance(float z)
|
||||||
}
|
}
|
||||||
|
|
||||||
// objects maximum?
|
// objects maximum?
|
||||||
return (z + m_layer_height_max > m_max_z) ?
|
return (z + m_slicing_params.max_layer_height > m_slicing_params.object_print_z_height()) ?
|
||||||
std::max<float>(m_max_z - z, 0.f) :
|
std::max<float>(m_slicing_params.object_print_z_height() - z, 0.f) :
|
||||||
m_layer_height_max;
|
m_slicing_params.max_layer_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
}; // namespace Slic3r
|
}; // namespace Slic3r
|
||||||
|
|
|
@ -15,16 +15,14 @@ class SlicingAdaptive
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void clear();
|
void clear();
|
||||||
void set_layer_height_range(float min, float max) { m_layer_height_min = min; m_layer_height_max = max; }
|
void set_slicing_parameters(SlicingParameters params) { m_slicing_params = params; }
|
||||||
void add_mesh(const TriangleMesh *mesh) { m_meshes.push_back(mesh); }
|
void add_mesh(const TriangleMesh *mesh) { m_meshes.push_back(mesh); }
|
||||||
void prepare();
|
void prepare();
|
||||||
float cusp_height(float z, float cusp_value, int ¤t_facet);
|
float cusp_height(float z, float cusp_value, int ¤t_facet);
|
||||||
float horizontal_facet_distance(float z);
|
float horizontal_facet_distance(float z);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float m_layer_height_min;
|
SlicingParameters m_slicing_params;
|
||||||
float m_layer_height_max;
|
|
||||||
float m_max_z;
|
|
||||||
|
|
||||||
std::vector<const TriangleMesh*> m_meshes;
|
std::vector<const TriangleMesh*> m_meshes;
|
||||||
// Collected faces of all meshes, sorted by raising Z of the bottom most face.
|
// Collected faces of all meshes, sorted by raising Z of the bottom most face.
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
%{
|
%{
|
||||||
#include <xsinit.h>
|
#include <xsinit.h>
|
||||||
#include "libslic3r/Print.hpp"
|
#include "libslic3r/Print.hpp"
|
||||||
|
#include "libslic3r/Slicing.hpp"
|
||||||
#include "libslic3r/PlaceholderParser.hpp"
|
#include "libslic3r/PlaceholderParser.hpp"
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
@ -58,6 +59,8 @@ _constant()
|
||||||
Points copies();
|
Points copies();
|
||||||
t_layer_height_ranges layer_height_ranges()
|
t_layer_height_ranges layer_height_ranges()
|
||||||
%code%{ RETVAL = THIS->layer_height_ranges; %};
|
%code%{ RETVAL = THIS->layer_height_ranges; %};
|
||||||
|
std::vector<double> layer_height_profile()
|
||||||
|
%code%{ RETVAL = THIS->layer_height_profile; %};
|
||||||
Ref<Point3> size()
|
Ref<Point3> size()
|
||||||
%code%{ RETVAL = &THIS->size; %};
|
%code%{ RETVAL = &THIS->size; %};
|
||||||
Clone<BoundingBox> bounding_box();
|
Clone<BoundingBox> bounding_box();
|
||||||
|
@ -82,6 +85,8 @@ _constant()
|
||||||
bool reload_model_instances();
|
bool reload_model_instances();
|
||||||
void set_layer_height_ranges(t_layer_height_ranges layer_height_ranges)
|
void set_layer_height_ranges(t_layer_height_ranges layer_height_ranges)
|
||||||
%code%{ THIS->layer_height_ranges = layer_height_ranges; %};
|
%code%{ THIS->layer_height_ranges = layer_height_ranges; %};
|
||||||
|
void set_layer_height_profile(std::vector<double> profile)
|
||||||
|
%code%{ THIS->layer_height_profile = profile; %};
|
||||||
|
|
||||||
size_t total_layer_count();
|
size_t total_layer_count();
|
||||||
size_t layer_count();
|
size_t layer_count();
|
||||||
|
@ -107,6 +112,7 @@ _constant()
|
||||||
void set_step_started(PrintObjectStep step)
|
void set_step_started(PrintObjectStep step)
|
||||||
%code%{ THIS->state.set_started(step); %};
|
%code%{ THIS->state.set_started(step); %};
|
||||||
|
|
||||||
|
void _slice();
|
||||||
void detect_surfaces_type();
|
void detect_surfaces_type();
|
||||||
void process_external_surfaces();
|
void process_external_surfaces();
|
||||||
void discover_vertical_shells();
|
void discover_vertical_shells();
|
||||||
|
@ -114,6 +120,23 @@ _constant()
|
||||||
void _make_perimeters();
|
void _make_perimeters();
|
||||||
void _infill();
|
void _infill();
|
||||||
|
|
||||||
|
void adjust_layer_height_profile(coordf_t z, coordf_t layer_thickness_delta, coordf_t band_width, int action)
|
||||||
|
%code%{
|
||||||
|
THIS->update_layer_height_profile();
|
||||||
|
adjust_layer_height_profile(
|
||||||
|
THIS->slicing_parameters(), THIS->layer_height_profile, z, layer_thickness_delta, band_width, action);
|
||||||
|
%};
|
||||||
|
|
||||||
|
int generate_layer_height_texture(void *data, int rows, int cols, bool level_of_detail_2nd_level = true)
|
||||||
|
%code%{
|
||||||
|
THIS->update_layer_height_profile();
|
||||||
|
SlicingParameters slicing_params = THIS->slicing_parameters();
|
||||||
|
RETVAL = generate_layer_height_texture(
|
||||||
|
slicing_params,
|
||||||
|
generate_object_layers(slicing_params, THIS->layer_height_profile),
|
||||||
|
data, rows, cols, level_of_detail_2nd_level);
|
||||||
|
%};
|
||||||
|
|
||||||
int ptr()
|
int ptr()
|
||||||
%code%{ RETVAL = (int)(intptr_t)THIS; %};
|
%code%{ RETVAL = (int)(intptr_t)THIS; %};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue