Merge remote-tracking branch 'origin/tm_slice_index'

This commit is contained in:
bubnikv 2019-03-22 17:08:38 +01:00
commit 8003dd4991
7 changed files with 517 additions and 206 deletions

View File

@ -56,6 +56,113 @@ public:
} }
}; };
template<class Vector,
class Value = typename Vector::value_type>
class IndexBasedIterator {
static const size_t NONE = size_t(-1);
std::reference_wrapper<Vector> m_index_ref;
size_t m_idx = NONE;
public:
using value_type = Value;
using pointer = Value *;
using reference = Value &;
using difference_type = long;
using iterator_category = std::random_access_iterator_tag;
inline explicit
IndexBasedIterator(Vector& index, size_t idx):
m_index_ref(index), m_idx(idx) {}
// Post increment
inline IndexBasedIterator operator++(int) {
IndexBasedIterator cpy(*this); ++m_idx; return cpy;
}
inline IndexBasedIterator operator--(int) {
IndexBasedIterator cpy(*this); --m_idx; return cpy;
}
inline IndexBasedIterator& operator++() {
++m_idx; return *this;
}
inline IndexBasedIterator& operator--() {
--m_idx; return *this;
}
inline IndexBasedIterator& operator+=(difference_type l) {
m_idx += size_t(l); return *this;
}
inline IndexBasedIterator operator+(difference_type l) {
auto cpy = *this; cpy += l; return cpy;
}
inline IndexBasedIterator& operator-=(difference_type l) {
m_idx -= size_t(l); return *this;
}
inline IndexBasedIterator operator-(difference_type l) {
auto cpy = *this; cpy -= l; return cpy;
}
operator difference_type() { return difference_type(m_idx); }
inline bool is_end() const { return m_idx >= m_index_ref.get().size();}
inline Value & operator*() const {
assert(m_idx < m_index_ref.get().size());
return m_index_ref.get().operator[](m_idx);
}
inline Value * operator->() const {
assert(m_idx < m_index_ref.get().size());
return &m_index_ref.get().operator[](m_idx);
}
inline bool operator ==(const IndexBasedIterator& other) {
size_t e = m_index_ref.get().size();
return m_idx == other.m_idx || (m_idx >= e && other.m_idx >= e);
}
inline bool operator !=(const IndexBasedIterator& other) {
return !(*this == other);
}
inline bool operator <=(const IndexBasedIterator& other) {
return (m_idx < other.m_idx) || (*this == other);
}
inline bool operator <(const IndexBasedIterator& other) {
return m_idx < other.m_idx && (*this != other);
}
inline bool operator >=(const IndexBasedIterator& other) {
return m_idx > other.m_idx || *this == other;
}
inline bool operator >(const IndexBasedIterator& other) {
return m_idx > other.m_idx && *this != other;
}
};
template<class It> class Range {
It from, to;
public:
It begin() const { return from; }
It end() const { return to; }
using Type = It;
Range() = default;
Range(It &&b, It &&e):
from(std::forward<It>(b)), to(std::forward<It>(e)) {}
inline size_t size() const { return end() - begin(); }
inline bool empty() const { return size() == 0; }
};
} }
#endif // MTUTILS_HPP #endif // MTUTILS_HPP

View File

@ -2240,6 +2240,18 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const
return ret; return ret;
} }
SlicedSupports SLASupportTree::slice(const std::vector<float> &heights,
float cr) const
{
TriangleMesh fullmesh = m_impl->merged_mesh();
fullmesh.merge(get_pad());
TriangleMeshSlicer slicer(&fullmesh);
SlicedSupports ret;
slicer.slice(heights, cr, &ret, get().ctl().cancelfn);
return ret;
}
const TriangleMesh &SLASupportTree::add_pad(const SliceLayer& baseplate, const TriangleMesh &SLASupportTree::add_pad(const SliceLayer& baseplate,
const PoolConfig& pcfg) const const PoolConfig& pcfg) const
{ {

View File

@ -181,6 +181,8 @@ public:
/// Get the sliced 2d layers of the support geometry. /// Get the sliced 2d layers of the support geometry.
SlicedSupports slice(float layerh, float init_layerh = -1.0) const; SlicedSupports slice(float layerh, float init_layerh = -1.0) const;
SlicedSupports slice(const std::vector<float>&, float closing_radius) const;
/// Adding the "pad" (base pool) under the supports /// Adding the "pad" (base pool) under the supports
const TriangleMesh& add_pad(const SliceLayer& baseplate, const TriangleMesh& add_pad(const SliceLayer& baseplate,
const PoolConfig& pcfg) const; const PoolConfig& pcfg) const;

View File

@ -30,7 +30,6 @@ public:
std::vector<sla::SupportPoint> support_points; // all the support points (manual/auto) std::vector<sla::SupportPoint> support_points; // all the support points (manual/auto)
SupportTreePtr support_tree_ptr; // the supports SupportTreePtr support_tree_ptr; // the supports
SlicedSupports support_slices; // sliced supports SlicedSupports support_slices; // sliced supports
std::vector<LevelID> level_ids;
inline SupportData(const TriangleMesh& trmesh): emesh(trmesh) {} inline SupportData(const TriangleMesh& trmesh): emesh(trmesh) {}
}; };
@ -567,6 +566,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));
@ -591,25 +602,9 @@ std::string SLAPrint::validate() const
return ""; return "";
} }
std::vector<float> SLAPrint::calculate_heights(const BoundingBoxf3& bb3d,
float elevation,
float initial_layer_height,
float layer_height) const
{
std::vector<float> heights;
float minZ = float(bb3d.min(Z)) - float(elevation);
float maxZ = float(bb3d.max(Z));
auto flh = float(layer_height);
auto gnd = float(bb3d.min(Z));
for(float h = minZ + initial_layer_height; h < maxZ; h += flh)
if(h >= gnd) heights.emplace_back(h);
return heights;
}
template<class...Args> template<class...Args>
void report_status(SLAPrint& p, int st, const std::string& msg, Args&&...args) { void report_status(SLAPrint& p, int st, const std::string& msg, Args&&...args)
{
BOOST_LOG_TRIVIAL(info) << st << "% " << msg; BOOST_LOG_TRIVIAL(info) << st << "% " << msg;
p.set_status(st, msg, std::forward<Args>(args)...); p.set_status(st, msg, std::forward<Args>(args)...);
} }
@ -620,12 +615,19 @@ void SLAPrint::process()
using namespace sla; using namespace sla;
using ExPolygon = Slic3r::ExPolygon; using ExPolygon = Slic3r::ExPolygon;
if(m_objects.empty()) return;
// Assumption: at this point the print objects should be populated only with // Assumption: at this point the print objects should be populated only with
// 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
double ilhd = m_material_config.initial_layer_height.getFloat(); double ilhd = m_material_config.initial_layer_height.getFloat();
auto ilh = float(ilhd); auto ilh = float(ilhd);
double lhd = m_objects.front()->m_config.layer_height.getFloat();
float lh = float(lhd);
auto ilhs = LevelID(ilhd / SCALING_FACTOR);
auto lhs = LevelID(lhd / SCALING_FACTOR);
const size_t objcount = m_objects.size(); const size_t objcount = m_objects.size();
const unsigned min_objstatus = 0; // where the per object operations start const unsigned min_objstatus = 0; // where the per object operations start
@ -646,24 +648,59 @@ 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, ilhs, lhs, ilh, lh](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();
double minZ = bb3d.min(Z) - po.get_elevation();
double maxZ = bb3d.max(Z);
auto minZs = LevelID(minZ / SCALING_FACTOR);
auto maxZs = LevelID(maxZ / SCALING_FACTOR);
po.m_slice_index.clear();
po.m_slice_index.reserve(size_t(maxZs - (minZs + ilhs) / lhs) + 1);
po.m_slice_index.emplace_back(minZs + ilhs, float(minZ) + ilh / 2.f, ilh);
for(LevelID h = minZs + ilhs + lhs; h <= maxZs; h += lhs) {
po.m_slice_index.emplace_back(h, float(h*SCALING_FACTOR) - lh / 2.f, lh);
}
auto slindex_it = po.search_slice_index(float(bb3d.min(Z)));
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_model_height_levels.clear();
po.m_model_height_levels.reserve(po.m_slice_index.size());
for(auto it = slindex_it; it != po.m_slice_index.end(); ++it)
{
po.m_model_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_model_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
// support points. Then we sprinkle the rest of the mesh. // support points. Then we sprinkle the rest of the mesh.
auto support_points = [this, ilh](SLAPrintObject& po) { auto support_points = [this](SLAPrintObject& po) {
const ModelObject& mo = *po.m_model_object; const ModelObject& mo = *po.m_model_object;
po.m_supportdata.reset( po.m_supportdata.reset(
new SLAPrintObject::SupportData(po.transformed_mesh()) ); new SLAPrintObject::SupportData(po.transformed_mesh()) );
@ -680,12 +717,7 @@ 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(); const std::vector<float>& heights = po.m_model_height_levels;
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;
@ -831,86 +863,34 @@ void SLAPrint::process()
// Slicing the support geometries similarly to the model slicing procedure. // Slicing the support geometries similarly to the model slicing procedure.
// If the pad had been added previously (see step "base_pool" than it will // If the pad had been added previously (see step "base_pool" than it will
// be part of the slices) // be part of the slices)
auto slice_supports = [ilh](SLAPrintObject& po) { auto slice_supports = [](SLAPrintObject& po) {
auto& sd = po.m_supportdata; auto& sd = po.m_supportdata;
if(sd) sd->support_slices.clear();
if(sd && sd->support_tree_ptr) { if(sd && sd->support_tree_ptr) {
auto lh = float(po.m_config.layer_height.getFloat());
sd->support_slices = sd->support_tree_ptr->slice(lh, ilh); std::vector<float> heights; heights.reserve(po.m_slice_index.size());
for(auto& rec : po.m_slice_index) {
heights.emplace_back(rec.slice_level());
}
sd->support_slices = sd->support_tree_ptr->slice(
heights, float(po.config().slice_closing_radius.value));
}
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();
auto sih = LevelID(scale_(ilhd));
// Establish the slice grid boundaries
auto bb = po.transformed_mesh().bounding_box();
double modelgnd = bb.min(Z);
double elevation = po.get_elevation();
double lh = po.m_config.layer_height.getFloat();
double minZ = modelgnd - elevation;
// scaled values:
auto sminZ = LevelID(scale_(minZ));
auto smaxZ = LevelID(scale_(bb.max(Z)));
auto smodelgnd = LevelID(scale_(modelgnd));
auto slh = LevelID(scale_(lh));
// It is important that the next levels match the levels in
// model_slice method. Only difference is that here it works with
// scaled coordinates
po.m_level_ids.clear();
for(LevelID h = sminZ + sih; h < smaxZ; h += slh)
if(h >= smodelgnd) po.m_level_ids.emplace_back(h);
std::vector<ExPolygons>& oslices = po.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(po.m_level_ids.size() < oslices.size()) { // extend the levels until...
BOOST_LOG_TRIVIAL(warning)
<< "Height level mismatch at rasterization!\n";
LevelID lastlvl = po.m_level_ids.back();
while(po.m_level_ids.size() < oslices.size()) {
lastlvl += slh;
po.m_level_ids.emplace_back(lastlvl);
}
}
for(size_t i = 0; i < oslices.size(); ++i) {
LevelID h = po.m_level_ids[i];
float fh = float(double(h) * SCALING_FACTOR);
// now for the public slice index:
SLAPrintObject::SliceRecord& sr = po.m_slice_index[fh];
// There should be only one slice layer for each print object
assert(sr.model_slices_idx == SLAPrintObject::SliceRecord::NONE);
sr.model_slices_idx = i;
}
if(po.m_supportdata) { // deal with the support slices if present
std::vector<ExPolygons>& sslices = po.m_supportdata->support_slices;
po.m_supportdata->level_ids.clear();
po.m_supportdata->level_ids.reserve(sslices.size());
for(int i = 0; i < int(sslices.size()); ++i) {
LevelID h = sminZ + sih + i * slh;
po.m_supportdata->level_ids.emplace_back(h);
float fh = float(double(h) * SCALING_FACTOR);
SLAPrintObject::SliceRecord& sr = po.m_slice_index[fh];
assert(sr.support_slices_idx == SLAPrintObject::SliceRecord::NONE);
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,30 +903,18 @@ void SLAPrint::process()
m_printer_input.clear(); m_printer_input.clear();
for(SLAPrintObject * o : m_objects) { for(SLAPrintObject * o : m_objects) {
auto& po = *o; LevelID gndlvl = o->get_slice_index().front().key();
std::vector<ExPolygons>& oslices = po.m_model_slices; for(auto& slicerecord : o->get_slice_index()) {
auto& lyrs = m_printer_input[slicerecord.key() - gndlvl];
// We need to adjust the min Z level of the slices to be zero const ExPolygons& objslices = o->get_slices_from_record(slicerecord, soModel);
LevelID smfirst = const ExPolygons& supslices = o->get_slices_from_record(slicerecord, soSupport);
po.m_supportdata && !po.m_supportdata->level_ids.empty() ?
po.m_supportdata->level_ids.front() : 0;
LevelID mfirst = po.m_level_ids.empty()? 0 : po.m_level_ids.front();
LevelID gndlvl = -(std::min(smfirst, mfirst));
// now merge this object's support and object slices with the rest if(!objslices.empty())
// of the print object slices lyrs.emplace_back(objslices, o->instances());
for(size_t i = 0; i < oslices.size(); ++i) { if(!supslices.empty())
auto& lyrs = m_printer_input[gndlvl + po.m_level_ids[i]]; lyrs.emplace_back(supslices, o->instances());
lyrs.emplace_back(oslices[i], po.m_instances);
}
if(!po.m_supportdata) continue;
std::vector<ExPolygons>& sslices = po.m_supportdata->support_slices;
for(size_t i = 0; i < sslices.size(); ++i) {
LayerRefs& lyrs =
m_printer_input[gndlvl + po.m_supportdata->level_ids[i]];
lyrs.emplace_back(sslices[i], po.m_instances);
} }
} }
@ -1249,13 +1217,13 @@ void SLAPrint::fill_statistics()
// find highest object // find highest object
// Which is a better bet? To compare by max_z or by number of layers in the index? // Which is a better bet? To compare by max_z or by number of layers in the index?
double max_z = 0.; float max_z = 0.;
size_t max_layers_cnt = 0; size_t max_layers_cnt = 0;
size_t highest_obj_idx = 0; size_t highest_obj_idx = 0;
for (SLAPrintObject *&po : m_objects) { for (SLAPrintObject *&po : m_objects) {
const SLAPrintObject::SliceIndex& slice_index = po->get_slice_index(); const SLAPrintObject::SliceIndex& slice_index = po->get_slice_index();
if (! slice_index.empty()) { if (! slice_index.empty()) {
double z = (-- slice_index.end())->first; float z = (-- slice_index.end())->slice_level();
size_t cnt = slice_index.size(); size_t cnt = slice_index.size();
//if (z > max_z) { //if (z > max_z) {
if (cnt > max_layers_cnt) { if (cnt > max_layers_cnt) {
@ -1275,7 +1243,7 @@ void SLAPrint::fill_statistics()
int sliced_layer_cnt = 0; int sliced_layer_cnt = 0;
for (const auto& layer : highest_obj_slice_index) for (const auto& layer : highest_obj_slice_index)
{ {
const double l_height = (layer.first == highest_obj_slice_index.begin()->first) ? init_layer_height : layer_height; const double l_height = (layer.key() == highest_obj_slice_index.begin()->key()) ? init_layer_height : layer_height;
// Calculation of the consumed material // Calculation of the consumed material
@ -1284,21 +1252,22 @@ void SLAPrint::fill_statistics()
for (SLAPrintObject * po : m_objects) for (SLAPrintObject * po : m_objects)
{ {
const SLAPrintObject::SliceRecord *record = nullptr; const SLAPrintObject::_SliceRecord *record = nullptr;
{ {
const SLAPrintObject::SliceIndex& index = po->get_slice_index(); const SLAPrintObject::SliceIndex& index = po->get_slice_index();
auto key = layer.first; auto it = po->search_slice_index(layer.slice_level() - float(EPSILON));
const SLAPrintObject::SliceIndex::const_iterator it_key = index.lower_bound(key - float(EPSILON)); if (it == index.end() || it->slice_level() > layer.slice_level() + float(EPSILON))
if (it_key == index.end() || it_key->first > key + EPSILON)
continue; continue;
record = &it_key->second; record = &(*it);
} }
if (record->model_slices_idx != SLAPrintObject::SliceRecord::NONE) const ExPolygons &modelslices = po->get_slices_from_record(*record, soModel);
append(model_polygons, get_all_polygons(po->get_model_slices()[record->model_slices_idx], po->instances())); if (!modelslices.empty())
append(model_polygons, get_all_polygons(modelslices, po->instances()));
if (record->support_slices_idx != SLAPrintObject::SliceRecord::NONE) const ExPolygons &supportslices = po->get_slices_from_record(*record, soSupport);
append(supports_polygons, get_all_polygons(po->get_support_slices()[record->support_slices_idx], po->instances())); if (!supportslices.empty())
append(supports_polygons, get_all_polygons(supportslices, po->instances()));
} }
model_polygons = union_(model_polygons); model_polygons = union_(model_polygons);
@ -1394,11 +1363,15 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf
for (const t_config_option_key &opt_key : opt_keys) { for (const t_config_option_key &opt_key : opt_keys) {
if ( opt_key == "layer_height" if ( opt_key == "layer_height"
|| opt_key == "faded_layers" || opt_key == "faded_layers"
|| opt_key == "pad_enable"
|| opt_key == "pad_wall_thickness"
|| opt_key == "supports_enable"
|| opt_key == "support_object_elevation"
|| opt_key == "slice_closing_radius") { || opt_key == "slice_closing_radius") {
steps.emplace_back(slaposObjectSlice); steps.emplace_back(slaposObjectSlice);
} else if ( } else if (
opt_key == "supports_enable"
|| opt_key == "support_points_density_relative" opt_key == "support_points_density_relative"
|| opt_key == "support_points_minimal_distance") { || opt_key == "support_points_minimal_distance") {
steps.emplace_back(slaposSupportPoints); steps.emplace_back(slaposSupportPoints);
} else if ( } else if (
@ -1413,12 +1386,10 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf
|| opt_key == "support_critical_angle" || opt_key == "support_critical_angle"
|| opt_key == "support_max_bridge_length" || opt_key == "support_max_bridge_length"
|| opt_key == "support_max_pillar_link_distance" || opt_key == "support_max_pillar_link_distance"
|| opt_key == "support_object_elevation") { ) {
steps.emplace_back(slaposSupportTree); steps.emplace_back(slaposSupportTree);
} else if ( } else if (
opt_key == "pad_enable" opt_key == "pad_wall_height"
|| opt_key == "pad_wall_thickness"
|| opt_key == "pad_wall_height"
|| opt_key == "pad_max_merge_distance" || opt_key == "pad_max_merge_distance"
|| opt_key == "pad_wall_slope" || opt_key == "pad_wall_slope"
|| opt_key == "pad_edge_radius") { || opt_key == "pad_edge_radius") {
@ -1474,11 +1445,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);
} }
@ -1502,6 +1469,7 @@ double SLAPrintObject::get_current_elevation() const
namespace { // dummy empty static containers for return values in some methods namespace { // dummy empty static containers for return values in some methods
const std::vector<ExPolygons> EMPTY_SLICES; const std::vector<ExPolygons> EMPTY_SLICES;
const TriangleMesh EMPTY_MESH; const TriangleMesh EMPTY_MESH;
const ExPolygons EMPTY_SLICE;
} }
const std::vector<sla::SupportPoint>& SLAPrintObject::get_support_points() const const std::vector<sla::SupportPoint>& SLAPrintObject::get_support_points() const
@ -1509,6 +1477,72 @@ const std::vector<sla::SupportPoint>& SLAPrintObject::get_support_points() const
return m_supportdata->support_points; return m_supportdata->support_points;
} }
SLAPrintObject::SliceIndex::iterator
SLAPrintObject::search_slice_index(float slice_level)
{
_SliceRecord query(0, slice_level, 0);
auto it = std::lower_bound(m_slice_index.begin(), m_slice_index.end(),
query,
[](const _SliceRecord& r1, const _SliceRecord& r2)
{
return r1.slice_level() < r2.slice_level();
});
return it;
}
SLAPrintObject::SliceIndex::const_iterator
SLAPrintObject::search_slice_index(float slice_level) const
{
_SliceRecord query(0, slice_level, 0);
auto it = std::lower_bound(m_slice_index.cbegin(), m_slice_index.cend(),
query,
[](const _SliceRecord& r1, const _SliceRecord& r2)
{
return r1.slice_level() < r2.slice_level();
});
return it;
}
SLAPrintObject::SliceIndex::iterator
SLAPrintObject::search_slice_index(SLAPrintObject::_SliceRecord::Key key,
bool exact)
{
_SliceRecord query(key, 0.f, 0.f);
auto it = std::lower_bound(m_slice_index.begin(), m_slice_index.end(),
query,
[](const _SliceRecord& r1, const _SliceRecord& r2)
{
return r1.key() < r2.key();
});
// Return valid iterator only if the keys really match
if(exact && it != m_slice_index.end() && it->key() != key)
it = m_slice_index.end();
return it;
}
SLAPrintObject::SliceIndex::const_iterator
SLAPrintObject::search_slice_index(SLAPrintObject::_SliceRecord::Key key,
bool exact) const
{
_SliceRecord query(key, 0.f, 0.f);
auto it = std::lower_bound(m_slice_index.cbegin(), m_slice_index.cend(),
query,
[](const _SliceRecord& r1, const _SliceRecord& r2)
{
return r1.key() < r2.key();
});
// Return valid iterator only if the keys really match
if(exact && it != m_slice_index.end() && it->key() != key)
it = m_slice_index.end();
return it;
}
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,7 +1550,30 @@ 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 ExPolygons &SLAPrintObject::get_slices_from_record(
const _SliceRecord &rec,
SliceOrigin o) const
{
size_t idx = o == soModel ? rec.get_model_slice_idx() :
rec.get_support_slice_idx();
const std::vector<ExPolygons>& v = o == soModel? get_model_slices() :
get_support_slices();
if(idx >= v.size()) return EMPTY_SLICE;
return idx >= v.size() ? EMPTY_SLICE : v[idx];
}
const ExPolygons &SLAPrintObject::get_slices_from_record(
SLAPrintObject::SliceRecordConstIterator it, SliceOrigin o) const
{
if(it.is_end()) return EMPTY_SLICE;
return get_slices_from_record(*it, o);
}
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;

View File

@ -6,6 +6,7 @@
#include "PrintExport.hpp" #include "PrintExport.hpp"
#include "Point.hpp" #include "Point.hpp"
#include "MTUtils.hpp" #include "MTUtils.hpp"
#include <iterator>
namespace Slic3r { namespace Slic3r {
@ -35,12 +36,19 @@ using _SLAPrintObjectBase =
// the printer (rasterizer) in the SLAPrint class. // the printer (rasterizer) in the SLAPrint class.
using LevelID = long long; using LevelID = long long;
enum SliceOrigin { soSupport, soModel };
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,40 +90,146 @@ 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;
// These two methods should be callable on the client side (e.g. UI thread)
// when the appropriate steps slaposObjectSlice and slaposSliceSupports
// are ready. All the print objects are processed before slapsRasterize so
// it is safe to call them during and/or after slapsRasterize.
const std::vector<ExPolygons>& get_model_slices() const;
const std::vector<ExPolygons>& get_support_slices() const;
// This method returns the support points of this SLAPrintObject. // This method returns the support points of this SLAPrintObject.
const std::vector<sla::SupportPoint>& get_support_points() const; const std::vector<sla::SupportPoint>& get_support_points() const;
// The public Slice record structure. It corresponds to one printable layer.
// To get the sliced polygons, use SLAPrintObject::get_slices_from_record
class SliceRecord {
public:
using Key = LevelID;
private:
Key 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
protected:
SliceRecord(Key key, float slicez, float height):
m_print_z(key), m_slice_z(slicez), m_height(height) {}
public:
// The key will be the integer height level of the top of the layer.
inline Key key() const { return m_print_z; }
// Returns the exact floating point Z coordinate of the slice
inline float slice_level() const { return m_slice_z; }
// Returns the current layer height
inline float layer_height() const { return m_height; }
};
private:
// An index record referencing the slices // An index record referencing the slices
// (get_model_slices(), get_support_slices()) where the keys are the height // (get_model_slices(), get_support_slices()) where the keys are the height
// levels of the model in scaled-clipper coordinates. The levels correspond // levels of the model in scaled-clipper coordinates. The levels correspond
// to the z coordinate of the object coordinate system. // to the z coordinate of the object coordinate system.
struct SliceRecord { class _SliceRecord: public SliceRecord {
using Key = float; public:
static const size_t NONE = size_t(-1); // this will be the max limit of size_t
private:
size_t m_model_slices_idx = NONE;
size_t m_support_slices_idx = NONE;
using Idx = size_t; public:
static const Idx NONE = Idx(-1); // this will be the max limit of size_t _SliceRecord(Key key, float slicez, float height):
SliceRecord(key, slicez, height) {}
Idx model_slices_idx = NONE; // Methods for setting the indices into the slice vectors.
Idx support_slices_idx = NONE; void set_model_slice_idx(size_t id) { m_model_slices_idx = id; }
void set_support_slice_idx(size_t id) { m_support_slices_idx = id; }
inline size_t get_model_slice_idx() const { return m_model_slices_idx; }
inline size_t get_support_slice_idx() const { return m_support_slices_idx; }
}; };
using SliceIndex = std::map<SliceRecord::Key, SliceRecord>; // Slice index will be a plain vector sorted by the integer height levels
using SliceIndex = std::vector<_SliceRecord>;
// Retrieve the slice index which is readable only after slaposIndexSlices // Retrieve the slice index which is readable only after slaposIndexSlices
// is done. // is done.
const SliceIndex& get_slice_index() const; const SliceIndex& get_slice_index() const;
// I refuse to grantee copying (Tamas) // Search slice index for the closest slice to the given level
SLAPrintObject(const SLAPrintObject&) = delete; SliceIndex::iterator search_slice_index(float slice_level);
SLAPrintObject& operator=(const SLAPrintObject&) = delete; SliceIndex::const_iterator search_slice_index(float slice_level) const;
// Search the slice index for a particular level in integer coordinates.
// If no such layer is present, it will return m_slice_index.end()
// This behavior can be suppressed by the second parameter. If it is true
// the method will return the closest (non-equal) record
SliceIndex::iterator search_slice_index(_SliceRecord::Key key, bool exact = false);
SliceIndex::const_iterator search_slice_index(_SliceRecord::Key key, bool = false) const;
const std::vector<ExPolygons>& get_model_slices() const;
const std::vector<ExPolygons>& get_support_slices() const;
public:
// Should work as a polymorphic bidirectional iterator to the slice records
using SliceRecordConstIterator =
IndexBasedIterator<const SliceIndex, const _SliceRecord>;
// /////////////////////////////////////////////////////////////////////////
//
// These two methods should be callable on the client side (e.g. UI thread)
// when the appropriate steps slaposObjectSlice and slaposSliceSupports
// are ready. All the print objects are processed before slapsRasterize so
// it is safe to call them during and/or after slapsRasterize.
//
// /////////////////////////////////////////////////////////////////////////
// Get the slice records from a range of slice levels (inclusive). Floating
// point keys are the levels where the model was sliced with the mesh
// slicer. Integral keys are the keys of the slice records, which
// correspond to the top of each layer.. The end() method of the returned
// range points *after* the last valid element. This is for being
// consistent with std and makeing range based for loops work. use
// std::prev(range.end()) or --range.end() to get the last element.
template<class Key> Range<SliceRecordConstIterator>
get_slice_records(Key from, Key to = std::numeric_limits<Key>::max()) const
{
SliceIndex::const_iterator it_from, it_to;
if(std::is_integral<Key>::value) {
it_from = search_slice_index(SliceRecord::Key(from));
it_to = search_slice_index(SliceRecord::Key(to));
} else if(std::is_floating_point<Key>::value) {
it_from = search_slice_index(float(from));
it_to = search_slice_index(float(to));
} else return {
SliceRecordConstIterator(m_slice_index, _SliceRecord::NONE ),
SliceRecordConstIterator(m_slice_index, _SliceRecord::NONE ),
};
auto start = m_slice_index.begin();
size_t bidx = it_from == m_slice_index.end() ? _SliceRecord::NONE :
size_t(it_from - start);
size_t eidx = it_to == m_slice_index.end() ? _SliceRecord::NONE :
size_t(it_to - start) + 1;
return {
SliceRecordConstIterator(m_slice_index, bidx),
SliceRecordConstIterator(m_slice_index, eidx),
};
}
// Get all the slice records as a range.
inline Range<SliceRecordConstIterator> get_slice_records() const {
return {
SliceRecordConstIterator(m_slice_index, 0),
SliceRecordConstIterator(m_slice_index, m_slice_index.size())
};
}
const ExPolygons& get_slices_from_record(SliceRecordConstIterator it,
SliceOrigin o) const;
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;
@ -145,8 +259,10 @@ protected:
private: private:
// Object specific configuration, pulled from the configuration layer. // Object specific configuration, pulled from the configuration layer.
SLAPrintObjectConfig m_config; SLAPrintObjectConfig m_config;
// Translation in Z + Rotation by Y and Z + Scaling / Mirroring. // Translation in Z + Rotation by Y and Z + Scaling / Mirroring.
Transform3d m_trafo = Transform3d::Identity(); Transform3d m_trafo = Transform3d::Identity();
std::vector<Instance> m_instances; std::vector<Instance> m_instances;
// Individual 2d slice polygons from lower z to higher z levels // Individual 2d slice polygons from lower z to higher z levels
@ -154,11 +270,9 @@ 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 std::vector<float> m_model_height_levels;
// be used at rasterization.
std::vector<LevelID> m_level_ids;
// 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;
@ -249,11 +363,6 @@ private:
// Invalidate steps based on a set of parameters changed. // Invalidate steps based on a set of parameters changed.
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys); bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
std::vector<float> calculate_heights(const BoundingBoxf3& bb,
float elevation,
float initial_layer_height,
float layer_height) const;
void fill_statistics(); void fill_statistics();
SLAPrintConfig m_print_config; SLAPrintConfig m_print_config;

View File

@ -5013,32 +5013,56 @@ void GLCanvas3D::_render_sla_slices() const
if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) && obj->is_step_done(slaposIndexSlices)) if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) && obj->is_step_done(slaposIndexSlices))
{ {
const std::vector<ExPolygons>& model_slices = obj->get_model_slices(); // FIXME: is this all right (by Tamas)?
const std::vector<ExPolygons>& support_slices = obj->get_support_slices(); auto slice_range = obj->get_slice_records(coord_t(min_z / SCALING_FACTOR),
coord_t(max_z / SCALING_FACTOR));
const ExPolygons& obj_bottom = obj->get_slices_from_record(slice_range.begin(), soModel);
const ExPolygons& obj_top = obj->get_slices_from_record(std::prev(slice_range.end()), soModel);
const ExPolygons& sup_bottom = obj->get_slices_from_record(slice_range.begin(), soSupport);
const ExPolygons& sup_top = obj->get_slices_from_record(std::prev(slice_range.end()), soSupport);
const SLAPrintObject::SliceIndex& index = obj->get_slice_index();
SLAPrintObject::SliceIndex::const_iterator it_min_z = std::find_if(index.begin(), index.end(), [min_z](const SLAPrintObject::SliceIndex::value_type& id) -> bool { return std::abs(min_z - id.first) < EPSILON; });
SLAPrintObject::SliceIndex::const_iterator it_max_z = std::find_if(index.begin(), index.end(), [max_z](const SLAPrintObject::SliceIndex::value_type& id) -> bool { return std::abs(max_z - id.first) < EPSILON; });
if (it_min_z != index.end())
{
// calculate model bottom cap // calculate model bottom cap
if (bottom_obj_triangles.empty() && (it_min_z->second.model_slices_idx < model_slices.size())) if(bottom_obj_triangles.empty() && !obj_bottom.empty())
bottom_obj_triangles = triangulate_expolygons_3d(model_slices[it_min_z->second.model_slices_idx], min_z, true); bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, min_z, true);
// calculate support bottom cap
if (bottom_sup_triangles.empty() && (it_min_z->second.support_slices_idx < support_slices.size())) // calculate support bottom cap
bottom_sup_triangles = triangulate_expolygons_3d(support_slices[it_min_z->second.support_slices_idx], min_z, true); if(bottom_sup_triangles.empty() && !sup_bottom.empty())
} bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, min_z, true);
if (it_max_z != index.end())
{
// calculate model top cap // calculate model top cap
if (top_obj_triangles.empty() && (it_max_z->second.model_slices_idx < model_slices.size())) if(top_obj_triangles.empty() && !obj_top.empty())
top_obj_triangles = triangulate_expolygons_3d(model_slices[it_max_z->second.model_slices_idx], max_z, false); top_obj_triangles = triangulate_expolygons_3d(obj_top, max_z, false);
// calculate support top cap // calculate support top cap
if (top_sup_triangles.empty() && (it_max_z->second.support_slices_idx < support_slices.size())) if(top_sup_triangles.empty() && !sup_top.empty())
top_sup_triangles = triangulate_expolygons_3d(support_slices[it_max_z->second.support_slices_idx], max_z, false); top_sup_triangles = triangulate_expolygons_3d(sup_top, max_z, false);
}
// const std::vector<ExPolygons>& model_slices = obj->get_model_slices();
// const std::vector<ExPolygons>& support_slices = obj->get_support_slices();
// const SLAPrintObject::SliceIndex& index = obj->get_slice_index();
// SLAPrintObject::SliceIndex::const_iterator it_min_z = std::find_if(index.begin(), index.end(), [min_z](const SLAPrintObject::SliceIndex::value_type& id) -> bool { return std::abs(min_z - id.first) < EPSILON; });
// SLAPrintObject::SliceIndex::const_iterator it_max_z = std::find_if(index.begin(), index.end(), [max_z](const SLAPrintObject::SliceIndex::value_type& id) -> bool { return std::abs(max_z - id.first) < EPSILON; });
// if (it_min_z != index.end())
// {
// // calculate model bottom cap
// if (bottom_obj_triangles.empty() && (it_min_z->second.model_slices_idx < model_slices.size()))
// bottom_obj_triangles = triangulate_expolygons_3d(model_slices[it_min_z->second.model_slices_idx], min_z, true);
// // calculate support bottom cap
// if (bottom_sup_triangles.empty() && (it_min_z->second.support_slices_idx < support_slices.size()))
// bottom_sup_triangles = triangulate_expolygons_3d(support_slices[it_min_z->second.support_slices_idx], min_z, true);
// }
// if (it_max_z != index.end())
// {
// // calculate model top cap
// if (top_obj_triangles.empty() && (it_max_z->second.model_slices_idx < model_slices.size()))
// top_obj_triangles = triangulate_expolygons_3d(model_slices[it_max_z->second.model_slices_idx], max_z, false);
// // calculate support top cap
// if (top_sup_triangles.empty() && (it_max_z->second.support_slices_idx < support_slices.size()))
// top_sup_triangles = triangulate_expolygons_3d(support_slices[it_max_z->second.support_slices_idx], max_z, false);
// }
} }
if (!bottom_obj_triangles.empty() || !top_obj_triangles.empty() || !bottom_sup_triangles.empty() || !top_sup_triangles.empty()) if (!bottom_obj_triangles.empty() || !top_obj_triangles.empty() || !bottom_sup_triangles.empty() || !top_sup_triangles.empty())

View File

@ -775,10 +775,10 @@ void Preview::load_print_as_sla()
double shift_z = obj->get_current_elevation(); double shift_z = obj->get_current_elevation();
if (obj->is_step_done(slaposIndexSlices)) if (obj->is_step_done(slaposIndexSlices))
{ {
const SLAPrintObject::SliceIndex& index = obj->get_slice_index(); auto slicerecords = obj->get_slice_records();
for (const SLAPrintObject::SliceIndex::value_type& id : index) for (auto& rec : slicerecords)
{ {
zs.insert(shift_z + id.first); zs.insert(shift_z + /*rec.slice_level()*/ rec.key() * SCALING_FACTOR);
} }
} }
} }