// SPDX-License-Identifier: LGPL-2.1-or-later /*************************************************************************** * Copyright (c) 2007 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 #include #include #include #include #include #include #include #include "Core/Degeneration.h" #include "Core/Segmentation.h" #include "Core/Smoothing.h" #include "Core/Triangulation.h" #include "Mesh.h" #include "MeshPy.h" #include "MeshPointPy.h" #include "FacetPy.h" #include "MeshPy.cpp" #include "MeshProperties.h" using namespace Mesh; struct MeshPropertyLock { explicit MeshPropertyLock(PropertyMeshKernel* p) : prop(p) { if (prop) { prop->startEditing(); } } ~MeshPropertyLock() { if (prop) { prop->finishEditing(); } } private: PropertyMeshKernel* prop; FC_DISABLE_COPY_MOVE(MeshPropertyLock) }; int MeshPy::PyInit(PyObject* args, PyObject*) { PyObject* pcObj = nullptr; if (!PyArg_ParseTuple(args, "|O", &pcObj)) { return -1; } try { this->parentProperty = nullptr; // if no mesh is given if (!pcObj) { return 0; } if (PyObject_TypeCheck(pcObj, &(MeshPy::Type))) { getMeshObjectPtr()->operator=(*static_cast(pcObj)->getMeshObjectPtr()); } else if (PyList_Check(pcObj)) { PyObject* ret = addFacets(args); bool ok = (ret != nullptr); Py_XDECREF(ret); if (!ok) { return -1; } } else if (PyTuple_Check(pcObj)) { PyObject* ret = addFacets(args); bool ok = (ret != nullptr); Py_XDECREF(ret); if (!ok) { return -1; } } else if (PyUnicode_Check(pcObj)) { getMeshObjectPtr()->load(PyUnicode_AsUTF8(pcObj)); } else { PyErr_Format(PyExc_TypeError, "Cannot create a mesh out of a '%s'", pcObj->ob_type->tp_name); return -1; } } catch (const Base::Exception& e) { e.setPyException(); return -1; } catch (const std::exception& e) { PyErr_SetString(Base::PyExc_FC_GeneralError, e.what()); return -1; } catch (const Py::Exception&) { return -1; } return 0; } // returns a string which represent the object e.g. when printed in python std::string MeshPy::representation() const { return getMeshObjectPtr()->representation(); } PyObject* MeshPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper { // create a new instance of MeshPy and the Twin object return new MeshPy(new MeshObject); } PyObject* MeshPy::copy(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } return new MeshPy(new MeshObject(*getMeshObjectPtr())); } PyObject* MeshPy::read(PyObject* args, PyObject* kwds) { char* Name {}; static const std::array keywords_path {"Filename", nullptr}; if (Base::Wrapped_ParseTupleAndKeywords(args, kwds, "et", keywords_path, "utf-8", &Name)) { getMeshObjectPtr()->load(Name); PyMem_Free(Name); Py_Return; } PyErr_Clear(); MeshCore::MeshIO::Format format = MeshCore::MeshIO::Undefined; std::map ext; ext["BMS"] = MeshCore::MeshIO::BMS; ext["STL"] = MeshCore::MeshIO::BSTL; ext["AST"] = MeshCore::MeshIO::ASTL; ext["OBJ"] = MeshCore::MeshIO::OBJ; ext["SMF"] = MeshCore::MeshIO::SMF; ext["OFF"] = MeshCore::MeshIO::OFF; ext["IV"] = MeshCore::MeshIO::IV; ext["X3D"] = MeshCore::MeshIO::X3D; ext["X3DZ"] = MeshCore::MeshIO::X3DZ; ext["VRML"] = MeshCore::MeshIO::VRML; ext["WRL"] = MeshCore::MeshIO::VRML; ext["WRZ"] = MeshCore::MeshIO::WRZ; ext["NAS"] = MeshCore::MeshIO::NAS; ext["BDF"] = MeshCore::MeshIO::NAS; ext["PLY"] = MeshCore::MeshIO::PLY; ext["APLY"] = MeshCore::MeshIO::APLY; ext["PY"] = MeshCore::MeshIO::PY; PyObject* input {}; char* Ext {}; static const std::array keywords_stream {"Stream", "Format", nullptr}; if (Base::Wrapped_ParseTupleAndKeywords(args, kwds, "Os", keywords_stream, &input, &Ext)) { std::string fmt(Ext); boost::to_upper(fmt); if (ext.find(fmt) != ext.end()) { format = ext[fmt]; } // read mesh Base::PyStreambuf buf(input); std::istream str(nullptr); str.rdbuf(&buf); getMeshObjectPtr()->load(str, format); Py_Return; } PyErr_SetString(PyExc_TypeError, "expect string or file object"); return nullptr; } PyObject* MeshPy::write(PyObject* args, PyObject* kwds) const { char* Name = nullptr; char* Ext = nullptr; char* ObjName = nullptr; PyObject* List = nullptr; MeshCore::MeshIO::Format format = MeshCore::MeshIO::Undefined; std::map ext; ext["BMS"] = MeshCore::MeshIO::BMS; ext["STL"] = MeshCore::MeshIO::BSTL; ext["AST"] = MeshCore::MeshIO::ASTL; ext["OBJ"] = MeshCore::MeshIO::OBJ; ext["SMF"] = MeshCore::MeshIO::SMF; ext["OFF"] = MeshCore::MeshIO::OFF; ext["IDTF"] = MeshCore::MeshIO::IDTF; ext["MGL"] = MeshCore::MeshIO::MGL; ext["IV"] = MeshCore::MeshIO::IV; ext["X3D"] = MeshCore::MeshIO::X3D; ext["X3DZ"] = MeshCore::MeshIO::X3DZ; ext["X3DOM"] = MeshCore::MeshIO::X3DOM; ext["VRML"] = MeshCore::MeshIO::VRML; ext["WRL"] = MeshCore::MeshIO::VRML; ext["WRZ"] = MeshCore::MeshIO::WRZ; ext["NAS"] = MeshCore::MeshIO::NAS; ext["BDF"] = MeshCore::MeshIO::NAS; ext["PLY"] = MeshCore::MeshIO::PLY; ext["APLY"] = MeshCore::MeshIO::APLY; ext["PY"] = MeshCore::MeshIO::PY; ext["ASY"] = MeshCore::MeshIO::ASY; ext["3MF"] = MeshCore::MeshIO::ThreeMF; static const std::array keywords_path {"Filename", "Format", "Name", "Material", nullptr}; if (Base::Wrapped_ParseTupleAndKeywords( args, kwds, "et|ssO", keywords_path, "utf-8", &Name, &Ext, &ObjName, &List )) { if (Ext) { std::string fmt(Ext); boost::to_upper(fmt); if (ext.find(fmt) != ext.end()) { format = ext[fmt]; } } if (List) { MeshCore::Material mat; Py::Sequence list(List); for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { Py::Tuple t(*it); float r = Py::Float(t.getItem(0)); float g = Py::Float(t.getItem(1)); float b = Py::Float(t.getItem(2)); mat.diffuseColor.emplace_back(r, g, b); } if (mat.diffuseColor.size() == getMeshObjectPtr()->countPoints()) { mat.binding = MeshCore::MeshIO::PER_VERTEX; } else if (mat.diffuseColor.size() == getMeshObjectPtr()->countFacets()) { mat.binding = MeshCore::MeshIO::PER_FACE; } else { mat.binding = MeshCore::MeshIO::OVERALL; } getMeshObjectPtr()->save(Name, format, &mat, ObjName); } else { getMeshObjectPtr()->save(Name, format, nullptr, ObjName); } PyMem_Free(Name); Py_Return; } PyErr_Clear(); static const std::array keywords_stream {"Stream", "Format", "Name", "Material", nullptr}; PyObject* input; if (Base::Wrapped_ParseTupleAndKeywords( args, kwds, "Os|sO", keywords_stream, &input, &Ext, &ObjName, &List )) { std::string fmt(Ext); boost::to_upper(fmt); if (ext.find(fmt) != ext.end()) { format = ext[fmt]; } std::unique_ptr mat; if (List) { mat = std::make_unique(); Py::Sequence list(List); for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { Py::Tuple t(*it); float r = Py::Float(t.getItem(0)); float g = Py::Float(t.getItem(1)); float b = Py::Float(t.getItem(2)); mat->diffuseColor.emplace_back(r, g, b); } if (mat->diffuseColor.size() == getMeshObjectPtr()->countPoints()) { mat->binding = MeshCore::MeshIO::PER_VERTEX; } else if (mat->diffuseColor.size() == getMeshObjectPtr()->countFacets()) { mat->binding = MeshCore::MeshIO::PER_FACE; } else { mat->binding = MeshCore::MeshIO::OVERALL; } } // write mesh Base::PyStreambuf buf(input); std::ostream str(nullptr); str.rdbuf(&buf); getMeshObjectPtr()->save(str, format, mat.get(), ObjName); Py_Return; } PyErr_SetString(PyExc_TypeError, "expect string or file object"); return nullptr; } PyObject* MeshPy::writeInventor(PyObject* args) const { float creaseangle = 0.0F; if (!PyArg_ParseTuple(args, "|f", &creaseangle)) { return nullptr; } std::stringstream result; MeshObject* mesh = getMeshObjectPtr(); mesh->writeInventor(result, creaseangle); return Py::new_reference_to(Py::String(result.str())); } PyObject* MeshPy::offset(PyObject* args) { float Float {}; if (!PyArg_ParseTuple(args, "f", &Float)) { return nullptr; } PY_TRY { getMeshObjectPtr()->offsetSpecial2(Float); } PY_CATCH; Py_Return; } PyObject* MeshPy::offsetSpecial(PyObject* args) { float Float {}; float zmin {}; float zmax {}; if (!PyArg_ParseTuple(args, "fff", &Float, &zmin, &zmax)) { return nullptr; } PY_TRY { getMeshObjectPtr()->offsetSpecial(Float, zmax, zmin); } PY_CATCH; Py_Return; } PyObject* MeshPy::crossSections(PyObject* args) const { PyObject* obj {}; PyObject* poly = Py_False; float min_eps = 1.0e-2F; if (!PyArg_ParseTuple(args, "O|fO!", &obj, &min_eps, &PyBool_Type, &poly)) { return nullptr; } Py::Sequence list(obj); Py::Type vType(Base::getTypeAsObject(&Base::VectorPy::Type)); std::vector csPlanes; for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { Py::Tuple pair(*it); Py::Object p1 = pair.getItem(0); Py::Object p2 = pair.getItem(1); if (p1.isType(vType) && p2.isType(vType)) { MeshObject::TPlane plane; Base::Vector3d b = static_cast(p1.ptr())->value(); Base::Vector3d n = static_cast(p2.ptr())->value(); plane.first.Set((float)b.x, (float)b.y, (float)b.z); plane.second.Set((float)n.x, (float)n.y, (float)n.z); csPlanes.push_back(plane); } else if (p1.isTuple() && p2.isTuple()) { Py::Tuple b(p1); Py::Tuple n(p2); float bx = Py::Float(b.getItem(0)); float by = Py::Float(b.getItem(1)); float bz = Py::Float(b.getItem(2)); float nx = Py::Float(n.getItem(0)); float ny = Py::Float(n.getItem(1)); float nz = Py::Float(n.getItem(2)); MeshObject::TPlane plane; plane.first.Set(bx, by, bz); plane.second.Set(nx, ny, nz); csPlanes.push_back(plane); } } std::vector sections; getMeshObjectPtr()->crossSections(csPlanes, sections, min_eps, Base::asBoolean(poly)); // convert to Python objects Py::List crossSections; for (const auto& it : sections) { Py::List section; for (const auto& jt : it) { Py::List polyline; for (auto kt : jt) { polyline.append(Py::asObject(new Base::VectorPy(kt))); } section.append(polyline); } crossSections.append(section); } return Py::new_reference_to(crossSections); } PyObject* MeshPy::unite(PyObject* args) const { MeshPy* pcObject {}; PyObject* pcObj {}; if (!PyArg_ParseTuple(args, "O!", &(MeshPy::Type), &pcObj)) { return nullptr; } pcObject = static_cast(pcObj); PY_TRY { MeshObject* mesh = getMeshObjectPtr()->unite(*pcObject->getMeshObjectPtr()); return new MeshPy(mesh); } PY_CATCH; Py_Return; } PyObject* MeshPy::intersect(PyObject* args) const { MeshPy* pcObject {}; PyObject* pcObj {}; if (!PyArg_ParseTuple(args, "O!", &(MeshPy::Type), &pcObj)) { return nullptr; } pcObject = static_cast(pcObj); PY_TRY { MeshObject* mesh = getMeshObjectPtr()->intersect(*pcObject->getMeshObjectPtr()); return new MeshPy(mesh); } PY_CATCH; Py_Return; } PyObject* MeshPy::difference(PyObject* args) const { MeshPy* pcObject {}; PyObject* pcObj {}; if (!PyArg_ParseTuple(args, "O!", &(MeshPy::Type), &pcObj)) { return nullptr; } pcObject = static_cast(pcObj); PY_TRY { MeshObject* mesh = getMeshObjectPtr()->subtract(*pcObject->getMeshObjectPtr()); return new MeshPy(mesh); } PY_CATCH; Py_Return; } PyObject* MeshPy::inner(PyObject* args) const { MeshPy* pcObject {}; PyObject* pcObj {}; if (!PyArg_ParseTuple(args, "O!", &(MeshPy::Type), &pcObj)) { return nullptr; } pcObject = static_cast(pcObj); PY_TRY { MeshObject* mesh = getMeshObjectPtr()->inner(*pcObject->getMeshObjectPtr()); return new MeshPy(mesh); } PY_CATCH; Py_Return; } PyObject* MeshPy::outer(PyObject* args) const { MeshPy* pcObject {}; PyObject* pcObj {}; if (!PyArg_ParseTuple(args, "O!", &(MeshPy::Type), &pcObj)) { return nullptr; } pcObject = static_cast(pcObj); PY_TRY { MeshObject* mesh = getMeshObjectPtr()->outer(*pcObject->getMeshObjectPtr()); return new MeshPy(mesh); } PY_CATCH; Py_Return; } PyObject* MeshPy::section(PyObject* args, PyObject* kwds) const { PyObject* pcObj {}; PyObject* connectLines = Py_True; float fMinDist = 0.0001F; static const std::array keywords_section {"Mesh", "ConnectLines", "MinDist", nullptr}; if (!Base::Wrapped_ParseTupleAndKeywords( args, kwds, "O!|O!f", keywords_section, &(MeshPy::Type), &pcObj, &PyBool_Type, &connectLines, &fMinDist )) { return nullptr; } MeshPy* pcObject = static_cast(pcObj); std::vector> curves = getMeshObjectPtr()->section( *pcObject->getMeshObjectPtr(), Base::asBoolean(connectLines), fMinDist ); Py::List outer; for (const auto& it : curves) { Py::List inner; for (const auto& jt : it) { inner.append(Py::Vector(jt)); } outer.append(inner); } return Py::new_reference_to(outer); } PyObject* MeshPy::translate(PyObject* args) { float x {}; float y {}; float z {}; if (!PyArg_ParseTuple(args, "fff", &x, &y, &z)) { return nullptr; } PY_TRY { Base::Matrix4D m; m.move(x, y, z); getMeshObjectPtr()->getKernel().Transform(m); } PY_CATCH; Py_Return; } PyObject* MeshPy::rotate(PyObject* args) { double x {}; double y {}; double z {}; if (!PyArg_ParseTuple(args, "ddd", &x, &y, &z)) { return nullptr; } PY_TRY { Base::Matrix4D m; m.rotX(x); m.rotY(y); m.rotZ(z); getMeshObjectPtr()->getKernel().Transform(m); } PY_CATCH; Py_Return; } PyObject* MeshPy::transform(PyObject* args) { PyObject* mat {}; if (!PyArg_ParseTuple(args, "O!", &(Base::MatrixPy::Type), &mat)) { return nullptr; } PY_TRY { getMeshObjectPtr()->getKernel().Transform(static_cast(mat)->value()); } PY_CATCH; Py_Return; } PyObject* MeshPy::transformToEigen(PyObject* args) { if (!PyArg_ParseTuple(args, "")) { return nullptr; } getMeshObjectPtr()->transformToEigenSystem(); Py_Return; } PyObject* MeshPy::getEigenSystem(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } Base::Vector3d vec; Base::Matrix4D mat = getMeshObjectPtr()->getEigenSystem(vec); Py::Tuple t(2); t.setItem(0, Py::Matrix(mat)); t.setItem(1, Py::Vector(vec)); return Py::new_reference_to(t); } PyObject* MeshPy::addFacet(PyObject* args) { double x1 {}; double y1 {}; double z1 {}; double x2 {}; double y2 {}; double z2 {}; double x3 {}; double y3 {}; double z3 {}; if (PyArg_ParseTuple(args, "ddddddddd", &x1, &y1, &z1, &x2, &y2, &z2, &x3, &y3, &z3)) { getMeshObjectPtr()->addFacet( MeshCore::MeshGeomFacet( Base::Vector3f((float)x1, (float)y1, (float)z1), Base::Vector3f((float)x2, (float)y2, (float)z2), Base::Vector3f((float)x3, (float)y3, (float)z3) ) ); Py_Return; } PyErr_Clear(); PyObject* v1 {}; PyObject* v2 {}; PyObject* v3 {}; if (PyArg_ParseTuple( args, "O!O!O!", &(Base::VectorPy::Type), &v1, &(Base::VectorPy::Type), &v2, &(Base::VectorPy::Type), &v3 )) { Base::Vector3d* p1 = static_cast(v1)->getVectorPtr(); Base::Vector3d* p2 = static_cast(v2)->getVectorPtr(); Base::Vector3d* p3 = static_cast(v3)->getVectorPtr(); getMeshObjectPtr()->addFacet( MeshCore::MeshGeomFacet( Base::Vector3f((float)p1->x, (float)p1->y, (float)p1->z), Base::Vector3f((float)p2->x, (float)p2->y, (float)p2->z), Base::Vector3f((float)p3->x, (float)p3->y, (float)p3->z) ) ); Py_Return; } PyErr_Clear(); PyObject* f {}; if (PyArg_ParseTuple(args, "O!", &(Mesh::FacetPy::Type), &f)) { Mesh::FacetPy* face = static_cast(f); getMeshObjectPtr()->addFacet(*face->getFacetPtr()); Py_Return; } PyErr_SetString(PyExc_TypeError, "set 9 floats or three vectors or a facet"); return nullptr; } PyObject* MeshPy::addFacets(PyObject* args) { PyObject* list {}; if (PyArg_ParseTuple(args, "O!", &PyList_Type, &list)) { Py::List list_f(list); Py::Type vVType(Base::getTypeAsObject(&Base::VectorPy::Type)); Py::Type vFType(Base::getTypeAsObject(&Mesh::FacetPy::Type)); std::vector facets; MeshCore::MeshGeomFacet facet; for (Py::List::iterator it = list_f.begin(); it != list_f.end(); ++it) { if ((*it).isType(vFType)) { Mesh::FacetPy* face = static_cast((*it).ptr()); facets.push_back(*face->getFacetPtr()); } else if ((*it).isSequence()) { Py::Sequence seq(*it); if (seq.size() == 3) { if (PyFloat_Check(seq[0].ptr())) { // every three triples build a triangle facet._aclPoints[0] = Base::getVectorFromTuple((*it).ptr()); ++it; facet._aclPoints[1] = Base::getVectorFromTuple((*it).ptr()); ++it; facet._aclPoints[2] = Base::getVectorFromTuple((*it).ptr()); } else if (seq[0].isSequence()) { // a sequence of sequence of flots for (int i = 0; i < 3; i++) { facet._aclPoints[i] = Base::getVectorFromTuple(seq[i].ptr()); } } else if (PyObject_TypeCheck(seq[0].ptr(), &(Base::VectorPy::Type))) { // a sequence of vectors for (int i = 0; i < 3; i++) { Base::Vector3d p = Py::Vector(seq[i]).toVector(); facet._aclPoints[i].Set((float)p.x, (float)p.y, (float)p.z); } } else { PyErr_SetString(PyExc_TypeError, "expect a sequence of floats or Vector"); return nullptr; } facet.CalcNormal(); facets.push_back(facet); } else { // 9 consecutive floats expected int index = 0; for (auto& point : facet._aclPoints) { point.x = Py::Float(seq[index++]); point.y = Py::Float(seq[index++]); point.z = Py::Float(seq[index++]); } facet.CalcNormal(); facets.push_back(facet); } } // sequence } getMeshObjectPtr()->addFacets(facets); Py_Return; } PyErr_Clear(); PyObject* check = Py_True; if (PyArg_ParseTuple(args, "O!|O!", &PyTuple_Type, &list, &PyBool_Type, &check)) { Py::Tuple tuple(list); Py::List list_v(tuple.getItem(0)); std::vector vertices; Py::Type vType(Base::getTypeAsObject(&Base::VectorPy::Type)); for (Py::List::iterator it = list_v.begin(); it != list_v.end(); ++it) { if ((*it).isType(vType)) { Base::Vector3d v = static_cast((*it).ptr())->value(); vertices.emplace_back((float)v.x, (float)v.y, (float)v.z); } } Py::List list_f(tuple.getItem(1)); MeshCore::MeshFacetArray faces; for (Py::List::iterator it = list_f.begin(); it != list_f.end(); ++it) { Py::Tuple f(*it); MeshCore::MeshFacet face; face._aulPoints[0] = static_cast(Py::Long(f.getItem(0))); face._aulPoints[1] = static_cast(Py::Long(f.getItem(1))); face._aulPoints[2] = static_cast(Py::Long(f.getItem(2))); faces.push_back(face); } getMeshObjectPtr()->addFacets(faces, vertices, Base::asBoolean(check)); Py_Return; } PyErr_SetString( PyExc_TypeError, "either expect\n" "-- [Vector] (3 of them define a facet)\n" "-- ([Vector],[(int,int,int)])" ); return nullptr; } PyObject* MeshPy::removeFacets(PyObject* args) { PyObject* list {}; if (!PyArg_ParseTuple(args, "O", &list)) { return nullptr; } std::vector indices; Py::Sequence ary(list); for (Py::Sequence::iterator it = ary.begin(); it != ary.end(); ++it) { Py::Long f(*it); indices.push_back((long)f); } getMeshObjectPtr()->deleteFacets(indices); Py_Return; } PyObject* MeshPy::getInternalFacets(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } const MeshCore::MeshKernel& kernel = getMeshObjectPtr()->getKernel(); MeshCore::MeshEvalInternalFacets eval(kernel); eval.Evaluate(); const std::vector& indices = eval.GetIndices(); Py::List ary(indices.size()); Py::List::size_type pos = 0; for (FacetIndex index : indices) { ary[pos++] = Py::Long(index); } return Py::new_reference_to(ary); } PyObject* MeshPy::rebuildNeighbourHood(PyObject* args) { if (!PyArg_ParseTuple(args, "")) { return nullptr; } MeshCore::MeshKernel& kernel = getMeshObjectPtr()->getKernel(); kernel.RebuildNeighbours(); Py_Return; } PyObject* MeshPy::addMesh(PyObject* args) { PyObject* mesh {}; if (!PyArg_ParseTuple(args, "O!", &(MeshPy::Type), &mesh)) { return nullptr; } PY_TRY { getMeshObjectPtr()->addMesh(*static_cast(mesh)->getMeshObjectPtr()); } PY_CATCH; Py_Return; } PyObject* MeshPy::setPoint(PyObject* args) { unsigned long index {}; PyObject* pnt {}; if (!PyArg_ParseTuple(args, "kO!", &index, &(Base::VectorPy::Type), &pnt)) { return nullptr; } PY_TRY { MeshObject* mesh = getMeshObjectPtr(); if (index >= mesh->countPoints()) { Base::IndexError exc("index out of range"); exc.setPyException(); return nullptr; } mesh->setPoint(index, static_cast(pnt)->value()); } PY_CATCH; Py_Return; } PyObject* MeshPy::movePoint(PyObject* args) { unsigned long index {}; Base::Vector3d vec; do { double x = 0.0; double y = 0.0; double z = 0.0; if (PyArg_ParseTuple(args, "kddd", &index, &x, &y, &z)) { vec.Set(x, y, z); break; } PyErr_Clear(); // set by PyArg_ParseTuple() PyObject* object {}; if (PyArg_ParseTuple(args, "kO!", &index, &(Base::VectorPy::Type), &object)) { vec = *(static_cast(object)->getVectorPtr()); break; } PyErr_SetString(PyExc_TypeError, "Tuple of three floats or Vector expected"); return nullptr; } while (false); MeshObject* mesh = getMeshObjectPtr(); if (index >= mesh->countPoints()) { Base::IndexError exc("index out of range"); exc.setPyException(); return nullptr; } mesh->movePoint(index, vec); Py_Return; } PyObject* MeshPy::getPointNormals(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } PY_TRY { std::vector normals = getMeshObjectPtr()->getPointNormals(); Py::Tuple ary(normals.size()); std::size_t numNormals = normals.size(); for (std::size_t i = 0; i < numNormals; i++) { ary.setItem(i, Py::Vector(normals[i])); } return Py::new_reference_to(ary); } PY_CATCH; } PyObject* MeshPy::addSegment(PyObject* args) { PyObject* pylist {}; if (!PyArg_ParseTuple(args, "O", &pylist)) { return nullptr; } Py::Sequence list(pylist); std::vector segment; unsigned long numFacets = getMeshObjectPtr()->countFacets(); segment.reserve(list.size()); for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { Py::Long value(*it); Mesh::FacetIndex index = static_cast(value); if (index < numFacets) { segment.push_back(index); } } getMeshObjectPtr()->addSegment(segment); Py_Return; } PyObject* MeshPy::countSegments(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } unsigned long count = getMeshObjectPtr()->countSegments(); return Py_BuildValue("k", count); } PyObject* MeshPy::getSegment(PyObject* args) const { unsigned long index {}; if (!PyArg_ParseTuple(args, "k", &index)) { return nullptr; } unsigned long count = getMeshObjectPtr()->countSegments(); if (index >= count) { PyErr_SetString(PyExc_IndexError, "index out of range"); return nullptr; } Py::List ary; const std::vector& segm = getMeshObjectPtr()->getSegment(index).getIndices(); for (FacetIndex it : segm) { ary.append(Py::Long(it)); } return Py::new_reference_to(ary); } PyObject* MeshPy::getSeparateComponents(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } Py::List meshesList; std::vector> segs; segs = getMeshObjectPtr()->getComponents(); for (const auto& it : segs) { MeshObject* mesh = getMeshObjectPtr()->meshFromSegment(it); meshesList.append(Py::Object(new MeshPy(mesh), true)); } return Py::new_reference_to(meshesList); } PyObject* MeshPy::getFacetSelection(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } Py::List ary; std::vector facets; getMeshObjectPtr()->getFacetsFromSelection(facets); for (FacetIndex facet : facets) { ary.append(Py::Long(int(facet))); } return Py::new_reference_to(ary); } PyObject* MeshPy::getPointSelection(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } Py::List ary; std::vector points; getMeshObjectPtr()->getPointsFromSelection(points); for (PointIndex point : points) { ary.append(Py::Long(int(point))); } return Py::new_reference_to(ary); } PyObject* MeshPy::meshFromSegment(PyObject* args) const { PyObject* list {}; if (!PyArg_ParseTuple(args, "O", &list)) { return nullptr; } std::vector segment; Py::Sequence ary(list); for (Py::Sequence::iterator it = ary.begin(); it != ary.end(); ++it) { Py::Long f(*it); segment.push_back((long)f); } MeshObject* mesh = getMeshObjectPtr()->meshFromSegment(segment); return new MeshPy(mesh); } PyObject* MeshPy::clear(PyObject* args) { if (!PyArg_ParseTuple(args, "")) { return nullptr; } getMeshObjectPtr()->clear(); Py_Return; } PyObject* MeshPy::isSolid(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } bool ok = getMeshObjectPtr()->isSolid(); return Py_BuildValue("O", (ok ? Py_True : Py_False)); } PyObject* MeshPy::hasNonManifolds(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } bool ok = getMeshObjectPtr()->hasNonManifolds(); return Py_BuildValue("O", (ok ? Py_True : Py_False)); } PyObject* MeshPy::hasInvalidNeighbourhood(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } bool ok = getMeshObjectPtr()->hasInvalidNeighbourhood(); return Py_BuildValue("O", (ok ? Py_True : Py_False)); } PyObject* MeshPy::hasPointsOutOfRange(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } bool ok = getMeshObjectPtr()->hasPointsOutOfRange(); return Py_BuildValue("O", (ok ? Py_True : Py_False)); } PyObject* MeshPy::hasFacetsOutOfRange(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } bool ok = getMeshObjectPtr()->hasFacetsOutOfRange(); return Py_BuildValue("O", (ok ? Py_True : Py_False)); } PyObject* MeshPy::hasCorruptedFacets(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } bool ok = getMeshObjectPtr()->hasFacetsOutOfRange(); return Py_BuildValue("O", (ok ? Py_True : Py_False)); } PyObject* MeshPy::removeNonManifolds(PyObject* args) { if (!PyArg_ParseTuple(args, "")) { return nullptr; } getMeshObjectPtr()->removeNonManifolds(); Py_Return; } PyObject* MeshPy::removeNonManifoldPoints(PyObject* args) { if (!PyArg_ParseTuple(args, "")) { return nullptr; } getMeshObjectPtr()->removeNonManifoldPoints(); Py_Return; } PyObject* MeshPy::hasSelfIntersections(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } bool ok = getMeshObjectPtr()->hasSelfIntersections(); return Py_BuildValue("O", (ok ? Py_True : Py_False)); } PyObject* MeshPy::getSelfIntersections(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } std::vector> selfIndices; std::vector selfLines; selfIndices = getMeshObjectPtr()->getSelfIntersections(); selfLines = getMeshObjectPtr()->getSelfIntersections(selfIndices); Py::Tuple tuple(selfIndices.size()); if (selfIndices.size() == selfLines.size()) { for (std::size_t i = 0; i < selfIndices.size(); i++) { Py::Tuple item(4); item.setItem(0, Py::Long(selfIndices[i].first)); item.setItem(1, Py::Long(selfIndices[i].second)); item.setItem(2, Py::Vector(selfLines[i].p1)); item.setItem(3, Py::Vector(selfLines[i].p2)); tuple.setItem(i, item); } } return Py::new_reference_to(tuple); } PyObject* MeshPy::fixSelfIntersections(PyObject* args) { if (!PyArg_ParseTuple(args, "")) { return nullptr; } try { getMeshObjectPtr()->removeSelfIntersections(); } catch (const Base::Exception& e) { e.setPyException(); return nullptr; } Py_Return; } PyObject* MeshPy::removeFoldsOnSurface(PyObject* args) { if (!PyArg_ParseTuple(args, "")) { return nullptr; } try { getMeshObjectPtr()->removeFoldsOnSurface(); } catch (const Base::Exception& e) { e.setPyException(); return nullptr; } Py_Return; } PyObject* MeshPy::hasInvalidPoints(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } bool ok = getMeshObjectPtr()->hasInvalidPoints(); return Py_BuildValue("O", (ok ? Py_True : Py_False)); } PyObject* MeshPy::removeInvalidPoints(PyObject* args) { if (!PyArg_ParseTuple(args, "")) { return nullptr; } try { getMeshObjectPtr()->removeInvalidPoints(); } catch (const Base::Exception& e) { e.setPyException(); return nullptr; } Py_Return; } PyObject* MeshPy::hasPointsOnEdge(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } bool ok = getMeshObjectPtr()->hasPointsOnEdge(); return Py_BuildValue("O", (ok ? Py_True : Py_False)); } PyObject* MeshPy::removePointsOnEdge(PyObject* args, PyObject* kwds) { PyObject* fillBoundary = Py_False; // NOLINT static const std::array keywords {"FillBoundary", nullptr}; if (!Base::Wrapped_ParseTupleAndKeywords(args, kwds, "|O!", keywords, &PyBool_Type, &fillBoundary)) { return nullptr; } try { getMeshObjectPtr()->removePointsOnEdge(Base::asBoolean(fillBoundary)); } catch (const Base::Exception& e) { e.setPyException(); return nullptr; } Py_Return; } PyObject* MeshPy::flipNormals(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } PY_TRY { MeshPropertyLock lock(this->parentProperty); getMeshObjectPtr()->flipNormals(); } PY_CATCH; Py_Return; } PyObject* MeshPy::hasNonUniformOrientedFacets(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } bool ok = getMeshObjectPtr()->countNonUniformOrientedFacets() > 0; return Py_BuildValue("O", (ok ? Py_True : Py_False)); } PyObject* MeshPy::countNonUniformOrientedFacets(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } unsigned long count = getMeshObjectPtr()->countNonUniformOrientedFacets(); return Py_BuildValue("k", count); } PyObject* MeshPy::getNonUniformOrientedFacets(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } const MeshCore::MeshKernel& kernel = getMeshObjectPtr()->getKernel(); MeshCore::MeshEvalOrientation cMeshEval(kernel); std::vector inds = cMeshEval.GetIndices(); Py::Tuple tuple(inds.size()); for (std::size_t i = 0; i < inds.size(); i++) { tuple.setItem(i, Py::Long(inds[i])); } return Py::new_reference_to(tuple); } PyObject* MeshPy::harmonizeNormals(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } PY_TRY { MeshPropertyLock lock(this->parentProperty); getMeshObjectPtr()->harmonizeNormals(); } PY_CATCH; Py_Return; } PyObject* MeshPy::countComponents(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } unsigned long count = getMeshObjectPtr()->countComponents(); return Py_BuildValue("k", count); } PyObject* MeshPy::removeComponents(PyObject* args) { unsigned long count {}; if (!PyArg_ParseTuple(args, "k", &count)) { return nullptr; } PY_TRY { if (count > 0) { getMeshObjectPtr()->removeComponents(count); } } PY_CATCH; Py_Return; } PyObject* MeshPy::fillupHoles(PyObject* args) const { unsigned long len {}; int level = 0; float max_area = 0.0F; if (!PyArg_ParseTuple(args, "k|if", &len, &level, &max_area)) { return nullptr; } try { std::unique_ptr tria; if (max_area > 0.0F) { tria = std::unique_ptr( new MeshCore::ConstraintDelaunayTriangulator(max_area) ); } else { tria = std::unique_ptr( new MeshCore::FlatTriangulator() ); } MeshPropertyLock lock(this->parentProperty); tria->SetVerifier(new MeshCore::TriangulationVerifierV2); getMeshObjectPtr()->fillupHoles(len, level, *tria); } catch (const Base::Exception& e) { e.setPyException(); return nullptr; } Py_Return; } PyObject* MeshPy::fixIndices(PyObject* args) { if (!PyArg_ParseTuple(args, "")) { return nullptr; } PY_TRY { getMeshObjectPtr()->validateIndices(); } PY_CATCH; Py_Return; } PyObject* MeshPy::fixCaps(PyObject* args) { float fMaxAngle = Base::toRadians(150.0F); float fSplitFactor = 0.25F; if (!PyArg_ParseTuple(args, "|ff", &fMaxAngle, &fSplitFactor)) { return nullptr; } PY_TRY { getMeshObjectPtr()->validateCaps(fMaxAngle, fSplitFactor); } PY_CATCH; Py_Return; } PyObject* MeshPy::fixDeformations(PyObject* args) { float fMaxAngle {}; float fEpsilon = MeshCore::MeshDefinitions::_fMinPointDistanceP2; if (!PyArg_ParseTuple(args, "f|f", &fMaxAngle, &fEpsilon)) { return nullptr; } PY_TRY { getMeshObjectPtr()->validateDeformations(fMaxAngle, fEpsilon); } PY_CATCH; Py_Return; } PyObject* MeshPy::fixDegenerations(PyObject* args) { float fEpsilon = MeshCore::MeshDefinitions::_fMinPointDistanceP2; if (!PyArg_ParseTuple(args, "|f", &fEpsilon)) { return nullptr; } PY_TRY { getMeshObjectPtr()->validateDegenerations(fEpsilon); } PY_CATCH; Py_Return; } PyObject* MeshPy::removeDuplicatedPoints(PyObject* args) { if (!PyArg_ParseTuple(args, "")) { return nullptr; } PY_TRY { getMeshObjectPtr()->removeDuplicatedPoints(); } PY_CATCH; Py_Return; } PyObject* MeshPy::removeDuplicatedFacets(PyObject* args) { if (!PyArg_ParseTuple(args, "")) { return nullptr; } PY_TRY { getMeshObjectPtr()->removeDuplicatedFacets(); } PY_CATCH; Py_Return; } PyObject* MeshPy::refine(PyObject* args) { if (!PyArg_ParseTuple(args, "")) { return nullptr; } PY_TRY { getMeshObjectPtr()->refine(); } PY_CATCH; Py_Return; } PyObject* MeshPy::removeNeedles(PyObject* args) { float length {}; if (!PyArg_ParseTuple(args, "f", &length)) { return nullptr; } PY_TRY { getMeshObjectPtr()->removeNeedles(length); } PY_CATCH; Py_Return; } PyObject* MeshPy::removeFullBoundaryFacets(PyObject* args) { if (!PyArg_ParseTuple(args, "")) { return nullptr; } PY_TRY { getMeshObjectPtr()->removeFullBoundaryFacets(); } PY_CATCH; Py_Return; } PyObject* MeshPy::mergeFacets(PyObject* args) { if (!PyArg_ParseTuple(args, "")) { return nullptr; } PY_TRY { getMeshObjectPtr()->mergeFacets(); } PY_CATCH; Py_Return; } PyObject* MeshPy::optimizeTopology(PyObject* args) const { float fMaxAngle = -1.0F; if (!PyArg_ParseTuple( args, "|f; specify the maximum allowed angle between the normals of two adjacent facets", &fMaxAngle )) { return nullptr; } PY_TRY { MeshPropertyLock lock(this->parentProperty); getMeshObjectPtr()->optimizeTopology(fMaxAngle); } PY_CATCH; Py_Return; } PyObject* MeshPy::optimizeEdges(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } PY_TRY { MeshPropertyLock lock(this->parentProperty); getMeshObjectPtr()->optimizeEdges(); } PY_CATCH; Py_Return; } PyObject* MeshPy::splitEdges(PyObject* args) { if (!PyArg_ParseTuple(args, "")) { return nullptr; } PY_TRY { getMeshObjectPtr()->splitEdges(); } PY_CATCH; Py_Return; } PyObject* MeshPy::splitEdge(PyObject* args) { unsigned long facet {}; unsigned long neighbour {}; PyObject* vertex {}; if (!PyArg_ParseTuple(args, "kkO!", &facet, &neighbour, &Base::VectorPy::Type, &vertex)) { return nullptr; } Base::VectorPy* pcObject = static_cast(vertex); Base::Vector3d* val = pcObject->getVectorPtr(); Base::Vector3f v((float)val->x, (float)val->y, (float)val->z); const MeshCore::MeshKernel& kernel = getMeshObjectPtr()->getKernel(); PY_TRY { if (facet >= kernel.CountFacets()) { PyErr_SetString(PyExc_IndexError, "Facet index out of range"); return nullptr; } if (neighbour >= kernel.CountFacets()) { PyErr_SetString(PyExc_IndexError, "Facet index out of range"); return nullptr; } const MeshCore::MeshFacet& rclF = kernel.GetFacets()[facet]; if (rclF._aulNeighbours[0] != neighbour && rclF._aulNeighbours[1] != neighbour && rclF._aulNeighbours[2] != neighbour) { PyErr_SetString(PyExc_IndexError, "No adjacent facets"); return nullptr; } getMeshObjectPtr()->splitEdge(facet, neighbour, v); } PY_CATCH; Py_Return; } PyObject* MeshPy::splitFacet(PyObject* args) { unsigned long facet {}; PyObject* vertex1 {}; PyObject* vertex2 {}; if (!PyArg_ParseTuple( args, "kO!O!", &facet, &Base::VectorPy::Type, &vertex1, &Base::VectorPy::Type, &vertex2 )) { return nullptr; } Base::VectorPy* pcObject = static_cast(vertex1); Base::Vector3d* val = pcObject->getVectorPtr(); Base::Vector3f v1((float)val->x, (float)val->y, (float)val->z); pcObject = static_cast(vertex2); val = pcObject->getVectorPtr(); Base::Vector3f v2((float)val->x, (float)val->y, (float)val->z); const MeshCore::MeshKernel& kernel = getMeshObjectPtr()->getKernel(); PY_TRY { if (facet >= kernel.CountFacets()) { PyErr_SetString(PyExc_IndexError, "Facet index out of range"); return nullptr; } getMeshObjectPtr()->splitFacet(facet, v1, v2); } PY_CATCH; Py_Return; } PyObject* MeshPy::swapEdge(PyObject* args) { unsigned long facet {}; unsigned long neighbour {}; if (!PyArg_ParseTuple(args, "kk", &facet, &neighbour)) { return nullptr; } const MeshCore::MeshKernel& kernel = getMeshObjectPtr()->getKernel(); PY_TRY { if (facet >= kernel.CountFacets()) { PyErr_SetString(PyExc_IndexError, "Facet index out of range"); return nullptr; } if (neighbour >= kernel.CountFacets()) { PyErr_SetString(PyExc_IndexError, "Facet index out of range"); return nullptr; } const MeshCore::MeshFacet& rclF = kernel.GetFacets()[facet]; if (rclF._aulNeighbours[0] != neighbour && rclF._aulNeighbours[1] != neighbour && rclF._aulNeighbours[2] != neighbour) { PyErr_SetString(PyExc_IndexError, "No adjacent facets"); return nullptr; } getMeshObjectPtr()->swapEdge(facet, neighbour); } PY_CATCH; Py_Return; } PyObject* MeshPy::collapseEdge(PyObject* args) { unsigned long facet {}; unsigned long neighbour {}; if (!PyArg_ParseTuple(args, "kk", &facet, &neighbour)) { return nullptr; } const MeshCore::MeshKernel& kernel = getMeshObjectPtr()->getKernel(); PY_TRY { if (facet >= kernel.CountFacets()) { PyErr_SetString(PyExc_IndexError, "Facet index out of range"); return nullptr; } if (neighbour >= kernel.CountFacets()) { PyErr_SetString(PyExc_IndexError, "Facet index out of range"); return nullptr; } const MeshCore::MeshFacet& rclF = kernel.GetFacets()[facet]; if (rclF._aulNeighbours[0] != neighbour && rclF._aulNeighbours[1] != neighbour && rclF._aulNeighbours[2] != neighbour) { PyErr_SetString(PyExc_IndexError, "No adjacent facets"); return nullptr; } getMeshObjectPtr()->collapseEdge(facet, neighbour); } PY_CATCH; Py_Return; } PyObject* MeshPy::collapseFacet(PyObject* args) { unsigned long facet {}; if (!PyArg_ParseTuple(args, "k", &facet)) { return nullptr; } PY_TRY { if (facet >= getMeshObjectPtr()->countFacets()) { PyErr_SetString(PyExc_IndexError, "Facet index out of range"); return nullptr; } getMeshObjectPtr()->collapseFacet(facet); } PY_CATCH; Py_Return; } PyObject* MeshPy::insertVertex(PyObject* args) { unsigned long facet {}; PyObject* vertex {}; if (!PyArg_ParseTuple(args, "kO!", &facet, &Base::VectorPy::Type, &vertex)) { return nullptr; } Base::VectorPy* pcObject = static_cast(vertex); Base::Vector3d* val = pcObject->getVectorPtr(); Base::Vector3f v((float)val->x, (float)val->y, (float)val->z); PY_TRY { if (facet >= getMeshObjectPtr()->countFacets()) { PyErr_SetString(PyExc_IndexError, "Facet index out of range"); return nullptr; } getMeshObjectPtr()->insertVertex(facet, v); } PY_CATCH; Py_Return; } PyObject* MeshPy::snapVertex(PyObject* args) { unsigned long facet {}; PyObject* vertex {}; if (!PyArg_ParseTuple(args, "kO!", &facet, &Base::VectorPy::Type, &vertex)) { return nullptr; } Base::VectorPy* pcObject = static_cast(vertex); Base::Vector3d* val = pcObject->getVectorPtr(); Base::Vector3f v((float)val->x, (float)val->y, (float)val->z); PY_TRY { if (facet >= getMeshObjectPtr()->countFacets()) { PyErr_SetString(PyExc_IndexError, "Facet index out of range"); return nullptr; } getMeshObjectPtr()->snapVertex(facet, v); } PY_CATCH; Py_Return; } PyObject* MeshPy::printInfo(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } return Py_BuildValue("s", getMeshObjectPtr()->topologyInfo().c_str()); } PyObject* MeshPy::collapseFacets(PyObject* args) { PyObject* pcObj = nullptr; if (!PyArg_ParseTuple(args, "O", &pcObj)) { return nullptr; } // if no mesh is given try { Py::Sequence list(pcObj); std::vector facets; for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { Py::Long idx(*it); unsigned long iIdx = static_cast(idx); facets.push_back(iIdx); } getMeshObjectPtr()->collapseFacets(facets); } catch (const Py::Exception&) { return nullptr; } Py_Return; } PyObject* MeshPy::foraminate(PyObject* args) const { PyObject* pnt_p {}; PyObject* dir_p {}; double maxAngle = MeshCore::Mathd::PI; if (!PyArg_ParseTuple(args, "OO|d", &pnt_p, &dir_p, &maxAngle)) { return nullptr; } try { Py::Vector pnt_t(pnt_p, false); Py::Vector dir_t(dir_p, false); MeshObject::TRay ray = std::make_pair(pnt_t.toVector(), dir_t.toVector()); auto output = getMeshObjectPtr()->foraminate(ray, maxAngle); Py::Dict dict; for (const auto& it : output) { Py::Tuple tuple(3); tuple.setItem(0, Py::Float(it.second.x)); tuple.setItem(1, Py::Float(it.second.y)); tuple.setItem(2, Py::Float(it.second.z)); dict.setItem(Py::Long(it.first), tuple); } return Py::new_reference_to(dict); } catch (const Py::Exception&) { return nullptr; } } PyObject* MeshPy::cut(PyObject* args) { PyObject* poly {}; int mode {}; if (!PyArg_ParseTuple(args, "Oi", &poly, &mode)) { return nullptr; } Py::Sequence list(poly); std::vector polygon; polygon.reserve(list.size()); for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { Base::Vector3d pnt = Py::Vector(*it).toVector(); polygon.push_back(Base::convertTo(pnt)); } MeshCore::FlatTriangulator tria; tria.SetPolygon(polygon); // this gives us the inverse matrix Base::Matrix4D inv = tria.GetTransformToFitPlane(); // compute the matrix for the coordinate transformation Base::Matrix4D mat = inv; mat.inverseOrthogonal(); polygon = tria.ProjectToFitPlane(); Base::ViewProjMatrix proj(mat); Base::Polygon2d polygon2d; for (auto it : polygon) { polygon2d.Add(Base::Vector2d(it.x, it.y)); } getMeshObjectPtr()->cut(polygon2d, proj, MeshObject::CutType(mode)); Py_Return; } PyObject* MeshPy::trim(PyObject* args) { PyObject* poly {}; int mode {}; if (!PyArg_ParseTuple(args, "Oi", &poly, &mode)) { return nullptr; } Py::Sequence list(poly); std::vector polygon; polygon.reserve(list.size()); for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { Base::Vector3d pnt = Py::Vector(*it).toVector(); polygon.push_back(Base::convertTo(pnt)); } MeshCore::FlatTriangulator tria; tria.SetPolygon(polygon); // this gives us the inverse matrix Base::Matrix4D inv = tria.GetTransformToFitPlane(); // compute the matrix for the coordinate transformation Base::Matrix4D mat = inv; mat.inverseOrthogonal(); polygon = tria.ProjectToFitPlane(); Base::ViewOrthoProjMatrix proj(mat); Base::Polygon2d polygon2d; for (auto it : polygon) { polygon2d.Add(Base::Vector2d(it.x, it.y)); } getMeshObjectPtr()->trim(polygon2d, proj, MeshObject::CutType(mode)); Py_Return; } PyObject* MeshPy::trimByPlane(PyObject* args) { PyObject* base {}; PyObject* norm {}; if (!PyArg_ParseTuple(args, "O!O!", &Base::VectorPy::Type, &base, &Base::VectorPy::Type, &norm)) { return nullptr; } Base::Vector3d pnt = Py::Vector(base, false).toVector(); Base::Vector3d dir = Py::Vector(norm, false).toVector(); getMeshObjectPtr()->trimByPlane( Base::convertTo(pnt), Base::convertTo(dir) ); Py_Return; } PyObject* MeshPy::smooth(PyObject* args, PyObject* kwds) const { const char* method = "Laplace"; int iter = 1; double lambda = 0; double micro = 0; double maximum = 1000; int weight = 1; static const std::array keywords_smooth {"Method", "Iteration", "Lambda", "Micro", "Maximum", "Weight", nullptr}; if (!Base::Wrapped_ParseTupleAndKeywords( args, kwds, "|sidddi", keywords_smooth, &method, &iter, &lambda, µ, &maximum, &weight )) { return nullptr; } PY_TRY { MeshPropertyLock lock(this->parentProperty); MeshCore::MeshKernel& kernel = getMeshObjectPtr()->getKernel(); if (strcmp(method, "Laplace") == 0) { MeshCore::LaplaceSmoothing smooth(kernel); if (lambda > 0) { smooth.SetLambda(lambda); } smooth.Smooth(iter); } else if (strcmp(method, "Taubin") == 0) { MeshCore::TaubinSmoothing smooth(kernel); if (lambda > 0) { smooth.SetLambda(lambda); } if (micro > 0) { smooth.SetMicro(micro); } smooth.Smooth(iter); } else if (strcmp(method, "PlaneFit") == 0) { MeshCore::PlaneFitSmoothing smooth(kernel); smooth.SetMaximum(maximum); smooth.Smooth(iter); } else if (strcmp(method, "MedianFilter") == 0) { MeshCore::MedianFilterSmoothing smooth(kernel); smooth.SetWeight(weight); smooth.Smooth(iter); } else { throw Py::ValueError("No such smoothing algorithm"); } } PY_CATCH; Py_Return; } PyObject* MeshPy::decimate(PyObject* args) { float fTol {}; float fRed {}; if (PyArg_ParseTuple(args, "ff", &fTol, &fRed)) { PY_TRY { getMeshObjectPtr()->decimate(fTol, fRed); } PY_CATCH; Py_Return; } PyErr_Clear(); int targetSize {}; if (PyArg_ParseTuple(args, "i", &targetSize)) { PY_TRY { getMeshObjectPtr()->decimate(targetSize); } PY_CATCH; Py_Return; } PyErr_SetString( PyExc_ValueError, "decimate(tolerance=float, reduction=float) or decimate(targetSize=int)" ); return nullptr; } PyObject* MeshPy::nearestFacetOnRay(PyObject* args) const { PyObject* pnt_p {}; PyObject* dir_p {}; double maxAngle = MeshCore::Mathd::PI; if (!PyArg_ParseTuple(args, "OO|d", &pnt_p, &dir_p, &maxAngle)) { return nullptr; } try { Py::Vector pnt_t(pnt_p, false); Py::Vector dir_t(dir_p, false); Py::Dict dict; MeshObject::TRay ray = std::make_pair(pnt_t.toVector(), dir_t.toVector()); MeshObject::TFaceSection output; if (getMeshObjectPtr()->nearestFacetOnRay(ray, maxAngle, output)) { Py::Tuple tuple(3); tuple.setItem(0, Py::Float(output.second.x)); tuple.setItem(1, Py::Float(output.second.y)); tuple.setItem(2, Py::Float(output.second.z)); dict.setItem(Py::Long(static_cast(output.first)), tuple); } return Py::new_reference_to(dict); } catch (const Py::Exception&) { return nullptr; } } PyObject* MeshPy::getPlanarSegments(PyObject* args) const { float dev {}; unsigned long minFacets = 0; if (!PyArg_ParseTuple(args, "f|k", &dev, &minFacets)) { return nullptr; } Mesh::MeshObject* mesh = getMeshObjectPtr(); std::vector segments = mesh->getSegmentsOfType(Mesh::MeshObject::PLANE, dev, minFacets); Py::List s; for (const auto& segment : segments) { const std::vector& segm = segment.getIndices(); Py::List ary; for (FacetIndex jt : segm) { ary.append(Py::Long(jt)); } s.append(ary); } return Py::new_reference_to(s); } PyObject* MeshPy::getSegmentsOfType(PyObject* args) const { char* type {}; float dev {}; unsigned long minFacets = 0; if (!PyArg_ParseTuple(args, "sf|k", &type, &dev, &minFacets)) { return nullptr; } Mesh::MeshObject::GeometryType geoType {}; if (strcmp(type, "Plane") == 0) { geoType = Mesh::MeshObject::PLANE; } else if (strcmp(type, "Cylinder") == 0) { geoType = Mesh::MeshObject::CYLINDER; } else if (strcmp(type, "Sphere") == 0) { geoType = Mesh::MeshObject::SPHERE; } else { PyErr_SetString(PyExc_ValueError, "Unsupported surface type"); return nullptr; } Mesh::MeshObject* mesh = getMeshObjectPtr(); std::vector segments = mesh->getSegmentsOfType(geoType, dev, minFacets); Py::List s; for (const auto& segment : segments) { const std::vector& segm = segment.getIndices(); Py::List ary; for (FacetIndex jt : segm) { ary.append(Py::Long(int(jt))); } s.append(ary); } return Py::new_reference_to(s); } PyObject* MeshPy::getSegmentsByCurvature(PyObject* args) const { PyObject* l {}; if (!PyArg_ParseTuple(args, "O", &l)) { return nullptr; } const MeshCore::MeshKernel& kernel = getMeshObjectPtr()->getKernel(); MeshCore::MeshSegmentAlgorithm finder(kernel); MeshCore::MeshCurvature meshCurv(kernel); meshCurv.ComputePerVertex(); Py::Sequence func(l); std::vector segm; for (Py::Sequence::iterator it = func.begin(); it != func.end(); ++it) { Py::Tuple t(*it); float c1 = Py::Float(t[0]); float c2 = Py::Float(t[1]); float tol1 = Py::Float(t[2]); float tol2 = Py::Float(t[3]); int num = (int)Py::Long(t[4]); segm.emplace_back( std::make_shared( meshCurv.GetCurvature(), num, tol1, tol2, c1, c2 ) ); } finder.FindSegments(segm); Py::List list; for (const auto& segmIt : segm) { const std::vector& data = segmIt->GetSegments(); for (const auto& it : data) { Py::List ary; for (FacetIndex jt : it) { ary.append(Py::Long(int(jt))); } list.append(ary); } } return Py::new_reference_to(list); } PyObject* MeshPy::getCurvaturePerVertex(PyObject* args) const { if (!PyArg_ParseTuple(args, "")) { return nullptr; } const MeshCore::MeshKernel& kernel = getMeshObjectPtr()->getKernel(); MeshCore::MeshCurvature meshCurv(kernel); meshCurv.ComputePerVertex(); const std::vector& curv = meshCurv.GetCurvature(); Base::Placement plm = getMeshObjectPtr()->getPlacement(); plm.setPosition(Base::Vector3d()); Py::List list; for (const auto& it : curv) { Base::Vector3d maxCurve = Base::convertTo(it.cMaxCurvDir); Base::Vector3d minCurve = Base::convertTo(it.cMinCurvDir); plm.multVec(maxCurve, maxCurve); plm.multVec(minCurve, minCurve); Py::Tuple tuple(4); tuple.setItem(0, Py::Float(it.fMaxCurvature)); tuple.setItem(1, Py::Float(it.fMinCurvature)); tuple.setItem(2, Py::Vector(maxCurve)); tuple.setItem(3, Py::Vector(minCurve)); list.append(tuple); } return Py::new_reference_to(list); } Py::Long MeshPy::getCountPoints() const { return Py::Long((long)getMeshObjectPtr()->countPoints()); } Py::Long MeshPy::getCountEdges() const { return Py::Long((long)getMeshObjectPtr()->countEdges()); } Py::Long MeshPy::getCountFacets() const { return Py::Long((long)getMeshObjectPtr()->countFacets()); } Py::Float MeshPy::getArea() const { return Py::Float(getMeshObjectPtr()->getSurface()); } Py::Float MeshPy::getVolume() const { return Py::Float(getMeshObjectPtr()->getVolume()); } PyObject* MeshPy::getCustomAttributes(const char* /*attr*/) const { return nullptr; } int MeshPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) { return 0; } Py::List MeshPy::getPoints() const { Py::List PointList; unsigned int Index = 0; MeshObject* mesh = getMeshObjectPtr(); for (MeshObject::const_point_iterator it = mesh->points_begin(); it != mesh->points_end(); ++it) { PointList.append( Py::Object(new MeshPointPy(new MeshPoint(*it, getMeshObjectPtr(), Index++)), true) ); } return PointList; } Py::List MeshPy::getFacets() const { Py::List FacetList; MeshObject* mesh = getMeshObjectPtr(); for (MeshObject::const_facet_iterator it = mesh->facets_begin(); it != mesh->facets_end(); ++it) { FacetList.append(Py::Object(new FacetPy(new Facet(*it)), true)); } return FacetList; } Py::Tuple MeshPy::getTopology() const { std::vector Points; std::vector Facets; getMeshObjectPtr()->getFaces(Points, Facets, 0.0); Py::Tuple tuple(2); Py::List vertex; for (const auto& Point : Points) { vertex.append(Py::asObject(new Base::VectorPy(Point))); } tuple.setItem(0, vertex); Py::List facet; for (auto it : Facets) { Py::Tuple f(3); f.setItem(0, Py::Long((int)it.I1)); f.setItem(1, Py::Long((int)it.I2)); f.setItem(2, Py::Long((int)it.I3)); facet.append(f); } tuple.setItem(1, facet); return tuple; }