From 97f4301398847151d60848b7fcf0012e627454c8 Mon Sep 17 00:00:00 2001 From: Florens Wasserfall Date: Thu, 26 Jan 2017 08:49:48 +0100 Subject: [PATCH] Class to interpolate layer height distribution based on BSplines --- xs/MANIFEST | 3 + xs/lib/Slic3r/XS.pm | 1 + xs/src/libslic3r/LayerHeightSpline.cpp | 194 +++++++++++++++++++++++++ xs/src/libslic3r/LayerHeightSpline.hpp | 40 +++++ xs/src/perlglue.cpp | 1 + xs/xsp/LayerHeightSpline.xsp | 23 +++ xs/xsp/my.map | 3 + xs/xsp/typemap.xspt | 3 + 8 files changed, 268 insertions(+) create mode 100644 xs/src/libslic3r/LayerHeightSpline.cpp create mode 100644 xs/src/libslic3r/LayerHeightSpline.hpp create mode 100644 xs/xsp/LayerHeightSpline.xsp diff --git a/xs/MANIFEST b/xs/MANIFEST index 4e544d472..fcc323bb9 100644 --- a/xs/MANIFEST +++ b/xs/MANIFEST @@ -43,6 +43,8 @@ src/libslic3r/IO.hpp src/libslic3r/Layer.cpp src/libslic3r/Layer.hpp src/libslic3r/LayerRegion.cpp +src/libslic3r/LayerHeightSpline.hpp +src/libslic3r/LayerHeightSpline.cpp src/libslic3r/libslic3r.h src/libslic3r/Line.cpp src/libslic3r/Line.hpp @@ -139,6 +141,7 @@ xsp/Geometry.xsp xsp/GUI.xsp xsp/GUI_3DScene.xsp xsp/Layer.xsp +xsp/LayerHeightSpline.xsp xsp/Line.xsp xsp/Model.xsp xsp/MotionPlanner.xsp diff --git a/xs/lib/Slic3r/XS.pm b/xs/lib/Slic3r/XS.pm index 4f53966de..e0c0268a9 100644 --- a/xs/lib/Slic3r/XS.pm +++ b/xs/lib/Slic3r/XS.pm @@ -228,6 +228,7 @@ for my $class (qw( Slic3r::Layer Slic3r::Layer::Region Slic3r::Layer::Support + Slic3r::LayerHeightSpline Slic3r::Line Slic3r::Linef3 Slic3r::Model diff --git a/xs/src/libslic3r/LayerHeightSpline.cpp b/xs/src/libslic3r/LayerHeightSpline.cpp new file mode 100644 index 000000000..5b3e59885 --- /dev/null +++ b/xs/src/libslic3r/LayerHeightSpline.cpp @@ -0,0 +1,194 @@ +/* + * This class represents a set of layers and their heights. + * It is intended for smoothing the height distribution (avoid very thin + * layers next to thick layers) and to correctly interpolate higher layers if + * a layer height changes somewhere in a lower position at the object. + * Uses http://www.eol.ucar.edu/homes/granger/bspline/doc/ for spline computation. + */ + +#include "LayerHeightSpline.hpp" +#include // std::abs + +namespace Slic3r { + +LayerHeightSpline::LayerHeightSpline(coordf_t object_height) +: _object_height(object_height), _layer_height_spline(NULL) +{ + this->_is_valid = false; + this->_update_required = true; +} + +LayerHeightSpline::~LayerHeightSpline() +{ + if (this->_layer_height_spline) { + delete this->_layer_height_spline; + } +} + +/* + * Indicates whether the object has valid data and the spline was successfully computed or not. + */ +bool LayerHeightSpline::hasData() +{ + return this->_is_valid; +} + +/* + * Does this object expect new layer heights during the slice step or should + * we use the layer heights values provided by the spline? + * An update is required if a config option is changed which affects the layer height. + * An update is not required if the spline was modified by a user interaction. + */ +bool LayerHeightSpline::updateRequired() +{ + bool result = true; // update spline by default + if(!this->_update_required && this->_is_valid) { + result = false; + } + this->_update_required = true; // reset to default after request + return result; +} + +/* + * Don't require an update for exactly one iteration. + */ +void LayerHeightSpline::suppressUpdate() { + if (this->_is_valid) { + this->_update_required = false; + } +} + +/* + * Set absolute layer positions in object coordinates. + * Heights (thickness of each layer) is generated from this list. + */ +bool LayerHeightSpline::setLayers(std::vector layers) +{ + this->_original_layers = layers; + + // generate updated layer height list from layers + this->_internal_layer_heights.clear(); + coordf_t last_z = 0; + for (std::vector::const_iterator l = this->_original_layers.begin(); l != this->_original_layers.end(); ++l) { + this->_internal_layer_heights.push_back(*l-last_z); + last_z = *l; + } + + // add 0-values at both ends to achieve correct boundary conditions + this->_internal_layers = this->_original_layers; + this->_internal_layers.insert(this->_internal_layers.begin(), 0); // add z = 0 to the front + this->_internal_layers.push_back(this->_internal_layers.back()+1); // and object_height + 1 to the end + this->_internal_layer_heights.insert(this->_internal_layer_heights.begin(), 0); + this->_internal_layer_heights.push_back(0); + + return this->_updateBSpline(); +} + + +/* + * Update only the desired thickness of the layers, but not their positions! + * This modifies the y-values for the spline computation and only affects + * the resulting layers which can be obtained with getInterpolatedLayers. + * The argument vector must be of the same size as the layers vector. + */ +bool LayerHeightSpline::updateLayerHeights(std::vector heights) +{ + bool result = false; + + // do we receive the correct number of values? + if(heights.size() == this->_internal_layers.size()-2) { + this->_internal_layer_heights = heights; + // add leading an trailing 0-value + this->_internal_layer_heights.insert(this->_internal_layer_heights.begin(), 0); + this->_internal_layer_heights.push_back(0); + result = this->_updateBSpline(); + } + + return result; +} + +/* + * Reset the this object, remove database and interpolated results. + */ +void LayerHeightSpline::clear() +{ + this->_original_layers.clear(); + this->_internal_layers.clear(); + this->_internal_layer_heights.clear(); + delete this->_layer_height_spline; + this->_layer_height_spline = NULL; + this->_is_valid = false; +} + + +/* + * Get a full set of layer z-positions by interpolation along the spline. + */ +std::vector LayerHeightSpline::getInterpolatedLayers() const +{ + std::vector layers; + if(this->_is_valid) { + // preserve first layer for bed contact + layers.push_back(this->_original_layers[0]); + coordf_t z = this->_original_layers[0]; + coordf_t h; + coordf_t h_diff = 0; + coordf_t eps = 0.0001; + while(z <= this->_object_height) { + h = 0; + // find intersection between layer height and spline + do { + h += h_diff/2; + h = this->_layer_height_spline->evaluate(z+h); + h_diff = this->_layer_height_spline->evaluate(z+h) - h; + } while(std::abs(h_diff) > eps); + z += h; + layers.push_back(z); + } + // how to make sure, the last layer is not higher than object while maintaining between min/max layer height? + } + return layers; +} + +/* + * Evaluate interpolated layer height (thickness) at given z-position + */ +const coordf_t LayerHeightSpline::getLayerHeightAt(coordf_t height) +{ + coordf_t result = 0; + if (this->_is_valid) { + result = this->_layer_height_spline->evaluate(height); + } + return result; +} + +/* + * Internal method to re-compute the spline + */ +bool LayerHeightSpline::_updateBSpline() +{ + bool result = false; + //TODO: exception if not enough points? + + delete this->_layer_height_spline; + this->_layer_height_spline = new BSpline(&this->_internal_layers[0], + this->_internal_layers.size(), + &this->_internal_layer_heights[0], + 0, + 0, + 0); + + if (this->_layer_height_spline->ok()) { + result = true; + } else { + result = false; + std::cerr << "Spline setup failed." << std::endl; + } + + this->_is_valid = result; + + return result; +} + + +} diff --git a/xs/src/libslic3r/LayerHeightSpline.hpp b/xs/src/libslic3r/LayerHeightSpline.hpp new file mode 100644 index 000000000..ea02b93ae --- /dev/null +++ b/xs/src/libslic3r/LayerHeightSpline.hpp @@ -0,0 +1,40 @@ +#ifndef slic3r_LayerHeightSpline_hpp_ +#define slic3r_LayerHeightSpline_hpp_ + +#include "libslic3r.h" +#include "BSpline/BSpline.h" // Warning: original BSplineBase.h/cpp merged into BSpline.h/cpp to avoid dependency issues caused by Build::WithXSpp which tries to compile all .cpp files in /src + + +namespace Slic3r { + + +class LayerHeightSpline +{ + public: + LayerHeightSpline(coordf_t object_height); + ~LayerHeightSpline(); + bool hasData(); // indicate that we have valid data + bool updateRequired(); // indicate whether we want to generate a new spline from the layers + void suppressUpdate(); + bool setLayers(std::vector layers); + bool updateLayerHeights(std::vector heights); + void clear(); + std::vector getOriginalLayers() const { return this->_original_layers; }; + std::vector getInterpolatedLayers() const; + const coordf_t getLayerHeightAt(coordf_t height); + + private: + bool _updateBSpline(); + + coordf_t _object_height; + bool _is_valid; + bool _update_required; // this should be always true except if we want to generate new layers from this spline + std::vector _original_layers; + std::vector _internal_layers; + std::vector _internal_layer_heights; + BSpline *_layer_height_spline; +}; + +} + +#endif diff --git a/xs/src/perlglue.cpp b/xs/src/perlglue.cpp index d8621ac91..5cdd45688 100644 --- a/xs/src/perlglue.cpp +++ b/xs/src/perlglue.cpp @@ -20,6 +20,7 @@ REGISTER_CLASS(GCodeWriter, "GCode::Writer"); REGISTER_CLASS(Layer, "Layer"); REGISTER_CLASS(SupportLayer, "Layer::Support"); REGISTER_CLASS(LayerRegion, "Layer::Region"); +REGISTER_CLASS(LayerHeightSpline, "LayerHeightSpline"); REGISTER_CLASS(Line, "Line"); REGISTER_CLASS(Linef3, "Linef3"); REGISTER_CLASS(PerimeterGenerator, "Layer::PerimeterGenerator"); diff --git a/xs/xsp/LayerHeightSpline.xsp b/xs/xsp/LayerHeightSpline.xsp new file mode 100644 index 000000000..ad5c5e58e --- /dev/null +++ b/xs/xsp/LayerHeightSpline.xsp @@ -0,0 +1,23 @@ +%module{Slic3r::XS}; + +%{ +#include +#include "libslic3r/LayerHeightSpline.hpp" +%} + +%name{Slic3r::LayerHeightSpline} class LayerHeightSpline { + // owned by PrintObject, no constructor/destructor + + bool hasData(); + bool updateRequired(); + void suppressUpdate(); + bool setLayers(std::vector layers) + %code%{ RETVAL = THIS->setLayers(layers); %}; + bool updateLayerHeights(std::vector heights) + %code%{ RETVAL = THIS->updateLayerHeights(heights); %}; + void clear(); + std::vector getOriginalLayers(); + std::vector getInterpolatedLayers(); + coordf_t getLayerHeightAt(coordf_t height); + //%code%{ RETVAL = THIS->upper_layer; %}; +}; diff --git a/xs/xsp/my.map b/xs/xsp/my.map index 5f87f51c2..7590ec90e 100644 --- a/xs/xsp/my.map +++ b/xs/xsp/my.map @@ -169,6 +169,9 @@ Ref O_OBJECT_SLIC3R_T SupportLayer* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T +LayerHeightSpline* O_OBJECT_SLIC3R +Ref O_OBJECT_SLIC3R_T + PlaceholderParser* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T Clone O_OBJECT_SLIC3R_T diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt index 37d7a9620..8eb09db3b 100644 --- a/xs/xsp/typemap.xspt +++ b/xs/xsp/typemap.xspt @@ -129,6 +129,9 @@ %typemap{Layer*}; %typemap{Ref}{simple}; +%typemap{LayerHeightSpline*}; +%typemap{Ref}{simple}; + %typemap{SupportLayer*}; %typemap{Ref}{simple};