Finalize new sla backend interface

no has_mesh or get_mesh based on states, but specific methods to get the mesh type needed (support, pad, object)

Commented out everything that does not conform in frontend
This commit is contained in:
tamasmeszaros 2022-10-19 16:30:58 +02:00
parent 39a1ed0e1a
commit 15fa4c42d6
10 changed files with 366 additions and 294 deletions

View File

@ -1056,6 +1056,23 @@ const TriangleMesh& SLAPrintObject::pad_mesh() const
return EMPTY_MESH; return EMPTY_MESH;
} }
const TriangleMesh &SLAPrintObject::get_mesh_to_print() const {
const TriangleMesh *ret = nullptr;
int s = SLAPrintObjectStep::slaposCount;
while (s > 0 && !ret) {
--s;
if (is_step_done(SLAPrintObjectStep(s)) && !m_preview_meshes[s].empty())
ret = &m_preview_meshes[s];
}
if (!ret)
ret = &m_transformed_rmesh;
return *ret;
}
//const indexed_triangle_set &SLAPrintObject::hollowed_interior_mesh() const //const indexed_triangle_set &SLAPrintObject::hollowed_interior_mesh() const
//{ //{
// if (m_hollowing_data && m_hollowing_data->interior && // if (m_hollowing_data && m_hollowing_data->interior &&

View File

@ -45,6 +45,24 @@ using _SLAPrintObjectBase =
enum SliceOrigin { soSupport, soModel }; enum SliceOrigin { soSupport, soModel };
} // namespace Slic3r
namespace std {
template<> struct hash<Slic3r::csg::VoxelizeParams> {
size_t operator() (const Slic3r::csg::VoxelizeParams &p) const {
std::string str = Slic3r::float_to_string_decimal_point(p.voxel_scale());
str += Slic3r::float_to_string_decimal_point(p.exterior_bandwidth());
str += Slic3r::float_to_string_decimal_point(p.interior_bandwidth());
return std::hash<std::string>{}(str);
}
};
} // namespace std
namespace Slic3r {
// Each sla object step can hold a collection of csg operations on the // Each sla object step can hold a collection of csg operations on the
// sla model to be sliced. Currently, Assembly step adds negative and positive // sla model to be sliced. Currently, Assembly step adds negative and positive
// volumes, hollowing adds the negative interior, drilling adds the hole cylinders. // volumes, hollowing adds the negative interior, drilling adds the hole cylinders.
@ -54,7 +72,7 @@ enum SliceOrigin { soSupport, soModel };
struct CSGPartForStep : public csg::CSGPart struct CSGPartForStep : public csg::CSGPart
{ {
SLAPrintObjectStep key; SLAPrintObjectStep key;
mutable struct { VoxelGridPtr gridptr; csg::VoxelizeParams params; } cache; mutable std::unordered_map<csg::VoxelizeParams, VoxelGridPtr> gridcache;
CSGPartForStep(SLAPrintObjectStep k, CSGPart &&p = {}) CSGPartForStep(SLAPrintObjectStep k, CSGPart &&p = {})
: key{k}, CSGPart{std::move(p)} : key{k}, CSGPart{std::move(p)}
@ -64,6 +82,7 @@ struct CSGPartForStep : public csg::CSGPart
{ {
this->its_ptr = std::move(part.its_ptr); this->its_ptr = std::move(part.its_ptr);
this->operation = part.operation; this->operation = part.operation;
return *this; return *this;
} }
@ -72,23 +91,27 @@ struct CSGPartForStep : public csg::CSGPart
namespace csg { namespace csg {
//inline VoxelGridPtr get_voxelgrid(const CSGPartForStep &part, inline bool operator==(const VoxelizeParams &a, const VoxelizeParams &b)
// const VoxelizeParams &p) {
//{ std::hash<Slic3r::csg::VoxelizeParams> h;
// if (!part.cache.gridptr || get_voxel_scale(*part.cache.gridptr) < p.voxel_scale()) { return h(a) == h(b);
// part.cache.gridptr = mesh_to_grid(*csg::get_mesh(part), p.voxel_scale(), }
// p.exterior_bandwidth(),
// p.interior_bandwidth());
// } /*else { inline VoxelGridPtr get_voxelgrid(const CSGPartForStep &part,
// float vscale = p.voxel_scale(); const VoxelizeParams &p)
// float oscale = get_voxel_scale(*part.cache.gridptr); {
VoxelGridPtr &ret = part.gridcache[p];
// rescale_grid(*part.cache.gridptr, oscale/vscale); if (!ret) {
// }*/ ret = mesh_to_grid(*csg::get_mesh(part),
csg::get_transform(part),
p.voxel_scale(),
p.exterior_bandwidth(),
p.interior_bandwidth());
}
// return clone(*part.cache.gridptr); return clone(*ret);
//} }
} // namespace csg } // namespace csg
@ -134,9 +157,7 @@ public:
// Get the mesh that is going to be printed with all the modifications // Get the mesh that is going to be printed with all the modifications
// like hollowing and drilled holes. // like hollowing and drilled holes.
const TriangleMesh & get_mesh_to_print() const { const TriangleMesh & get_mesh_to_print() const;
return !m_mesh_from_slices.empty() ? m_mesh_from_slices : m_transformed_rmesh;
}
// // This will return the transformed mesh which is cached // // This will return the transformed mesh which is cached
// const TriangleMesh& transformed_mesh() const; // const TriangleMesh& transformed_mesh() const;
@ -379,9 +400,16 @@ private:
}; };
std::unique_ptr<SupportData> m_supportdata; std::unique_ptr<SupportData> m_supportdata;
TriangleMesh m_mesh_from_slices;
// Holds CSG operations for the printed object, prioritized by print steps.
std::multiset<CSGPartForStep> m_mesh_to_slice; std::multiset<CSGPartForStep> m_mesh_to_slice;
// Holds the preview of the object to be printed (as it will look like with
// all its holes and cavities, negatives and positive volumes unified.
// Essentially this should be a m_mesh_to_slice after the CSG operations
// or an approximation of that.
std::array<TriangleMesh, SLAPrintObjectStep::slaposCount> m_preview_meshes;
class HollowingData class HollowingData
{ {
public: public:

View File

@ -22,7 +22,7 @@
#include <libslic3r/QuadricEdgeCollapse.hpp> #include <libslic3r/QuadricEdgeCollapse.hpp>
#include <libslic3r/ClipperUtils.hpp> #include <libslic3r/ClipperUtils.hpp>
#include <libslic3r/QuadricEdgeCollapse.hpp> #include <libslic3r/ShortEdgeCollapse.hpp>
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
@ -128,6 +128,54 @@ void SLAPrint::Steps::apply_printer_corrections(SLAPrintObject &po, SliceOrigin
} }
} }
void SLAPrint::Steps::generate_preview(SLAPrintObject &po, SLAPrintObjectStep step)
{
Benchmark bench;
bench.start();
// update preview mesh
double vscale = 1. / (2. * po.m_config.layer_height.getFloat());
auto voxparams = csg::VoxelizeParams{}
.voxel_scale(vscale)
.exterior_bandwidth(1.f)
.interior_bandwidth(1.f);
auto grid = csg::voxelize_csgmesh(range(po.m_mesh_to_slice), voxparams);
indexed_triangle_set m = grid_to_mesh(*grid);
// if (!m.empty()) {
// // simplify mesh lossless
// std::cout << "simplify started" << std::endl;
// int expected_cnt = m.indices.size() * 0.8; //std::pow(po.m_transformed_rmesh.volume() / std::pow(1./vscale, 3), 2./3.);
// std::cout << "expected triangles " << expected_cnt << std::endl;
// float err = std::pow(vscale, 3);
// its_quadric_edge_collapse(m, 0U, &err);
// std::cout << "simplify ended " << m.indices.size() << " triangles" << std::endl;
// std::cout << "cleanup started" << std::endl;
// its_compactify_vertices(m);
// its_merge_vertices(m);
// std::cout << "cleanup ended" << std::endl;
// }
po.m_preview_meshes[step] = TriangleMesh{std::move(m)};
for (size_t i = size_t(step) + 1; i < slaposCount; ++i)
{
po.m_preview_meshes[i] = {};
}
bench.stop();
std::cout << "Preview gen took: " << bench.getElapsedSec() << std::endl;
using namespace std::string_literals;
report_status(-2, "Reload preview from step "s + std::to_string(int(step)), SlicingStatus::RELOAD_SLA_PREVIEW);
}
static inline
void clear_csg(std::multiset<CSGPartForStep> &s, SLAPrintObjectStep step) void clear_csg(std::multiset<CSGPartForStep> &s, SLAPrintObjectStep step)
{ {
auto r = s.equal_range(step); auto r = s.equal_range(step);
@ -153,6 +201,8 @@ void SLAPrint::Steps::mesh_assembly(SLAPrintObject &po)
csg::model_to_csgmesh(*po.model_object(), po.trafo(), csg::model_to_csgmesh(*po.model_object(), po.trafo(),
csg_inserter{po.m_mesh_to_slice, slaposAssembly}, csg_inserter{po.m_mesh_to_slice, slaposAssembly},
csg::mpartsPositive | csg::mpartsNegative); csg::mpartsPositive | csg::mpartsNegative);
generate_preview(po, slaposAssembly);
} }
void SLAPrint::Steps::hollow_model(SLAPrintObject &po) void SLAPrint::Steps::hollow_model(SLAPrintObject &po)
@ -185,11 +235,24 @@ void SLAPrint::Steps::hollow_model(SLAPrintObject &po)
po.m_hollowing_data.reset(new SLAPrintObject::HollowingData()); po.m_hollowing_data.reset(new SLAPrintObject::HollowingData());
po.m_hollowing_data->interior = std::move(interior); po.m_hollowing_data->interior = std::move(interior);
indexed_triangle_set &m = sla::get_mesh(*po.m_hollowing_data->interior);
if (!m.empty()) {
// simplify mesh lossless
float loss_less_max_error = 2*std::numeric_limits<float>::epsilon();
its_quadric_edge_collapse(m, 0U, &loss_less_max_error);
its_compactify_vertices(m);
its_merge_vertices(m);
}
// Put the interior into the target mesh as a negative // Put the interior into the target mesh as a negative
po.m_mesh_to_slice po.m_mesh_to_slice
.emplace(slaposHollowing, .emplace(slaposHollowing,
csg::CSGPart{&sla::get_mesh(*po.m_hollowing_data->interior), csg::CSGPart{&sla::get_mesh(*po.m_hollowing_data->interior),
csg::CSGType::Difference}); csg::CSGType::Difference});
generate_preview(po, slaposHollowing);
} }
} }
@ -203,14 +266,7 @@ void SLAPrint::Steps::drill_holes(SLAPrintObject &po)
csg::mpartsDrillHoles); csg::mpartsDrillHoles);
// update preview mesh // update preview mesh
double vscale = 1. / 0.05; generate_preview(po, slaposDrillHoles);
auto voxparams = csg::VoxelizeParams{}
.voxel_scale(vscale)
.exterior_bandwidth(1.f)
.interior_bandwidth(1.f);
auto grid = csg::voxelize_csgmesh(range(po.m_mesh_to_slice), voxparams);
indexed_triangle_set mesh_from_slices = grid_to_mesh(*grid);
po.m_mesh_from_slices = TriangleMesh{mesh_from_slices};
} }
template<class Pred> template<class Pred>
@ -331,38 +387,7 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po)
// We apply the printer correction offset here. // We apply the printer correction offset here.
apply_printer_corrections(po, soModel); apply_printer_corrections(po, soModel);
// auto simpl_slices = reserve_vector<ExPolygons>(po.m_model_slices.size()); generate_preview(po, slaposObjectSlice);
// for (const ExPolygons &slice : po.m_model_slices) {
// simpl_slices.emplace_back(expolygons_simplify(slice, scaled(1e-2)));
// }
// po.m_mesh_from_slices = TriangleMesh{
// slices_to_mesh(simpl_slices, slice_grid.front(), lhd, ilhd)};
double vscale = 1. / lhd;
auto voxparams = csg::VoxelizeParams{}
.voxel_scale(vscale)
.exterior_bandwidth(1.f)
.interior_bandwidth(1.f);
auto grid = csg::voxelize_csgmesh(range(po.m_mesh_to_slice), voxparams);
assert(grid);
// size_t max_face_cnt = 0;
// for (const CSGMesh &part : po.m_mesh_to_slice)
// max_face_cnt += part.its_ptr->indices.size();
indexed_triangle_set mesh_from_slices = grid_to_mesh(*grid);
// its_quadric_edge_collapse(mesh_from_slices, vscale * max_face_cnt);
// its_compactify_vertices(mesh_from_slices);
// its_merge_vertices(mesh_from_slices);
po.m_mesh_from_slices = TriangleMesh{mesh_from_slices};
// po.m_mesh_from_slices = TriangleMesh{sla::get_mesh(*po.m_hollowing_data->interior)};
} }
static void filter_support_points_by_modifiers( static void filter_support_points_by_modifiers(
@ -421,7 +446,10 @@ void SLAPrint::Steps::support_points(SLAPrintObject &po)
if(!po.m_config.supports_enable.getBool()) return; if(!po.m_config.supports_enable.getBool()) return;
if (!po.m_supportdata) if (!po.m_supportdata)
po.m_supportdata.reset(new SLAPrintObject::SupportData(po.m_mesh_from_slices)); po.m_supportdata =
std::make_unique<SLAPrintObject::SupportData>(
po.m_preview_meshes[slaposObjectSlice]
);
po.m_supportdata->input.zoffset = csgmesh_positive_bb(po.m_mesh_to_slice) po.m_supportdata->input.zoffset = csgmesh_positive_bb(po.m_mesh_to_slice)
.min.z(); .min.z();

View File

@ -45,6 +45,8 @@ private:
void apply_printer_corrections(SLAPrintObject &po, SliceOrigin o); void apply_printer_corrections(SLAPrintObject &po, SliceOrigin o);
void generate_preview(SLAPrintObject &po, SLAPrintObjectStep step);
public: public:
explicit Steps(SLAPrint *print); explicit Steps(SLAPrint *print);

View File

@ -852,73 +852,73 @@ int GLVolumeCollection::load_object_volume(
return int(this->volumes.size() - 1); return int(this->volumes.size() - 1);
} }
// Load SLA auxiliary GLVolumes (for support trees or pad). //// Load SLA auxiliary GLVolumes (for support trees or pad).
// This function produces volumes for multiple instances in a single shot, //// This function produces volumes for multiple instances in a single shot,
// as some object specific mesh conversions may be expensive. //// as some object specific mesh conversions may be expensive.
#if ENABLE_LEGACY_OPENGL_REMOVAL //#if ENABLE_LEGACY_OPENGL_REMOVAL
void GLVolumeCollection::load_object_auxiliary( //void GLVolumeCollection::load_object_auxiliary(
const SLAPrintObject* print_object, // const SLAPrintObject* print_object,
int obj_idx, // int obj_idx,
// pairs of <instance_idx, print_instance_idx> // // pairs of <instance_idx, print_instance_idx>
const std::vector<std::pair<size_t, size_t>>& instances, // const std::vector<std::pair<size_t, size_t>>& instances,
SLAPrintObjectStep milestone, // SLAPrintObjectStep milestone,
// Timestamp of the last change of the milestone // // Timestamp of the last change of the milestone
size_t timestamp) // size_t timestamp)
#else //#else
void GLVolumeCollection::load_object_auxiliary( //void GLVolumeCollection::load_object_auxiliary(
const SLAPrintObject *print_object, // const SLAPrintObject *print_object,
int obj_idx, // int obj_idx,
// pairs of <instance_idx, print_instance_idx> // // pairs of <instance_idx, print_instance_idx>
const std::vector<std::pair<size_t, size_t>>& instances, // const std::vector<std::pair<size_t, size_t>>& instances,
SLAPrintObjectStep milestone, // SLAPrintObjectStep milestone,
// Timestamp of the last change of the milestone // // Timestamp of the last change of the milestone
size_t timestamp, // size_t timestamp,
bool opengl_initialized) // bool opengl_initialized)
#endif // ENABLE_LEGACY_OPENGL_REMOVAL //#endif // ENABLE_LEGACY_OPENGL_REMOVAL
{ //{
assert(print_object->is_step_done(milestone)); // assert(print_object->is_step_done(milestone));
Transform3d mesh_trafo_inv = print_object->trafo().inverse(); // Transform3d mesh_trafo_inv = print_object->trafo().inverse();
// Get the support mesh. // // Get the support mesh.
TriangleMesh mesh = print_object->get_mesh(milestone); // TriangleMesh mesh = print_object->get_mesh(milestone);
mesh.transform(mesh_trafo_inv); // mesh.transform(mesh_trafo_inv);
// Convex hull is required for out of print bed detection. // // Convex hull is required for out of print bed detection.
TriangleMesh convex_hull = mesh.convex_hull_3d(); // TriangleMesh convex_hull = mesh.convex_hull_3d();
for (const std::pair<size_t, size_t>& instance_idx : instances) { // for (const std::pair<size_t, size_t>& instance_idx : instances) {
const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first]; // const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first];
this->volumes.emplace_back(new GLVolume((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR)); // this->volumes.emplace_back(new GLVolume((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR));
GLVolume& v = *this->volumes.back(); // GLVolume& v = *this->volumes.back();
#if ENABLE_LEGACY_OPENGL_REMOVAL //#if ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_SMOOTH_NORMALS //#if ENABLE_SMOOTH_NORMALS
v.model.init_from(mesh, true); // v.model.init_from(mesh, true);
#else //#else
v.model.init_from(mesh); // v.model.init_from(mesh);
v.model.set_color((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR); // v.model.set_color((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR);
#if ENABLE_RAYCAST_PICKING //#if ENABLE_RAYCAST_PICKING
v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(std::make_shared<const TriangleMesh>(mesh)); // v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(std::make_shared<const TriangleMesh>(mesh));
#endif // ENABLE_RAYCAST_PICKING //#endif // ENABLE_RAYCAST_PICKING
#endif // ENABLE_SMOOTH_NORMALS //#endif // ENABLE_SMOOTH_NORMALS
#else //#else
#if ENABLE_SMOOTH_NORMALS //#if ENABLE_SMOOTH_NORMALS
v.indexed_vertex_array.load_mesh(mesh, true); // v.indexed_vertex_array.load_mesh(mesh, true);
#else //#else
v.indexed_vertex_array.load_mesh(mesh); // v.indexed_vertex_array.load_mesh(mesh);
#endif // ENABLE_SMOOTH_NORMALS //#endif // ENABLE_SMOOTH_NORMALS
v.indexed_vertex_array.finalize_geometry(opengl_initialized); // v.indexed_vertex_array.finalize_geometry(opengl_initialized);
#endif // ENABLE_LEGACY_OPENGL_REMOVAL //#endif // ENABLE_LEGACY_OPENGL_REMOVAL
v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first); // v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first);
v.geometry_id = std::pair<size_t, size_t>(timestamp, model_instance.id().id); // v.geometry_id = std::pair<size_t, size_t>(timestamp, model_instance.id().id);
// Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance. // // Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance.
if (&instance_idx == &instances.back()) // if (&instance_idx == &instances.back())
v.set_convex_hull(std::move(convex_hull)); // v.set_convex_hull(std::move(convex_hull));
else // else
v.set_convex_hull(convex_hull); // v.set_convex_hull(convex_hull);
v.is_modifier = false; // v.is_modifier = false;
v.shader_outside_printer_detection_enabled = (milestone == slaposSupportTree); // v.shader_outside_printer_detection_enabled = (milestone == slaposSupportTree);
v.set_instance_transformation(model_instance.get_transformation()); // v.set_instance_transformation(model_instance.get_transformation());
// Leave the volume transformation at identity. // // Leave the volume transformation at identity.
// v.set_volume_transformation(model_volume->get_transformation()); // // v.set_volume_transformation(model_volume->get_transformation());
} // }
} //}
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_OPENGL_ES #if ENABLE_OPENGL_ES

View File

@ -659,14 +659,14 @@ public:
int instance_idx); int instance_idx);
// Load SLA auxiliary GLVolumes (for support trees or pad). // Load SLA auxiliary GLVolumes (for support trees or pad).
void load_object_auxiliary( // void load_object_auxiliary(
const SLAPrintObject* print_object, // const SLAPrintObject* print_object,
int obj_idx, // int obj_idx,
// pairs of <instance_idx, print_instance_idx> // // pairs of <instance_idx, print_instance_idx>
const std::vector<std::pair<size_t, size_t>>& instances, // const std::vector<std::pair<size_t, size_t>>& instances,
SLAPrintObjectStep milestone, // SLAPrintObjectStep milestone,
// Timestamp of the last change of the milestone // // Timestamp of the last change of the milestone
size_t timestamp); // size_t timestamp);
#if ENABLE_OPENGL_ES #if ENABLE_OPENGL_ES
int load_wipe_tower_preview( int load_wipe_tower_preview(

View File

@ -2189,143 +2189,146 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
} }
} }
if (printer_technology == ptSLA) { if (printer_technology == ptSLA) {
size_t idx = 0; // size_t idx = 0;
const SLAPrint *sla_print = this->sla_print(); // const SLAPrint *sla_print = this->sla_print();
std::vector<double> shift_zs(m_model->objects.size(), 0); // std::vector<double> shift_zs(m_model->objects.size(), 0);
double relative_correction_z = sla_print->relative_correction().z(); // double relative_correction_z = sla_print->relative_correction().z();
if (relative_correction_z <= EPSILON) // if (relative_correction_z <= EPSILON)
relative_correction_z = 1.; // relative_correction_z = 1.;
for (const SLAPrintObject *print_object : sla_print->objects()) { // for (const SLAPrintObject *print_object : sla_print->objects()) {
SLASupportState &state = sla_support_state[idx ++]; // SLASupportState &state = sla_support_state[idx ++];
const ModelObject *model_object = print_object->model_object(); // const ModelObject *model_object = print_object->model_object();
// Find an index of the ModelObject // // Find an index of the ModelObject
int object_idx; // int object_idx;
// There may be new SLA volumes added to the scene for this print_object. // // There may be new SLA volumes added to the scene for this print_object.
// Find the object index of this print_object in the Model::objects list. // // Find the object index of this print_object in the Model::objects list.
auto it = std::find(sla_print->model().objects.begin(), sla_print->model().objects.end(), model_object); // auto it = std::find(sla_print->model().objects.begin(), sla_print->model().objects.end(), model_object);
assert(it != sla_print->model().objects.end()); // assert(it != sla_print->model().objects.end());
object_idx = it - sla_print->model().objects.begin(); // object_idx = it - sla_print->model().objects.begin();
// Cache the Z offset to be applied to all volumes with this object_idx. // // Cache the Z offset to be applied to all volumes with this object_idx.
shift_zs[object_idx] = print_object->get_current_elevation() / relative_correction_z; // shift_zs[object_idx] = print_object->get_current_elevation() / relative_correction_z;
// Collect indices of this print_object's instances, for which the SLA support meshes are to be added to the scene. // // Collect indices of this print_object's instances, for which the SLA support meshes are to be added to the scene.
// pairs of <instance_idx, print_instance_idx> // // pairs of <instance_idx, print_instance_idx>
std::vector<std::pair<size_t, size_t>> instances[std::tuple_size<SLASteps>::value]; // std::vector<std::pair<size_t, size_t>> instances[std::tuple_size<SLASteps>::value];
for (size_t print_instance_idx = 0; print_instance_idx < print_object->instances().size(); ++ print_instance_idx) { // for (size_t print_instance_idx = 0; print_instance_idx < print_object->instances().size(); ++ print_instance_idx) {
const SLAPrintObject::Instance &instance = print_object->instances()[print_instance_idx]; // const SLAPrintObject::Instance &instance = print_object->instances()[print_instance_idx];
// Find index of ModelInstance corresponding to this SLAPrintObject::Instance. // // Find index of ModelInstance corresponding to this SLAPrintObject::Instance.
auto it = std::find_if(model_object->instances.begin(), model_object->instances.end(), // auto it = std::find_if(model_object->instances.begin(), model_object->instances.end(),
[&instance](const ModelInstance *mi) { return mi->id() == instance.instance_id; }); // [&instance](const ModelInstance *mi) { return mi->id() == instance.instance_id; });
assert(it != model_object->instances.end()); // assert(it != model_object->instances.end());
int instance_idx = it - model_object->instances.begin(); // int instance_idx = it - model_object->instances.begin();
for (size_t istep = 0; istep < sla_steps.size(); ++ istep) // for (size_t istep = 0; istep < sla_steps.size(); ++ istep)
if (sla_steps[istep] == slaposDrillHoles) { // if (sla_steps[istep] == slaposDrillHoles) {
// Hollowing is a special case, where the mesh from the backend is being loaded into the 1st volume of an instance, // // Hollowing is a special case, where the mesh from the backend is being loaded into the 1st volume of an instance,
// not into its own GLVolume. // // not into its own GLVolume.
// There shall always be such a GLVolume allocated. // // There shall always be such a GLVolume allocated.
ModelVolumeState key(model_object->volumes.front()->id(), instance.instance_id); // ModelVolumeState key(model_object->volumes.front()->id(), instance.instance_id);
auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower); // auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower);
assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id); // assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id);
assert(!it->new_geometry()); // assert(!it->new_geometry());
GLVolume &volume = *m_volumes.volumes[it->volume_idx]; // GLVolume &volume = *m_volumes.volumes[it->volume_idx];
if (! volume.offsets.empty() && state.step[istep].timestamp != volume.offsets.front()) { // if (! volume.offsets.empty() && state.step[istep].timestamp != volume.offsets.front()) {
// The backend either produced a new hollowed mesh, or it invalidated the one that the front end has seen. // // The backend either produced a new hollowed mesh, or it invalidated the one that the front end has seen.
#if ENABLE_LEGACY_OPENGL_REMOVAL //#if ENABLE_LEGACY_OPENGL_REMOVAL
volume.model.reset(); // volume.model.reset();
#else //#else
volume.indexed_vertex_array.release_geometry(); // volume.indexed_vertex_array.release_geometry();
#endif // ENABLE_LEGACY_OPENGL_REMOVAL //#endif // ENABLE_LEGACY_OPENGL_REMOVAL
if (state.step[istep].state == PrintStateBase::DONE) { // if (state.step[istep].state == PrintStateBase::DONE) {
TriangleMesh mesh = print_object->get_mesh(slaposDrillHoles); // TriangleMesh mesh = print_object->get_mesh(slaposDrillHoles);
assert(! mesh.empty()); // assert(! mesh.empty());
// sla_trafo does not contain volume trafo. To get a mesh to create // // sla_trafo does not contain volume trafo. To get a mesh to create
// a new volume from, we have to apply vol trafo inverse separately. // // a new volume from, we have to apply vol trafo inverse separately.
const ModelObject& mo = *m_model->objects[volume.object_idx()]; // const ModelObject& mo = *m_model->objects[volume.object_idx()];
Transform3d trafo = sla_print->sla_trafo(mo) // Transform3d trafo = sla_print->sla_trafo(mo)
* mo.volumes.front()->get_transformation().get_matrix(); // * mo.volumes.front()->get_transformation().get_matrix();
mesh.transform(trafo.inverse()); // mesh.transform(trafo.inverse());
#if ENABLE_SMOOTH_NORMALS //#if ENABLE_SMOOTH_NORMALS
#if ENABLE_LEGACY_OPENGL_REMOVAL //#if ENABLE_LEGACY_OPENGL_REMOVAL
volume.model.init_from(mesh, true); // volume.model.init_from(mesh, true);
#else //#else
volume.indexed_vertex_array.load_mesh(mesh, true); // volume.indexed_vertex_array.load_mesh(mesh, true);
#endif // ENABLE_LEGACY_OPENGL_REMOVAL //#endif // ENABLE_LEGACY_OPENGL_REMOVAL
#else //#else
#if ENABLE_LEGACY_OPENGL_REMOVAL //#if ENABLE_LEGACY_OPENGL_REMOVAL
volume.model.init_from(mesh); // volume.model.init_from(mesh);
#if ENABLE_RAYCAST_PICKING //#if ENABLE_RAYCAST_PICKING
volume.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(std::make_shared<TriangleMesh>(mesh)); // volume.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(std::make_shared<TriangleMesh>(mesh));
#endif // ENABLE_RAYCAST_PICKING //#endif // ENABLE_RAYCAST_PICKING
#else //#else
volume.indexed_vertex_array.load_mesh(mesh); // volume.indexed_vertex_array.load_mesh(mesh);
#endif // ENABLE_LEGACY_OPENGL_REMOVAL //#endif // ENABLE_LEGACY_OPENGL_REMOVAL
#endif // ENABLE_SMOOTH_NORMALS //#endif // ENABLE_SMOOTH_NORMALS
} // }
else { // else {
// Reload the original volume. // // Reload the original volume.
#if ENABLE_SMOOTH_NORMALS //#if ENABLE_SMOOTH_NORMALS
#if ENABLE_LEGACY_OPENGL_REMOVAL //#if ENABLE_LEGACY_OPENGL_REMOVAL
volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true); // volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true);
#else //#else
volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true); // volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true);
#endif // ENABLE_LEGACY_OPENGL_REMOVAL //#endif // ENABLE_LEGACY_OPENGL_REMOVAL
#else //#else
#if ENABLE_LEGACY_OPENGL_REMOVAL //#if ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_RAYCAST_PICKING //#if ENABLE_RAYCAST_PICKING
const TriangleMesh& new_mesh = m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(); // const TriangleMesh& new_mesh = m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh();
volume.model.init_from(new_mesh); // volume.model.init_from(new_mesh);
volume.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(std::make_shared<TriangleMesh>(new_mesh)); // volume.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(std::make_shared<TriangleMesh>(new_mesh));
#else //#else
volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh()); // volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh());
#endif // ENABLE_RAYCAST_PICKING //#endif // ENABLE_RAYCAST_PICKING
#else //#else
volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh()); // volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh());
#endif // ENABLE_LEGACY_OPENGL_REMOVAL //#endif // ENABLE_LEGACY_OPENGL_REMOVAL
#endif // ENABLE_SMOOTH_NORMALS //#endif // ENABLE_SMOOTH_NORMALS
} // }
#if !ENABLE_LEGACY_OPENGL_REMOVAL //#if !ENABLE_LEGACY_OPENGL_REMOVAL
volume.finalize_geometry(true); // volume.finalize_geometry(true);
#endif // !ENABLE_LEGACY_OPENGL_REMOVAL //#endif // !ENABLE_LEGACY_OPENGL_REMOVAL
} // }
//FIXME it is an ugly hack to write the timestamp into the "offsets" field to not have to add another member variable // //FIXME it is an ugly hack to write the timestamp into the "offsets" field to not have to add another member variable
// to the GLVolume. We should refactor GLVolume significantly, so that the GLVolume will not contain member variables // // to the GLVolume. We should refactor GLVolume significantly, so that the GLVolume will not contain member variables
// of various concenrs (model vs. 3D print path). // // of various concenrs (model vs. 3D print path).
volume.offsets = { state.step[istep].timestamp }; // volume.offsets = { state.step[istep].timestamp };
} // }
else if (state.step[istep].state == PrintStateBase::DONE) { // else if (state.step[istep].state == PrintStateBase::DONE) {
// Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created. // // Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created.
ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id); // ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id);
auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower); // auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower);
assert(it != aux_volume_state.end() && it->geometry_id == key.geometry_id); // assert(it != aux_volume_state.end() && it->geometry_id == key.geometry_id);
if (it->new_geometry()) { // if (it->new_geometry()) {
// This can be an SLA support structure that should not be rendered (in case someone used undo // // This can be an SLA support structure that should not be rendered (in case someone used undo
// to revert to before it was generated). If that's the case, we should not generate anything. // // to revert to before it was generated). If that's the case, we should not generate anything.
if (model_object->sla_points_status != sla::PointsStatus::NoPoints) // if (model_object->sla_points_status != sla::PointsStatus::NoPoints)
instances[istep].emplace_back(std::pair<size_t, size_t>(instance_idx, print_instance_idx)); // instances[istep].emplace_back(std::pair<size_t, size_t>(instance_idx, print_instance_idx));
else // else
shift_zs[object_idx] = 0.; // shift_zs[object_idx] = 0.;
} // }
else { // else {
// Recycling an old GLVolume. Update the Object/Instance indices into the current Model. // // Recycling an old GLVolume. Update the Object/Instance indices into the current Model.
m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx); // m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx);
m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation()); // m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation());
} // }
} // }
// }
// for (size_t istep = 0; istep < sla_steps.size(); ++istep)
// if (!instances[istep].empty())
//#if ENABLE_LEGACY_OPENGL_REMOVAL
// m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp);
//#else
// m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp, m_initialized);
//#endif // ENABLE_LEGACY_OPENGL_REMOVAL
// }
// Shift-up all volumes of the object so that it has the right elevation with respect to the print bed
for (GLVolume* volume : m_volumes.volumes)
if (volume->object_idx() < (int)m_model->objects.size() && m_model->objects[volume->object_idx()]->instances[volume->instance_idx()]->is_printable()) {
const SLAPrintObject *po = sla_print()->objects()[volume->object_idx()];
float zoffs = po->get_current_elevation() / sla_print()->relative_correction().z();
volume->set_sla_shift_z(zoffs);
} }
for (size_t istep = 0; istep < sla_steps.size(); ++istep)
if (!instances[istep].empty())
#if ENABLE_LEGACY_OPENGL_REMOVAL
m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp);
#else
m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp, m_initialized);
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
}
// Shift-up all volumes of the object so that it has the right elevation with respect to the print bed
for (GLVolume* volume : m_volumes.volumes)
if (volume->object_idx() < (int)m_model->objects.size() && m_model->objects[volume->object_idx()]->instances[volume->instance_idx()]->is_printable())
volume->set_sla_shift_z(shift_zs[volume->object_idx()]);
} }
if (printer_technology == ptFFF && m_config->has("nozzle_diameter")) { if (printer_technology == ptFFF && m_config->has("nozzle_diameter")) {
@ -7635,7 +7638,7 @@ void GLCanvas3D::_load_sla_shells()
// adds objects' volumes // adds objects' volumes
for (const SLAPrintObject* obj : print->objects()) for (const SLAPrintObject* obj : print->objects())
if (obj->is_step_done(slaposSliceSupports)) { /*if (obj->is_step_done(slaposSliceSupports))*/ {
unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size(); unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size();
for (const SLAPrintObject::Instance& instance : obj->instances()) { for (const SLAPrintObject::Instance& instance : obj->instances()) {
add_volume(*obj, 0, instance, obj->get_mesh_to_print(), GLVolume::MODEL_COLOR[0], true); add_volume(*obj, 0, instance, obj->get_mesh_to_print(), GLVolume::MODEL_COLOR[0], true);

View File

@ -281,10 +281,10 @@ void HollowedMesh::on_update()
// If there is a valid SLAPrintObject, check state of Hollowing step. // If there is a valid SLAPrintObject, check state of Hollowing step.
if (print_object) { if (print_object) {
if (print_object->is_step_done(slaposDrillHoles) && print_object->has_mesh(slaposDrillHoles)) { if (print_object->is_step_done(slaposDrillHoles) && !print_object->get_mesh_to_print().empty()) {
size_t timestamp = print_object->step_state_with_timestamp(slaposDrillHoles).timestamp; size_t timestamp = print_object->step_state_with_timestamp(slaposDrillHoles).timestamp;
if (timestamp > m_old_hollowing_timestamp) { if (timestamp > m_old_hollowing_timestamp) {
const TriangleMesh& backend_mesh = print_object->get_mesh_to_slice(); const TriangleMesh& backend_mesh = print_object->get_mesh_to_print();
if (! backend_mesh.empty()) { if (! backend_mesh.empty()) {
m_hollowed_mesh_transformed.reset(new TriangleMesh(backend_mesh)); m_hollowed_mesh_transformed.reset(new TriangleMesh(backend_mesh));
Transform3d trafo_inv = (canvas->sla_print()->sla_trafo(*mo) * print_object->model_object()->volumes.front()->get_transformation().get_matrix()).inverse(); Transform3d trafo_inv = (canvas->sla_print()->sla_trafo(*mo) * print_object->model_object()->volumes.front()->get_transformation().get_matrix()).inverse();
@ -292,10 +292,10 @@ void HollowedMesh::on_update()
m_drainholes = print_object->model_object()->sla_drain_holes; m_drainholes = print_object->model_object()->sla_drain_holes;
m_old_hollowing_timestamp = timestamp; m_old_hollowing_timestamp = timestamp;
indexed_triangle_set interior = print_object->hollowed_interior_mesh(); // indexed_triangle_set interior = print_object->hollowed_interior_mesh();
its_flip_triangles(interior); // its_flip_triangles(interior);
m_hollowed_interior_transformed = std::make_unique<TriangleMesh>(std::move(interior)); // m_hollowed_interior_transformed = std::make_unique<TriangleMesh>(std::move(interior));
m_hollowed_interior_transformed->transform(trafo_inv); // m_hollowed_interior_transformed->transform(trafo_inv);
} }
else { else {
m_hollowed_mesh_transformed.reset(nullptr); m_hollowed_mesh_transformed.reset(nullptr);

View File

@ -944,7 +944,7 @@ bool MainFrame::can_export_supports() const
const PrintObjects& objects = m_plater->sla_print().objects(); const PrintObjects& objects = m_plater->sla_print().objects();
for (const SLAPrintObject* object : objects) for (const SLAPrintObject* object : objects)
{ {
if (object->has_mesh(slaposPad) || object->has_mesh(slaposSupportTree)) if (!object->support_mesh().empty())
{ {
can_export = true; can_export = true;
break; break;

View File

@ -6155,19 +6155,13 @@ void Plater::export_stl_obj(bool extended, bool selection_only)
const Transform3d mesh_trafo_inv = object->trafo().inverse(); const Transform3d mesh_trafo_inv = object->trafo().inverse();
const bool is_left_handed = object->is_left_handed(); const bool is_left_handed = object->is_left_handed();
TriangleMesh pad_mesh; auto pad_mesh = extended? object->pad_mesh() : TriangleMesh{};
const bool has_pad_mesh = extended && object->has_mesh(slaposPad); pad_mesh = object->pad_mesh();
if (has_pad_mesh) { pad_mesh.transform(mesh_trafo_inv);
pad_mesh = object->get_mesh(slaposPad);
pad_mesh.transform(mesh_trafo_inv); auto supports_mesh = extended ? object->support_mesh() : TriangleMesh{};
} supports_mesh.transform(mesh_trafo_inv);
TriangleMesh supports_mesh;
const bool has_supports_mesh = extended && object->has_mesh(slaposSupportTree);
if (has_supports_mesh) {
supports_mesh = object->get_mesh(slaposSupportTree);
supports_mesh.transform(mesh_trafo_inv);
}
const std::vector<SLAPrintObject::Instance>& obj_instances = object->instances(); const std::vector<SLAPrintObject::Instance>& obj_instances = object->instances();
for (const SLAPrintObject::Instance& obj_instance : obj_instances) { for (const SLAPrintObject::Instance& obj_instance : obj_instances) {
auto it = std::find_if(model_object->instances.begin(), model_object->instances.end(), auto it = std::find_if(model_object->instances.begin(), model_object->instances.end(),
@ -6184,19 +6178,19 @@ void Plater::export_stl_obj(bool extended, bool selection_only)
TriangleMesh inst_mesh; TriangleMesh inst_mesh;
if (has_pad_mesh) { if (!pad_mesh.empty()) {
TriangleMesh inst_pad_mesh = pad_mesh; TriangleMesh inst_pad_mesh = pad_mesh;
inst_pad_mesh.transform(inst_transform, is_left_handed); inst_pad_mesh.transform(inst_transform, is_left_handed);
inst_mesh.merge(inst_pad_mesh); inst_mesh.merge(inst_pad_mesh);
} }
if (has_supports_mesh) { if (!supports_mesh.empty()) {
TriangleMesh inst_supports_mesh = supports_mesh; TriangleMesh inst_supports_mesh = supports_mesh;
inst_supports_mesh.transform(inst_transform, is_left_handed); inst_supports_mesh.transform(inst_transform, is_left_handed);
inst_mesh.merge(inst_supports_mesh); inst_mesh.merge(inst_supports_mesh);
} }
TriangleMesh inst_object_mesh = object->get_mesh_to_slice(); TriangleMesh inst_object_mesh = object->get_mesh_to_print();
inst_object_mesh.transform(mesh_trafo_inv); inst_object_mesh.transform(mesh_trafo_inv);
inst_object_mesh.transform(inst_transform, is_left_handed); inst_object_mesh.transform(inst_transform, is_left_handed);