Class to interpolate layer height distribution based on BSplines

This commit is contained in:
Florens Wasserfall 2017-01-26 08:49:48 +01:00
parent c3f7a226a0
commit 97f4301398
8 changed files with 268 additions and 0 deletions

View File

@ -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

View File

@ -228,6 +228,7 @@ for my $class (qw(
Slic3r::Layer
Slic3r::Layer::Region
Slic3r::Layer::Support
Slic3r::LayerHeightSpline
Slic3r::Line
Slic3r::Linef3
Slic3r::Model

View File

@ -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 <cmath> // 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<coordf_t> 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<coordf_t>::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<coordf_t> 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<coordf_t> LayerHeightSpline::getInterpolatedLayers() const
{
std::vector<coordf_t> 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<double>(&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;
}
}

View File

@ -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<coordf_t> layers);
bool updateLayerHeights(std::vector<coordf_t> heights);
void clear();
std::vector<coordf_t> getOriginalLayers() const { return this->_original_layers; };
std::vector<coordf_t> 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<coordf_t> _original_layers;
std::vector<coordf_t> _internal_layers;
std::vector<coordf_t> _internal_layer_heights;
BSpline<double> *_layer_height_spline;
};
}
#endif

View File

@ -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");

View File

@ -0,0 +1,23 @@
%module{Slic3r::XS};
%{
#include <xsinit.h>
#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<double> layers)
%code%{ RETVAL = THIS->setLayers(layers); %};
bool updateLayerHeights(std::vector<double> heights)
%code%{ RETVAL = THIS->updateLayerHeights(heights); %};
void clear();
std::vector<double> getOriginalLayers();
std::vector<double> getInterpolatedLayers();
coordf_t getLayerHeightAt(coordf_t height);
//%code%{ RETVAL = THIS->upper_layer; %};
};

View File

@ -169,6 +169,9 @@ Ref<Layer> O_OBJECT_SLIC3R_T
SupportLayer* O_OBJECT_SLIC3R
Ref<SupportLayer> O_OBJECT_SLIC3R_T
LayerHeightSpline* O_OBJECT_SLIC3R
Ref<LayerHeightSpline> O_OBJECT_SLIC3R_T
PlaceholderParser* O_OBJECT_SLIC3R
Ref<PlaceholderParser> O_OBJECT_SLIC3R_T
Clone<PlaceholderParser> O_OBJECT_SLIC3R_T

View File

@ -129,6 +129,9 @@
%typemap{Layer*};
%typemap{Ref<Layer>}{simple};
%typemap{LayerHeightSpline*};
%typemap{Ref<LayerHeightSpline>}{simple};
%typemap{SupportLayer*};
%typemap{Ref<SupportLayer>}{simple};