Skip to content

Commit

Permalink
Mesh: refactor mesh exporter for better support of Link
Browse files Browse the repository at this point in the history
  • Loading branch information
realthunder authored and wwmayer committed Feb 6, 2021
1 parent 13927b2 commit ea61253
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 220 deletions.
17 changes: 2 additions & 15 deletions src/Mod/Mesh/App/AppMeshPy.cpp
Expand Up @@ -382,29 +382,16 @@ class Module : public Py::ExtensionModule<Module>

// collect all object types that can be exported as mesh
std::vector<App::DocumentObject*> objectList;
std::string label;
for (auto it : list) {
PyObject *item = it.ptr();
if (PyObject_TypeCheck(item, &(App::DocumentObjectPy::Type))) {
auto obj( static_cast<App::DocumentObjectPy *>(item)->getDocumentObjectPtr() );
label = obj->Label.getValue();
if (Exporter::isSupported(obj))
objectList.push_back(obj);
objectList.push_back(obj);
}
}

if (objectList.empty()) {
std::string errorMessage;
if (list.length() == 1) {
std::stringstream str;
str << label << " cannot be exported to a mesh file";
errorMessage = str.str();
}
else {
errorMessage = "None of the objects can be exported to a mesh file";
}

throw Py::TypeError(errorMessage);
throw Py::TypeError("None of the objects can be exported to a mesh file");
}

auto exportFormat( MeshOutput::GetFormat(outputFileName.c_str()) );
Expand Down
247 changes: 78 additions & 169 deletions src/Mod/Mesh/App/Exporter.cpp
Expand Up @@ -28,6 +28,7 @@
#endif // #ifndef _PreComp_

#include "Exporter.h"
#include "MeshFeature.h"

#include "Core/Iterator.h"

Expand All @@ -38,17 +39,49 @@
#include "Base/Stream.h"
#include "Base/Tools.h"

#include "App/Part.h"
#include "App/Application.h"
#include "App/ComplexGeoData.h"
#include "App/ComplexGeoDataPy.h"
#include "App/DocumentObject.h"

#include <zipios++/zipoutputstream.h>

using namespace Mesh;
using namespace MeshCore;

Exporter::Exporter() :
meshFeatId( Base::Type::fromName("Mesh::Feature") ),
appPartId( Base::Type::fromName("Part::Feature") ),
groupExtensionId( App::GroupExtension::getExtensionClassTypeId() )
static std::vector<std::string>
expandSubObjects(const App::DocumentObject *obj,
std::map<const App::DocumentObject*, std::vector<std::string> > &cache,
int depth)
{
if (!App::GetApplication().checkLinkDepth(depth))
return {};

auto subs = obj->getSubObjects();
if (subs.empty()) {
subs.emplace_back("");
return subs;
}

std::vector<std::string> res;
for (auto & sub : subs) {
int vis = sub.empty() ? 1 : obj->isElementVisible(sub.c_str());
if (vis == 0)
continue;
auto sobj = obj->getSubObject(sub.c_str());
if (!sobj || (vis < 0 && !sobj->Visibility.getValue()))
continue;
auto linked = sobj->getLinkedObject(true);
auto it = cache.find(linked);
if (it == cache.end())
it = cache.emplace(linked, expandSubObjects(linked, cache, depth+1)).first;
for (auto & ssub : it->second)
res.push_back(sub + ssub);
}
return res;
}

Exporter::Exporter()
{ }

//static
Expand All @@ -63,63 +96,42 @@ std::string Exporter::xmlEscape(const std::string &input)
return out;
}

bool Exporter::isSupported(App::DocumentObject *obj)
{
Base::Type meshFeatId(Base::Type::fromName("Mesh::Feature"));
Base::Type appPartId(Base::Type::fromName("Part::Feature"));
Base::Type groupExtensionId(App::GroupExtension::getExtensionClassTypeId());

if (obj->getTypeId().isDerivedFrom(meshFeatId)) {
return true;
}
else if (obj->getTypeId().isDerivedFrom(appPartId)) {
return true;
}
else if (obj->hasExtension(groupExtensionId)) {
auto groupEx( obj->getExtensionByType<App::GroupExtension>() );
for (auto it : groupEx->Group.getValues()) {
bool ok = isSupported(it);
if (ok)
return true;
}
}

return false;
}

bool Exporter::addAppGroup(App::DocumentObject *obj, float tol)
int Exporter::addObject(App::DocumentObject *obj, float tol)
{
auto ret(true);

auto groupEx( obj->getExtensionByType<App::GroupExtension>() );
for (auto it : groupEx->Group.getValues()) {
if (it->getTypeId().isDerivedFrom(meshFeatId)) {
ret &= addMeshFeat(it);
} else if (it->getTypeId().isDerivedFrom(appPartId)) {
ret &= addPartFeat(it, tol);
} else if (it->hasExtension(groupExtensionId)) {
// Recurse
ret &= addAppGroup(it, tol);
int count = 0;
for (std::string & sub : expandSubObjects(obj, cache, 0)) {
Base::Matrix4D matrix;
auto sobj = obj->getSubObject(sub.c_str(), nullptr, &matrix);
auto linked = sobj->getLinkedObject(true, &matrix, false);
auto it = meshCache.find(linked);
if (it == meshCache.end()) {
if (linked->isDerivedFrom(Mesh::Feature::getClassTypeId())) {
it = meshCache.emplace(linked,
static_cast<Mesh::Feature*>(linked)->Mesh.getValue()).first;
it->second.setTransform(Base::Matrix4D());
} else {
Base::PyGILStateLocker lock;
PyObject *pyobj = nullptr;
linked->getSubObject("", &pyobj, nullptr, false);
if (!pyobj)
continue;
if (PyObject_TypeCheck(pyobj, &Data::ComplexGeoDataPy::Type)) {
std::vector<Base::Vector3d> aPoints;
std::vector<Data::ComplexGeoData::Facet> aTopo;
auto geoData = static_cast<Data::ComplexGeoDataPy*>(pyobj)->getComplexGeoDataPtr();
geoData->getFaces(aPoints, aTopo, tol);
it = meshCache.emplace(linked, MeshObject()).first;
it->second.setFacets(aTopo, aPoints);
}
Py_DECREF(pyobj);
}
}
MeshObject mesh(it->second);
mesh.transformGeometry(matrix);
if (addMesh(sobj->Label.getValue(), mesh))
++count;
}

return ret;
}

bool Exporter::addObject(App::DocumentObject *obj, float tol)
{
if (obj->getTypeId().isDerivedFrom(meshFeatId)) {
return addMeshFeat( obj );
} else if (obj->getTypeId().isDerivedFrom(appPartId)) {
return addPartFeat( obj, tol );
} else if (obj->hasExtension(groupExtensionId)) {
return addAppGroup( obj, tol );
} else {
Base::Console().Message(
"'%s' is of type %s, and can not be exported as a mesh.\n",
obj->Label.getValue(), obj->getTypeId().getName() );
return false;
}
return count;
}

MergeExporter::MergeExporter(std::string fileName, MeshIO::Format)
Expand All @@ -145,14 +157,9 @@ MergeExporter::~MergeExporter()
}


bool MergeExporter::addMeshFeat(App::DocumentObject *obj)
bool MergeExporter::addMesh(const char *name, const MeshObject & mesh)
{
const MeshObject &mesh( static_cast<Mesh::Feature *>(obj)->Mesh.getValue() );
Base::Placement plm = static_cast<Mesh::Feature *>(obj)->globalPlacement();

MeshCore::MeshKernel kernel(mesh.getKernel());
kernel.Transform(plm.toMatrix());

const auto & kernel = mesh.getKernel();
auto countFacets( mergingMesh.countFacets() );
if (countFacets == 0) {
mergingMesh.setKernel(kernel);
Expand Down Expand Up @@ -188,68 +195,13 @@ bool MergeExporter::addMeshFeat(App::DocumentObject *obj)
indices.resize(mergingMesh.countFacets() - countFacets);
std::generate(indices.begin(), indices.end(), Base::iotaGen<unsigned long>(countFacets));
Segment segm(&mergingMesh, indices, true);
segm.setName(obj->Label.getValue());
segm.setName(name);
mergingMesh.addSegment(segm);
}

return true;
}

bool MergeExporter::addPartFeat(App::DocumentObject *obj, float tol)
{
auto *shape(obj->getPropertyByName("Shape"));
if (shape && shape->getTypeId().isDerivedFrom(App::PropertyComplexGeoData::getClassTypeId())) {
Base::Reference<MeshObject> mesh(new MeshObject());

auto countFacets( mergingMesh.countFacets() );

auto geoData( static_cast<App::PropertyComplexGeoData*>(shape)->getComplexData() );
if (geoData) {
App::GeoFeature* gf = static_cast<App::GeoFeature*>(obj);
Base::Placement plm = gf->globalPlacement();
Base::Placement pl = gf->Placement.getValue();
bool applyGlobal = false;
if (pl == plm) {
//no extension placement
applyGlobal = false;
} else {
//there is a placement from extension
applyGlobal = true;
}

std::vector<Base::Vector3d> aPoints;
std::vector<Data::ComplexGeoData::Facet> aTopo;
geoData->getFaces(aPoints, aTopo, tol);

if (applyGlobal) {
Base::Placement diff_plm = plm * pl.inverse();
for (auto& it : aPoints) {
diff_plm.multVec(it,it);
}
}

mesh->addFacets(aTopo, aPoints, false);
if (countFacets == 0)
mergingMesh = *mesh;
else
mergingMesh.addMesh(*mesh);
} else {
return false;
}

// now create a segment for the added mesh
std::vector<unsigned long> indices;
indices.resize(mergingMesh.countFacets() - countFacets);
std::generate(indices.begin(), indices.end(), Base::iotaGen<unsigned long>(countFacets));
Segment segm(&mergingMesh, indices, true);
segm.setName(obj->Label.getValue());
mergingMesh.addSegment(segm);

return true;
}
return false;
}

AmfExporter::AmfExporter( std::string fileName,
const std::map<std::string, std::string> &meta,
bool compress ) :
Expand Down Expand Up @@ -304,50 +256,10 @@ AmfExporter::~AmfExporter()
}
}

bool AmfExporter::addPartFeat(App::DocumentObject *obj, float tol)
{
auto *shape(obj->getPropertyByName("Shape"));

if (shape && shape->getTypeId().isDerivedFrom(App::PropertyComplexGeoData::getClassTypeId())) {
Base::Reference<MeshObject> mesh(new MeshObject());

auto geoData( static_cast<App::PropertyComplexGeoData*>(shape)->getComplexData() );
if (geoData) {
std::vector<Base::Vector3d> aPoints;
std::vector<Data::ComplexGeoData::Facet> aTopo;
geoData->getFaces(aPoints, aTopo, tol);

mesh->addFacets(aTopo, aPoints, false);
} else {
return false;
}

MeshCore::MeshKernel kernel = mesh->getKernel();
kernel.Transform(mesh->getTransform());

std::map<std::string, std::string> meta;
meta["name"] = xmlEscape(obj->Label.getStrValue());

return addMesh(kernel, meta);
}
return false;
}

bool AmfExporter::addMeshFeat(App::DocumentObject *obj)
bool AmfExporter::addMesh(const char *name, const MeshObject & mesh)
{
const MeshObject &mesh( static_cast<Mesh::Feature *>(obj)->Mesh.getValue() );
MeshCore::MeshKernel kernel( mesh.getKernel() );
kernel.Transform(mesh.getTransform());

std::map<std::string, std::string> meta;
meta["name"] = xmlEscape(obj->Label.getStrValue());

return addMesh(kernel, meta);
}
const auto & kernel = mesh.getKernel();

bool AmfExporter::addMesh(const MeshCore::MeshKernel &kernel,
const std::map<std::string, std::string> &meta)
{
if (!outputStreamPtr || outputStreamPtr->bad()) {
return false;
}
Expand All @@ -363,11 +275,8 @@ bool AmfExporter::addMesh(const MeshCore::MeshKernel &kernel,
Base::SequencerLauncher seq("Saving...", 2 * numFacets + 1);

*outputStreamPtr << "\t<object id=\"" << nextObjectIndex << "\">\n";

for (auto const &metaEntry : meta) {
*outputStreamPtr << "\t\t<metadata type=\"" << metaEntry.first
<< "\">" << metaEntry.second << "</metadata>\n";
}
*outputStreamPtr << "\t\t<metadata type=\"name\">"
<< xmlEscape(name) << "</metadata>\n";
*outputStreamPtr << "\t\t<mesh>\n"
<< "\t\t\t<vertices>\n";

Expand Down

0 comments on commit ea61253

Please sign in to comment.