mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	Improved accuracy of ModelVolume matrix store / restore
into the 3MF / AMF. Improved accuracy of ModelVolume's mesh transform back from Object's coordinate space to its own coordinate space after reloading from 3MF / AMF.
This commit is contained in:
		
							parent
							
								
									2bf472988b
								
							
						
					
					
						commit
						26b7dbd6f5
					
				
					 5 changed files with 73 additions and 68 deletions
				
			
		|  | @ -34,10 +34,12 @@ namespace pt = boost::property_tree; | |||
| // VERSION NUMBERS
 | ||||
| // 0 : .3mf, files saved by older slic3r or other applications. No version definition in them.
 | ||||
| // 1 : Introduction of 3mf versioning. No other change in data saved into 3mf files.
 | ||||
| // 2 : Meshes saved in their local system; Volumes' matrices and source data added to Metadata/Slic3r_PE_model.config file.
 | ||||
| // 2 : Volumes' matrices and source data added to Metadata/Slic3r_PE_model.config file, meshes transformed back to their coordinate system on loading.
 | ||||
| // WARNING !! -> the version number has been rolled back to 1
 | ||||
| //               the next change should use 3
 | ||||
| const unsigned int VERSION_3MF = 1; | ||||
| // Allow loading version 2 file as well.
 | ||||
| const unsigned int VERSION_3MF_COMPATIBLE = 2; | ||||
| const char* SLIC3RPE_3MF_VERSION = "slic3rpe:Version3mf"; // definition of the metadata name saved into .model file
 | ||||
| 
 | ||||
| const std::string MODEL_FOLDER = "3D/"; | ||||
|  | @ -1513,7 +1515,7 @@ namespace Slic3r { | |||
|         { | ||||
|             m_version = (unsigned int)atoi(m_curr_characters.c_str()); | ||||
| 
 | ||||
|             if (m_check_version && (m_version > VERSION_3MF)) | ||||
|             if (m_check_version && (m_version > VERSION_3MF_COMPATIBLE)) | ||||
|             { | ||||
|                 // std::string msg = _(L("The selected 3mf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible."));
 | ||||
|                 // throw version_error(msg.c_str());
 | ||||
|  | @ -1699,20 +1701,19 @@ namespace Slic3r { | |||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             Slic3r::Geometry::Transformation transform; | ||||
|             if (m_version > 1) | ||||
|             Transform3d volume_matrix_to_object = Transform3d::Identity(); | ||||
|             bool        has_transform 		    = false; | ||||
|             // extract the volume transformation from the volume's metadata, if present
 | ||||
|             for (const Metadata& metadata : volume_data.metadata) | ||||
|             { | ||||
|                 // extract the volume transformation from the volume's metadata, if present
 | ||||
|                 for (const Metadata& metadata : volume_data.metadata) | ||||
|                 if (metadata.key == MATRIX_KEY) | ||||
|                 { | ||||
|                     if (metadata.key == MATRIX_KEY) | ||||
|                     { | ||||
|                         transform.set_from_string(metadata.value); | ||||
|                         break; | ||||
|                     } | ||||
|                     volume_matrix_to_object = Slic3r::Geometry::transform3d_from_string(metadata.value); | ||||
|                     has_transform 			= ! volume_matrix_to_object.isApprox(Transform3d::Identity(), 1e-10); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             Transform3d inv_matrix = transform.get_matrix().inverse(); | ||||
|             Transform3d inv_matrix = volume_matrix_to_object.inverse(); | ||||
| 
 | ||||
|             // splits volume out of imported geometry
 | ||||
| 			TriangleMesh triangle_mesh; | ||||
|  | @ -1733,10 +1734,10 @@ namespace Slic3r { | |||
|                 { | ||||
|                     unsigned int tri_id = geometry.triangles[src_start_id + ii + v] * 3; | ||||
|                     Vec3f vertex(geometry.vertices[tri_id + 0], geometry.vertices[tri_id + 1], geometry.vertices[tri_id + 2]); | ||||
|                     if (m_version > 1) | ||||
|                     facet.vertex[v] = has_transform ? | ||||
|                         // revert the vertices to the original mesh reference system
 | ||||
|                         vertex = (inv_matrix * vertex.cast<double>()).cast<float>(); | ||||
|                     ::memcpy(facet.vertex[v].data(), (const void*)vertex.data(), 3 * sizeof(float)); | ||||
|                         (inv_matrix * vertex.cast<double>()).cast<float>() : | ||||
|                         vertex; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|  | @ -1745,8 +1746,8 @@ namespace Slic3r { | |||
| 
 | ||||
| 			ModelVolume* volume = object.add_volume(std::move(triangle_mesh)); | ||||
|             // apply the volume matrix taken from the metadata, if present
 | ||||
|             if (m_version > 1) | ||||
|                 volume->set_transformation(transform); | ||||
|             if (has_transform) | ||||
|                 volume->set_transformation(Slic3r::Geometry::Transformation(volume_matrix_to_object)); | ||||
|             volume->calculate_convex_hull(); | ||||
| 
 | ||||
|             // apply the remaining volume's metadata
 | ||||
|  | @ -2471,6 +2472,9 @@ namespace Slic3r { | |||
|     bool _3MF_Exporter::_add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data) | ||||
|     { | ||||
|         std::stringstream stream; | ||||
|         // Store mesh transformation in full precision, as the volumes are stored transformed and they need to be transformed back
 | ||||
|         // when loaded as accurately as possible.
 | ||||
| 		stream << std::setprecision(std::numeric_limits<double>::max_digits10); | ||||
|         stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; | ||||
|         stream << "<" << CONFIG_TAG << ">\n"; | ||||
| 
 | ||||
|  |  | |||
|  | @ -41,10 +41,11 @@ namespace pt = boost::property_tree; | |||
| //     Added x and y components of rotation
 | ||||
| //     Added x, y and z components of scale
 | ||||
| //     Added x, y and z components of mirror
 | ||||
| // 3 : Meshes saved in their local system; Added volumes' matrices and source data
 | ||||
| // 3 : Added volumes' matrices and source data, meshes transformed back to their coordinate system on loading.
 | ||||
| // WARNING !! -> the version number has been rolled back to 2
 | ||||
| //               the next change should use 4
 | ||||
| const unsigned int VERSION_AMF = 2; | ||||
| const unsigned int VERSION_AMF_COMPATIBLE = 3; | ||||
| const char* SLIC3RPE_AMF_VERSION = "slic3rpe_amf_version"; | ||||
| 
 | ||||
| const char* SLIC3R_CONFIG_TYPE = "slic3rpe_config"; | ||||
|  | @ -230,6 +231,8 @@ struct AMFParserContext | |||
|     ModelVolume             *m_volume; | ||||
|     // Faces collected for the current m_volume.
 | ||||
|     std::vector<int>         m_volume_facets; | ||||
|     // Transformation matrix of a volume mesh from its coordinate system to Object's coordinate system.
 | ||||
|     Transform3d 			 m_volume_transform; | ||||
|     // Current material allocated for an amf/metadata subtree.
 | ||||
|     ModelMaterial           *m_material; | ||||
|     // Current instance allocated for an amf/constellation/instance subtree.
 | ||||
|  | @ -321,6 +324,7 @@ void AMFParserContext::startElement(const char *name, const char **atts) | |||
| 			else if (strcmp(name, "volume") == 0) { | ||||
| 				assert(! m_volume); | ||||
|                 m_volume = m_object->add_volume(TriangleMesh()); | ||||
|                 m_volume_transform = Transform3d::Identity(); | ||||
|                 node_type_new = NODE_TYPE_VOLUME; | ||||
| 			} | ||||
|         } else if (m_path[2] == NODE_TYPE_INSTANCE) { | ||||
|  | @ -580,27 +584,25 @@ void AMFParserContext::endElement(const char * /* name */) | |||
|         stl.stats.original_num_facets = stl.stats.number_of_facets; | ||||
|         stl_allocate(&stl); | ||||
| 
 | ||||
|         Slic3r::Geometry::Transformation transform; | ||||
|         if (m_version > 2) | ||||
|             transform = m_volume->get_transformation(); | ||||
| 
 | ||||
|         Transform3d inv_matrix = transform.get_matrix().inverse(); | ||||
| 
 | ||||
|         bool has_transform = ! m_volume_transform.isApprox(Transform3d::Identity(), 1e-10); | ||||
|         Transform3d inv_matrix = m_volume_transform.inverse(); | ||||
|         for (size_t i = 0; i < m_volume_facets.size();) { | ||||
|             stl_facet &facet = stl.facet_start[i/3]; | ||||
|             for (unsigned int v = 0; v < 3; ++v) | ||||
|             { | ||||
|                 unsigned int tri_id = m_volume_facets[i++] * 3; | ||||
|                 Vec3f vertex(m_object_vertices[tri_id + 0], m_object_vertices[tri_id + 1], m_object_vertices[tri_id + 2]); | ||||
|                 if (m_version > 2) | ||||
|                 facet.vertex[v] = has_transform ? | ||||
|                     // revert the vertices to the original mesh reference system
 | ||||
|                     vertex = (inv_matrix * vertex.cast<double>()).cast<float>(); | ||||
|                 ::memcpy((void*)facet.vertex[v].data(), (const void*)vertex.data(), 3 * sizeof(float)); | ||||
|                     (inv_matrix * vertex.cast<double>()).cast<float>() : | ||||
|                     vertex; | ||||
|             } | ||||
|         } | ||||
|         }         | ||||
|         stl_get_size(&stl); | ||||
|         mesh.repair(); | ||||
| 		m_volume->set_mesh(std::move(mesh)); | ||||
| 		if (has_transform) | ||||
| 			m_volume->set_transformation(m_volume_transform); | ||||
|         if (m_volume->source.input_file.empty() && (m_volume->type() == ModelVolumeType::MODEL_PART)) | ||||
|         { | ||||
|             m_volume->source.object_idx = (int)m_model.objects.size() - 1; | ||||
|  | @ -720,9 +722,7 @@ void AMFParserContext::endElement(const char * /* name */) | |||
|                     m_volume->set_type(ModelVolume::type_from_string(m_value[1])); | ||||
|                 } | ||||
|                 else if (strcmp(opt_key, "matrix") == 0) { | ||||
|                     Geometry::Transformation transform; | ||||
|                     transform.set_from_string(m_value[1]); | ||||
|                     m_volume->set_transformation(transform); | ||||
|                     m_volume_transform = Slic3r::Geometry::transform3d_from_string(m_value[1]); | ||||
|                 } | ||||
|                 else if (strcmp(opt_key, "source_file") == 0) { | ||||
|                     m_volume->source.input_file = m_value[1]; | ||||
|  | @ -912,7 +912,7 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi | |||
| 
 | ||||
|     ctx.endDocument(); | ||||
| 
 | ||||
|     if (check_version && (ctx.m_version > VERSION_AMF)) | ||||
|     if (check_version && (ctx.m_version > VERSION_AMF_COMPATIBLE)) | ||||
|     { | ||||
|         // std::string msg = _(L("The selected amf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible."));
 | ||||
|         // throw std::runtime_error(msg.c_str());
 | ||||
|  | @ -1148,6 +1148,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) | |||
|             stream << "        <metadata type=\"slic3r.volume_type\">" << ModelVolume::type_to_string(volume->type()) << "</metadata>\n"; | ||||
|             stream << "        <metadata type=\"slic3r.matrix\">"; | ||||
|             const Transform3d& matrix = volume->get_matrix(); | ||||
| 			stream << std::setprecision(std::numeric_limits<double>::max_digits10); | ||||
|             for (int r = 0; r < 4; ++r) | ||||
|             { | ||||
|                 for (int c = 0; c < 4; ++c) | ||||
|  | @ -1167,6 +1168,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) | |||
|                 stream << "        <metadata type=\"slic3r.source_offset_y\">" << volume->source.mesh_offset(1) << "</metadata>\n"; | ||||
|                 stream << "        <metadata type=\"slic3r.source_offset_z\">" << volume->source.mesh_offset(2) << "</metadata>\n"; | ||||
|             } | ||||
| 			stream << std::setprecision(std::numeric_limits<float>::max_digits10); | ||||
|             const indexed_triangle_set &its = volume->mesh().its; | ||||
|             for (size_t i = 0; i < its.indices.size(); ++i) { | ||||
|                 stream << "        <triangle>\n"; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv