diff --git a/src/Mod/Mesh/App/AppMeshPy.cpp b/src/Mod/Mesh/App/AppMeshPy.cpp index 367959169..0b25c12d3 100644 --- a/src/Mod/Mesh/App/AppMeshPy.cpp +++ b/src/Mod/Mesh/App/AppMeshPy.cpp @@ -331,21 +331,28 @@ private: exporter.reset( new MergeExporter(outputFileName, exportFormat) ); } - Base::Type meshId = Base::Type::fromName("Mesh::Feature"); - Base::Type partId = Base::Type::fromName("Part::Feature"); + const auto meshFeatId( Base::Type::fromName("Mesh::Feature") ); + const auto partFeatId( Base::Type::fromName("Part::Feature") ); + const auto appPartId( Base::Type::fromName("App::Part") ); + const auto appDOGId( Base::Type::fromName("App::DocumentObjectGroup") ); Py::Sequence list(objects); for (auto it : list) { - PyObject* item = it.ptr(); + PyObject *item = it.ptr(); if (PyObject_TypeCheck(item, &(App::DocumentObjectPy::Type))) { - App::DocumentObject* obj( static_cast(item)->getDocumentObjectPtr() ); + auto obj( static_cast(item)->getDocumentObjectPtr() ); - if (obj->getTypeId().isDerivedFrom(meshId)) { - exporter->addMesh( static_cast(obj) ); - } else if (obj->getTypeId().isDerivedFrom(partId)) { - exporter->addPart( obj, fTolerance ); + if (obj->getTypeId().isDerivedFrom(meshFeatId)) { + exporter->addMeshFeat( obj ); + } else if (obj->getTypeId().isDerivedFrom(partFeatId)) { + exporter->addPartFeat( obj, fTolerance ); + } else if ( obj->getTypeId().isDerivedFrom(appPartId) || + obj->getTypeId().isDerivedFrom(appDOGId) ) { + exporter->addAppGroup( obj, fTolerance ); } else { - Base::Console().Message("'%s' is not a mesh or shape, export will be ignored.\n", obj->Label.getValue()); + Base::Console().Message( + "'%s' is of type %s, and can not be exported as a mesh.\n", + obj->Label.getValue(), obj->getTypeId().getName() ); } } } diff --git a/src/Mod/Mesh/App/Exporter.cpp b/src/Mod/Mesh/App/Exporter.cpp index ea040e9c8..4fbab116b 100644 --- a/src/Mod/Mesh/App/Exporter.cpp +++ b/src/Mod/Mesh/App/Exporter.cpp @@ -37,6 +37,8 @@ #include "Base/Stream.h" #include "Base/Tools.h" +#include "App/Part.h" + #include using namespace Mesh; @@ -54,7 +56,32 @@ std::string Exporter::xmlEscape(const std::string &input) return out; } -MergeExporter::MergeExporter(std::string fileName, MeshIO::Format fmt) +bool Exporter::addAppGroup(App::DocumentObject *obj, float tol) +{ + const auto meshFeatId( Base::Type::fromName("Mesh::Feature") ); + const auto partFeatId( Base::Type::fromName("Part::Feature") ); + const auto appPartId( Base::Type::fromName("App::Part") ); + const auto appDOGId( Base::Type::fromName("App::DocumentObjectGroup") ); + + auto ret(true); + + for (auto it : static_cast(obj)->getOutList()) { + if (it->getTypeId().isDerivedFrom(meshFeatId)) { + ret &= addMeshFeat(it); + } else if (it->getTypeId().isDerivedFrom(partFeatId)) { + ret &= addPartFeat(it, tol); + } else if ( it->getTypeId().isDerivedFrom(appPartId) || + it->getTypeId().isDerivedFrom(appDOGId) ) { + // Recurse + ret &= addAppGroup(it, tol); + } + } + + return ret; +} + + +MergeExporter::MergeExporter(std::string fileName, MeshIO::Format) :fName(fileName) { } @@ -72,9 +99,9 @@ MergeExporter::~MergeExporter() } -bool MergeExporter::addMesh(Mesh::Feature *meshFeat) +bool MergeExporter::addMeshFeat(App::DocumentObject *obj) { - const MeshObject &mesh( meshFeat->Mesh.getValue() ); + const MeshObject &mesh( static_cast(obj)->Mesh.getValue() ); MeshCore::MeshKernel kernel( mesh.getKernel() ); kernel.Transform(mesh.getTransform()); @@ -114,14 +141,14 @@ bool MergeExporter::addMesh(Mesh::Feature *meshFeat) indices.resize(mergingMesh.countFacets() - countFacets); std::generate(indices.begin(), indices.end(), Base::iotaGen(countFacets)); Segment segm(&mergingMesh, indices, true); - segm.setName(meshFeat->Label.getValue()); + segm.setName(obj->Label.getValue()); mergingMesh.addSegment(segm); } return true; } -bool MergeExporter::addPart(App::DocumentObject *obj, float tol) +bool MergeExporter::addPartFeat(App::DocumentObject *obj, float tol) { auto *shape(obj->getPropertyByName("Shape")); if (shape && shape->getTypeId().isDerivedFrom(App::PropertyComplexGeoData::getClassTypeId())) { @@ -211,7 +238,7 @@ AmfExporter::~AmfExporter() } } -bool AmfExporter::addPart(App::DocumentObject *obj, float tol) +bool AmfExporter::addPartFeat(App::DocumentObject *obj, float tol) { auto *shape(obj->getPropertyByName("Shape")); // TODO: Look into a different way to extract mesh with vertex normals @@ -240,15 +267,15 @@ bool AmfExporter::addPart(App::DocumentObject *obj, float tol) return false; } -bool AmfExporter::addMesh(Mesh::Feature *meshFeat) +bool AmfExporter::addMeshFeat(App::DocumentObject *obj) { // TODO: Add name, colour, etc. from the mesh feature - const MeshObject &mesh( meshFeat->Mesh.getValue() ); + const MeshObject &mesh( static_cast(obj)->Mesh.getValue() ); MeshCore::MeshKernel kernel( mesh.getKernel() ); kernel.Transform(mesh.getTransform()); std::map meta; - meta["name"] = xmlEscape(meshFeat->Label.getStrValue()); + meta["name"] = xmlEscape(obj->Label.getStrValue()); return addMesh(kernel, meta); } diff --git a/src/Mod/Mesh/App/Exporter.h b/src/Mod/Mesh/App/Exporter.h index 67d9ea9d2..cbb9db1d1 100644 --- a/src/Mod/Mesh/App/Exporter.h +++ b/src/Mod/Mesh/App/Exporter.h @@ -40,7 +40,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(), addPart(), etc. + * Objects are added using the addMeshFeat(), addPartFeat(), etc. * * If objects are meant to be combined into a single file, then the file should * be saved from the derived class' destructor. @@ -48,9 +48,16 @@ namespace Mesh class Exporter { public: - virtual bool addMesh(Mesh::Feature *meshFeat) = 0; - virtual bool addPart(App::DocumentObject *obj, float tol) = 0; - virtual ~Exporter() {}; + virtual bool addMeshFeat(App::DocumentObject *obj) = 0; + virtual bool addPartFeat(App::DocumentObject *obj, float tol) = 0; + + /// Recursively adds objects from App::Part & App::DocumentObjectGroup + /*! + * \return true if all applicable objects within the group were + * added successfully. + */ + bool addAppGroup(App::DocumentObject *obj, float tol); + virtual ~Exporter() = default; protected: /// Does some simple escaping of characters for XML-type exports @@ -65,10 +72,12 @@ class MergeExporter : public Exporter MergeExporter(std::string fileName, MeshCore::MeshIO::Format fmt); ~MergeExporter(); - /// Directly adds a mesh - bool addMesh(Mesh::Feature *meshFeat); + /// Directly adds a mesh feature + bool addMeshFeat(App::DocumentObject *obj) override; + /// Converts the a Part::Feature to a mesh, adds that mesh - bool addPart(App::DocumentObject *obj, float tol); + bool addPartFeat(App::DocumentObject *obj, float tol) override; + protected: MeshObject mergingMesh; std::string fName; @@ -93,14 +102,15 @@ class AmfExporter : public Exporter /// Writes AMF footer ~AmfExporter(); - bool addMesh(Mesh::Feature *meshFeat); + bool addMeshFeat(App::DocumentObject *obj) override; + + bool addPartFeat(App::DocumentObject *obj, float tol) override; /*! * 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;