WIP on slice indexing

This commit is contained in:
tamasmeszaros 2019-03-20 18:03:11 +01:00
parent 8b73608e9f
commit 19a96336ff
2 changed files with 289 additions and 123 deletions

View File

@ -567,6 +567,18 @@ sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) {
return scfg; return scfg;
} }
sla::PoolConfig make_pool_config(const SLAPrintObjectConfig& c) {
sla::PoolConfig pcfg;
pcfg.min_wall_thickness_mm = c.pad_wall_thickness.getFloat();
pcfg.wall_slope = c.pad_wall_slope.getFloat();
pcfg.edge_radius_mm = c.pad_edge_radius.getFloat();
pcfg.max_merge_distance_mm = c.pad_max_merge_distance.getFloat();
pcfg.min_wall_height_mm = c.pad_wall_height.getFloat();
return pcfg;
}
void swapXY(ExPolygon& expoly) { void swapXY(ExPolygon& expoly) {
for(auto& p : expoly.contour.points) std::swap(p(X), p(Y)); for(auto& p : expoly.contour.points) std::swap(p(X), p(Y));
for(auto& h : expoly.holes) for(auto& p : h.points) std::swap(p(X), p(Y)); for(auto& h : expoly.holes) for(auto& p : h.points) std::swap(p(X), p(Y));
@ -647,18 +659,58 @@ void SLAPrint::process()
// 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](SLAPrintObject& po) {
double lh = po.m_config.layer_height.getFloat();
TriangleMesh mesh = po.transformed_mesh(); TriangleMesh mesh = po.transformed_mesh();
// We need to prepare the slice index...
auto&& bb3d = mesh.bounding_box();
float minZ = float(bb3d.min(Z)) - float(po.get_elevation());
float maxZ = float(bb3d.max(Z));
auto flh = float(po.m_config.layer_height.getFloat());
auto slh = [](float h) { return LevelID( double(h) / SCALING_FACTOR); };
po.m_slice_index.clear();
po.m_slice_index.reserve(size_t(maxZ - (minZ + ilh) / flh) + 1);
po.m_slice_index.emplace_back(slh(minZ + ilh), minZ + ilh / 2.f, ilh);
for(float h = minZ + ilh + flh; h <= maxZ; h += flh) {
po.m_slice_index.emplace_back(slh(h), h - flh / 2.f, flh);
}
using SlRec = SLAPrintObject::SliceRecord;
auto slindex_it = std::lower_bound(po.m_slice_index.begin(),
po.m_slice_index.end(),
float(bb3d.min(Z)), // model start z
[](const SlRec& sr1, const SlRec& sr2){
return sr1.slice_level() < sr2.slice_level();
});
if(slindex_it == po.m_slice_index.end())
throw std::runtime_error(L("Slicing had to be stopped "
"due to an internal error."));
po.m_height_levels.clear();
po.m_height_levels.reserve(po.m_slice_index.size());
for(auto it = slindex_it; it != po.m_slice_index.end(); ++it)
po.m_height_levels.emplace_back(it->slice_level());
TriangleMeshSlicer slicer(&mesh); TriangleMeshSlicer slicer(&mesh);
// The 1D grid heights po.m_model_slices.clear();
std::vector<float> heights = calculate_heights(mesh.bounding_box(), slicer.slice(po.m_height_levels,
float(po.get_elevation()), float(po.config().slice_closing_radius.value),
ilh, float(lh)); &po.m_model_slices,
[this](){ throw_if_canceled(); });
auto& layers = po.m_model_slices; layers.clear(); auto mit = slindex_it;
slicer.slice(heights, float(po.config().slice_closing_radius.value), &layers, [this](){ throw_if_canceled(); }); for(size_t id = 0;
id < po.m_model_slices.size() && mit != po.m_slice_index.end();
id++)
{
mit->set_model_slice_idx(id); ++mit;
}
}; };
// In this step we check the slices, identify island and cover them with // In this step we check the slices, identify island and cover them with
@ -680,12 +732,8 @@ void SLAPrint::process()
if (mo.sla_points_status != sla::PointsStatus::UserModified) { if (mo.sla_points_status != sla::PointsStatus::UserModified) {
// calculate heights of slices (slices are calculated already) // calculate heights of slices (slices are calculated already)
double lh = po.m_config.layer_height.getFloat(); auto&& bb = po.transformed_mesh().bounding_box();
std::vector<float> heights = po.get_slice_levels(float(bb.min(Z)));
std::vector<float> heights =
calculate_heights(po.transformed_mesh().bounding_box(),
float(po.get_elevation()),
ilh, float(lh));
this->throw_if_canceled(); this->throw_if_canceled();
SLAAutoSupports::Config config; SLAAutoSupports::Config config;
@ -837,79 +885,86 @@ void SLAPrint::process()
auto lh = float(po.m_config.layer_height.getFloat()); auto lh = float(po.m_config.layer_height.getFloat());
sd->support_slices = sd->support_tree_ptr->slice(lh, ilh); sd->support_slices = sd->support_tree_ptr->slice(lh, ilh);
} }
for(size_t i = 0;
i < sd->support_slices.size() && i < po.m_slice_index.size();
++i)
{
po.m_slice_index[i].set_support_slice_idx(i);
}
}; };
// We have the layer polygon collection but we need to unite them into // We have the layer polygon collection but we need to unite them into
// an index where the key is the height level in discrete levels (clipper) // an index where the key is the height level in discrete levels (clipper)
auto index_slices = [this, ilhd](SLAPrintObject& po) { auto index_slices = [this, ilhd](SLAPrintObject& po) {
po.m_slice_index.clear(); // po.m_slice_index.clear();
auto sih = LevelID(scale_(ilhd)); // auto sih = LevelID(scale_(ilhd));
// Establish the slice grid boundaries // // Establish the slice grid boundaries
auto bb = po.transformed_mesh().bounding_box(); // auto bb = po.transformed_mesh().bounding_box();
double modelgnd = bb.min(Z); // double modelgnd = bb.min(Z);
double elevation = po.get_elevation(); // double elevation = po.get_elevation();
double lh = po.m_config.layer_height.getFloat(); // double lh = po.m_config.layer_height.getFloat();
double minZ = modelgnd - elevation; // double minZ = modelgnd - elevation;
// scaled values: // // scaled values:
auto sminZ = LevelID(scale_(minZ)); // auto sminZ = LevelID(scale_(minZ));
auto smaxZ = LevelID(scale_(bb.max(Z))); // auto smaxZ = LevelID(scale_(bb.max(Z)));
auto smodelgnd = LevelID(scale_(modelgnd)); // auto smodelgnd = LevelID(scale_(modelgnd));
auto slh = LevelID(scale_(lh)); // auto slh = LevelID(scale_(lh));
// It is important that the next levels match the levels in // // It is important that the next levels match the levels in
// model_slice method. Only difference is that here it works with // // model_slice method. Only difference is that here it works with
// scaled coordinates // // scaled coordinates
po.m_level_ids.clear(); // po.m_level_ids.clear();
for(LevelID h = sminZ + sih; h < smaxZ; h += slh) // for(LevelID h = sminZ + sih; h < smaxZ; h += slh)
if(h >= smodelgnd) po.m_level_ids.emplace_back(h); // if(h >= smodelgnd) po.m_level_ids.emplace_back(h);
std::vector<ExPolygons>& oslices = po.m_model_slices; // std::vector<ExPolygons>& oslices = po.m_model_slices;
// If everything went well this code should not run at all, but // // If everything went well this code should not run at all, but
// let's be robust... // // let's be robust...
// assert(levelids.size() == oslices.size()); // // assert(levelids.size() == oslices.size());
if(po.m_level_ids.size() < oslices.size()) { // extend the levels until... // if(po.m_level_ids.size() < oslices.size()) { // extend the levels until...
BOOST_LOG_TRIVIAL(warning) // BOOST_LOG_TRIVIAL(warning)
<< "Height level mismatch at rasterization!\n"; // << "Height level mismatch at rasterization!\n";
LevelID lastlvl = po.m_level_ids.back(); // LevelID lastlvl = po.m_level_ids.back();
while(po.m_level_ids.size() < oslices.size()) { // while(po.m_level_ids.size() < oslices.size()) {
lastlvl += slh; // lastlvl += slh;
po.m_level_ids.emplace_back(lastlvl); // po.m_level_ids.emplace_back(lastlvl);
} // }
} // }
for(size_t i = 0; i < oslices.size(); ++i) { // for(size_t i = 0; i < oslices.size(); ++i) {
LevelID h = po.m_level_ids[i]; // LevelID h = po.m_level_ids[i];
float fh = float(double(h) * SCALING_FACTOR); // float fh = float(double(h) * SCALING_FACTOR);
// now for the public slice index: // // now for the public slice index:
SLAPrintObject::SliceRecord& sr = po.m_slice_index[fh]; // SLAPrintObject::SliceRecord& sr = po.m_slice_index[fh];
// There should be only one slice layer for each print object // // There should be only one slice layer for each print object
assert(sr.model_slices_idx == SLAPrintObject::SliceRecord::NONE); // assert(sr.model_slices_idx == SLAPrintObject::SliceRecord::NONE);
sr.model_slices_idx = i; // sr.model_slices_idx = i;
} // }
if(po.m_supportdata) { // deal with the support slices if present // if(po.m_supportdata) { // deal with the support slices if present
std::vector<ExPolygons>& sslices = po.m_supportdata->support_slices; // std::vector<ExPolygons>& sslices = po.m_supportdata->support_slices;
po.m_supportdata->level_ids.clear(); // po.m_supportdata->level_ids.clear();
po.m_supportdata->level_ids.reserve(sslices.size()); // po.m_supportdata->level_ids.reserve(sslices.size());
for(int i = 0; i < int(sslices.size()); ++i) { // for(int i = 0; i < int(sslices.size()); ++i) {
LevelID h = sminZ + sih + i * slh; // LevelID h = sminZ + sih + i * slh;
po.m_supportdata->level_ids.emplace_back(h); // po.m_supportdata->level_ids.emplace_back(h);
float fh = float(double(h) * SCALING_FACTOR); // float fh = float(double(h) * SCALING_FACTOR);
SLAPrintObject::SliceRecord& sr = po.m_slice_index[fh]; // SLAPrintObject::SliceRecord& sr = po.m_slice_index[fh];
assert(sr.support_slices_idx == SLAPrintObject::SliceRecord::NONE); // assert(sr.support_slices_idx == SLAPrintObject::SliceRecord::NONE);
sr.support_slices_idx = SLAPrintObject::SliceRecord::Idx(i); // sr.support_slices_idx = SLAPrintObject::SliceRecord::Idx(i);
} // }
} // }
// Using RELOAD_SLA_PREVIEW to tell the Plater to pass the update status to the 3D preview to load the SLA slices. // Using RELOAD_SLA_PREVIEW to tell the Plater to pass the update status to the 3D preview to load the SLA slices.
report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW);
@ -923,31 +978,33 @@ void SLAPrint::process()
m_printer_input.clear(); m_printer_input.clear();
for(SLAPrintObject * o : m_objects) { for(SLAPrintObject * o : m_objects) {
auto& po = *o; // auto& po = *o;
std::vector<ExPolygons>& oslices = po.m_model_slices; // std::vector<ExPolygons>& oslices = po.m_model_slices;
// We need to adjust the min Z level of the slices to be zero // // We need to adjust the min Z level of the slices to be zero
LevelID smfirst = // LevelID smfirst =
po.m_supportdata && !po.m_supportdata->level_ids.empty() ? // po.m_supportdata && !po.m_supportdata->level_ids.empty() ?
po.m_supportdata->level_ids.front() : 0; // po.m_supportdata->level_ids.front() : 0;
LevelID mfirst = po.m_level_ids.empty()? 0 : po.m_level_ids.front(); // LevelID mfirst = po.m_level_ids.empty()? 0 : po.m_level_ids.front();
LevelID gndlvl = -(std::min(smfirst, mfirst)); // LevelID gndlvl = -(std::min(smfirst, mfirst));
// now merge this object's support and object slices with the rest // // now merge this object's support and object slices with the rest
// of the print object slices // // of the print object slices
for(size_t i = 0; i < oslices.size(); ++i) { // for(size_t i = 0; i < oslices.size(); ++i) {
auto& lyrs = m_printer_input[gndlvl + po.m_level_ids[i]]; // auto& lyrs = m_printer_input[gndlvl + po.m_level_ids[i]];
lyrs.emplace_back(oslices[i], po.m_instances); // lyrs.emplace_back(oslices[i], po.m_instances);
} // }
if(!po.m_supportdata) continue; // if(!po.m_supportdata) continue;
std::vector<ExPolygons>& sslices = po.m_supportdata->support_slices; // std::vector<ExPolygons>& sslices = po.m_supportdata->support_slices;
for(size_t i = 0; i < sslices.size(); ++i) { // for(size_t i = 0; i < sslices.size(); ++i) {
LayerRefs& lyrs = // LayerRefs& lyrs =
m_printer_input[gndlvl + po.m_supportdata->level_ids[i]]; // m_printer_input[gndlvl + po.m_supportdata->level_ids[i]];
lyrs.emplace_back(sslices[i], po.m_instances); // lyrs.emplace_back(sslices[i], po.m_instances);
} // }
// for(size_t i = 0; i < o->m_sli)
} }
// collect all the keys // collect all the keys
@ -1474,11 +1531,7 @@ double SLAPrintObject::get_elevation() const {
// its walls but currently it is half of its thickness. Whatever it // 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 // will be in the future, we provide the config to the get_pad_elevation
// method and we will have the correct value // method and we will have the correct value
sla::PoolConfig pcfg; sla::PoolConfig pcfg = make_pool_config(m_config);
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); ret += sla::get_pad_elevation(pcfg);
} }
@ -1509,6 +1562,33 @@ const std::vector<sla::SupportPoint>& SLAPrintObject::get_support_points() const
return m_supportdata->support_points; return m_supportdata->support_points;
} }
SliceIterator SLAPrintObject::get_slices(SliceOrigin so, LevelID k) const
{
SliceIterator ret = so == soModel ? get_model_slices().end() :
get_support_slices().end();
auto it = std::lower_bound(m_slice_index.begin(),
m_slice_index.end(),
k,
SliceRecord::cmpfn);
if(it != m_slice_index.end()) {
ret = it->get_slices(*this, so);
}
return ret;
}
SliceRange SLAPrintObject::get_slices(SliceOrigin so,
float from_level,
float to_level) const
{
auto from = LevelID(double(from_level) / SCALING_FACTOR);
auto to = LevelID(double(to_level) / SCALING_FACTOR);
return SliceRange(get_slices(so, from), get_slices(so, to));
}
const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const
{ {
// assert(is_step_done(slaposSliceSupports)); // assert(is_step_done(slaposSliceSupports));
@ -1516,12 +1596,28 @@ const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const
return m_supportdata->support_slices; return m_supportdata->support_slices;
} }
const SLAPrintObject::SliceIndex &SLAPrintObject::get_slice_index() const const std::vector<SLAPrintObject::SliceRecord>&
SLAPrintObject::get_slice_index() const
{ {
// assert(is_step_done(slaposIndexSlices)); // assert(is_step_done(slaposIndexSlices));
return m_slice_index; return m_slice_index;
} }
std::vector<float> SLAPrintObject::get_slice_levels(float from_eq) const
{
using SlRec = SLAPrintObject::SliceRecord;
auto it = std::lower_bound(m_slice_index.begin(),
m_slice_index.end(),
from_eq, // model start z
[](const SlRec& sr1, const SlRec& sr2){
return sr1.slice_level() < sr2.slice_level();
});
std::vector<float> heights; heights.reserve(m_slice_index.size());
for(; it != m_slice_index.end(); ++it)
heights.emplace_back(it->slice_level());
}
const std::vector<ExPolygons> &SLAPrintObject::get_model_slices() const const std::vector<ExPolygons> &SLAPrintObject::get_model_slices() const
{ {
// assert(is_step_done(slaposObjectSlice)); // assert(is_step_done(slaposObjectSlice));
@ -1639,4 +1735,18 @@ std::string SLAPrintStatistics::finalize_output_path(const std::string &path_in)
return final_path; return final_path;
} }
SliceIterator SLAPrintObject::SliceRecord::get_slices(const SLAPrintObject &po,
SliceOrigin so) const
{
const std::vector<ExPolygons>& v = so == soModel? po.get_model_slices() :
po.get_support_slices();
Idx idx = so == soModel ? m_model_slices_idx : m_support_slices_idx;
using DiffT = std::vector<ExPolygons>::const_iterator::difference_type;
return idx == NONE? v.end() : v.begin() + DiffT(idx);
}
} // namespace Slic3r } // namespace Slic3r

View File

@ -35,12 +35,34 @@ using _SLAPrintObjectBase =
// the printer (rasterizer) in the SLAPrint class. // the printer (rasterizer) in the SLAPrint class.
using LevelID = long long; using LevelID = long long;
template<class It> struct Range {
It from, to;
It begin() const { return from; }
It end() const { return to; }
using Type = It;
Range() = default;
explicit Range(It &&b, It &&e):
from(std::forward<It>(b)), to(std::forward<It>(e)) {}
};
enum SliceOrigin { soSlice, soModel };
using SliceStore = std::vector<ExPolygons>;
using SliceIterator = SliceStore::const_iterator;
using SliceRange = Range<SliceIterator>;
class SLAPrintObject : public _SLAPrintObjectBase class SLAPrintObject : public _SLAPrintObjectBase
{ {
private: // Prevents erroneous use by other classes. private: // Prevents erroneous use by other classes.
using Inherited = _SLAPrintObjectBase; using Inherited = _SLAPrintObjectBase;
public: public:
// I refuse to grantee copying (Tamas)
SLAPrintObject(const SLAPrintObject&) = delete;
SLAPrintObject& operator=(const SLAPrintObject&) = delete;
const SLAPrintObjectConfig& config() const { return m_config; } const SLAPrintObjectConfig& config() const { return m_config; }
const Transform3d& trafo() const { return m_trafo; } const Transform3d& trafo() const { return m_trafo; }
@ -82,6 +104,66 @@ public:
// pad is not, then without the pad, otherwise the full value is returned. // pad is not, then without the pad, otherwise the full value is returned.
double get_current_elevation() const; double get_current_elevation() const;
// This method returns the support points of this SLAPrintObject.
const std::vector<sla::SupportPoint>& get_support_points() const;
private:
// An index record referencing the slices
// (get_model_slices(), get_support_slices()) where the keys are the height
// levels of the model in scaled-clipper coordinates. The levels correspond
// to the z coordinate of the object coordinate system.
class SliceRecord {
public:
using Key = LevelID;
private:
using Idx = size_t;
static const Idx NONE = Idx(-1); // this will be the max limit of size_t
LevelID m_print_z = 0; // Top of the layer
float m_slice_z = 0.f; // Exact level of the slice
float m_height = 0.f; // Height of the sliced layer
Idx m_model_slices_idx = NONE;
Idx m_support_slices_idx = NONE;
public:
SliceRecord(Key key, float slicez, float height):
m_print_z(key), m_slice_z(slicez), m_height(height) {}
inline static bool cmpfn(const SliceRecord& sr1, const SliceRecord& sr2)
{
return sr1.key() < sr2.key();
}
inline Key key() const { return m_print_z; }
inline float slice_level() const { return m_slice_z; }
inline float layer_height() const { return m_height; }
SliceIterator get_slices(const SLAPrintObject& po,
SliceOrigin so) const;
void set_model_slice_idx(Idx id) { m_model_slices_idx = id; }
void set_support_slice_idx(Idx id) { m_support_slices_idx = id; }
};
// Retrieve the slice index which is readable only after slaposIndexSlices
// is done.
const std::vector<SliceRecord>& get_slice_index() const;
std::vector<float> get_slice_levels(float from_eq) const;
public:
SliceIterator get_slices(SliceOrigin so, LevelID k) const;
SliceRange get_slices(
SliceOrigin so,
float from_level,
float to_level = std::numeric_limits<float>::infinity()) const;
// These two methods should be callable on the client side (e.g. UI thread) // These two methods should be callable on the client side (e.g. UI thread)
// when the appropriate steps slaposObjectSlice and slaposSliceSupports // when the appropriate steps slaposObjectSlice and slaposSliceSupports
// are ready. All the print objects are processed before slapsRasterize so // are ready. All the print objects are processed before slapsRasterize so
@ -89,33 +171,6 @@ public:
const std::vector<ExPolygons>& get_model_slices() const; const std::vector<ExPolygons>& get_model_slices() const;
const std::vector<ExPolygons>& get_support_slices() const; const std::vector<ExPolygons>& get_support_slices() const;
// This method returns the support points of this SLAPrintObject.
const std::vector<sla::SupportPoint>& get_support_points() const;
// An index record referencing the slices
// (get_model_slices(), get_support_slices()) where the keys are the height
// levels of the model in scaled-clipper coordinates. The levels correspond
// to the z coordinate of the object coordinate system.
struct SliceRecord {
using Key = float;
using Idx = size_t;
static const Idx NONE = Idx(-1); // this will be the max limit of size_t
Idx model_slices_idx = NONE;
Idx support_slices_idx = NONE;
};
using SliceIndex = std::map<SliceRecord::Key, SliceRecord>;
// Retrieve the slice index which is readable only after slaposIndexSlices
// is done.
const SliceIndex& get_slice_index() const;
// I refuse to grantee copying (Tamas)
SLAPrintObject(const SLAPrintObject&) = delete;
SLAPrintObject& operator=(const SLAPrintObject&) = delete;
protected: protected:
// to be called from SLAPrint only. // to be called from SLAPrint only.
friend class SLAPrint; friend class SLAPrint;
@ -154,11 +209,12 @@ private:
// Exact (float) height levels mapped to the slices. Each record contains // Exact (float) height levels mapped to the slices. Each record contains
// the index to the model and the support slice vectors. // the index to the model and the support slice vectors.
SliceIndex m_slice_index; std::vector<SliceRecord> m_slice_index;
// The height levels corrected and scaled up in integer values. This will // The height levels corrected and scaled up in integer values. This will
// be used at rasterization. // be used at rasterization.
std::vector<LevelID> m_level_ids; std::vector<LevelID> m_level_ids;
std::vector<float> m_height_levels;
// Caching the transformed (m_trafo) raw mesh of the object // Caching the transformed (m_trafo) raw mesh of the object
mutable CachedObject<TriangleMesh> m_transformed_rmesh; mutable CachedObject<TriangleMesh> m_transformed_rmesh;