/*************************************************************************** * Copyright (c) 2004 Werner Mayer * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include "PreCompiled.h" #ifndef _PreComp_ #endif #include #include #include #include #include #include #include #include #include #include #include "Core/MeshKernel.h" #include "Core/MeshIO.h" #include "Core/Evaluation.h" #include "Core/Iterator.h" #include "Core/Approximation.h" #include "MeshPy.h" #include "Mesh.h" #include "FeatureMeshImport.h" using namespace Mesh; using namespace MeshCore; /* module functions */ static PyObject * read(PyObject *self, PyObject *args) { char* Name; if (!PyArg_ParseTuple(args, "et","utf-8",&Name)) return NULL; std::string EncodedName = std::string(Name); PyMem_Free(Name); PY_TRY { std::auto_ptr mesh(new MeshObject); if (mesh->load(EncodedName.c_str())) { return new MeshPy(mesh.release()); } else { PyErr_SetString(Base::BaseExceptionFreeCADError, "Loading of mesh was aborted"); return NULL; } } PY_CATCH; Py_Return; } static PyObject * open(PyObject *self, PyObject *args) { char* Name; if (!PyArg_ParseTuple(args, "et","utf-8",&Name)) return NULL; std::string EncodedName = std::string(Name); PyMem_Free(Name); PY_TRY { MeshObject mesh; if (mesh.load(EncodedName.c_str())) { Base::FileInfo file(EncodedName.c_str()); // create new document and add Import feature App::Document *pcDoc = App::GetApplication().newDocument("Unnamed"); unsigned long segmct = mesh.countSegments(); if (segmct > 1) { for (unsigned long i=0; i segm(mesh.meshFromSegment(mesh.getSegment(i).getIndices())); Mesh::Feature *pcFeature = static_cast (pcDoc->addObject("Mesh::Feature", file.fileNamePure().c_str())); pcFeature->Label.setValue(file.fileNamePure().c_str()); pcFeature->Mesh.swapMesh(*segm); pcFeature->purgeTouched(); } } else { Mesh::Feature *pcFeature = static_cast (pcDoc->addObject("Mesh::Feature", file.fileNamePure().c_str())); pcFeature->Label.setValue(file.fileNamePure().c_str()); pcFeature->Mesh.swapMesh(mesh); pcFeature->purgeTouched(); } } } PY_CATCH; Py_Return; } static PyObject * importer(PyObject *self, PyObject *args) { char* Name; char* DocName=0; if (!PyArg_ParseTuple(args, "et|s","utf-8",&Name,&DocName)) return NULL; std::string EncodedName = std::string(Name); PyMem_Free(Name); PY_TRY { App::Document *pcDoc = 0; if (DocName) pcDoc = App::GetApplication().getDocument(DocName); else pcDoc = App::GetApplication().getActiveDocument(); if (!pcDoc) { pcDoc = App::GetApplication().newDocument(DocName); } MeshObject mesh; if (mesh.load(EncodedName.c_str())) { Base::FileInfo file(EncodedName.c_str()); unsigned long segmct = mesh.countSegments(); if (segmct > 1) { for (unsigned long i=0; i segm(mesh.meshFromSegment(mesh.getSegment(i).getIndices())); Mesh::Feature *pcFeature = static_cast (pcDoc->addObject("Mesh::Feature", file.fileNamePure().c_str())); pcFeature->Label.setValue(file.fileNamePure().c_str()); pcFeature->Mesh.swapMesh(*segm); pcFeature->purgeTouched(); } } else { Mesh::Feature *pcFeature = static_cast (pcDoc->addObject("Mesh::Feature", file.fileNamePure().c_str())); pcFeature->Label.setValue(file.fileNamePure().c_str()); pcFeature->Mesh.swapMesh(mesh); pcFeature->purgeTouched(); } } } PY_CATCH; Py_Return; } static PyObject * exporter(PyObject *self, PyObject *args) { PyObject* object; char* Name; if (!PyArg_ParseTuple(args, "Oet",&object,"utf-8",&Name)) return NULL; std::string EncodedName = std::string(Name); PyMem_Free(Name); float fTolerance = 0.1f; MeshObject global_mesh; PY_TRY { Py::Sequence list(object); Base::Type meshId = Base::Type::fromName("Mesh::Feature"); Base::Type partId = Base::Type::fromName("Part::Feature"); for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { PyObject* item = (*it).ptr(); if (PyObject_TypeCheck(item, &(App::DocumentObjectPy::Type))) { App::DocumentObject* obj = static_cast(item)->getDocumentObjectPtr(); if (obj->getTypeId().isDerivedFrom(meshId)) { const MeshObject& mesh = static_cast(obj)->Mesh.getValue(); MeshCore::MeshKernel kernel = mesh.getKernel(); kernel.Transform(mesh.getTransform()); if (global_mesh.countFacets() == 0) global_mesh.setKernel(kernel); else global_mesh.addMesh(kernel); } else if (obj->getTypeId().isDerivedFrom(partId)) { App::Property* shape = obj->getPropertyByName("Shape"); Base::Reference mesh(new MeshObject()); if (shape && shape->getTypeId().isDerivedFrom(App::PropertyComplexGeoData::getClassTypeId())) { std::vector aPoints; std::vector aTopo; static_cast(shape)->getFaces(aPoints, aTopo,fTolerance); mesh->addFacets(aTopo, aPoints); if (global_mesh.countFacets() == 0) global_mesh = *mesh; else global_mesh.addMesh(*mesh); } } else { Base::Console().Message("'%s' is not a mesh or shape, export will be ignored.\n", obj->Label.getValue()); } } } // export mesh compound global_mesh.save(EncodedName.c_str()); } PY_CATCH; Py_Return; } static PyObject * show(PyObject *self, PyObject *args) { PyObject *pcObj; if (!PyArg_ParseTuple(args, "O!", &(MeshPy::Type), &pcObj)) return NULL; PY_TRY { App::Document *pcDoc = App::GetApplication().getActiveDocument(); if (!pcDoc) pcDoc = App::GetApplication().newDocument(); MeshPy* pMesh = static_cast(pcObj); Mesh::Feature *pcFeature = (Mesh::Feature *)pcDoc->addObject("Mesh::Feature", "Mesh"); Mesh::MeshObject* mo = pMesh->getMeshObjectPtr(); if (!mo) { PyErr_SetString(PyExc_ReferenceError, "object doesn't reference a valid mesh"); return 0; } // copy the data pcFeature->Mesh.setValue(*mo); } PY_CATCH; Py_Return; } static PyObject * createPlane(PyObject *self, PyObject *args) { float x=1,y=0,z=0; if (!PyArg_ParseTuple(args, "|fff",&x,&y,&z)) // convert args: Python->C return NULL; // NULL triggers exception if(y==0) y=x; float hx = x/2.0f; float hy = y/2.0f; PY_TRY { std::vector TriaList; TriaList.push_back(MeshCore::MeshGeomFacet(Base::Vector3f(-hx, -hy, 0.0),Base::Vector3f(hx, hy, 0.0),Base::Vector3f(-hx, hy, 0.0))); TriaList.push_back(MeshCore::MeshGeomFacet(Base::Vector3f(-hx, -hy, 0.0),Base::Vector3f(hx, -hy, 0.0),Base::Vector3f(hx, hy, 0.0))); std::auto_ptr mesh(new MeshObject); mesh->addFacets(TriaList); return new MeshPy(mesh.release()); } PY_CATCH; } static PyObject * createSphere(PyObject *self, PyObject *args) { float radius = 5.0f; int sampling = 50; if (!PyArg_ParseTuple(args, "|fi",&radius,&sampling)) // convert args: Python->C return NULL; // NULL triggers exception PY_TRY { MeshObject* mesh = MeshObject::createSphere(radius, sampling); if (!mesh) { PyErr_SetString(Base::BaseExceptionFreeCADError, "Creation of sphere failed"); return NULL; } return new MeshPy(mesh); } PY_CATCH; } static PyObject * createEllipsoid(PyObject *self, PyObject *args) { float radius1 = 2.0f; float radius2 = 4.0f; int sampling = 50; if (!PyArg_ParseTuple(args, "|ffi",&radius1,&radius2,&sampling)) // convert args: Python->C return NULL; // NULL triggers exception PY_TRY { MeshObject* mesh = MeshObject::createEllipsoid(radius1, radius2, sampling); if (!mesh) { PyErr_SetString(Base::BaseExceptionFreeCADError, "Creation of ellipsoid failed"); return NULL; } return new MeshPy(mesh); } PY_CATCH; } static PyObject * createCylinder(PyObject *self, PyObject *args) { float radius = 2.0f; float length = 10.0f; int closed = 1; float edgelen = 1.0f; int sampling = 50; if (!PyArg_ParseTuple(args, "|ffifi",&radius,&length,&closed,&edgelen,&sampling)) // convert args: Python->C return NULL; // NULL triggers exception PY_TRY { MeshObject* mesh = MeshObject::createCylinder(radius, length, closed, edgelen, sampling); if (!mesh) { PyErr_SetString(Base::BaseExceptionFreeCADError, "Creation of cylinder failed"); return NULL; } return new MeshPy(mesh); } PY_CATCH; } static PyObject * createCone(PyObject *self, PyObject *args) { float radius1 = 2.0f; float radius2 = 4.0f; float len = 10.0f; int closed = 1; float edgelen = 1.0f; int sampling = 50; if (!PyArg_ParseTuple(args, "|fffifi",&radius1,&radius2,&len,&closed,&edgelen,&sampling)) // convert args: Python->C return NULL; // NULL triggers exception PY_TRY { MeshObject* mesh = MeshObject::createCone(radius1, radius2, len, closed, edgelen, sampling); if (!mesh) { PyErr_SetString(Base::BaseExceptionFreeCADError, "Creation of cone failed"); return NULL; } return new MeshPy(mesh); } PY_CATCH; } static PyObject * createTorus(PyObject *self, PyObject *args) { float radius1 = 10.0f; float radius2 = 2.0f; int sampling = 50; if (!PyArg_ParseTuple(args, "|ffi",&radius1,&radius2,&sampling)) // convert args: Python->C return NULL; // NULL triggers exception PY_TRY { MeshObject* mesh = MeshObject::createTorus(radius1, radius2, sampling); if (!mesh) { PyErr_SetString(Base::BaseExceptionFreeCADError, "Creation of torus failed"); return NULL; } return new MeshPy(mesh); } PY_CATCH; } static PyObject * createBox(PyObject *self, PyObject *args) { float length = 10.0f; float width = 10.0f; float height = 10.0f; float edgelen = -1.0f; if (!PyArg_ParseTuple(args, "|ffff",&length,&width,&height,&edgelen)) // convert args: Python->C return NULL; // NULL triggers exception PY_TRY { MeshObject* mesh; if (edgelen < 0.0f) mesh = MeshObject::createCube(length, width, height); else mesh = MeshObject::createCube(length, width, height, edgelen); if (!mesh) { PyErr_SetString(Base::BaseExceptionFreeCADError, "Creation of box failed"); return NULL; } return new MeshPy(mesh); } PY_CATCH; } static PyObject * calculateEigenTransform(PyObject *self, PyObject *args) { PyObject *input; if (!PyArg_ParseTuple(args, "O",&input)) return NULL; if (!PySequence_Check(input)) { PyErr_SetString(Base::BaseExceptionFreeCADError, "Input has to be a sequence of Base.Vector()"); return NULL; } PY_TRY { MeshCore::MeshKernel aMesh; MeshCore::MeshPointArray vertices; vertices.clear(); MeshCore::MeshFacetArray faces; faces.clear(); MeshCore::MeshPoint current_node; Py::Sequence list(input); for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { PyObject* value = (*it).ptr(); if (PyObject_TypeCheck(value, &(Base::VectorPy::Type))) { Base::VectorPy *pcObject = static_cast(value); Base::Vector3d* val = pcObject->getVectorPtr(); current_node.Set(float(val->x),float(val->y),float(val->z)); vertices.push_back(current_node); } } MeshCore::MeshFacet aFacet; aFacet._aulPoints[0] = 0;aFacet._aulPoints[1] = 1;aFacet._aulPoints[2] = 2; faces.push_back(aFacet); //Fill the Kernel with the temp mesh structure and delete the current containers aMesh.Adopt(vertices,faces); MeshCore::MeshEigensystem pca(aMesh); pca.Evaluate(); Base::Matrix4D Trafo = pca.Transform(); return new Base::PlacementPy(new Base::Placement(Trafo) ); } PY_CATCH; Py_Return; } static PyObject * polynomialFit(PyObject *self, PyObject *args) { PyObject *input; if (!PyArg_ParseTuple(args, "O",&input)) return NULL; if (!PySequence_Check(input)) { PyErr_SetString(Base::BaseExceptionFreeCADError, "Input has to be a sequence of Base.Vector()"); return NULL; } PY_TRY { MeshCore::SurfaceFit polyFit; Base::Vector3f point; Py::Sequence list(input); for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { PyObject* value = (*it).ptr(); if (PyObject_TypeCheck(value, &(Base::VectorPy::Type))) { Base::VectorPy *pcObject = static_cast(value); Base::Vector3d* val = pcObject->getVectorPtr(); point.Set(float(val->x),float(val->y),float(val->z)); polyFit.AddPoint(point); } } // fit quality float fit = polyFit.Fit(); Py::Dict dict; dict.setItem(Py::String("Sigma"), Py::Float(fit)); // coefficients double a,b,c,d,e,f; polyFit.GetCoefficients(a,b,c,d,e,f); Py::Tuple p(6); p.setItem(0, Py::Float(a)); p.setItem(1, Py::Float(b)); p.setItem(2, Py::Float(c)); p.setItem(3, Py::Float(d)); p.setItem(4, Py::Float(e)); p.setItem(5, Py::Float(f)); dict.setItem(Py::String("Coefficients"), p); // residuals std::vector local = polyFit.GetLocalPoints(); Py::Tuple r(local.size()); for (std::vector::iterator it = local.begin(); it != local.end(); ++it) { double z = polyFit.Value(it->x, it->y); double d = it->z - z; r.setItem(it-local.begin(), Py::Float(d)); } dict.setItem(Py::String("Residuals"), r); return Py::new_reference_to(dict); } PY_CATCH; } PyDoc_STRVAR(open_doc, "open(string) -- Create a new document and a Mesh::Import feature to load the file into the document."); PyDoc_STRVAR(inst_doc, "insert(string|mesh,[string]) -- Load or insert a mesh into the given or active document."); PyDoc_STRVAR(export_doc, "export(list,string) -- Export a list of objects into a single file."); PyDoc_STRVAR(calculateEigenTransform_doc, "calculateEigenTransform(seq(Base.Vector)) -- Calculates the eigen Transformation from a list of points.\n" "calculate the point's local coordinate system with the center\n" "of gravity as origin. The local coordinate system is computed\n" "this way that u has minimum and w has maximum expansion.\n" "The local coordinate system is right-handed.\n" ); PyDoc_STRVAR(polynomialFit_doc, "polynomialFit(seq(Base.Vector)) -- Calculates a polynomial fit.\n" ); /* List of functions defined in the module */ struct PyMethodDef Mesh_Import_methods[] = { {"open" ,open , METH_VARARGS, open_doc}, {"insert" ,importer, METH_VARARGS, inst_doc}, {"export" ,exporter, METH_VARARGS, export_doc}, {"read" ,read, Py_NEWARGS, "Read a mesh from a file and returns a Mesh object."}, {"show" ,show, Py_NEWARGS, "Put a mesh object in the active document or creates one if needed"}, {"createBox" ,createBox, Py_NEWARGS, "Create a solid mesh box"}, {"createPlane",createPlane, Py_NEWARGS, "Create a mesh XY plane normal +Z"}, {"createSphere",createSphere, Py_NEWARGS, "Create a tessellated sphere"}, {"createEllipsoid",createEllipsoid, Py_NEWARGS, "Create a tessellated ellipsoid"}, {"createCylinder",createCylinder, Py_NEWARGS, "Create a tessellated cylinder"}, {"createCone",createCone, Py_NEWARGS, "Create a tessellated cone"}, {"createTorus",createTorus, Py_NEWARGS, "Create a tessellated torus"}, {"calculateEigenTransform",calculateEigenTransform, METH_VARARGS, calculateEigenTransform_doc}, {"polynomialFit",polynomialFit, METH_VARARGS, polynomialFit_doc}, {NULL, NULL} /* sentinel */ };