diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index fef1f6e7f..a3247b929 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -241,8 +241,7 @@ int CLI::run(int argc, char **argv) } else if (opt_key == "cut" || opt_key == "cut_x" || opt_key == "cut_y") { std::vector new_models; for (auto &model : m_models) { - model.repair(); - model.translate(0, 0, -model.bounding_box().min.z()); // align to z = 0 + model.translate(0, 0, -model.bounding_box().min.z()); // align to z = 0 size_t num_objects = model.objects.size(); for (size_t i = 0; i < num_objects; ++ i) { @@ -301,8 +300,9 @@ int CLI::run(int argc, char **argv) } } } else if (opt_key == "repair") { - for (auto &model : m_models) - model.repair(); + // Models are repaired by default. + //for (auto &model : m_models) + // model.repair(); } else { boost::nowide::cerr << "error: option not implemented yet: " << opt_key << std::endl; return 1; diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp index be782b1b7..1a7b7965d 100644 --- a/src/admesh/connect.cpp +++ b/src/admesh/connect.cpp @@ -59,7 +59,7 @@ struct HashEdge { // Ensure identical vertex ordering of equal edges. // This method is numerically robust. - if (stl_vertex_lower(*a, *b)) { + if (vertex_lower(*a, *b)) { } else { // This edge is loaded backwards. std::swap(a, b); @@ -110,6 +110,12 @@ struct HashEdge { } return true; } + +private: + inline bool vertex_lower(const stl_vertex &a, const stl_vertex &b) { + return (a(0) != b(0)) ? (a(0) < b(0)) : + ((a(1) != b(1)) ? (a(1) < b(1)) : (a(2) < b(2))); + } }; struct HashTableEdges { @@ -440,7 +446,9 @@ void stl_check_facets_exact(stl_file *stl) stl_facet &facet = stl->facet_start[i]; if (facet.vertex[0] == facet.vertex[1] || facet.vertex[1] == facet.vertex[2] || facet.vertex[0] == facet.vertex[2]) { // Remove the degenerate facet. - facet = stl->facet_start[--stl->stats.number_of_facets]; + facet = stl->facet_start[-- stl->stats.number_of_facets]; + stl->facet_start.pop_back(); + stl->neighbors_start.pop_back(); stl->stats.facets_removed += 1; stl->stats.degenerate_facets += 1; } else @@ -526,23 +534,25 @@ void stl_remove_unconnected_facets(stl_file *stl) assert(false); } - if (facet_number == -- stl->stats.number_of_facets) - // Removing the last face is easy, just forget the last face. - return; - - // Copy the face and neighborship from the last face to facet_number. - stl->facet_start[facet_number] = stl->facet_start[stl->stats.number_of_facets]; - neighbors = stl->neighbors_start[stl->stats.number_of_facets]; - // Update neighborship of faces, which used to point to the last face, now moved to facet_number. - for (int i = 0; i < 3; ++ i) - if (neighbors.neighbor[i] != -1) { - int &other_face_idx = stl->neighbors_start[neighbors.neighbor[i]].neighbor[(neighbors.which_vertex_not[i] + 1) % 3]; - if (other_face_idx != stl->stats.number_of_facets) { - BOOST_LOG_TRIVIAL(info) << "in remove_facet: neighbor = " << other_face_idx << " numfacets = " << stl->stats.number_of_facets << " this is wrong"; - return; + if (facet_number < -- stl->stats.number_of_facets) { + // Removing a face, which was not the last one. + // Copy the face and neighborship from the last face to facet_number. + stl->facet_start[facet_number] = stl->facet_start[stl->stats.number_of_facets]; + neighbors = stl->neighbors_start[stl->stats.number_of_facets]; + // Update neighborship of faces, which used to point to the last face, now moved to facet_number. + for (int i = 0; i < 3; ++ i) + if (neighbors.neighbor[i] != -1) { + int &other_face_idx = stl->neighbors_start[neighbors.neighbor[i]].neighbor[(neighbors.which_vertex_not[i] + 1) % 3]; + if (other_face_idx != stl->stats.number_of_facets) { + BOOST_LOG_TRIVIAL(info) << "in remove_facet: neighbor = " << other_face_idx << " numfacets = " << stl->stats.number_of_facets << " this is wrong"; + return; + } + other_face_idx = facet_number; } - other_face_idx = facet_number; - } + } + + stl->facet_start.pop_back(); + stl->neighbors_start.pop_back(); }; auto remove_degenerate = [stl, remove_facet](int facet) diff --git a/src/admesh/stl.h b/src/admesh/stl.h index fce23eb3f..c419c567b 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -128,6 +128,8 @@ struct indexed_triangle_set void clear() { indices.clear(); vertices.clear(); } std::vector indices; std::vector vertices; + //FIXME add normals once we get rid of the stl_file from TriangleMesh completely. + //std::vector normals }; extern bool stl_open(stl_file *stl, const char *file); @@ -186,7 +188,7 @@ template inline void stl_transform(stl_file *stl, const Eigen::Transform& t) { const Eigen::Matrix r = t.matrix().template block<3, 3>(0, 0); - for (size_t i = 0; i < stl->stats.number_of_facets; ++i) { + for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) { stl_facet &f = stl->facet_start[i]; for (size_t j = 0; j < 3; ++j) f.vertex[j] = (t * f.vertex[j].template cast()).template cast().eval(); @@ -199,7 +201,7 @@ inline void stl_transform(stl_file *stl, const Eigen::Transform inline void stl_transform(stl_file *stl, const Eigen::Matrix& m) { - for (size_t i = 0; i < stl->stats.number_of_facets; ++i) { + for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) { stl_facet &f = stl->facet_start[i]; for (size_t j = 0; j < 3; ++j) f.vertex[j] = (m * f.vertex[j].template cast()).template cast().eval(); @@ -209,6 +211,34 @@ inline void stl_transform(stl_file *stl, const Eigen::Matrix +extern void its_transform(indexed_triangle_set &its, T *trafo3x4) +{ + for (stl_vertex &v_dst : its.vertices) { + stl_vertex &v_dst = face.vertex[i_vertex]; + stl_vertex v_src = v_dst; + v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]); + v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]); + v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]); + } +} + +template +inline void its_transform(indexed_triangle_set &its, const Eigen::Transform& t) +{ + const Eigen::Matrix r = t.matrix().template block<3, 3>(0, 0); + for (stl_vertex &v : its.vertices) + v = (t * v.template cast()).template cast().eval(); +} + +template +inline void its_transform(indexed_triangle_set &its, const Eigen::Matrix& m) +{ + for (stl_vertex &v : its.vertices) + v = (m * v.template cast()).template cast().eval(); +} + extern void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its); extern bool its_write_obj(const indexed_triangle_set &its, const char *file); extern bool its_write_off(const indexed_triangle_set &its, const char *file); @@ -225,10 +255,6 @@ inline void stl_normalize_vector(stl_normal &normal) { else normal *= float(1.0 / length); } -inline bool stl_vertex_lower(const stl_vertex &a, const stl_vertex &b) { - return (a(0) != b(0)) ? (a(0) < b(0)) : - ((a(1) != b(1)) ? (a(1) < b(1)) : (a(2) < b(2))); -} extern void stl_calculate_volume(stl_file *stl); extern void stl_repair(stl_file *stl, bool fixall_flag, bool exact_flag, bool tolerance_flag, float tolerance, bool increment_flag, float increment, bool nearby_flag, int iterations, bool remove_unconnected_flag, bool fill_holes_flag, bool normal_directions_flag, bool normal_values_flag, bool reverse_all_flag, bool verbose_flag); diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp index 24fbe9edc..0cc6e50c7 100644 --- a/src/admesh/stlinit.cpp +++ b/src/admesh/stlinit.cpp @@ -147,7 +147,7 @@ static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first) rewind(fp); char normal_buf[3][32]; - for (uint32_t i = first_facet; i < stl->stats.number_of_facets; ++i) { + for (uint32_t i = first_facet; i < stl->stats.number_of_facets; ++ i) { stl_facet facet; if (stl->stats.type == binary) { diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp index 6fff8a8ed..70f4ffc27 100644 --- a/src/admesh/util.cpp +++ b/src/admesh/util.cpp @@ -108,7 +108,7 @@ void stl_scale_versor(stl_file *stl, const stl_vertex &versor) static void calculate_normals(stl_file *stl) { stl_normal normal; - for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) { + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { stl_calculate_normal(normal, &stl->facet_start[i]); stl_normalize_vector(normal); stl->facet_start[i].normal = normal; diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 654426528..4793586e3 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -1489,10 +1489,10 @@ namespace Slic3r { } // splits volume out of imported geometry - unsigned int triangles_count = volume_data.last_triangle_id - volume_data.first_triangle_id + 1; - ModelVolume* volume = object.add_volume(TriangleMesh()); - stl_file& stl = volume->mesh.stl; - stl.stats.type = inmemory; + TriangleMesh triangle_mesh; + stl_file &stl = triangle_mesh.stl; + unsigned int triangles_count = volume_data.last_triangle_id - volume_data.first_triangle_id + 1; + stl.stats.type = inmemory; stl.stats.number_of_facets = (uint32_t)triangles_count; stl.stats.original_num_facets = (int)stl.stats.number_of_facets; stl_allocate(&stl); @@ -1509,9 +1509,11 @@ namespace Slic3r { } } - stl_get_size(&stl); - volume->mesh.repair(); - volume->center_geometry(); + stl_get_size(&stl); + triangle_mesh.repair(); + + ModelVolume* volume = object.add_volume(std::move(triangle_mesh)); + volume->center_geometry_after_creation(); volume->calculate_convex_hull(); // apply volume's name and config data @@ -1879,11 +1881,14 @@ namespace Slic3r { if (volume == nullptr) continue; + if (!volume->mesh().repaired) + throw std::runtime_error("store_3mf() requires repair()"); + if (!volume->mesh().has_shared_vertices()) + throw std::runtime_error("store_3mf() requires shared vertices"); + volumes_offsets.insert(VolumeToOffsetsMap::value_type(volume, Offsets(vertices_count))).first; - volume->mesh.require_shared_vertices(); - - const indexed_triangle_set &its = volume->mesh.its; + const indexed_triangle_set &its = volume->mesh().its; if (its.vertices.empty()) { add_error("Found invalid mesh"); @@ -1916,7 +1921,7 @@ namespace Slic3r { VolumeToOffsetsMap::iterator volume_it = volumes_offsets.find(volume); assert(volume_it != volumes_offsets.end()); - const indexed_triangle_set &its = volume->mesh.its; + const indexed_triangle_set &its = volume->mesh().its; // updates triangle offsets volume_it->second.first_triangle_id = triangles_count; diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 48887bc78..a33d21c9f 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -522,7 +522,8 @@ void AMFParserContext::endElement(const char * /* name */) case NODE_TYPE_VOLUME: { assert(m_object && m_volume); - stl_file &stl = m_volume->mesh.stl; + TriangleMesh mesh; + stl_file &stl = mesh.stl; stl.stats.type = inmemory; stl.stats.number_of_facets = int(m_volume_facets.size() / 3); stl.stats.original_num_facets = stl.stats.number_of_facets; @@ -533,8 +534,9 @@ void AMFParserContext::endElement(const char * /* name */) memcpy(facet.vertex[v].data(), &m_object_vertices[m_volume_facets[i ++] * 3], 3 * sizeof(float)); } stl_get_size(&stl); - m_volume->mesh.repair(); - m_volume->center_geometry(); + mesh.repair(); + m_volume->set_mesh(std::move(mesh)); + m_volume->center_geometry_after_creation(); m_volume->calculate_convex_hull(); m_volume_facets.clear(); m_volume = nullptr; @@ -923,10 +925,11 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) int num_vertices = 0; for (ModelVolume *volume : object->volumes) { vertices_offsets.push_back(num_vertices); - if (! volume->mesh.repaired) + if (! volume->mesh().repaired) throw std::runtime_error("store_amf() requires repair()"); - volume->mesh.require_shared_vertices(); - const indexed_triangle_set &its = volume->mesh.its; + if (! volume->mesh().has_shared_vertices()) + throw std::runtime_error("store_amf() requires shared vertices"); + const indexed_triangle_set &its = volume->mesh().its; const Transform3d& matrix = volume->get_matrix(); for (size_t i = 0; i < its.vertices.size(); ++i) { stream << " \n"; @@ -955,10 +958,11 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) if (volume->is_modifier()) stream << " 1\n"; stream << " " << ModelVolume::type_to_string(volume->type()) << "\n"; - for (size_t i = 0; i < (int)volume->mesh.its.indices.size(); ++i) { + const indexed_triangle_set &its = volume->mesh().its; + for (size_t i = 0; i < (int)its.indices.size(); ++i) { stream << " \n"; for (int j = 0; j < 3; ++j) - stream << " " << volume->mesh.its.indices[i][j] + vertices_offset << "\n"; + stream << " " << its.indices[i][j] + vertices_offset << "\n"; stream << " \n"; } stream << " \n"; diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 770581c03..113b21503 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -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::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(); @@ -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 + 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(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(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(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(); } diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 41bf5bd4b..0fd1140f0 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -7,7 +7,9 @@ #include "Point.hpp" #include "TriangleMesh.hpp" #include "Slicing.hpp" + #include +#include #include #include #include @@ -261,6 +263,7 @@ public: void rotate(double angle, const Vec3d& axis); void mirror(Axis axis); + // This method could only be called before the meshes of this ModelVolumes are not shared! void scale_mesh(const Vec3d& versor); size_t materials_count() const; @@ -268,7 +271,6 @@ public: bool needed_repair() const; ModelObjectPtrs cut(size_t instance, coordf_t z, bool keep_upper = true, bool keep_lower = true, bool rotate_lower = false); // Note: z is in world coordinates void split(ModelObjectPtrs* new_objects); - void 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. @@ -340,7 +342,12 @@ class ModelVolume : public ModelBase public: std::string name; // The triangular model. - TriangleMesh mesh; + const TriangleMesh& mesh() const { return *m_mesh.get(); } + void set_mesh(const TriangleMesh &mesh) { m_mesh = std::make_shared(mesh); } + void set_mesh(TriangleMesh &&mesh) { m_mesh = std::make_shared(std::move(mesh)); } + void set_mesh(std::shared_ptr &mesh) { m_mesh = mesh; } + void set_mesh(std::unique_ptr &&mesh) { m_mesh = std::move(mesh); } + void reset_mesh() { m_mesh = std::make_shared(); } // Configuration parameters specific to an object model geometry or a modifier volume, // overriding the global Slic3r settings and the ModelObject settings. DynamicPrintConfig config; @@ -377,13 +384,16 @@ public: void rotate(double angle, const Vec3d& axis); void mirror(Axis axis); + // This method could only be called before the meshes of this ModelVolumes are not shared! void scale_geometry(const Vec3d& versor); - // translates the mesh and the convex hull so that the origin of their vertices is in the center of this volume's bounding box - void center_geometry(); + // Translates the mesh and the convex hull so that the origin of their vertices is in the center of this volume's bounding box. + // Attention! This method may only be called just after ModelVolume creation! It must not be called once the TriangleMesh of this ModelVolume is shared! + void center_geometry_after_creation(); void calculate_convex_hull(); const TriangleMesh& get_convex_hull() const; + std::shared_ptr get_convex_hull_shared_ptr() const { return m_convex_hull; } // Get count of errors in the mesh int get_mesh_errors_count() const; @@ -430,18 +440,20 @@ protected: explicit ModelVolume(const ModelVolume &rhs) = default; void set_model_object(ModelObject *model_object) { object = model_object; } - void transform_mesh(const Transform3d& t, bool fix_left_handed); - void transform_mesh(const Matrix3d& m, bool fix_left_handed); + void transform_this_mesh(const Transform3d& t, bool fix_left_handed); + void transform_this_mesh(const Matrix3d& m, bool fix_left_handed); private: // Parent object owning this ModelVolume. - ModelObject* object; + ModelObject* object; + // The triangular model. + std::shared_ptr m_mesh; // Is it an object to be printed, or a modifier volume? - ModelVolumeType m_type; - t_model_material_id m_material_id; + ModelVolumeType m_type; + t_model_material_id m_material_id; // The convex hull of this model's mesh. - TriangleMesh m_convex_hull; - Geometry::Transformation m_transformation; + std::shared_ptr m_convex_hull; + Geometry::Transformation m_transformation; // flag to optimize the checking if the volume is splittable // -1 -> is unknown value (before first cheking) @@ -449,24 +461,24 @@ private: // 1 -> is splittable mutable int m_is_splittable{ -1 }; - ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), m_type(ModelVolumeType::MODEL_PART), object(object) + ModelVolume(ModelObject *object, const TriangleMesh &mesh) : m_mesh(new TriangleMesh(mesh)), m_type(ModelVolumeType::MODEL_PART), object(object) { if (mesh.stl.stats.number_of_facets > 1) calculate_convex_hull(); } ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull) : - mesh(std::move(mesh)), m_convex_hull(std::move(convex_hull)), m_type(ModelVolumeType::MODEL_PART), object(object) {} + m_mesh(new TriangleMesh(std::move(mesh))), m_convex_hull(new TriangleMesh(std::move(convex_hull))), m_type(ModelVolumeType::MODEL_PART), object(object) {} // Copying an existing volume, therefore this volume will get a copy of the ID assigned. ModelVolume(ModelObject *object, const ModelVolume &other) : ModelBase(other), // copy the ID - name(other.name), mesh(other.mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation) + name(other.name), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation) { this->set_material_id(other.material_id()); } // Providing a new mesh, therefore this volume will get a new unique ID assigned. ModelVolume(ModelObject *object, const ModelVolume &other, const TriangleMesh &&mesh) : - name(other.name), mesh(std::move(mesh)), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation) + name(other.name), m_mesh(new TriangleMesh(std::move(mesh))), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation) { this->set_material_id(other.material_id()); if (mesh.stl.stats.number_of_facets > 1) @@ -597,10 +609,6 @@ public: static Model read_from_file(const std::string &input_file, DynamicPrintConfig *config = nullptr, bool add_default_instances = true); static Model read_from_archive(const std::string &input_file, DynamicPrintConfig *config, bool add_default_instances = true); - /// Repair the ModelObjects of the current Model. - /// This function calls repair function on each TriangleMesh of each model object volume - void repair(); - // Add a new ModelObject to this Model, generate a new ID for this ModelObject. ModelObject* add_object(); ModelObject* add_object(const char *name, const char *path, const TriangleMesh &mesh); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 660a2d939..d99aceabf 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1797,7 +1797,7 @@ std::vector PrintObject::_slice_volumes(const std::vector &z, if (! volumes.empty()) { // Compose mesh. //FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them. - TriangleMesh mesh(volumes.front()->mesh); + TriangleMesh mesh(volumes.front()->mesh()); mesh.transform(volumes.front()->get_matrix(), true); assert(mesh.repaired); if (volumes.size() == 1 && mesh.repaired) { @@ -1806,7 +1806,7 @@ std::vector PrintObject::_slice_volumes(const std::vector &z, } for (size_t idx_volume = 1; idx_volume < volumes.size(); ++ idx_volume) { const ModelVolume &model_volume = *volumes[idx_volume]; - TriangleMesh vol_mesh(model_volume.mesh); + TriangleMesh vol_mesh(model_volume.mesh()); vol_mesh.transform(model_volume.get_matrix(), true); mesh.merge(vol_mesh); } @@ -1815,10 +1815,11 @@ std::vector PrintObject::_slice_volumes(const std::vector &z, // apply XY shift mesh.translate(- unscale(m_copies_shift(0)), - unscale(m_copies_shift(1)), 0); // perform actual slicing - TriangleMeshSlicer mslicer; const Print *print = this->print(); auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();}); - mesh.require_shared_vertices(); // TriangleMeshSlicer needs this + // TriangleMeshSlicer needs shared vertices, also this calls the repair() function. + mesh.require_shared_vertices(); + TriangleMeshSlicer mslicer; mslicer.init(&mesh, callback); mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback); m_print->throw_if_canceled(); @@ -1832,7 +1833,7 @@ std::vector PrintObject::_slice_volume(const std::vector &z, std::vector layers; // Compose mesh. //FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them. - TriangleMesh mesh(volume.mesh); + TriangleMesh mesh(volume.mesh()); mesh.transform(volume.get_matrix(), true); if (mesh.repaired) { //FIXME The admesh repair function may break the face connectivity, rather refresh it here as the slicing code relies on it. @@ -1846,7 +1847,8 @@ std::vector PrintObject::_slice_volume(const std::vector &z, TriangleMeshSlicer mslicer; const Print *print = this->print(); auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();}); - mesh.require_shared_vertices(); // TriangleMeshSlicer needs this + // TriangleMeshSlicer needs the shared vertices. + mesh.require_shared_vertices(); mslicer.init(&mesh, callback); mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback); m_print->throw_if_canceled(); diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp index 3a05e9d8a..e1bb4b313 100644 --- a/src/libslic3r/Slicing.cpp +++ b/src/libslic3r/Slicing.cpp @@ -227,7 +227,7 @@ std::vector layer_height_profile_adaptive( as.set_slicing_parameters(slicing_params); for (const ModelVolume *volume : volumes) if (volume->is_model_part()) - as.add_mesh(&volume->mesh); + as.add_mesh(&volume->mesh()); as.prepare(); // 2) Generate layers using the algorithm of @platsch diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 5b0ecbd00..11f45147c 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -82,11 +82,14 @@ TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other) // #define SLIC3R_TRACE_REPAIR -void TriangleMesh::repair() +void TriangleMesh::repair(bool update_shared_vertices) { - if (this->repaired) + if (this->repaired) { + if (update_shared_vertices) + this->require_shared_vertices(); return; - + } + // admesh fails when repairing empty meshes if (this->stl.stats.number_of_facets == 0) return; @@ -97,6 +100,7 @@ void TriangleMesh::repair() #ifdef SLIC3R_TRACE_REPAIR BOOST_LOG_TRIVIAL(trace) << "\tstl_check_faces_exact"; #endif /* SLIC3R_TRACE_REPAIR */ + assert(stl_validate(&this->stl)); stl_check_facets_exact(&stl); assert(stl_validate(&this->stl)); stl.stats.facets_w_1_bad_edge = (stl.stats.connected_facets_2_edge - stl.stats.connected_facets_3_edge); @@ -179,6 +183,12 @@ void TriangleMesh::repair() this->repaired = true; BOOST_LOG_TRIVIAL(debug) << "TriangleMesh::repair() finished"; + + // This call should be quite cheap, a lot of code requires the indexed_triangle_set data structure, + // and it is risky to generate such a structure once the meshes are shared. Do it now. + this->its.clear(); + if (update_shared_vertices) + this->require_shared_vertices(); } float TriangleMesh::volume() @@ -238,8 +248,7 @@ bool TriangleMesh::needed_repair() const void TriangleMesh::WriteOBJFile(const char* output_file) { - stl_generate_shared_vertices(&stl, its); - its_write_obj(its, output_file); + its_write_obj(this->its, output_file); } void TriangleMesh::scale(float factor) @@ -294,6 +303,7 @@ void TriangleMesh::rotate(float angle, const Vec3d& axis) Transform3d m = Transform3d::Identity(); m.rotate(Eigen::AngleAxisd(angle, axis_norm)); stl_transform(&stl, m); + its_transform(its, m); } void TriangleMesh::mirror(const Axis &axis) @@ -311,22 +321,26 @@ void TriangleMesh::mirror(const Axis &axis) void TriangleMesh::transform(const Transform3d& t, bool fix_left_handed) { stl_transform(&stl, t); - this->its.clear(); + its_transform(its, t); if (fix_left_handed && t.matrix().block(0, 0, 3, 3).determinant() < 0.) { // Left handed transformation is being applied. It is a good idea to flip the faces and their normals. - this->repair(); + this->repair(false); stl_reverse_all_facets(&stl); + this->its.clear(); + this->require_shared_vertices(); } } void TriangleMesh::transform(const Matrix3d& m, bool fix_left_handed) { stl_transform(&stl, m); - this->its.clear(); + its_transform(its, m); if (fix_left_handed && m.determinant() < 0.) { // Left handed transformation is being applied. It is a good idea to flip the faces and their normals. - this->repair(); + this->repair(false); stl_reverse_all_facets(&stl); + this->its.clear(); + this->require_shared_vertices(); } } @@ -482,7 +496,6 @@ ExPolygons TriangleMesh::horizontal_projection() const // 2D convex hull of a 3D mesh projected into the Z=0 plane. Polygon TriangleMesh::convex_hull() { - this->require_shared_vertices(); Points pp; pp.reserve(this->its.vertices.size()); for (size_t i = 0; i < this->its.vertices.size(); ++ i) { @@ -519,26 +532,32 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d &trafo) c TriangleMesh TriangleMesh::convex_hull_3d() const { - // Helper struct for qhull: - struct PointForQHull{ - PointForQHull(float x_p, float y_p, float z_p) : x((realT)x_p), y((realT)y_p), z((realT)z_p) {} - realT x, y, z; - }; - std::vector src_vertices; - - // We will now fill the vector with input points for computation: - for (const stl_facet &facet : stl.facet_start) - for (int i = 0; i < 3; ++ i) { - const stl_vertex& v = facet.vertex[i]; - src_vertices.emplace_back(v(0), v(1), v(2)); - } - // The qhull call: orgQhull::Qhull qhull; qhull.disableOutputStream(); // we want qhull to be quiet - try + std::vector src_vertices; + try { - qhull.runQhull("", 3, (int)src_vertices.size(), (const realT*)(src_vertices.data()), "Qt"); + if (this->has_shared_vertices()) { +#if REALfloat + qhull.runQhull("", 3, (int)this->its.vertices.size() / 3, (const realT*)(this->its.vertices.front().data()), "Qt"); +#else + src_vertices.reserve(this->its.vertices() * 3); + // We will now fill the vector with input points for computation: + for (const stl_vertex &v : ths->its.vertices.size()) + for (int i = 0; i < 3; ++ i) + src_vertices.emplace_back(v(i)); + qhull.runQhull("", 3, (int)src_vertices.size() / 3, src_vertices.data(), "Qt"); +#endif + } else { + src_vertices.reserve(this->stl.facet_start.size() * 9); + // We will now fill the vector with input points for computation: + for (const stl_facet &f : this->stl.facet_start) + for (int i = 0; i < 3; ++ i) + for (int j = 0; j < 3; ++ j) + src_vertices.emplace_back(f.vertex[i](j)); + qhull.runQhull("", 3, (int)src_vertices.size() / 3, src_vertices.data(), "Qt"); + } } catch (...) { @@ -566,7 +585,6 @@ TriangleMesh TriangleMesh::convex_hull_3d() const TriangleMesh output_mesh(dst_vertices, facets); output_mesh.repair(); - output_mesh.require_shared_vertices(); return output_mesh; } diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index 75082cfdb..ffd9b7e62 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -33,7 +33,7 @@ public: bool ReadSTLFile(const char* input_file) { return stl_open(&stl, input_file); } bool write_ascii(const char* output_file) { return stl_write_ascii(&this->stl, output_file, ""); } bool write_binary(const char* output_file) { return stl_write_binary(&this->stl, output_file, ""); } - void repair(); + void repair(bool update_shared_vertices = true); float volume(); void check_topology(); bool is_manifold() const { return this->stl.stats.connected_facets_3_edge == (int)this->stl.stats.number_of_facets; } diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 59480de1c..33ab1f5d1 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -241,8 +241,6 @@ GLVolume::GLVolume(float r, float g, float b, float a) : m_transformed_bounding_box_dirty(true) , m_sla_shift_z(0.0) , m_transformed_convex_hull_bounding_box_dirty(true) - , m_convex_hull(nullptr) - , m_convex_hull_owned(false) // geometry_id == 0 -> invalid , geometry_id(std::pair(0, 0)) , extruder_id(0) @@ -268,12 +266,6 @@ GLVolume::GLVolume(float r, float g, float b, float a) set_render_color(r, g, b, a); } -GLVolume::~GLVolume() -{ - if (m_convex_hull_owned) - delete m_convex_hull; -} - void GLVolume::set_render_color(float r, float g, float b, float a) { render_color[0] = r; @@ -335,12 +327,6 @@ void GLVolume::set_color_from_model_volume(const ModelVolume *model_volume) color[3] = model_volume->is_model_part() ? 1.f : 0.5f; } -void GLVolume::set_convex_hull(const TriangleMesh *convex_hull, bool owned) -{ - m_convex_hull = convex_hull; - m_convex_hull_owned = owned; -} - Transform3d GLVolume::world_matrix() const { Transform3d m = m_instance_transformation.get_matrix() * m_volume_transformation.get_matrix(); @@ -377,7 +363,7 @@ const BoundingBoxf3& GLVolume::transformed_convex_hull_bounding_box() const BoundingBoxf3 GLVolume::transformed_convex_hull_bounding_box(const Transform3d &trafo) const { - return (m_convex_hull != nullptr && m_convex_hull->stl.stats.number_of_facets > 0) ? + return (m_convex_hull && m_convex_hull->stl.stats.number_of_facets > 0) ? m_convex_hull->transformed_bounding_box(trafo) : bounding_box.transformed(trafo); } @@ -587,7 +573,7 @@ int GLVolumeCollection::load_object_volume( const ModelVolume *model_volume = model_object->volumes[volume_idx]; const int extruder_id = model_volume->extruder_id(); const ModelInstance *instance = model_object->instances[instance_idx]; - const TriangleMesh& mesh = model_volume->mesh; + const TriangleMesh& mesh = model_volume->mesh(); float color[4]; memcpy(color, GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3); /* if (model_volume->is_support_blocker()) { @@ -613,7 +599,7 @@ int GLVolumeCollection::load_object_volume( if (model_volume->is_model_part()) { // GLVolume will reference a convex hull from model_volume! - v.set_convex_hull(&model_volume->get_convex_hull(), false); + v.set_convex_hull(model_volume->get_convex_hull_shared_ptr()); if (extruder_id != -1) v.extruder_id = extruder_id; } @@ -656,7 +642,10 @@ void GLVolumeCollection::load_object_auxiliary( v.composite_id = GLVolume::CompositeID(obj_idx, - int(milestone), (int)instance_idx.first); v.geometry_id = std::pair(timestamp, model_instance.id().id); // Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance. - v.set_convex_hull((&instance_idx == &instances.back()) ? new TriangleMesh(std::move(convex_hull)) : new TriangleMesh(convex_hull), true); + if (&instance_idx == &instances.back()) + v.set_convex_hull(std::move(convex_hull)); + else + v.set_convex_hull(convex_hull); v.is_modifier = false; v.shader_outside_printer_detection_enabled = (milestone == slaposSupportTree); v.set_instance_transformation(model_instance.get_transformation()); diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 2ca11073b..b9ac668e0 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -10,6 +10,7 @@ #include "slic3r/GUI/GLCanvas3DManager.hpp" #include +#include #ifndef NDEBUG #define HAS_GLSAFE @@ -243,7 +244,6 @@ public: GLVolume(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f); GLVolume(const float *rgba) : GLVolume(rgba[0], rgba[1], rgba[2], rgba[3]) {} - ~GLVolume(); private: Geometry::Transformation m_instance_transformation; @@ -255,10 +255,8 @@ private: mutable BoundingBoxf3 m_transformed_bounding_box; // Whether or not is needed to recalculate the transformed bounding box. mutable bool m_transformed_bounding_box_dirty; - // Pointer to convex hull of the original mesh, if any. - // This object may or may not own the convex hull instance based on m_convex_hull_owned - const TriangleMesh* m_convex_hull; - bool m_convex_hull_owned; + // Convex hull of the volume, if any. + std::shared_ptr m_convex_hull; // Bounding box of this volume, in unscaled coordinates. mutable BoundingBoxf3 m_transformed_convex_hull_bounding_box; // Whether or not is needed to recalculate the transformed convex hull bounding box. @@ -395,7 +393,9 @@ public: double get_sla_shift_z() const { return m_sla_shift_z; } void set_sla_shift_z(double z) { m_sla_shift_z = z; } - void set_convex_hull(const TriangleMesh *convex_hull, bool owned); + void set_convex_hull(std::shared_ptr &convex_hull) { m_convex_hull = convex_hull; } + void set_convex_hull(const TriangleMesh &convex_hull) { m_convex_hull = std::make_shared(convex_hull); } + void set_convex_hull(TriangleMesh &&convex_hull) { m_convex_hull = std::make_shared(std::move(convex_hull)); } int object_idx() const { return this->composite_id.object_id; } int volume_idx() const { return this->composite_id.volume_id; } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index b8ca905d2..f0a40950d 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5498,7 +5498,7 @@ void GLCanvas3D::_load_sla_shells() v.set_instance_offset(unscale(instance.shift(0), instance.shift(1), 0)); v.set_instance_rotation(Vec3d(0.0, 0.0, (double)instance.rotation)); v.set_instance_mirror(X, object.is_left_handed() ? -1. : 1.); - v.set_convex_hull(new TriangleMesh(std::move(mesh.convex_hull_3d())), true); + v.set_convex_hull(mesh.convex_hull_3d()); }; // adds objects' volumes diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index dffa02e95..cbf7a5ef5 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -261,7 +261,7 @@ wxString ObjectList::get_mesh_errors_list(const int obj_idx, const int vol_idx / const stl_stats& stats = vol_idx == -1 ? (*m_objects)[obj_idx]->get_object_stl_stats() : - (*m_objects)[obj_idx]->volumes[vol_idx]->mesh.stl.stats; + (*m_objects)[obj_idx]->volumes[vol_idx]->mesh().stl.stats; std::map error_msg = { { L("degenerate facets"), stats.degenerate_facets }, @@ -1592,7 +1592,7 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode // First (any) GLVolume of the selected instance. They all share the same instance matrix. const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); // Transform the new modifier to be aligned with the print bed. - const BoundingBoxf3 mesh_bb = new_volume->mesh.bounding_box(); + const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box(); new_volume->set_transformation(volume_to_bed_transformation(v->get_instance_transformation(), mesh_bb)); // Set the modifier position. auto offset = (type_name == "Slab") ? diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 89475a058..2a2adcae9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -388,8 +388,7 @@ void GLGizmoSlaSupports::update_mesh() wxBusyCursor wait; // this way we can use that mesh directly. // This mesh does not account for the possible Z up SLA offset. - m_mesh = &m_model_object->volumes.front()->mesh; - const_cast(m_mesh)->require_shared_vertices(); // TriangleMeshSlicer needs this + m_mesh = &m_model_object->volumes.front()->mesh(); m_its = &m_mesh->its; m_current_mesh_model_id = m_model_object->id(); m_editing_mode = false; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 44f77b3f7..18b3078bb 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3565,7 +3565,7 @@ void Plater::export_stl(bool extended, bool selection_only) else { const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); - mesh = model_object->volumes[volume->volume_idx()]->mesh; + mesh = model_object->volumes[volume->volume_idx()]->mesh(); mesh.transform(volume->get_volume_transformation().get_matrix()); mesh.translate(-model_object->origin_translation.cast()); } diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp index a1c8890ef..6a2cc6080 100644 --- a/xs/xsp/Model.xsp +++ b/xs/xsp/Model.xsp @@ -253,7 +253,7 @@ ModelMaterial::attributes() Ref config() %code%{ RETVAL = &THIS->config; %}; Ref mesh() - %code%{ RETVAL = &THIS->mesh; %}; + %code%{ RETVAL = &THIS->mesh(); %}; bool modifier() %code%{ RETVAL = THIS->is_modifier(); %};