|
@@ -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();
|
|
|
}
|