From 580c124b2203a9650289d8c8fb6450a3caeb8ee2 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 31 Aug 2022 17:07:44 +0200 Subject: [PATCH] Mesh: improve 3MF support --- src/Mod/Mesh/App/Core/IO/Writer3MF.cpp | 137 ++++++++++++++++--------- src/Mod/Mesh/App/Core/IO/Writer3MF.h | 44 ++++++-- src/Mod/Mesh/App/Core/MeshIO.cpp | 6 +- 3 files changed, 130 insertions(+), 57 deletions(-) diff --git a/src/Mod/Mesh/App/Core/IO/Writer3MF.cpp b/src/Mod/Mesh/App/Core/IO/Writer3MF.cpp index bfdd9f530f..f6b09fcd4d 100644 --- a/src/Mod/Mesh/App/Core/IO/Writer3MF.cpp +++ b/src/Mod/Mesh/App/Core/IO/Writer3MF.cpp @@ -24,31 +24,61 @@ #include "PreCompiled.h" #ifndef _PreComp_ # include +# include #endif #include "Writer3MF.h" +#include "Core/Evaluation.h" #include "Core/MeshKernel.h" #include -#include -#include using namespace MeshCore; - -void Writer3MF::SetTransform(const Base::Matrix4D& mat) +Writer3MF::Writer3MF(std::ostream &str) + : zip(str) + , objectIndex(0) { - transform = mat; - if (mat != Base::Matrix4D()) - applyTransform = true; + zip.putNextEntry("3D/3dmodel.model"); + Initialize(zip); } -bool Writer3MF::Save(std::ostream &str) const +Writer3MF::Writer3MF(const std::string &filename) + : zip(filename) + , objectIndex(0) { - zipios::ZipOutputStream zip(str); zip.putNextEntry("3D/3dmodel.model"); - if (!SaveModel(zip)) - return false; + Initialize(zip); +} + +void Writer3MF::Initialize(std::ostream &str) +{ + str << "\n" + "\n" + " FreeCAD\n"; + str << Base::blanks(1) << "\n"; +} + +void Writer3MF::Finish(std::ostream &str) +{ + str << Base::blanks(1) << "\n"; + str << Base::blanks(1) << "\n"; + for (const auto& it : items) + str << Base::blanks(2) << it; + str << Base::blanks(1) << "\n"; + str << "\n"; +} + +bool Writer3MF::AddMesh(const MeshKernel& mesh, const Base::Matrix4D& mat) +{ + int id = ++objectIndex; + SaveBuildItem(id, mat); + return SaveObject(zip, id, mesh); +} + +bool Writer3MF::Save() +{ + Finish(zip); zip.closeEntry(); zip.putNextEntry("_rels/.rels"); @@ -63,59 +93,74 @@ bool Writer3MF::Save(std::ostream &str) const return true; } -bool Writer3MF::SaveModel(std::ostream &str) const +bool Writer3MF::SaveObject(std::ostream &str, int id, const MeshKernel& mesh) const { - const MeshPointArray& rPoints = kernel.GetPoints(); - const MeshFacetArray& rFacets = kernel.GetFacets(); + const MeshPointArray& rPoints = mesh.GetPoints(); + const MeshFacetArray& rFacets = mesh.GetFacets(); if (!str || str.bad()) return false; - str << "\n" - << "\n" - << "FreeCAD\n"; - str << Base::blanks(2) << "\n"; - str << Base::blanks(4) << "\n"; - str << Base::blanks(6) << "\n"; + str << Base::blanks(2) << "\n"; + str << Base::blanks(3) << "\n"; // vertices - str << Base::blanks(8) << "\n"; - Base::Vector3f pt; + str << Base::blanks(4) << "\n"; std::size_t index = 0; for (MeshPointArray::_TConstIterator it = rPoints.begin(); it != rPoints.end(); ++it, ++index) { - pt.Set(it->x, it->y, it->z); - if (this->applyTransform) { - this->transform.multVec(pt, pt); - } - str << Base::blanks(10) << "\n"; + str << Base::blanks(5) << "x + << "\" y=\"" << it->y + << "\" z=\"" << it->z + << "\" />\n"; } - str << Base::blanks(8) << "\n"; + str << Base::blanks(4) << "\n"; // facet indices - str << Base::blanks(8) << "\n"; + str << Base::blanks(4) << "\n"; for (MeshFacetArray::_TConstIterator it = rFacets.begin(); it != rFacets.end(); ++it) { - str << Base::blanks(10) << "_aulPoints[0] - << "\" v2=\"" << it->_aulPoints[1] - << "\" v3=\"" << it->_aulPoints[2] - << "\" />\n"; + str << Base::blanks(5) << "_aulPoints[0] + << "\" v2=\"" << it->_aulPoints[1] + << "\" v3=\"" << it->_aulPoints[2] + << "\" />\n"; } - str << Base::blanks(8) << "\n"; + str << Base::blanks(4) << "\n"; + + str << Base::blanks(3) << "\n"; + str << Base::blanks(2) << "\n"; - str << Base::blanks(6) << "\n"; - str << Base::blanks(4) << "\n"; - str << Base::blanks(2) << "\n"; - str << Base::blanks(2) << "\n"; - str << Base::blanks(4) << "\n"; - str << Base::blanks(2) << "\n"; - str << "\n"; return true; } +std::string Writer3MF::GetType(const MeshKernel& mesh) const +{ + if (MeshEvalSolid(mesh).Evaluate()) + return "model"; + else + return "surface"; +} + +void Writer3MF::SaveBuildItem(int id, const Base::Matrix4D& mat) +{ + std::stringstream str; + str << "\n"; + items.push_back(str.str()); +} + +std::string Writer3MF::DumpMatrix(const Base::Matrix4D& mat) const +{ + // The matrix representation in the specs is the transposed version of Matrix4D + // This means that for the 3x3 sub-matrix the indices must be swapped + // + // 3D Manufacturing Format / Core Specification & Reference Guide v1.2.3 + // Chapter: 3.3 3D Matrices (page 9) + std::stringstream str; + str << mat[0][0] << " " << mat[1][0] << " " << mat[2][0] << " " + << mat[0][1] << " " << mat[1][1] << " " << mat[2][1] << " " + << mat[0][2] << " " << mat[1][2] << " " << mat[2][2] << " " + << mat[0][3] << " " << mat[1][3] << " " << mat[2][3]; + return str.str(); +} + bool Writer3MF::SaveRels(std::ostream &str) const { str << "\n" diff --git a/src/Mod/Mesh/App/Core/IO/Writer3MF.h b/src/Mod/Mesh/App/Core/IO/Writer3MF.h index 4f7ffb8b75..8dbfe0e103 100644 --- a/src/Mod/Mesh/App/Core/IO/Writer3MF.h +++ b/src/Mod/Mesh/App/Core/IO/Writer3MF.h @@ -27,6 +27,7 @@ #include #include "Core/Elements.h" +#include namespace MeshCore { @@ -36,21 +37,48 @@ class MeshKernel; class MeshExport Writer3MF { public: - Writer3MF(const MeshKernel &mesh): - kernel(mesh) {} + /*! + * \brief Writer3MF + * Passes an output stream to the constructor. + * \param str + */ + Writer3MF(std::ostream &str); - void SetTransform(const Base::Matrix4D&); - bool Save(std::ostream &str) const; + /*! + * \brief Writer3MF + * Passes a file name to the constructor + * \param filename + */ + Writer3MF(const std::string &filename); + + /*! + * \brief Add a mesh object resource to the 3MF file. + * \param mesh The mesh object to be written + * \param mat The placement of the mesh object + * \return true if the added mesh could be written successfully, false otherwise. + */ + bool AddMesh(const MeshKernel& mesh, const Base::Matrix4D& mat); + /*! + * \brief After having added the mesh objects with \ref AddMesh save the meta-information + * to the 3MF file. + * \return true if the data could be written successfully, false otherwise. + */ + bool Save(); private: - bool SaveModel(std::ostream &str) const; + void Initialize(std::ostream &str); + void Finish(std::ostream &str); + std::string GetType(const MeshKernel& mesh) const; + void SaveBuildItem(int id, const Base::Matrix4D& mat); + std::string DumpMatrix(const Base::Matrix4D& mat) const; + bool SaveObject(std::ostream &str, int id, const MeshKernel& mesh) const; bool SaveRels(std::ostream &str) const; bool SaveContent(std::ostream &str) const; private: - bool applyTransform = false; - Base::Matrix4D transform; - const MeshKernel &kernel; + zipios::ZipOutputStream zip; + int objectIndex; + std::vector items; }; } // namespace MeshCore diff --git a/src/Mod/Mesh/App/Core/MeshIO.cpp b/src/Mod/Mesh/App/Core/MeshIO.cpp index b79c99cb30..46356904d7 100644 --- a/src/Mod/Mesh/App/Core/MeshIO.cpp +++ b/src/Mod/Mesh/App/Core/MeshIO.cpp @@ -2883,9 +2883,9 @@ void MeshOutput::SaveXML (Base::Writer &writer) const /** Saves the mesh object into a 3MF file. */ bool MeshOutput::Save3MF(std::ostream &str) const { - Writer3MF writer(_rclMesh); - writer.SetTransform(_transform); - return writer.Save(str); + Writer3MF writer(str); + writer.AddMesh(_rclMesh, _transform); + return writer.Save(); } /** Writes an IDTF file. */