From e178d93c61987ee5514dfdb6ae0c061c8f4a6f1b Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sun, 20 Dec 2015 13:35:09 +1300 Subject: [PATCH] Added some metadata to exported AMF --- src/Mod/Mesh/App/AppMeshPy.cpp | 11 ++++++-- src/Mod/Mesh/App/Exporter.cpp | 51 +++++++++++++++++++++++++++------- src/Mod/Mesh/App/Exporter.h | 28 +++++++++++++++---- 3 files changed, 72 insertions(+), 18 deletions(-) diff --git a/src/Mod/Mesh/App/AppMeshPy.cpp b/src/Mod/Mesh/App/AppMeshPy.cpp index f4ee30741..646096f12 100644 --- a/src/Mod/Mesh/App/AppMeshPy.cpp +++ b/src/Mod/Mesh/App/AppMeshPy.cpp @@ -24,6 +24,7 @@ #ifndef _PreComp_ # include # include +# include #endif #include @@ -305,7 +306,13 @@ private: std::unique_ptr exporter; if (exportFormat == MeshIO::AMF) { - exporter.reset( new AmfExporter(EncodedName) ); + std::map meta; + meta["cad"] = App::Application::Config()["ExeName"] + " " + + App::Application::Config()["ExeVersion"]; + meta[App::Application::Config()["ExeName"] + "-buildRevisionHash"] = + App::Application::Config()["BuildRevisionHash"]; + + exporter.reset( new AmfExporter(EncodedName, meta) ); } else { // TODO: How do we handle unknown exportFormats? exporter.reset( new MergeExporter(EncodedName, exportFormat) ); @@ -323,7 +330,7 @@ private: if (obj->getTypeId().isDerivedFrom(meshId)) { exporter->addMesh( static_cast(obj) ); } else if (obj->getTypeId().isDerivedFrom(partId)) { - exporter->addShape( obj->getPropertyByName("Shape"), fTolerance ); + exporter->addPart( obj, fTolerance ); } else { Base::Console().Message("'%s' is not a mesh or shape, export will be ignored.\n", obj->Label.getValue()); } diff --git a/src/Mod/Mesh/App/Exporter.cpp b/src/Mod/Mesh/App/Exporter.cpp index c715498fc..cc6afa23c 100644 --- a/src/Mod/Mesh/App/Exporter.cpp +++ b/src/Mod/Mesh/App/Exporter.cpp @@ -23,8 +23,8 @@ #include "PreCompiled.h" #ifndef _PreComp_ #include - #include #include + #include #endif // #ifndef _PreComp_ #include "Exporter.h" @@ -42,6 +42,17 @@ using namespace Mesh; using namespace MeshCore; +//static +std::string Exporter::xmlEscape(const std::string &input) +{ + std::string out(input); + boost::replace_all(out, "&", "&"); + boost::replace_all(out, "\"", """); + boost::replace_all(out, "'", "'"); + boost::replace_all(out, "<", "<"); + boost::replace_all(out, ">", ">"); + return out; +} MergeExporter::MergeExporter(std::string fileName, MeshIO::Format fmt) :fName(fileName) @@ -110,8 +121,9 @@ bool MergeExporter::addMesh(Mesh::Feature *meshFeat) return true; } -bool MergeExporter::addShape(App::Property *shape, float tol) +bool MergeExporter::addPart(App::DocumentObject *obj, float tol) { + auto *shape(obj->getPropertyByName("Shape")); if (shape && shape->getTypeId().isDerivedFrom(App::PropertyComplexGeoData::getClassTypeId())) { Base::Reference mesh(new MeshObject()); @@ -145,7 +157,9 @@ bool MergeExporter::addShape(App::Property *shape, float tol) return false; } -AmfExporter::AmfExporter(std::string fileName, bool compress) : +AmfExporter::AmfExporter( std::string fileName, + const std::map &meta, + bool compress ) : outputStreamPtr(nullptr), nextObjectIndex(0) { // ask for write permission @@ -173,6 +187,10 @@ AmfExporter::AmfExporter(std::string fileName, bool compress) : if (outputStreamPtr) { *outputStreamPtr << "\n" << "\n"; + for (auto const &metaEntry : meta) { + *outputStreamPtr << "\t" << metaEntry.second << "\n"; + } } } @@ -193,9 +211,10 @@ AmfExporter::~AmfExporter() } } -bool AmfExporter::addShape(App::Property *shape, float tol) +bool AmfExporter::addPart(App::DocumentObject *obj, float tol) { - // TODO: Add meta info, look into a different way to extract mesh with vertex normals + auto *shape(obj->getPropertyByName("Shape")); + // TODO: Look into a different way to extract mesh with vertex normals if (shape && shape->getTypeId().isDerivedFrom(App::PropertyComplexGeoData::getClassTypeId())) { Base::Reference mesh(new MeshObject()); @@ -213,7 +232,10 @@ bool AmfExporter::addShape(App::Property *shape, float tol) MeshCore::MeshKernel kernel = mesh->getKernel(); kernel.Transform(mesh->getTransform()); - return addMesh(kernel); + std::map meta; + meta["name"] = xmlEscape(obj->Label.getStrValue()); + + return addMesh(kernel, meta); } return false; } @@ -225,10 +247,14 @@ bool AmfExporter::addMesh(Mesh::Feature *meshFeat) MeshCore::MeshKernel kernel( mesh.getKernel() ); kernel.Transform(mesh.getTransform()); - return addMesh(kernel); + std::map meta; + meta["name"] = xmlEscape(meshFeat->Label.getStrValue()); + + return addMesh(kernel, meta); } -bool AmfExporter::addMesh(const MeshCore::MeshKernel &kernel) +bool AmfExporter::addMesh(const MeshCore::MeshKernel &kernel, + const std::map &meta) { if (!outputStreamPtr || outputStreamPtr->bad()) { return false; @@ -244,8 +270,13 @@ bool AmfExporter::addMesh(const MeshCore::MeshKernel &kernel) Base::SequencerLauncher seq("Saving...", 2 * numFacets + 1); - *outputStreamPtr << "\t\n" - << "\t\t\n" + *outputStreamPtr << "\t\n"; + + for (auto const &metaEntry : meta) { + *outputStreamPtr << "\t\t" << metaEntry.second << "\n"; + } + *outputStreamPtr << "\t\t\n" << "\t\t\t\n"; const MeshCore::MeshGeomFacet *facet; diff --git a/src/Mod/Mesh/App/Exporter.h b/src/Mod/Mesh/App/Exporter.h index d1c7a2ca6..bd12cef15 100644 --- a/src/Mod/Mesh/App/Exporter.h +++ b/src/Mod/Mesh/App/Exporter.h @@ -25,6 +25,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ + #include #include #endif // #ifndef _PreComp_ @@ -42,7 +43,7 @@ namespace Mesh * Constructors of derived classes are expected to be required, for passing * in the name of output file. * - * Objects are added using the addMesh(), addShape(), etc. + * Objects are added using the addMesh(), addPart(), etc. * * If objects are meant to be combined into a single file, then the file should * be saved from the derived class' destructor. @@ -51,8 +52,13 @@ class Exporter { public: virtual bool addMesh(Mesh::Feature *meshFeat) = 0; - virtual bool addShape(App::Property *shape, float tol) = 0; + virtual bool addPart(App::DocumentObject *obj, float tol) = 0; virtual ~Exporter() {}; + + protected: + /// Does some simple escaping of characters for XML-type exports + //TODO: Use xerces or something instead? + static std::string xmlEscape(const std::string &input); }; /// Creates a single mesh, in a file, from one or more objects @@ -65,7 +71,7 @@ class MergeExporter : public Exporter /// Directly adds a mesh bool addMesh(Mesh::Feature *meshFeat); /// Converts the a Part::Feature to a mesh, adds that mesh - bool addShape(App::Property *shape, float tol); + bool addPart(App::DocumentObject *obj, float tol); protected: MeshObject mergingMesh; std::string fName; @@ -80,14 +86,24 @@ class AmfExporter : public Exporter { public: /// Writes AMF header - AmfExporter(std::string fileName, bool compress = true); + /*! + * meta information passed in is applied at the tag level + */ + AmfExporter(std::string fileName, + const std::map &meta, + bool compress = false); /// Writes AMF footer ~AmfExporter(); bool addMesh(Mesh::Feature *meshFeat); - bool addMesh(const MeshCore::MeshKernel &kernel); - bool addShape(App::Property *shape, float tol); + + /*! + * meta is included for the AMF object created + */ + bool addMesh(const MeshCore::MeshKernel &kernel, + const std::map &meta); + bool addPart(App::DocumentObject *obj, float tol); private: std::ostream *outputStreamPtr;