mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-05-17 13:16:49 +08:00
height level mismatches seems to be fixed.
This commit is contained in:
parent
7482b619b5
commit
d27e22c2c3
@ -2525,6 +2525,13 @@ void PrintConfigDef::init_sla_params()
|
|||||||
def->min = 0;
|
def->min = 0;
|
||||||
def->default_value = new ConfigOptionFloat(5.0);
|
def->default_value = new ConfigOptionFloat(5.0);
|
||||||
|
|
||||||
|
def = this->add("pad_enable", coBool);
|
||||||
|
def->label = L("Use pad");
|
||||||
|
def->tooltip = L("Add a pad underneath the supported model");
|
||||||
|
def->sidetext = L("");
|
||||||
|
def->cli = "";
|
||||||
|
def->default_value = new ConfigOptionBool(true);
|
||||||
|
|
||||||
def = this->add("pad_wall_thickness", coFloat);
|
def = this->add("pad_wall_thickness", coFloat);
|
||||||
def->label = L("Pad wall thickness");
|
def->label = L("Pad wall thickness");
|
||||||
def->tooltip = L("");
|
def->tooltip = L("");
|
||||||
|
@ -942,6 +942,7 @@ public:
|
|||||||
|
|
||||||
// Now for the base pool (pad) /////////////////////////////////////////////
|
// Now for the base pool (pad) /////////////////////////////////////////////
|
||||||
|
|
||||||
|
ConfigOptionBool pad_enable;
|
||||||
ConfigOptionFloat pad_wall_thickness /*= 2*/;
|
ConfigOptionFloat pad_wall_thickness /*= 2*/;
|
||||||
ConfigOptionFloat pad_wall_height /*= 5*/;
|
ConfigOptionFloat pad_wall_height /*= 5*/;
|
||||||
ConfigOptionFloat pad_max_merge_distance /*= 50*/;
|
ConfigOptionFloat pad_max_merge_distance /*= 50*/;
|
||||||
@ -961,6 +962,7 @@ protected:
|
|||||||
OPT_PTR(support_critical_angle);
|
OPT_PTR(support_critical_angle);
|
||||||
OPT_PTR(support_max_bridge_length);
|
OPT_PTR(support_max_bridge_length);
|
||||||
OPT_PTR(support_object_elevation);
|
OPT_PTR(support_object_elevation);
|
||||||
|
OPT_PTR(pad_enable);
|
||||||
OPT_PTR(pad_wall_thickness);
|
OPT_PTR(pad_wall_thickness);
|
||||||
OPT_PTR(pad_wall_height);
|
OPT_PTR(pad_wall_height);
|
||||||
OPT_PTR(pad_max_merge_distance);
|
OPT_PTR(pad_max_merge_distance);
|
||||||
|
@ -23,6 +23,13 @@ struct PoolConfig {
|
|||||||
double min_wall_height_mm = 5;
|
double min_wall_height_mm = 5;
|
||||||
double max_merge_distance_mm = 50;
|
double max_merge_distance_mm = 50;
|
||||||
double edge_radius_mm = 1;
|
double edge_radius_mm = 1;
|
||||||
|
|
||||||
|
inline PoolConfig() {}
|
||||||
|
inline PoolConfig(double wt, double wh, double md, double er):
|
||||||
|
min_wall_thickness_mm(wt),
|
||||||
|
min_wall_height_mm(wh),
|
||||||
|
max_merge_distance_mm(md),
|
||||||
|
edge_radius_mm(er) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Calculate the pool for the mesh for SLA printing
|
/// Calculate the pool for the mesh for SLA printing
|
||||||
@ -31,6 +38,15 @@ void create_base_pool(const ExPolygons& base_plate,
|
|||||||
const PoolConfig& = PoolConfig()
|
const PoolConfig& = PoolConfig()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// TODO: Currently the base plate of the pool will have half the height of the
|
||||||
|
/// whole pool. So the carved out space has also half the height. This is not
|
||||||
|
/// a particularly elegant solution, the thickness should be exactly
|
||||||
|
/// min_wall_thickness and it should be corrected in the future. This method
|
||||||
|
/// will return the correct value for further processing.
|
||||||
|
inline double get_pad_elevation(const PoolConfig& cfg) {
|
||||||
|
return cfg.min_wall_height_mm / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -512,7 +512,7 @@ struct Pad {
|
|||||||
double ground_level,
|
double ground_level,
|
||||||
const PoolConfig& pcfg) :
|
const PoolConfig& pcfg) :
|
||||||
cfg(pcfg),
|
cfg(pcfg),
|
||||||
zlevel(ground_level + cfg.min_wall_height_mm/2)
|
zlevel(ground_level + sla::get_pad_elevation(pcfg))
|
||||||
{
|
{
|
||||||
ExPolygons basep;
|
ExPolygons basep;
|
||||||
base_plate(object_support_mesh, basep,
|
base_plate(object_support_mesh, basep,
|
||||||
@ -1634,7 +1634,7 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const
|
|||||||
const auto modelh = float(stree.full_height());
|
const auto modelh = float(stree.full_height());
|
||||||
auto gndlvl = float(this->m_impl->ground_level);
|
auto gndlvl = float(this->m_impl->ground_level);
|
||||||
const Pad& pad = m_impl->pad();
|
const Pad& pad = m_impl->pad();
|
||||||
if(!pad.empty()) gndlvl -= float(pad.cfg.min_wall_height_mm/2);
|
if(!pad.empty()) gndlvl -= float(get_pad_elevation(pad.cfg));
|
||||||
|
|
||||||
std::vector<float> heights = {gndlvl};
|
std::vector<float> heights = {gndlvl};
|
||||||
heights.reserve(size_t(modelh/layerh) + 1);
|
heights.reserve(size_t(modelh/layerh) + 1);
|
||||||
@ -1673,20 +1673,12 @@ const TriangleMesh &SLASupportTree::get_pad() const
|
|||||||
return m_impl->pad().tmesh;
|
return m_impl->pad().tmesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
double SLASupportTree::get_elevation() const
|
|
||||||
{
|
|
||||||
double ph = m_impl->pad().empty()? 0 :
|
|
||||||
m_impl->pad().cfg.min_wall_height_mm/2.0;
|
|
||||||
return m_elevation + ph;
|
|
||||||
}
|
|
||||||
|
|
||||||
SLASupportTree::SLASupportTree(const PointSet &points,
|
SLASupportTree::SLASupportTree(const PointSet &points,
|
||||||
const EigenMesh3D& emesh,
|
const EigenMesh3D& emesh,
|
||||||
const SupportConfig &cfg,
|
const SupportConfig &cfg,
|
||||||
const Controller &ctl):
|
const Controller &ctl):
|
||||||
m_impl(new Impl()), m_ctl(ctl)
|
m_impl(new Impl()), m_ctl(ctl)
|
||||||
{
|
{
|
||||||
m_elevation = cfg.object_elevation_mm;
|
|
||||||
m_impl->ground_level = emesh.ground_level - cfg.object_elevation_mm;
|
m_impl->ground_level = emesh.ground_level - cfg.object_elevation_mm;
|
||||||
generate(points, emesh, cfg, ctl);
|
generate(points, emesh, cfg, ctl);
|
||||||
}
|
}
|
||||||
|
@ -118,9 +118,6 @@ class SLASupportTree {
|
|||||||
std::unique_ptr<Impl> m_impl;
|
std::unique_ptr<Impl> m_impl;
|
||||||
Controller m_ctl;
|
Controller m_ctl;
|
||||||
|
|
||||||
// the only value from config that is also needed after construction
|
|
||||||
double m_elevation = 0;
|
|
||||||
|
|
||||||
Impl& get() { return *m_impl; }
|
Impl& get() { return *m_impl; }
|
||||||
const Impl& get() const { return *m_impl; }
|
const Impl& get() const { return *m_impl; }
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#include "SLA/SLABasePool.hpp"
|
#include "SLA/SLABasePool.hpp"
|
||||||
|
|
||||||
#include <tbb/parallel_for.h>
|
#include <tbb/parallel_for.h>
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
//#include <tbb/spin_mutex.h>//#include "tbb/mutex.h"
|
//#include <tbb/spin_mutex.h>//#include "tbb/mutex.h"
|
||||||
|
|
||||||
#include "I18N.hpp"
|
#include "I18N.hpp"
|
||||||
@ -128,32 +130,36 @@ void SLAPrint::process()
|
|||||||
// the model objects we have to process and the instances are also filtered
|
// the model objects we have to process and the instances are also filtered
|
||||||
|
|
||||||
// shortcut to initial layer height
|
// shortcut to initial layer height
|
||||||
auto ilh = float(m_material_config.initial_layer_height.getFloat());
|
double ilhd = m_material_config.initial_layer_height.getFloat();
|
||||||
|
auto ilh = float(ilhd);
|
||||||
std::cout << "Initial layer height: " << m_material_config.initial_layer_height.getFloat() << std::endl;
|
|
||||||
|
|
||||||
// Slicing the model object. This method is oversimplified and needs to
|
// Slicing the model object. This method is oversimplified and needs to
|
||||||
// be compared with the fff slicing algorithm for verification
|
// be compared with the fff slicing algorithm for verification
|
||||||
auto slice_model = [this, ilh](SLAPrintObject& po) {
|
auto slice_model = [this, ilh, ilhd](SLAPrintObject& po) {
|
||||||
auto lh = float(po.m_config.layer_height.getFloat());
|
double lh = po.m_config.layer_height.getFloat();
|
||||||
|
|
||||||
TriangleMesh mesh = po.transformed_mesh();
|
TriangleMesh mesh = po.transformed_mesh();
|
||||||
TriangleMeshSlicer slicer(&mesh);
|
TriangleMeshSlicer slicer(&mesh);
|
||||||
auto bb3d = mesh.bounding_box();
|
auto bb3d = mesh.bounding_box();
|
||||||
|
|
||||||
auto H = bb3d.max(Z) - bb3d.min(Z);
|
double elevation = po.get_elevation();
|
||||||
|
|
||||||
|
float minZ = float(bb3d.min(Z)) - float(elevation);
|
||||||
|
float maxZ = float(bb3d.max(Z)) ;
|
||||||
|
auto flh = float(lh);
|
||||||
auto gnd = float(bb3d.min(Z));
|
auto gnd = float(bb3d.min(Z));
|
||||||
|
|
||||||
double elevation = po.m_config.support_object_elevation.getFloat();
|
std::vector<float> heights;
|
||||||
float ih = elevation > 0 ? lh : ilh;
|
|
||||||
|
|
||||||
std::vector<float> heights = {gnd};
|
// The first layer (the one before the initial height) is added only
|
||||||
for(float h = gnd + ih; h < gnd + H; h += lh) heights.emplace_back(h);
|
// if the there is no pad and no elevation value
|
||||||
|
if(minZ >= gnd) heights.emplace_back(minZ);
|
||||||
|
|
||||||
|
for(float h = minZ + ilh; h < maxZ; h += flh)
|
||||||
|
if(h >= gnd) heights.emplace_back(h);
|
||||||
|
|
||||||
auto& layers = po.m_model_slices;
|
auto& layers = po.m_model_slices;
|
||||||
slicer.slice(heights, &layers, [this](){
|
slicer.slice(heights, &layers, [this](){ throw_if_canceled(); });
|
||||||
throw_if_canceled();
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
auto support_points = [](SLAPrintObject& po) {
|
auto support_points = [](SLAPrintObject& po) {
|
||||||
@ -216,6 +222,7 @@ void SLAPrint::process()
|
|||||||
// repeated)
|
// repeated)
|
||||||
|
|
||||||
if(po.is_step_done(slaposSupportTree) &&
|
if(po.is_step_done(slaposSupportTree) &&
|
||||||
|
po.m_config.pad_enable.getBool() &&
|
||||||
po.m_supportdata &&
|
po.m_supportdata &&
|
||||||
po.m_supportdata->support_tree_ptr)
|
po.m_supportdata->support_tree_ptr)
|
||||||
{
|
{
|
||||||
@ -225,10 +232,12 @@ void SLAPrint::process()
|
|||||||
double er = po.m_config.pad_edge_radius.getFloat();
|
double er = po.m_config.pad_edge_radius.getFloat();
|
||||||
double lh = po.m_config.layer_height.getFloat();
|
double lh = po.m_config.layer_height.getFloat();
|
||||||
double elevation = po.m_config.support_object_elevation.getFloat();
|
double elevation = po.m_config.support_object_elevation.getFloat();
|
||||||
|
sla::PoolConfig pcfg(wt, h, md, er);
|
||||||
|
|
||||||
sla::ExPolygons bp;
|
sla::ExPolygons bp;
|
||||||
if(elevation < h/2) sla::base_plate(po.transformed_mesh(), bp,
|
double pad_h = sla::get_pad_elevation(pcfg);
|
||||||
float(h/2), float(lh));
|
if(elevation < pad_h) sla::base_plate(po.transformed_mesh(), bp,
|
||||||
|
float(pad_h), float(lh));
|
||||||
|
|
||||||
po.m_supportdata->support_tree_ptr->add_pad(bp, wt, h, md, er);
|
po.m_supportdata->support_tree_ptr->add_pad(bp, wt, h, md, er);
|
||||||
}
|
}
|
||||||
@ -246,7 +255,7 @@ void SLAPrint::process()
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Rasterizing the model objects, and their supports
|
// Rasterizing the model objects, and their supports
|
||||||
auto rasterize = [this, ilh]() {
|
auto rasterize = [this, ilh, ilhd]() {
|
||||||
using Layer = sla::ExPolygons;
|
using Layer = sla::ExPolygons;
|
||||||
using LayerCopies = std::vector<SLAPrintObject::Instance>;
|
using LayerCopies = std::vector<SLAPrintObject::Instance>;
|
||||||
struct LayerRef {
|
struct LayerRef {
|
||||||
@ -262,51 +271,60 @@ void SLAPrint::process()
|
|||||||
// layers according to quantized height levels
|
// layers according to quantized height levels
|
||||||
std::map<LevelID, LayerRefs> levels;
|
std::map<LevelID, LayerRefs> levels;
|
||||||
|
|
||||||
auto sinitlh = LevelID(scale_(ilh));
|
auto sih = LevelID(scale_(ilh));
|
||||||
|
|
||||||
// For all print objects, go through its initial layers and place them
|
// For all print objects, go through its initial layers and place them
|
||||||
// into the layers hash
|
// into the layers hash
|
||||||
for(SLAPrintObject *o : m_objects) {
|
for(SLAPrintObject *o : m_objects) {
|
||||||
|
auto bb = o->transformed_mesh().bounding_box();
|
||||||
double gndlvl = o->transformed_mesh().bounding_box().min(Z);
|
double modelgnd = bb.min(Z);
|
||||||
double elevation = o->m_config.support_object_elevation.getFloat();
|
double elevation = o->get_elevation();
|
||||||
|
|
||||||
double lh = o->m_config.layer_height.getFloat();
|
double lh = o->m_config.layer_height.getFloat();
|
||||||
|
double minZ = modelgnd - elevation;
|
||||||
|
|
||||||
// TODO: this juust misses the support layers with a slight offset...
|
// scaled values:
|
||||||
double ih = elevation > 0 ? lh : ilh;
|
auto sminZ = LevelID(scale_(minZ));
|
||||||
|
auto smaxZ = LevelID(scale_(bb.max(Z)));
|
||||||
|
auto smodelgnd = LevelID(scale_(modelgnd));
|
||||||
|
auto slh = LevelID(scale_(lh));
|
||||||
|
|
||||||
auto sgl = LevelID(scale_(gndlvl));
|
// It is important that the next levels math the levels in
|
||||||
auto slh = LevelID(scale_(lh)); // scaled layer height
|
// model_slice method. Only difference is that here it works with
|
||||||
auto sih = LevelID(scale_(ih));
|
// scaled coordinates
|
||||||
|
std::vector<LevelID> levelids;
|
||||||
|
if(sminZ >= smodelgnd) levelids.emplace_back(sminZ);
|
||||||
|
for(LevelID h = sminZ + sih; h < smaxZ; h += slh)
|
||||||
|
if(h >= smodelgnd) levelids.emplace_back(h);
|
||||||
|
|
||||||
SlicedModel & oslices = o->m_model_slices;
|
SlicedModel & oslices = o->m_model_slices;
|
||||||
|
|
||||||
|
// If everything went well this code should not run at all, but
|
||||||
|
// let's be robust...
|
||||||
|
assert(levelids.size() == oslices.size());
|
||||||
|
if(levelids.size() < oslices.size()) { // extend the levels until...
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(warning)
|
||||||
|
<< "Height level mismatch at rasterization!\n";
|
||||||
|
|
||||||
|
LevelID lastlvl = levelids.back();
|
||||||
|
while(levelids.size() < oslices.size()) {
|
||||||
|
lastlvl += slh;
|
||||||
|
levelids.emplace_back(lastlvl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for(int i = 0; i < oslices.size(); ++i) {
|
for(int i = 0; i < oslices.size(); ++i) {
|
||||||
int a = i == 0 ? 0 : 1;
|
LevelID h = levelids[i];
|
||||||
int b = i == 0 ? 0 : i - 1;
|
|
||||||
|
|
||||||
LevelID h = sgl + sih * a + b * slh;
|
|
||||||
|
|
||||||
std::cout << "Model layer level: " << h << std::endl;
|
|
||||||
|
|
||||||
auto& lyrs = levels[h]; // this initializes a new record
|
auto& lyrs = levels[h]; // this initializes a new record
|
||||||
lyrs.emplace_back(oslices[i], o->m_instances);
|
lyrs.emplace_back(oslices[i], o->m_instances);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(o->m_supportdata) { // deal with the support slices if present
|
if(o->m_supportdata) { // deal with the support slices if present
|
||||||
auto& sslices = o->m_supportdata->support_slices;
|
auto& sslices = o->m_supportdata->support_slices;
|
||||||
|
|
||||||
// Supports start below the ground level.
|
|
||||||
// Counting the pad height as well
|
|
||||||
double el = o->get_elevation();
|
|
||||||
auto sel = LevelID(scale_(el));
|
|
||||||
|
|
||||||
for(int i = 0; i < sslices.size(); ++i) {
|
for(int i = 0; i < sslices.size(); ++i) {
|
||||||
int a = i == 0 ? 0 : 1;
|
int a = i == 0 ? 0 : 1;
|
||||||
int b = i == 0 ? 0 : i - 1;
|
int b = i == 0 ? 0 : i - 1;
|
||||||
|
LevelID h = sminZ + a * sih + b * slh;
|
||||||
LevelID h = sgl - sel + sinitlh * a + b * slh;
|
|
||||||
std::cout << "Support layer level: " << h << std::endl;
|
|
||||||
|
|
||||||
auto& lyrs = levels[h];
|
auto& lyrs = levels[h];
|
||||||
lyrs.emplace_back(sslices[i], o->m_instances);
|
lyrs.emplace_back(sslices[i], o->m_instances);
|
||||||
@ -473,9 +491,23 @@ SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object):
|
|||||||
SLAPrintObject::~SLAPrintObject() {}
|
SLAPrintObject::~SLAPrintObject() {}
|
||||||
|
|
||||||
double SLAPrintObject::get_elevation() const {
|
double SLAPrintObject::get_elevation() const {
|
||||||
return m_supportdata && m_supportdata->support_tree_ptr?
|
double ret = m_config.support_object_elevation.getFloat();
|
||||||
m_supportdata->support_tree_ptr->get_elevation() :
|
|
||||||
0;
|
// if the pad is enabled, then half of the pad height is its base plate
|
||||||
|
if(m_config.pad_enable.getBool()) {
|
||||||
|
// Normally the elevation for the pad itself would be the thickness of
|
||||||
|
// its walls but currently it is half of its thickness. Whatever it
|
||||||
|
// will be in the future, we provide the config to the get_pad_elevation
|
||||||
|
// method and we will have the correct value
|
||||||
|
sla::PoolConfig pcfg;
|
||||||
|
pcfg.min_wall_height_mm = m_config.pad_wall_height.getFloat();
|
||||||
|
pcfg.min_wall_thickness_mm = m_config.pad_wall_thickness.getFloat();
|
||||||
|
pcfg.edge_radius_mm = m_config.pad_edge_radius.getFloat();
|
||||||
|
pcfg.max_merge_distance_mm = m_config.pad_max_merge_distance.getFloat();
|
||||||
|
ret += sla::get_pad_elevation(pcfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
//const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const
|
//const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const
|
||||||
|
@ -412,6 +412,7 @@ const std::vector<std::string>& Preset::sla_print_options()
|
|||||||
"support_critical_angle",
|
"support_critical_angle",
|
||||||
"support_max_bridge_length",
|
"support_max_bridge_length",
|
||||||
"support_object_elevation",
|
"support_object_elevation",
|
||||||
|
"pad_enable",
|
||||||
"pad_wall_thickness",
|
"pad_wall_thickness",
|
||||||
"pad_wall_height",
|
"pad_wall_height",
|
||||||
"pad_max_merge_distance",
|
"pad_max_merge_distance",
|
||||||
|
@ -3012,6 +3012,7 @@ void TabSLAPrint::build()
|
|||||||
optgroup->append_single_option_line("support_max_bridge_length");
|
optgroup->append_single_option_line("support_max_bridge_length");
|
||||||
|
|
||||||
optgroup = page->new_optgroup(_(L("Pad")));
|
optgroup = page->new_optgroup(_(L("Pad")));
|
||||||
|
optgroup->append_single_option_line("pad_enable");
|
||||||
optgroup->append_single_option_line("pad_wall_thickness");
|
optgroup->append_single_option_line("pad_wall_thickness");
|
||||||
optgroup->append_single_option_line("pad_wall_height");
|
optgroup->append_single_option_line("pad_wall_height");
|
||||||
optgroup->append_single_option_line("pad_max_merge_distance");
|
optgroup->append_single_option_line("pad_max_merge_distance");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user