Sharing TriangleMesh objects between the front end (UI) and back end

(background processing)
This commit is contained in:
bubnikv 2019-06-11 17:08:47 +02:00
parent 5fc465b7e8
commit 0bb8ee149e
20 changed files with 254 additions and 193 deletions
src/libslic3r

View file

@ -160,12 +160,6 @@ Model Model::read_from_archive(const std::string &input_file, DynamicPrintConfig
return model;
}
void Model::repair()
{
for (ModelObject *o : this->objects)
o->repair();
}
ModelObject* Model::add_object()
{
this->objects.emplace_back(new ModelObject(this));
@ -472,7 +466,7 @@ bool Model::looks_like_multipart_object() const
if (obj->volumes.size() > 1 || obj->config.keys().size() > 1)
return false;
for (const ModelVolume *vol : obj->volumes) {
double zmin_this = vol->mesh.bounding_box().min(2);
double zmin_this = vol->mesh().bounding_box().min(2);
if (zmin == std::numeric_limits<double>::max())
zmin = zmin_this;
else if (std::abs(zmin - zmin_this) > EPSILON)
@ -679,7 +673,7 @@ ModelVolume* ModelObject::add_volume(const TriangleMesh &mesh)
{
ModelVolume* v = new ModelVolume(this, mesh);
this->volumes.push_back(v);
v->center_geometry();
v->center_geometry_after_creation();
this->invalidate_bounding_box();
return v;
}
@ -688,7 +682,7 @@ ModelVolume* ModelObject::add_volume(TriangleMesh &&mesh)
{
ModelVolume* v = new ModelVolume(this, std::move(mesh));
this->volumes.push_back(v);
v->center_geometry();
v->center_geometry_after_creation();
this->invalidate_bounding_box();
return v;
}
@ -697,7 +691,7 @@ ModelVolume* ModelObject::add_volume(const ModelVolume &other)
{
ModelVolume* v = new ModelVolume(this, other);
this->volumes.push_back(v);
v->center_geometry();
v->center_geometry_after_creation();
this->invalidate_bounding_box();
return v;
}
@ -706,7 +700,7 @@ ModelVolume* ModelObject::add_volume(const ModelVolume &other, TriangleMesh &&me
{
ModelVolume* v = new ModelVolume(this, other, std::move(mesh));
this->volumes.push_back(v);
v->center_geometry();
v->center_geometry_after_creation();
this->invalidate_bounding_box();
return v;
}
@ -827,7 +821,7 @@ TriangleMesh ModelObject::raw_mesh() const
for (const ModelVolume *v : this->volumes)
if (v->is_model_part())
{
TriangleMesh vol_mesh(v->mesh);
TriangleMesh vol_mesh(v->mesh());
vol_mesh.transform(v->get_matrix());
mesh.merge(vol_mesh);
}
@ -840,7 +834,7 @@ TriangleMesh ModelObject::full_raw_mesh() const
TriangleMesh mesh;
for (const ModelVolume *v : this->volumes)
{
TriangleMesh vol_mesh(v->mesh);
TriangleMesh vol_mesh(v->mesh());
vol_mesh.transform(v->get_matrix());
mesh.merge(vol_mesh);
}
@ -854,7 +848,7 @@ const BoundingBoxf3& ModelObject::raw_mesh_bounding_box() const
m_raw_mesh_bounding_box.reset();
for (const ModelVolume *v : this->volumes)
if (v->is_model_part())
m_raw_mesh_bounding_box.merge(v->mesh.transformed_bounding_box(v->get_matrix()));
m_raw_mesh_bounding_box.merge(v->mesh().transformed_bounding_box(v->get_matrix()));
}
return m_raw_mesh_bounding_box;
}
@ -863,7 +857,7 @@ BoundingBoxf3 ModelObject::full_raw_mesh_bounding_box() const
{
BoundingBoxf3 bb;
for (const ModelVolume *v : this->volumes)
bb.merge(v->mesh.transformed_bounding_box(v->get_matrix()));
bb.merge(v->mesh().transformed_bounding_box(v->get_matrix()));
return bb;
}
@ -881,7 +875,7 @@ const BoundingBoxf3& ModelObject::raw_bounding_box() const
for (const ModelVolume *v : this->volumes)
{
if (v->is_model_part())
m_raw_bounding_box.merge(v->mesh.transformed_bounding_box(inst_matrix * v->get_matrix()));
m_raw_bounding_box.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix()));
}
}
return m_raw_bounding_box;
@ -895,7 +889,7 @@ BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_
for (ModelVolume *v : this->volumes)
{
if (v->is_model_part())
bb.merge(v->mesh.transformed_bounding_box(inst_matrix * v->get_matrix()));
bb.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix()));
}
return bb;
}
@ -909,10 +903,10 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) const
for (const ModelVolume *v : this->volumes)
if (v->is_model_part()) {
Transform3d trafo = trafo_instance * v->get_matrix();
const indexed_triangle_set &its = v->mesh.its;
const indexed_triangle_set &its = v->mesh().its;
if (its.vertices.empty()) {
// Using the STL faces.
const stl_file& stl = v->mesh.stl;
const stl_file& stl = v->mesh().stl;
for (const stl_facet &facet : stl.facet_start)
for (size_t j = 0; j < 3; ++ j) {
Vec3d p = trafo * facet.vertex[j].cast<double>();
@ -1038,6 +1032,7 @@ void ModelObject::mirror(Axis axis)
this->invalidate_bounding_box();
}
// This method could only be called before the meshes of this ModelVolumes are not shared!
void ModelObject::scale_mesh(const Vec3d &versor)
{
for (ModelVolume *v : this->volumes)
@ -1061,14 +1056,14 @@ size_t ModelObject::facets_count() const
size_t num = 0;
for (const ModelVolume *v : this->volumes)
if (v->is_model_part())
num += v->mesh.stl.stats.number_of_facets;
num += v->mesh().stl.stats.number_of_facets;
return num;
}
bool ModelObject::needed_repair() const
{
for (const ModelVolume *v : this->volumes)
if (v->is_model_part() && v->mesh.needed_repair())
if (v->is_model_part() && v->mesh().needed_repair())
return true;
return false;
}
@ -1134,11 +1129,12 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
// Transform the mesh by the combined transformation matrix.
// Flip the triangles in case the composite transformation is left handed.
volume->mesh.transform(instance_matrix * volume_matrix, true);
TriangleMesh mesh(volume->mesh());
mesh.transform(instance_matrix * volume_matrix, true);
volume->reset_mesh();
// Perform cut
volume->mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
TriangleMeshSlicer tms(&volume->mesh);
TriangleMeshSlicer tms(&mesh);
tms.cut(float(z), &upper_mesh, &lower_mesh);
// Reset volume transformation except for offset
@ -1157,14 +1153,14 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
if (keep_upper && upper_mesh.facets_count() > 0) {
ModelVolume* vol = upper->add_volume(upper_mesh);
vol->name = volume->name;
vol->config = volume->config;
vol->name = volume->name;
vol->config = volume->config;
vol->set_material(volume->material_id(), *volume->material());
}
if (keep_lower && lower_mesh.facets_count() > 0) {
ModelVolume* vol = lower->add_volume(lower_mesh);
vol->name = volume->name;
vol->config = volume->config;
vol->name = volume->name;
vol->config = volume->config;
vol->set_material(volume->material_id(), *volume->material());
// Compute the lower part instances' bounding boxes to figure out where to place
@ -1232,7 +1228,7 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
}
ModelVolume* volume = this->volumes.front();
TriangleMeshPtrs meshptrs = volume->mesh.split();
TriangleMeshPtrs meshptrs = volume->mesh().split();
for (TriangleMesh *mesh : meshptrs) {
mesh->repair();
@ -1259,12 +1255,6 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
return;
}
void ModelObject::repair()
{
for (ModelVolume *v : this->volumes)
v->mesh.repair();
}
// Support for non-uniform scaling of instances. If an instance is rotated by angles, which are not multiples of ninety degrees,
// then the scaling in world coordinate system is not representable by the Geometry::Transformation structure.
// This situation is solved by baking in the instance transformation into the mesh vertices.
@ -1294,8 +1284,8 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
// Adjust the meshes.
// Transformation to be applied to the meshes.
Eigen::Matrix3d mesh_trafo_3x3 = reference_trafo.get_matrix(true, false, uniform_scaling, ! has_mirrorring).matrix().block<3, 3>(0, 0);
Transform3d volume_offset_correction = this->instances[instance_idx]->get_transformation().get_matrix().inverse() * reference_trafo.get_matrix();
Eigen::Matrix3d mesh_trafo_3x3 = reference_trafo.get_matrix(true, false, uniform_scaling, ! has_mirrorring).matrix().block<3, 3>(0, 0);
Transform3d volume_offset_correction = this->instances[instance_idx]->get_transformation().get_matrix().inverse() * reference_trafo.get_matrix();
for (ModelVolume *model_volume : this->volumes) {
const Geometry::Transformation volume_trafo = model_volume->get_transformation();
bool volume_left_handed = volume_trafo.is_left_handed();
@ -1305,7 +1295,8 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
double volume_new_scaling_factor = volume_uniform_scaling ? volume_trafo.get_scaling_factor().x() : 1.;
// Transform the mesh.
Matrix3d volume_trafo_3x3 = volume_trafo.get_matrix(true, false, volume_uniform_scaling, !volume_has_mirrorring).matrix().block<3, 3>(0, 0);
model_volume->transform_mesh(mesh_trafo_3x3 * volume_trafo_3x3, left_handed != volume_left_handed);
// Following method creates a new shared_ptr<TriangleMesh>
model_volume->transform_this_mesh(mesh_trafo_3x3 * volume_trafo_3x3, left_handed != volume_left_handed);
// Reset the rotation, scaling and mirroring.
model_volume->set_rotation(Vec3d(0., 0., 0.));
model_volume->set_scaling_factor(Vec3d(volume_new_scaling_factor, volume_new_scaling_factor, volume_new_scaling_factor));
@ -1447,7 +1438,7 @@ std::string ModelObject::get_export_filename() const
stl_stats ModelObject::get_object_stl_stats() const
{
if (this->volumes.size() == 1)
return this->volumes[0]->mesh.stl.stats;
return this->volumes[0]->mesh().stl.stats;
stl_stats full_stats;
memset(&full_stats, 0, sizeof(stl_stats));
@ -1458,7 +1449,7 @@ stl_stats ModelObject::get_object_stl_stats() const
if (volume->id() == this->volumes[0]->id())
continue;
const stl_stats& stats = volume->mesh.stl.stats;
const stl_stats& stats = volume->mesh().stl.stats;
// initialize full_stats (for repaired errors)
full_stats.degenerate_facets += stats.degenerate_facets;
@ -1526,30 +1517,30 @@ bool ModelVolume::is_splittable() const
{
// the call mesh.is_splittable() is expensive, so cache the value to calculate it only once
if (m_is_splittable == -1)
m_is_splittable = (int)mesh.is_splittable();
m_is_splittable = (int)this->mesh().is_splittable();
return m_is_splittable == 1;
}
void ModelVolume::center_geometry()
void ModelVolume::center_geometry_after_creation()
{
Vec3d shift = mesh.bounding_box().center();
Vec3d shift = this->mesh().bounding_box().center();
if (!shift.isApprox(Vec3d::Zero()))
{
mesh.translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
m_convex_hull.translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
m_mesh->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
m_convex_hull->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
translate(shift);
}
}
void ModelVolume::calculate_convex_hull()
{
m_convex_hull = mesh.convex_hull_3d();
m_convex_hull = std::make_shared<TriangleMesh>(this->mesh().convex_hull_3d());
}
int ModelVolume::get_mesh_errors_count() const
{
const stl_stats& stats = this->mesh.stl.stats;
const stl_stats& stats = this->mesh().stl.stats;
return stats.degenerate_facets + stats.edges_fixed + stats.facets_removed +
stats.facets_added + stats.facets_reversed + stats.backwards_edges;
@ -1557,7 +1548,7 @@ int ModelVolume::get_mesh_errors_count() const
const TriangleMesh& ModelVolume::get_convex_hull() const
{
return m_convex_hull;
return *m_convex_hull.get();
}
ModelVolumeType ModelVolume::type_from_string(const std::string &s)
@ -1597,7 +1588,7 @@ std::string ModelVolume::type_to_string(const ModelVolumeType t)
// This is useful to assign different materials to different volumes of an object.
size_t ModelVolume::split(unsigned int max_extruders)
{
TriangleMeshPtrs meshptrs = this->mesh.split();
TriangleMeshPtrs meshptrs = this->mesh().split();
if (meshptrs.size() <= 1) {
delete meshptrs.front();
return 1;
@ -1614,7 +1605,7 @@ size_t ModelVolume::split(unsigned int max_extruders)
mesh->repair();
if (idx == 0)
{
this->mesh = std::move(*mesh);
this->set_mesh(std::move(*mesh));
this->calculate_convex_hull();
// Assign a new unique ID, so that a new GLVolume will be generated.
this->set_new_unique_id();
@ -1623,7 +1614,7 @@ size_t ModelVolume::split(unsigned int max_extruders)
this->object->volumes.insert(this->object->volumes.begin() + (++ivolume), new ModelVolume(object, *this, std::move(*mesh)));
this->object->volumes[ivolume]->set_offset(Vec3d::Zero());
this->object->volumes[ivolume]->center_geometry();
this->object->volumes[ivolume]->center_geometry_after_creation();
this->object->volumes[ivolume]->translate(offset);
this->object->volumes[ivolume]->name = name + "_" + std::to_string(idx + 1);
this->object->volumes[ivolume]->config.set_deserialize("extruder", Model::get_auto_extruder_id_as_string(max_extruders));
@ -1689,24 +1680,33 @@ void ModelVolume::mirror(Axis axis)
set_mirror(mirror);
}
// This method could only be called before the meshes of this ModelVolumes are not shared!
void ModelVolume::scale_geometry(const Vec3d& versor)
{
mesh.scale(versor);
m_convex_hull.scale(versor);
m_mesh->scale(versor);
m_convex_hull->scale(versor);
}
void ModelVolume::transform_mesh(const Transform3d &mesh_trafo, bool fix_left_handed)
void ModelVolume::transform_this_mesh(const Transform3d &mesh_trafo, bool fix_left_handed)
{
this->mesh.transform(mesh_trafo, fix_left_handed);
this->m_convex_hull.transform(mesh_trafo, fix_left_handed);
TriangleMesh mesh = this->mesh();
mesh.transform(mesh_trafo, fix_left_handed);
this->set_mesh(std::move(mesh));
TriangleMesh convex_hull = this->get_convex_hull();
convex_hull.transform(mesh_trafo, fix_left_handed);
this->m_convex_hull = std::make_shared<TriangleMesh>(std::move(convex_hull));
// Let the rest of the application know that the geometry changed, so the meshes have to be reloaded.
this->set_new_unique_id();
}
void ModelVolume::transform_mesh(const Matrix3d &matrix, bool fix_left_handed)
void ModelVolume::transform_this_mesh(const Matrix3d &matrix, bool fix_left_handed)
{
this->mesh.transform(matrix, fix_left_handed);
this->m_convex_hull.transform(matrix, fix_left_handed);
TriangleMesh mesh = this->mesh();
mesh.transform(matrix, fix_left_handed);
this->set_mesh(std::move(mesh));
TriangleMesh convex_hull = this->get_convex_hull();
convex_hull.transform(matrix, fix_left_handed);
this->m_convex_hull = std::make_shared<TriangleMesh>(std::move(convex_hull));
// Let the rest of the application know that the geometry changed, so the meshes have to be reloaded.
this->set_new_unique_id();
}