Browse Source

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

bubnikv 5 years ago
parent
commit
0bb8ee149e

+ 4 - 4
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<Model> 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;

+ 28 - 18
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)

+ 32 - 6
src/admesh/stl.h

@@ -128,6 +128,8 @@ struct indexed_triangle_set
 	void clear() { indices.clear(); vertices.clear(); }
 	std::vector<stl_triangle_vertex_indices> 	indices;
 	std::vector<stl_vertex>       				vertices;
+	//FIXME add normals once we get rid of the stl_file from TriangleMesh completely.
+	//std::vector<stl_normal> 					normals
 };
 
 extern bool stl_open(stl_file *stl, const char *file);
@@ -186,7 +188,7 @@ template<typename T>
 inline void stl_transform(stl_file *stl, const Eigen::Transform<T, 3, Eigen::Affine, Eigen::DontAlign>& t)
 {
 	const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> 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<T>()).template cast<float>().eval();
@@ -199,7 +201,7 @@ inline void stl_transform(stl_file *stl, const Eigen::Transform<T, 3, Eigen::Aff
 template<typename T>
 inline void stl_transform(stl_file *stl, const Eigen::Matrix<T, 3, 3, Eigen::DontAlign>& 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<T>()).template cast<float>().eval();
@@ -209,6 +211,34 @@ inline void stl_transform(stl_file *stl, const Eigen::Matrix<T, 3, 3, Eigen::Don
 	stl_get_size(stl);
 }
 
+
+template<typename T>
+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<typename T>
+inline void its_transform(indexed_triangle_set &its, const Eigen::Transform<T, 3, Eigen::Affine, Eigen::DontAlign>& t)
+{
+	const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> r = t.matrix().template block<3, 3>(0, 0);
+	for (stl_vertex &v : its.vertices)
+		v = (t * v.template cast<T>()).template cast<float>().eval();
+}
+
+template<typename T>
+inline void its_transform(indexed_triangle_set &its, const Eigen::Matrix<T, 3, 3, Eigen::DontAlign>& m)
+{
+	for (stl_vertex &v : its.vertices)
+		v = (m * v.template cast<T>()).template cast<float>().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);

+ 1 - 1
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) {

+ 1 - 1
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;

+ 16 - 11
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;
 
-            volumes_offsets.insert(VolumeToOffsetsMap::value_type(volume, Offsets(vertices_count))).first;
+			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");
 
-			volume->mesh.require_shared_vertices();
+            volumes_offsets.insert(VolumeToOffsetsMap::value_type(volume, Offsets(vertices_count))).first;
 
-            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;

+ 12 - 8
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 << "         <vertex>\n";
@@ -955,10 +958,11 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
             if (volume->is_modifier())
                 stream << "        <metadata type=\"slic3r.modifier\">1</metadata>\n";
             stream << "        <metadata type=\"slic3r.volume_type\">" << ModelVolume::type_to_string(volume->type()) << "</metadata>\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 << "        <triangle>\n";
                 for (int j = 0; j < 3; ++j)
-                stream << "          <v" << j + 1 << ">" << volume->mesh.its.indices[i][j] + vertices_offset << "</v" << j + 1 << ">\n";
+                stream << "          <v" << j + 1 << ">" << its.indices[i][j] + vertices_offset << "</v" << j + 1 << ">\n";
                 stream << "        </triangle>\n";
             }
             stream << "      </volume>\n";

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

+ 27 - 19
src/libslic3r/Model.hpp

@@ -7,7 +7,9 @@
 #include "Point.hpp"
 #include "TriangleMesh.hpp"
 #include "Slicing.hpp"
+
 #include <map>
+#include <memory>
 #include <string>
 #include <utility>
 #include <vector>
@@ -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<TriangleMesh>(mesh); }
+    void                set_mesh(TriangleMesh &&mesh) { m_mesh = std::make_shared<TriangleMesh>(std::move(mesh)); }
+    void                set_mesh(std::shared_ptr<TriangleMesh> &mesh) { m_mesh = mesh; }
+    void                set_mesh(std::unique_ptr<TriangleMesh> &&mesh) { m_mesh = std::move(mesh); }
+	void				reset_mesh() { m_mesh = std::make_shared<TriangleMesh>(); }
     // 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<const TriangleMesh> 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<TriangleMesh>   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<TriangleMesh>   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);

+ 8 - 6
src/libslic3r/PrintObject.cpp

@@ -1797,7 +1797,7 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &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<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &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<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z,
             // apply XY shift
             mesh.translate(- unscale<float>(m_copies_shift(0)), - unscale<float>(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<ExPolygons> PrintObject::_slice_volume(const std::vector<float> &z,
     std::vector<ExPolygons> 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<ExPolygons> PrintObject::_slice_volume(const std::vector<float> &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();

Some files were not shown because too many files changed in this diff