Further refactor and simplification of slice index and print data.

This commit is contained in:
tamasmeszaros 2019-03-26 10:57:45 +01:00
parent b4ea43a6b0
commit 57e28b53f2
3 changed files with 105 additions and 96 deletions

View file

@ -698,7 +698,7 @@ void SLAPrint::process()
id < po.m_model_slices.size() && mit != po.m_slice_index.end(); id < po.m_model_slices.size() && mit != po.m_slice_index.end();
id++) id++)
{ {
mit->set_model_slice_idx(id); ++mit; mit->set_model_slice_idx(po, id); ++mit;
} }
}; };
@ -894,7 +894,7 @@ void SLAPrint::process()
i < sd->support_slices.size() && i < po.m_slice_index.size(); i < sd->support_slices.size() && i < po.m_slice_index.size();
++i) ++i)
{ {
po.m_slice_index[i].set_support_slice_idx(i); po.m_slice_index[i].set_support_slice_idx(po, i);
} }
}; };
@ -924,7 +924,7 @@ void SLAPrint::process()
for(SLAPrintObject * o : m_objects) { for(SLAPrintObject * o : m_objects) {
coord_t gndlvl = o->get_slice_index().front().print_level() - ilhs; coord_t gndlvl = o->get_slice_index().front().print_level() - ilhs;
for(auto& slicerecord : o->get_slice_index()) { for(const SliceRecord& slicerecord : o->get_slice_index()) {
coord_t lvlid = slicerecord.print_level() - gndlvl; coord_t lvlid = slicerecord.print_level() - gndlvl;
// Neat trick to round the layer levels to the grid. // Neat trick to round the layer levels to the grid.
@ -932,21 +932,13 @@ void SLAPrint::process()
auto it = std::lower_bound(m_printer_input.begin(), auto it = std::lower_bound(m_printer_input.begin(),
m_printer_input.end(), m_printer_input.end(),
LayerRefs(lvlid)); PrintLayer(lvlid));
if(it == m_printer_input.end() || it->level != lvlid) if(it == m_printer_input.end() || it->level != lvlid)
it = m_printer_input.insert(it, LayerRefs(lvlid)); it = m_printer_input.insert(it, PrintLayer(lvlid));
auto& lyrs = *it;
const ExPolygons& objslices = o->get_slices_from_record(slicerecord, soModel); it->slices.emplace_back(std::cref(slicerecord));
const ExPolygons& supslices = o->get_slices_from_record(slicerecord, soSupport);
if(!objslices.empty())
lyrs.refs.emplace_back(objslices, o->instances());
if(!supslices.empty())
lyrs.refs.emplace_back(supslices, o->instances());
} }
} }
@ -998,25 +990,40 @@ void SLAPrint::process()
{ {
if(canceled()) return; if(canceled()) return;
LayerRefs& lrange = m_printer_input[level_id]; PrintLayer& lrange = m_printer_input[level_id];
// Switch to the appropriate layer in the printer // Switch to the appropriate layer in the printer
printer.begin_layer(level_id); printer.begin_layer(level_id);
for(auto& lyrref : lrange.refs) { // for all layers in the current level for(const SliceRecord& slrecord : lrange.slices)
{ // for all layers in the current level
if(canceled()) break; if(canceled()) break;
const Layer& sl = lyrref.lref; // get the layer reference
const LayerCopies& copies = lyrref.copies; // get the layer reference
const ExPolygons& objslice = slrecord.get_slice(soModel);
const ExPolygons& supslice = slrecord.get_slice(soModel);
const SLAPrintObject *po = slrecord.print_obj();
assert(po != nullptr);
// Draw all the polygons in the slice to the actual layer. // Draw all the polygons in the slice to the actual layer.
for(auto& cp : copies) { for(const SLAPrintObject::Instance& tr : po->instances()) {
for(ExPolygon slice : sl) { for(ExPolygon poly : objslice) {
// The order is important here: // The order is important here:
// apply rotation before translation... // apply rotation before translation...
slice.rotate(double(cp.rotation)); poly.rotate(double(tr.rotation));
slice.translate(cp.shift(X), cp.shift(Y)); poly.translate(tr.shift(X), tr.shift(Y));
if(flpXY) swapXY(slice); if(flpXY) swapXY(poly);
printer.draw_polygon(slice, level_id); printer.draw_polygon(poly, level_id);
}
for(ExPolygon poly : supslice) {
// The order is important here:
// apply rotation before translation...
poly.rotate(double(tr.rotation));
poly.translate(tr.shift(X), tr.shift(Y));
if(flpXY) swapXY(poly);
printer.draw_polygon(poly, level_id);
} }
} }
} }
@ -1026,11 +1033,13 @@ void SLAPrint::process()
// Status indication guarded with the spinlock // Status indication guarded with the spinlock
auto st = ist + unsigned(sd*level_id*slot/m_printer_input.size()); auto st = ist + unsigned(sd*level_id*slot/m_printer_input.size());
{ std::lock_guard<SpinMutex> lck(slck); {
if( st > pst) { std::lock_guard<SpinMutex> lck(slck);
report_status(*this, int(st), PRINT_STEP_LABELS[slapsRasterize]); if( st > pst) {
pst = st; report_status(*this, int(st),
} PRINT_STEP_LABELS[slapsRasterize]);
pst = st;
}
} }
}; };
@ -1290,11 +1299,11 @@ void SLAPrint::fill_statistics()
record = &slr; record = &slr;
} }
const ExPolygons &modelslices = po->get_slices_from_record(*record, soModel); const ExPolygons &modelslices = record->get_slice(soModel);
if (!modelslices.empty()) if (!modelslices.empty())
append(model_polygons, get_all_polygons(modelslices, po->instances())); append(model_polygons, get_all_polygons(modelslices, po->instances()));
const ExPolygons &supportslices = po->get_slices_from_record(*record, soSupport); const ExPolygons &supportslices = record->get_slice(soSupport);
if (!supportslices.empty()) if (!supportslices.empty())
append(supports_polygons, get_all_polygons(supportslices, po->instances())); append(supports_polygons, get_all_polygons(supportslices, po->instances()));
} }
@ -1515,15 +1524,15 @@ const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const
return m_supportdata->support_slices; return m_supportdata->support_slices;
} }
const ExPolygons &SLAPrintObject::get_slices_from_record( const ExPolygons &SliceRecord::get_slice(SliceOrigin o) const
const SliceRecord &rec,
SliceOrigin o) const
{ {
size_t idx = o == soModel ? rec.get_model_slice_idx() : size_t idx = o == soModel ? m_model_slices_idx :
rec.get_support_slice_idx(); m_support_slices_idx;
const std::vector<ExPolygons>& v = o == soModel? get_model_slices() : if(m_po == nullptr) return EMPTY_SLICE;
get_support_slices();
const std::vector<ExPolygons>& v = o == soModel? m_po->get_model_slices() :
m_po->get_support_slices();
if(idx >= v.size()) return EMPTY_SLICE; if(idx >= v.size()) return EMPTY_SLICE;

View file

@ -38,8 +38,9 @@ using _SLAPrintObjectBase =
enum SliceOrigin { soSupport, soModel }; enum SliceOrigin { soSupport, soModel };
class SLAPrintObject;
// The public Slice record structure. It corresponds to one printable layer. // The public Slice record structure. It corresponds to one printable layer.
// To get the sliced polygons, use SLAPrintObject::get_slices_from_record
class SliceRecord { class SliceRecord {
public: public:
// this will be the max limit of size_t // this will be the max limit of size_t
@ -54,6 +55,7 @@ private:
size_t m_model_slices_idx = NONE; size_t m_model_slices_idx = NONE;
size_t m_support_slices_idx = NONE; size_t m_support_slices_idx = NONE;
const SLAPrintObject *m_po = nullptr;
public: public:
@ -61,38 +63,28 @@ public:
m_print_z(key), m_slice_z(slicez), m_height(height) {} m_print_z(key), m_slice_z(slicez), m_height(height) {}
// The key will be the integer height level of the top of the layer. // The key will be the integer height level of the top of the layer.
inline coord_t print_level() const { return m_print_z; } coord_t print_level() const { return m_print_z; }
// Returns the exact floating point Z coordinate of the slice // Returns the exact floating point Z coordinate of the slice
inline float slice_level() const { return m_slice_z; } float slice_level() const { return m_slice_z; }
// Returns the current layer height // Returns the current layer height
inline float layer_height() const { return m_height; } float layer_height() const { return m_height; }
bool is_valid() const { return std::isnan(m_slice_z); } bool is_valid() const { return std::isnan(m_slice_z); }
template <class T> inline T level() const { const SLAPrintObject* print_obj() const { return m_po; }
static_assert(std::is_integral<T>::value ||
std::is_floating_point<T>::value,
"Slice record level is only valid for numeric types!");
if (std::is_integral<T>::value) return T(print_level());
else return T(slice_level());
}
template <class T> inline static SliceRecord create(T val) {
static_assert(std::is_integral<T>::value ||
std::is_floating_point<T>::value,
"Slice record level is only valid for numeric types!");
if (std::is_integral<T>::value) return { coord_t(val), 0.f, 0.f };
else return { 0, float(val), 0.f };
}
// Methods for setting the indices into the slice vectors. // Methods for setting the indices into the slice vectors.
void set_model_slice_idx(size_t id) { m_model_slices_idx = id; } void set_model_slice_idx(const SLAPrintObject &po, size_t id) {
void set_support_slice_idx(size_t id) { m_support_slices_idx = id; } m_po = &po; m_model_slices_idx = id;
}
inline size_t get_model_slice_idx() const { return m_model_slices_idx; } void set_support_slice_idx(const SLAPrintObject& po, size_t id) {
inline size_t get_support_slice_idx() const { return m_support_slices_idx; } m_po = &po; m_support_slices_idx = id;
}
const ExPolygons& get_slice(SliceOrigin o) const;
}; };
@ -153,6 +145,16 @@ public:
private: private:
template <class T> inline static T level(const SliceRecord& sr) {
static_assert(std::is_arithmetic<T>::value, "Arithmetic only!");
return std::is_integral<T>::value ? T(sr.print_level()) : T(sr.slice_level());
}
template <class T> inline static SliceRecord create_slice_record(T val) {
static_assert(std::is_arithmetic<T>::value, "Arithmetic only!");
return std::is_integral<T>::value ? SliceRecord{ coord_t(val), 0.f, 0.f } : SliceRecord{ 0, float(val), 0.f };
}
// This is a template method for searching the slice index either by // This is a template method for searching the slice index either by
// an integer key: print_level or a floating point key: slice_level. // an integer key: print_level or a floating point key: slice_level.
// The eps parameter gives the max deviation in + or - direction. // The eps parameter gives the max deviation in + or - direction.
@ -162,23 +164,23 @@ private:
static auto closest_slice_record(Container& cont, T lvl, T eps) -> decltype (cont.begin()) static auto closest_slice_record(Container& cont, T lvl, T eps) -> decltype (cont.begin())
{ {
if(cont.empty()) return cont.end(); if(cont.empty()) return cont.end();
if(cont.size() == 1 && std::abs(cont.front().template level<T>() - lvl) > eps) if(cont.size() == 1 && std::abs(level<T>(cont.front()) - lvl) > eps)
return cont.end(); return cont.end();
SliceRecord query = SliceRecord::create(lvl); SliceRecord query = create_slice_record(lvl);
auto it = std::lower_bound(cont.begin(), cont.end(), query, auto it = std::lower_bound(cont.begin(), cont.end(), query,
[](const SliceRecord& r1, [](const SliceRecord& r1,
const SliceRecord& r2) const SliceRecord& r2)
{ {
return r1.level<T>() < r2.level<T>(); return level<T>(r1) < level<T>(r2);
}); });
T diff = std::abs(it->template level<T>() - lvl); T diff = std::abs(level<T>(*it) - lvl);
if(it != cont.begin()) { if(it != cont.begin()) {
auto it_prev = std::prev(it); auto it_prev = std::prev(it);
T diff_prev = std::abs(it_prev->template level<T>() - lvl); T diff_prev = std::abs(level<T>(*it_prev) - lvl);
if(diff_prev < diff) { diff = diff_prev; it = it_prev; } if(diff_prev < diff) { diff = diff_prev; it = it_prev; }
} }
@ -226,9 +228,6 @@ public:
return *it; return *it;
} }
// Get the actual slice polygons using a valid slice record.
const ExPolygons& get_slices_from_record(
const SliceRecord& rec, SliceOrigin o) const;
protected: protected:
// to be called from SLAPrint only. // to be called from SLAPrint only.
friend class SLAPrint; friend class SLAPrint;
@ -327,6 +326,24 @@ private: // Prevents erroneous use by other classes.
typedef PrintBaseWithState<SLAPrintStep, slapsCount> Inherited; typedef PrintBaseWithState<SLAPrintStep, slapsCount> Inherited;
public: public:
// An aggregation of SliceRecord-s from all the print objects for each
// occupied layer. Slice record levels dont have to match exactly.
// They are unified if the level difference is within +/- SCALED_EPSILON
struct PrintLayer {
coord_t level;
// The collection of slice records for the current level.
std::vector<std::reference_wrapper<const SliceRecord>> slices;
explicit PrintLayer(coord_t lvl) : level(lvl) {}
// for being sorted in their container (see m_printer_input)
bool operator<(const PrintLayer& other) const {
return level < other.level;
}
};
SLAPrint(): m_stepmask(slapsCount, true) {} SLAPrint(): m_stepmask(slapsCount, true) {}
virtual ~SLAPrint() override { this->clear(); } virtual ~SLAPrint() override { this->clear(); }
@ -360,6 +377,10 @@ public:
std::string validate() const override; std::string validate() const override;
// The aggregated and leveled print records from various objects.
// TODO: use this structure for the preview in the future.
const std::vector<PrintLayer>& print_layers() const { return m_printer_input; }
private: private:
using SLAPrinter = FilePrinter<FilePrinterFormat::SLA_PNGZIP>; using SLAPrinter = FilePrinter<FilePrinterFormat::SLA_PNGZIP>;
using SLAPrinterPtr = std::unique_ptr<SLAPrinter>; using SLAPrinterPtr = std::unique_ptr<SLAPrinter>;
@ -377,29 +398,8 @@ private:
PrintObjects m_objects; PrintObjects m_objects;
std::vector<bool> m_stepmask; std::vector<bool> m_stepmask;
// Definition of the print input map. It consists of the slices indexed // Ready-made data for rasterization.
// with scaled (clipper) Z coordinates. Also contains the instance std::vector<PrintLayer> m_printer_input;
// transformations in scaled and filtered version. This is enough for the
// rasterizer to be able to draw every layer in the right position
using Layer = ExPolygons;
using LayerCopies = std::vector<SLAPrintObject::Instance>;
struct LayerRef {
std::reference_wrapper<const Layer> lref;
std::reference_wrapper<const LayerCopies> copies;
LayerRef(const Layer& lyr, const LayerCopies& cp) :
lref(std::cref(lyr)), copies(std::cref(cp)) {}
};
// One level may contain multiple slices from multiple objects and their
// supports
struct LayerRefs {
coord_t level;
std::vector<LayerRef> refs;
bool operator<(const LayerRefs& other) const { return level < other.level; }
explicit LayerRefs(coord_t lvl) : level(lvl) {}
};
std::vector<LayerRefs> m_printer_input;
// The printer itself // The printer itself
SLAPrinterPtr m_printer; SLAPrinterPtr m_printer;

View file

@ -5021,8 +5021,8 @@ void GLCanvas3D::_render_sla_slices() const
SliceRecord slice_high = obj->closest_slice_to_print_level(key_high, coord_t(SCALED_EPSILON)); SliceRecord slice_high = obj->closest_slice_to_print_level(key_high, coord_t(SCALED_EPSILON));
if (! slice_low.is_valid()) { if (! slice_low.is_valid()) {
const ExPolygons& obj_bottom = obj->get_slices_from_record(slice_low, soModel); const ExPolygons& obj_bottom = slice_low.get_slice(soModel);
const ExPolygons& sup_bottom = obj->get_slices_from_record(slice_low, soSupport); const ExPolygons& sup_bottom = slice_low.get_slice(soSupport);
// calculate model bottom cap // calculate model bottom cap
if (bottom_obj_triangles.empty() && !obj_bottom.empty()) if (bottom_obj_triangles.empty() && !obj_bottom.empty())
bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z, true); bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z, true);
@ -5032,8 +5032,8 @@ void GLCanvas3D::_render_sla_slices() const
} }
if (! slice_high.is_valid()) { if (! slice_high.is_valid()) {
const ExPolygons& obj_top = obj->get_slices_from_record(slice_high, soModel); const ExPolygons& obj_top = slice_high.get_slice(soModel);
const ExPolygons& sup_top = obj->get_slices_from_record(slice_high, soSupport); const ExPolygons& sup_top = slice_high.get_slice(soSupport);
// calculate model top cap // calculate model top cap
if (top_obj_triangles.empty() && !obj_top.empty()) if (top_obj_triangles.empty() && !obj_top.empty())
top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z, false); top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z, false);