/*************************************************************************** * Copyright (c) 2008 Jürgen Riegel * * * * 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_ # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "OCCError.h" #include "PartPyCXX.h" #include "ShapeMapHasher.h" #include "TopoShapeMapper.h" using namespace Part; static Py_hash_t _TopoShapeHash(PyObject* self) { if (!self) { PyErr_SetString(PyExc_TypeError, "descriptor 'hash' of 'Part.TopoShape' object needs an argument"); return 0; } if (!static_cast(self)->isValid()) { PyErr_SetString(PyExc_ReferenceError, "This object is already deleted most likely through closing a document. " "This reference is no longer valid!"); return 0; } #if OCC_VERSION_HEX >= 0x070800 return std::hash {}(static_cast(self)->getTopoShapePtr()->getShape()); #else return static_cast(self)->getTopoShapePtr()->getShape().HashCode(INT_MAX); #endif } struct TopoShapePyInit { TopoShapePyInit() { TopoShapePy::Type.tp_hash = _TopoShapeHash; } } _TopoShapePyInit; // returns a string which represents the object e.g. when printed in python std::string TopoShapePy::representation() const { std::stringstream str; str << ""; return str.str(); } PyObject *TopoShapePy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper { // create a new instance of TopoShapePy and the Twin object return new TopoShapePy(new TopoShape); } int TopoShapePy::PyInit(PyObject* args, PyObject* keywds) { static const std::array kwlist{ "shape", "op", "tag", "hasher", nullptr }; long tag = 0; PyObject* pyHasher = nullptr; const char* op = nullptr; PyObject* pcObj = nullptr; if (!Base::Wrapped_ParseTupleAndKeywords(args, keywds, "|OsiO!", kwlist, &pcObj, &op, &tag, &App::StringHasherPy::Type, &pyHasher)) { return -1; } auto& self = *getTopoShapePtr(); self.Tag = tag; if (pyHasher) { self.Hasher = static_cast(pyHasher)->getStringHasherPtr(); } auto shapes = getPyShapes(pcObj); PY_TRY { if (shapes.size() == 1 && !op) { auto s = shapes.front(); if (self.Tag) { if ((s.Tag && self.Tag != s.Tag) || (self.Hasher && s.getElementMapSize() && self.Hasher != s.Hasher)) { s.reTagElementMap(self.Tag, self.Hasher); } else { s.Tag = self.Tag; s.Hasher = self.Hasher; } } self = s; } else if (shapes.size()) { if (!op) { op = Part::OpCodes::Fuse; } self.makeElementBoolean(op, shapes); } } _PY_CATCH_OCC(return (-1)) return 0; } PyObject* TopoShapePy::copy(PyObject *args) { PyObject* copyGeom = Py_True; PyObject* copyMesh = Py_False; const char* op = nullptr; PyObject* pyHasher = nullptr; if (!PyArg_ParseTuple(args, "|sO!O!O!", &op, &App::StringHasherPy::Type, &pyHasher, &PyBool_Type, ©Geom, &PyBool_Type, ©Mesh)) { PyErr_Clear(); if (!PyArg_ParseTuple(args, "|O!O!", &PyBool_Type, ©Geom, &PyBool_Type, ©Mesh)) { return 0; } } if (op && !op[0]) { op = nullptr; } App::StringHasherRef hasher; if (pyHasher) { hasher = static_cast(pyHasher)->getStringHasherPtr(); } auto& self = *getTopoShapePtr(); return Py::new_reference_to(shape2pyshape( TopoShape(self.Tag, hasher) .makeElementCopy(self, op, PyObject_IsTrue(copyGeom), PyObject_IsTrue(copyMesh)))); } PyObject* TopoShapePy::cleaned(PyObject *args) { if (!PyArg_ParseTuple(args, "")) return nullptr; auto& self = *getTopoShapePtr(); TopoShape copy(self.makeElementCopy()); if (!copy.isNull()) { BRepTools::Clean(copy.getShape()); // remove triangulation } return Py::new_reference_to(shape2pyshape(copy)); } PyObject* TopoShapePy::replaceShape(PyObject *args) { PyObject *l; if (!PyArg_ParseTuple(args, "O",&l)) return nullptr; try { Py::Sequence list(l); std::vector> shapes; for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { Py::Tuple tuple(*it); Py::TopoShape sh1(tuple[0]); Py::TopoShape sh2(tuple[1]); shapes.push_back(std::make_pair(*sh1.extensionObject()->getTopoShapePtr(), *sh2.extensionObject()->getTopoShapePtr())); } return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->replaceElementShape(shapes))); } catch (const Py::Exception&) { return nullptr; } catch (...) { PyErr_SetString(PartExceptionOCCError, "failed to replace shape"); return nullptr; } } PyObject* TopoShapePy::removeShape(PyObject *args) { PyObject *l; if (!PyArg_ParseTuple(args, "O",&l)) return nullptr; try { return Py::new_reference_to( shape2pyshape(getTopoShapePtr()->removeElementShape(getPyShapes(l)))); } catch (...) { PyErr_SetString(PartExceptionOCCError, "failed to remove shape"); return nullptr; } } PyObject* TopoShapePy::read(PyObject *args) { char* Name; if (!PyArg_ParseTuple(args, "et","utf-8",&Name)) return nullptr; std::string EncodedName = std::string(Name); PyMem_Free(Name); getTopoShapePtr()->read(EncodedName.c_str()); Py_Return; } PyObject* TopoShapePy::writeInventor(PyObject * args, PyObject * keywds) { static const std::array kwlist{"Mode", "Deviation", "Angle", "FaceColors", nullptr}; double dev = 0.3, angle = 0.4; int mode = 2; PyObject *pylist = nullptr; if (!Base::Wrapped_ParseTupleAndKeywords(args, keywds, "|iddO", kwlist, &mode, &dev, &angle, &pylist)) { return nullptr; } std::vector faceColors; if (pylist) { App::PropertyColorList prop; prop.setPyObject(pylist); faceColors = prop.getValues(); } std::stringstream result; BRepMesh_IncrementalMesh(getTopoShapePtr()->getShape(),dev); if (mode == 0) { getTopoShapePtr()->exportFaceSet(dev, angle, faceColors, result); } else if (mode == 1) { getTopoShapePtr()->exportLineSet(result); } else { getTopoShapePtr()->exportFaceSet(dev, angle, faceColors, result); getTopoShapePtr()->exportLineSet(result); } return Py::new_reference_to(Py::String(result.str())); } PyObject* TopoShapePy::exportIges(PyObject *args) { char* Name; if (!PyArg_ParseTuple(args, "et","utf-8",&Name)) return nullptr; std::string EncodedName = std::string(Name); PyMem_Free(Name); try { // write iges file getTopoShapePtr()->exportIges(EncodedName.c_str()); } catch (const Base::Exception& e) { PyErr_SetString(PartExceptionOCCError,e.what()); return nullptr; } Py_Return; } PyObject* TopoShapePy::exportStep(PyObject *args) { char* Name; if (!PyArg_ParseTuple(args, "et","utf-8",&Name)) return nullptr; std::string EncodedName = std::string(Name); PyMem_Free(Name); try { // write step file getTopoShapePtr()->exportStep(EncodedName.c_str()); } catch (const Base::Exception& e) { PyErr_SetString(PartExceptionOCCError,e.what()); return nullptr; } Py_Return; } PyObject* TopoShapePy::exportBrep(PyObject *args) { char* Name; if (PyArg_ParseTuple(args, "et","utf-8",&Name)) { std::string EncodedName = std::string(Name); PyMem_Free(Name); try { // write brep file getTopoShapePtr()->exportBrep(EncodedName.c_str()); } catch (const Base::Exception& e) { PyErr_SetString(PartExceptionOCCError,e.what()); return nullptr; } Py_Return; } PyErr_Clear(); PyObject* input; if (PyArg_ParseTuple(args, "O", &input)) { try { // write brep Base::PyStreambuf buf(input); std::ostream str(nullptr); str.rdbuf(&buf); getTopoShapePtr()->exportBrep(str); } catch (const Base::Exception& e) { PyErr_SetString(PartExceptionOCCError,e.what()); return nullptr; } Py_Return; } PyErr_SetString(PyExc_TypeError, "expect string or file object"); return nullptr; } PyObject* TopoShapePy::exportBinary(PyObject *args) { char* input; if (!PyArg_ParseTuple(args, "s", &input)) return nullptr; try { // read binary brep Base::FileInfo fi(input); Base::ofstream str(fi, std::ios::out | std::ios::binary); getTopoShapePtr()->exportBinary(str); str.close(); } catch (const Base::Exception& e) { PyErr_SetString(PartExceptionOCCError,e.what()); return nullptr; } Py_Return; } PyObject* TopoShapePy::dumpToString(PyObject *args) { if (!PyArg_ParseTuple(args, "")) return nullptr; try { std::stringstream str; getTopoShapePtr()->dump(str); return Py::new_reference_to(Py::String(str.str())); } catch (const Base::Exception& e) { PyErr_SetString(PartExceptionOCCError,e.what()); return nullptr; } catch (const std::exception& e) { PyErr_SetString(PartExceptionOCCError,e.what()); return nullptr; } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::exportBrepToString(PyObject *args) { if (!PyArg_ParseTuple(args, "")) return nullptr; try { // write brep file std::stringstream str; getTopoShapePtr()->exportBrep(str); return Py::new_reference_to(Py::String(str.str())); } catch (const Base::Exception& e) { PyErr_SetString(PartExceptionOCCError,e.what()); return nullptr; } catch (const std::exception& e) { PyErr_SetString(PartExceptionOCCError,e.what()); return nullptr; } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::importBrep(PyObject *args) { char* Name; if (PyArg_ParseTuple(args, "et","utf-8",&Name)) { std::string EncodedName = std::string(Name); PyMem_Free(Name); try { // write brep file getTopoShapePtr()->importBrep(EncodedName.c_str()); } catch (const Base::Exception& e) { PyErr_SetString(PartExceptionOCCError,e.what()); return nullptr; } Py_Return; } PyErr_Clear(); PyObject* input; if (PyArg_ParseTuple(args, "O", &input)) { try { // read brep Base::PyStreambuf buf(input); std::istream str(nullptr); str.rdbuf(&buf); getTopoShapePtr()->importBrep(str); } catch (const Base::Exception& e) { PyErr_SetString(PartExceptionOCCError,e.what()); return nullptr; } Py_Return; } PyErr_SetString(PyExc_TypeError, "expect string or file object"); return nullptr; } PyObject* TopoShapePy::importBinary(PyObject *args) { char* input; if (!PyArg_ParseTuple(args, "s", &input)) return nullptr; try { // read binary brep Base::FileInfo fi(input); Base::ifstream str(fi, std::ios::in | std::ios::binary); getTopoShapePtr()->importBinary(str); str.close(); } catch (const Base::Exception& e) { PyErr_SetString(PartExceptionOCCError,e.what()); return nullptr; } Py_Return; } PyObject* TopoShapePy::importBrepFromString(PyObject *args) { char* input; int indicator=1; if (!PyArg_ParseTuple(args, "s|i", &input, &indicator)) return nullptr; try { // read brep std::stringstream str(input); getTopoShapePtr()->importBrep(str,indicator); } catch (const Base::Exception& e) { PyErr_SetString(PartExceptionOCCError,e.what()); return nullptr; } catch (const std::exception& e) { PyErr_SetString(PartExceptionOCCError,e.what()); return nullptr; } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } Py_Return; } PyObject* TopoShapePy::dumps(PyObject *args) { return exportBrepToString(args); } PyObject* TopoShapePy::loads(PyObject *args) { if (! getTopoShapePtr()) { PyErr_SetString(Base::PyExc_FC_GeneralError,"no c++ object"); return nullptr; } else { return importBrepFromString(args); } } PyObject* TopoShapePy::exportStl(PyObject *args) { double deflection = 0.01; char* Name; if (!PyArg_ParseTuple(args, "et|d","utf-8",&Name,&deflection)) return nullptr; std::string EncodedName = std::string(Name); PyMem_Free(Name); try { // write stl file getTopoShapePtr()->exportStl(EncodedName.c_str(), deflection); } catch (const Base::Exception& e) { PyErr_SetString(PartExceptionOCCError,e.what()); return nullptr; } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } Py_Return; } PyObject* TopoShapePy::extrude(PyObject *args) { PyObject *pVec; if (!PyArg_ParseTuple(args, "O!", &(Base::VectorPy::Type), &pVec)) return nullptr; try { Base::Vector3d vec = static_cast(pVec)->value(); return Py::new_reference_to( shape2pyshape(getTopoShapePtr()->makeElementPrism(gp_Vec(vec.x, vec.y, vec.z)))); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::revolve(PyObject *args) { PyObject *pPos,*pDir; double angle=360; if (!PyArg_ParseTuple(args, "O!O!|d", &(Base::VectorPy::Type), &pPos, &(Base::VectorPy::Type), &pDir,&angle)) return nullptr; Base::Vector3d pos = static_cast(pPos)->value(); Base::Vector3d dir = static_cast(pDir)->value(); try { return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementRevolve( gp_Ax1(gp_Pnt(pos.x, pos.y, pos.z), gp_Dir(dir.x, dir.y, dir.z)), Base::toRadians(angle)))); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::check(PyObject *args) { PyObject* runBopCheck = Py_False; if (!PyArg_ParseTuple(args, "|O!", &(PyBool_Type), &runBopCheck)) return nullptr; if (!getTopoShapePtr()->getShape().IsNull()) { std::stringstream str; if (!getTopoShapePtr()->analyze(Base::asBoolean(runBopCheck), str)) { PyErr_SetString(PyExc_ValueError, str.str().c_str()); return nullptr; } } Py_Return; } static PyObject *makeShape(const char *op,const TopoShape &shape, PyObject *args) { double tol=0; PyObject *pcObj; if (!PyArg_ParseTuple(args, "O|d", &pcObj,&tol)) return 0; PY_TRY { std::vector shapes; shapes.push_back(shape); getPyShapes(pcObj,shapes); return Py::new_reference_to(shape2pyshape(TopoShape().makeElementBoolean(op,shapes,0,tol))); } PY_CATCH_OCC } PyObject* TopoShapePy::fuse(PyObject *args) { return makeShape(Part::OpCodes::Fuse, *getTopoShapePtr(), args); } PyObject* TopoShapePy::multiFuse(PyObject *args) { return makeShape(Part::OpCodes::Fuse, *getTopoShapePtr(), args); } PyObject* TopoShapePy::oldFuse(PyObject *args) { PyObject *pcObj; if (!PyArg_ParseTuple(args, "O!", &(TopoShapePy::Type), &pcObj)) return nullptr; TopoDS_Shape shape = static_cast(pcObj)->getTopoShapePtr()->getShape(); try { // Let's call algorithm computing a fuse operation: TopoDS_Shape fusShape = this->getTopoShapePtr()->oldFuse(shape); return new TopoShapePy(new TopoShape(fusShape)); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } catch (const std::exception& e) { PyErr_SetString(PartExceptionOCCError, e.what()); return nullptr; } } PyObject* TopoShapePy::common(PyObject *args) { return makeShape(Part::OpCodes::Common, *getTopoShapePtr(), args); } PyObject* TopoShapePy::section(PyObject *args) { return makeShape(Part::OpCodes::Section, *getTopoShapePtr(), args); } PyObject* TopoShapePy::slice(PyObject *args) { PyObject *dir; double d; if (!PyArg_ParseTuple(args, "O!d", &(Base::VectorPy::Type), &dir, &d)) return nullptr; Base::Vector3d vec = Py::Vector(dir, false).toVector(); try { Py::List wires; for (auto& w : getTopoShapePtr()->makeElementSlice(vec, d).getSubTopoShapes(TopAbs_WIRE)) { wires.append(shape2pyshape(w)); } return Py::new_reference_to(wires); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } catch (const std::exception& e) { PyErr_SetString(PartExceptionOCCError, e.what()); return nullptr; } } PyObject* TopoShapePy::slices(PyObject *args) { PyObject *dir, *dist; if (!PyArg_ParseTuple(args, "O!O", &(Base::VectorPy::Type), &dir, &dist)) return nullptr; try { Base::Vector3d vec = Py::Vector(dir, false).toVector(); Py::Sequence list(dist); std::vector d; d.reserve(list.size()); for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) d.push_back((double)Py::Float(*it)); return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementSlices(vec, d))); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } catch (const std::exception& e) { PyErr_SetString(PartExceptionOCCError, e.what()); return nullptr; } } PyObject* TopoShapePy::cut(PyObject *args) { return makeShape(Part::OpCodes::Cut, *getTopoShapePtr(), args); } PyObject* TopoShapePy::generalFuse(PyObject *args) { double tolerance = 0.0; PyObject *pcObj; if (!PyArg_ParseTuple(args, "O|d", &pcObj, &tolerance)) return nullptr; std::vector> modifies; std::vector shapes; shapes.push_back(*getTopoShapePtr()); try { getPyShapes(pcObj, shapes); TopoShape res; res.makeElementGeneralFuse(shapes, modifies, tolerance); Py::List mapPy; for (auto& mod : modifies) { Py::List shapesPy; for (auto& sh : mod) { shapesPy.append(shape2pyshape(sh)); } mapPy.append(shapesPy); } Py::Tuple ret(2); ret[0] = shape2pyshape(res); ret[1] = mapPy; return Py::new_reference_to(ret); } PY_CATCH_OCC } PyObject* TopoShapePy::sewShape(PyObject *args) { double tolerance = 1.0e-06; if (!PyArg_ParseTuple(args, "|d", &tolerance)) return nullptr; try { getTopoShapePtr()->sewShape(); Py_Return; } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::childShapes(PyObject *args) { PyObject* cumOri = Py_True; PyObject* cumLoc = Py_True; if (!PyArg_ParseTuple(args, "|O!O!", &(PyBool_Type), &cumOri, &(PyBool_Type), &cumLoc)) return nullptr; TopoShape shape = *getTopoShapePtr(); if (!PyObject_IsTrue(cumOri)) { shape.setShape(shape.getShape().Oriented(TopAbs_FORWARD), false); } if (!PyObject_IsTrue(cumLoc)) { shape.setShape(shape.getShape().Located(TopLoc_Location()), false); } Py::List list; PY_TRY { for (auto& s : shape.getSubTopoShapes()) { list.append(shape2pyshape(s)); } return Py::new_reference_to(list); } PY_CATCH_OCC } namespace Part { // Containers to associate TopAbs_ShapeEnum values to each TopoShape*Py class static const std::vector> vecTypeShape = { {&TopoShapeCompoundPy::Type, TopAbs_COMPOUND}, {&TopoShapeCompSolidPy::Type, TopAbs_COMPSOLID}, {&TopoShapeSolidPy::Type, TopAbs_SOLID}, {&TopoShapeShellPy::Type, TopAbs_SHELL}, {&TopoShapeFacePy::Type, TopAbs_FACE}, {&TopoShapeWirePy::Type, TopAbs_WIRE}, {&TopoShapeEdgePy::Type, TopAbs_EDGE}, {&TopoShapeVertexPy::Type, TopAbs_VERTEX}, {&TopoShapePy::Type, TopAbs_SHAPE} }; static const std::map mapTypeShape( vecTypeShape.begin(), vecTypeShape.end()); // Returns shape type of a Python type. Similar to TopAbs::ShapeTypeFromString. // Returns TopAbs_SHAPE if pyType is not a subclass of any of the TopoShape*Py. static TopAbs_ShapeEnum ShapeTypeFromPyType(PyTypeObject* pyType) { for (const auto & it : vecTypeShape) { if (PyType_IsSubtype(pyType, it.first)) return it.second; } return TopAbs_SHAPE; } } PyObject* TopoShapePy::ancestorsOfType(PyObject *args) { PyObject *pcObj; PyObject *type; if (!PyArg_ParseTuple(args, "O!O!", &(TopoShapePy::Type), &pcObj, &PyType_Type, &type)) return nullptr; try { const TopoDS_Shape& model = getTopoShapePtr()->getShape(); const TopoDS_Shape& shape = static_cast(pcObj)-> getTopoShapePtr()->getShape(); if (model.IsNull() || shape.IsNull()) { PyErr_SetString(PyExc_ValueError, "Shape is null"); return nullptr; } PyTypeObject* pyType = reinterpret_cast(type); TopAbs_ShapeEnum shapetype = ShapeTypeFromPyType(pyType); if (!PyType_IsSubtype(pyType, &TopoShapePy::Type)) { PyErr_SetString(PyExc_TypeError, "type must be a Shape subtype"); return nullptr; } TopTools_IndexedDataMapOfShapeListOfShape mapOfShapeShape; TopExp::MapShapesAndAncestors(model, shape.ShapeType(), shapetype, mapOfShapeShape); const TopTools_ListOfShape& ancestors = mapOfShapeShape.FindFromKey(shape); Py::List list; std::set hashes; TopTools_ListIteratorOfListOfShape it(ancestors); for (; it.More(); it.Next()) { // make sure to avoid duplicates Standard_Integer code = ShapeMapHasher{}(it.Value()); if (hashes.find(code) == hashes.end()) { list.append(shape2pyshape(it.Value())); hashes.insert(code); } } return Py::new_reference_to(list); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::removeInternalWires(PyObject *args) { double minArea; if (!PyArg_ParseTuple(args, "d",&minArea)) return nullptr; try { bool ok = getTopoShapePtr()->removeInternalWires(minArea); PyObject* ret = ok ? Py_True : Py_False; Py_INCREF(ret); return ret; } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::mirror(PyObject *args) { PyObject *v1, *v2; if (!PyArg_ParseTuple(args, "O!O!", &(Base::VectorPy::Type),&v1, &(Base::VectorPy::Type),&v2)) return nullptr; Base::Vector3d base = Py::Vector(v1,false).toVector(); Base::Vector3d norm = Py::Vector(v2,false).toVector(); try { gp_Ax2 ax2(gp_Pnt(base.x,base.y,base.z), gp_Dir(norm.x,norm.y,norm.z)); return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementMirror(ax2))); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::transformGeometry(PyObject *args) { PyObject *obj; PyObject *cpy = Py_False; if (!PyArg_ParseTuple(args, "O!|O!", &(Base::MatrixPy::Type), &obj, &PyBool_Type, &cpy)) return nullptr; try { Base::Matrix4D mat = static_cast(obj)->value(); TopoDS_Shape shape = this->getTopoShapePtr()->transformGShape(mat, Base::asBoolean(cpy)); return new TopoShapePy(new TopoShape(shape)); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::transformShape(PyObject *args) { PyObject *obj; PyObject *copy = Py_False; PyObject *checkScale = Py_False; if (!PyArg_ParseTuple(args, "O!|O!O!", &(Base::MatrixPy::Type),&obj,&(PyBool_Type), ©, &(PyBool_Type), &checkScale)) return nullptr; Base::Matrix4D mat = static_cast(obj)->value(); PY_TRY { this->getTopoShapePtr()->transformShape(mat, Base::asBoolean(copy), Base::asBoolean(checkScale)); return IncRef(); } PY_CATCH_OCC } PyObject* TopoShapePy::transformed(PyObject *args, PyObject *keywds) { static const std::array kwlist{"matrix", "copy", "checkScale", "op", nullptr}; PyObject *pymat; PyObject *copy = Py_False; PyObject *checkScale = Py_False; const char *op = nullptr; if (!Base::Wrapped_ParseTupleAndKeywords(args, keywds, "O!|O!O!s", kwlist, &Base::MatrixPy::Type, &pymat, &PyBool_Type, ©, &PyBool_Type, &checkScale, &op)) { return nullptr; } Base::Matrix4D mat = static_cast(pymat)->value(); (void)op; PY_TRY { TopoShape s(*getTopoShapePtr()); s.transformShape(mat,Base::asBoolean(copy), Base::asBoolean(checkScale)); return Py::new_reference_to(shape2pyshape(s)); } PY_CATCH_OCC } PyObject* TopoShapePy::translate(PyObject *args) { PyObject *obj; if (!PyArg_ParseTuple(args, "O", &obj)) return nullptr; Base::Vector3d vec; if (PyObject_TypeCheck(obj, &(Base::VectorPy::Type))) { vec = static_cast(obj)->value(); } else if (PyObject_TypeCheck(obj, &PyTuple_Type)) { vec = Base::getVectorFromTuple(obj); } else { PyErr_SetString(PyExc_TypeError, "either vector or tuple expected"); return nullptr; } gp_Trsf mov; mov.SetTranslation(gp_Vec(vec.x,vec.y,vec.z)); TopLoc_Location loc(mov); TopoDS_Shape shape = getTopoShapePtr()->getShape(); shape.Move(loc); getTopoShapePtr()->setShape(shape); return IncRef(); } PyObject* TopoShapePy::rotate(PyObject *args) { PyObject *obj1, *obj2; double angle; if (!PyArg_ParseTuple(args, "OOd", &obj1, &obj2, &angle)) return nullptr; PY_TRY { // Vector also supports sequence Py::Sequence p1(obj1), p2(obj2); // Convert into OCC representation gp_Pnt pos = gp_Pnt((double)Py::Float(p1[0]), (double)Py::Float(p1[1]), (double)Py::Float(p1[2])); gp_Dir dir = gp_Dir((double)Py::Float(p2[0]), (double)Py::Float(p2[1]), (double)Py::Float(p2[2])); gp_Ax1 axis(pos, dir); gp_Trsf mov; mov.SetRotation(axis, Base::toRadians(angle)); TopLoc_Location loc(mov); TopoDS_Shape shape = getTopoShapePtr()->getShape(); shape.Move(loc); getTopoShapePtr()->setShape(shape); return IncRef(); } PY_CATCH_OCC } PyObject* TopoShapePy::scale(PyObject *args) { double factor; PyObject* p=nullptr; if (!PyArg_ParseTuple(args, "d|O!", &factor, &(Base::VectorPy::Type), &p)) return nullptr; gp_Pnt pos(0,0,0); if (p) { Base::Vector3d pnt = static_cast(p)->value(); pos.SetX(pnt.x); pos.SetY(pnt.y); pos.SetZ(pnt.z); } if (fabs(factor) < Precision::Confusion()) { PyErr_SetString(PyExc_ValueError, "scale factor too small"); return nullptr; } PY_TRY { const TopoDS_Shape& shape = getTopoShapePtr()->getShape(); if (!shape.IsNull()) { gp_Trsf scl; scl.SetScale(pos, factor); BRepBuilderAPI_Transform BRepScale(scl); bool bCopy = true; BRepScale.Perform(shape, bCopy); TopoShape copy(*getTopoShapePtr()); getTopoShapePtr()->makeElementShape(BRepScale, copy); } return IncRef(); } PY_CATCH_OCC } PyObject* TopoShapePy::translated(PyObject *args) { Py::Object pyobj(shape2pyshape(*getTopoShapePtr())); return static_cast(pyobj.ptr())->translate(args); } PyObject* TopoShapePy::rotated(PyObject *args) { Py::Object pyobj(shape2pyshape(*getTopoShapePtr())); return static_cast(pyobj.ptr())->rotate(args); } PyObject* TopoShapePy::scaled(PyObject *args) { Py::Object pyobj(shape2pyshape(*getTopoShapePtr())); return static_cast(pyobj.ptr())->scale(args); } PyObject* TopoShapePy::makeFillet(PyObject *args) { // use two radii for all edges double radius1, radius2; PyObject *obj; if (!PyArg_ParseTuple(args, "ddO", &radius1, &radius2, &obj)) { PyErr_Clear(); if (!PyArg_ParseTuple(args, "dO", &radius1, &obj)) { PyErr_SetString(PyExc_TypeError, "This method accepts:\n" "-- one radius and a list of edges\n" "-- two radii and a list of edges"); return 0; } radius2 = radius1; } PY_TRY { return Py::new_reference_to(shape2pyshape( getTopoShapePtr()->makeElementFillet(getPyShapes(obj), radius1, radius2))); } PY_CATCH_OCC PyErr_Clear(); // use one radius for all edges double radius; if (PyArg_ParseTuple(args, "dO", &radius, &obj)) { try { const TopoDS_Shape& shape = this->getTopoShapePtr()->getShape(); BRepFilletAPI_MakeFillet mkFillet(shape); Py::Sequence list(obj); for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { if (PyObject_TypeCheck((*it).ptr(), &(Part::TopoShapePy::Type))) { const TopoDS_Shape& edge = static_cast((*it).ptr())->getTopoShapePtr()->getShape(); if (edge.ShapeType() == TopAbs_EDGE) { //Add edge to fillet algorithm mkFillet.Add(radius, TopoDS::Edge(edge)); } } } return new TopoShapePy(new TopoShape(mkFillet.Shape())); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyErr_SetString(PyExc_TypeError, "This method accepts:\n" "-- one radius and a list of edges\n" "-- two radii and a list of edges"); return nullptr; } // TODO: Should this python interface support all three chamfer methods and not just two? PyObject* TopoShapePy::makeChamfer(PyObject *args) { // use two radii for all edges double radius1, radius2; PyObject *obj; if (!PyArg_ParseTuple(args, "ddO", &radius1, &radius2, &obj)) { if (!PyArg_ParseTuple(args, "dO", &radius1, &obj)) { PyErr_SetString(PyExc_TypeError, "This method accepts:\n" "-- one radius and a list of edges\n" "-- two radii and a list of edges"); return 0; } PyErr_Clear(); radius2 = radius1; } PY_TRY { return Py::new_reference_to(shape2pyshape( getTopoShapePtr()->makeElementChamfer(getPyShapes(obj), Part::ChamferType::twoDistances, radius1, radius2))); } PY_CATCH_OCC PyErr_Clear(); // use one radius for all edges // TODO: Should this be using makeElementChamfer to support Toponaming fixes? double radius; if (PyArg_ParseTuple(args, "dO", &radius, &obj)) { try { const TopoDS_Shape& shape = this->getTopoShapePtr()->getShape(); BRepFilletAPI_MakeChamfer mkChamfer(shape); TopTools_IndexedMapOfShape mapOfEdges; TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; TopExp::MapShapesAndAncestors(shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); TopExp::MapShapes(shape, TopAbs_EDGE, mapOfEdges); Py::Sequence list(obj); for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { if (PyObject_TypeCheck((*it).ptr(), &(Part::TopoShapePy::Type))) { const TopoDS_Shape& edge = static_cast((*it).ptr())->getTopoShapePtr()->getShape(); if (edge.ShapeType() == TopAbs_EDGE) { //Add edge to fillet algorithm const TopoDS_Face& face = TopoDS::Face(mapEdgeFace.FindFromKey(edge).First()); mkChamfer.Add(radius, radius, TopoDS::Edge(edge), face); } } } return new TopoShapePy(new TopoShape(mkChamfer.Shape())); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyErr_SetString(PyExc_TypeError, "This method accepts:\n" "-- one radius and a list of edges\n" "-- two radii and a list of edges"); return nullptr; } PyObject* TopoShapePy::makeThickness(PyObject *args) { PyObject *obj; double offset, tolerance; PyObject* inter = Py_False; PyObject* self_inter = Py_False; short offsetMode = 0, join = 0; if (!PyArg_ParseTuple(args, "Odd|O!O!hh", &obj, &offset, &tolerance, &(PyBool_Type), &inter, &(PyBool_Type), &self_inter, &offsetMode, &join)) return nullptr; try { return Py::new_reference_to(shape2pyshape( getTopoShapePtr()->makeElementThickSolid(getPyShapes(obj), offset, tolerance, PyObject_IsTrue(inter) ? true : false, PyObject_IsTrue(self_inter) ? true : false, offsetMode, static_cast(join)))); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::makeOffsetShape(PyObject *args, PyObject *keywds) { static const std::array kwlist{"offset", "tolerance", "inter", "self_inter", "offsetMode", "join", "fill", nullptr}; double offset, tolerance; PyObject *inter = Py_False; PyObject *self_inter = Py_False; PyObject *fill = Py_False; short offsetMode = 0, join = 0; if (!Base::Wrapped_ParseTupleAndKeywords(args, keywds, "dd|O!O!hhO!", kwlist, &offset, &tolerance, &(PyBool_Type), &inter, &(PyBool_Type), &self_inter, &offsetMode, &join, &(PyBool_Type), &fill)) { return nullptr; } try { return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementOffset( offset, tolerance, PyObject_IsTrue(inter) ? true : false, PyObject_IsTrue(self_inter) ? true : false, offsetMode, static_cast(join), PyObject_IsTrue(fill) ? FillType::fill : FillType::noFill))); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::makeOffset2D(PyObject *args, PyObject *keywds) { static const std::array kwlist {"offset", "join", "fill", "openResult", "intersection", nullptr}; double offset; PyObject* fill = Py_False; PyObject* openResult = Py_False; PyObject* inter = Py_False; short join = 0; if (!Base::Wrapped_ParseTupleAndKeywords(args, keywds, "d|hO!O!O!", kwlist, &offset, &join, &(PyBool_Type), &fill, &(PyBool_Type), &openResult, &(PyBool_Type), &inter)) { return nullptr; } try { return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementOffset2D( offset, static_cast(join), PyObject_IsTrue(fill) ? FillType::fill : FillType::noFill, PyObject_IsTrue(openResult) ? OpenResult::allowOpenResult : OpenResult::noOpenResult, PyObject_IsTrue(inter) ? true : false))); } PY_CATCH_OCC; } PyObject* TopoShapePy::reverse(PyObject *args) { if (!PyArg_ParseTuple(args, "")) return nullptr; TopoDS_Shape shape = getTopoShapePtr()->getShape(); shape.Reverse(); getTopoShapePtr()->setShape(shape); Py_Return; } PyObject* TopoShapePy::reversed(PyObject *args) { if (!PyArg_ParseTuple(args, "")) return nullptr; TopoDS_Shape shape = getTopoShapePtr()->getShape(); shape = shape.Reversed(); PyTypeObject* type = this->GetType(); PyObject* cpy = nullptr; // let the type object decide if (type->tp_new) cpy = type->tp_new(type, this, nullptr); if (!cpy) { PyErr_SetString(PyExc_TypeError, "failed to create copy of shape"); return nullptr; } if (!shape.IsNull()) { static_cast(cpy)->getTopoShapePtr()->setShape(shape); } return cpy; } PyObject* TopoShapePy::complement(PyObject *args) { if (!PyArg_ParseTuple(args, "")) return nullptr; TopoDS_Shape shape = getTopoShapePtr()->getShape(); shape.Complement(); getTopoShapePtr()->setShape(shape); Py_Return; } PyObject* TopoShapePy::nullify(PyObject *args) { if (!PyArg_ParseTuple(args, "")) return nullptr; TopoDS_Shape shape = getTopoShapePtr()->getShape(); shape.Nullify(); getTopoShapePtr()->setShape(shape); Py_Return; } PyObject* TopoShapePy::isNull(PyObject *args) { if (!PyArg_ParseTuple(args, "")) return nullptr; bool null = getTopoShapePtr()->isNull(); return Py_BuildValue("O", (null ? Py_True : Py_False)); } PyObject* TopoShapePy::isClosed(PyObject *args) { if (!PyArg_ParseTuple(args, "")) return nullptr; try { if (getTopoShapePtr()->getShape().IsNull()) Standard_Failure::Raise("Cannot determine the 'Closed'' flag of an empty shape"); return Py_BuildValue("O", (getTopoShapePtr()->isClosed() ? Py_True : Py_False)); } catch (...) { PyErr_SetString(PyExc_RuntimeError, "check failed, shape may be empty"); return nullptr; } } PyObject* TopoShapePy::isEqual(PyObject *args) { PyObject *pcObj; if (!PyArg_ParseTuple(args, "O!", &(TopoShapePy::Type), &pcObj)) return nullptr; TopoDS_Shape shape = static_cast(pcObj)->getTopoShapePtr()->getShape(); Standard_Boolean test = (getTopoShapePtr()->getShape().IsEqual(shape)); return Py_BuildValue("O", (test ? Py_True : Py_False)); } PyObject* TopoShapePy::isSame(PyObject *args) { PyObject *pcObj; if (!PyArg_ParseTuple(args, "O!", &(TopoShapePy::Type), &pcObj)) return nullptr; TopoDS_Shape shape = static_cast(pcObj)->getTopoShapePtr()->getShape(); Standard_Boolean test = getTopoShapePtr()->getShape().IsSame(shape); return Py_BuildValue("O", (test ? Py_True : Py_False)); } PyObject* TopoShapePy::isPartner(PyObject *args) { PyObject *pcObj; if (!PyArg_ParseTuple(args, "O!", &(TopoShapePy::Type), &pcObj)) return nullptr; TopoDS_Shape shape = static_cast(pcObj)->getTopoShapePtr()->getShape(); Standard_Boolean test = getTopoShapePtr()->getShape().IsPartner(shape); return Py_BuildValue("O", (test ? Py_True : Py_False)); } PyObject* TopoShapePy::isValid(PyObject *args) { if (!PyArg_ParseTuple(args, "")) return nullptr; PY_TRY { return Py_BuildValue("O", (getTopoShapePtr()->isValid() ? Py_True : Py_False)); } PY_CATCH_OCC } PyObject* TopoShapePy::isCoplanar(PyObject *args) { PyObject *pyObj; double tol = -1; if (!PyArg_ParseTuple(args, "O!|d", &TopoShapePy::Type, &pyObj, &tol)) return nullptr; PY_TRY { return Py::new_reference_to(Py::Boolean(getTopoShapePtr()->isCoplanar( *static_cast(pyObj)->getTopoShapePtr(),tol))); } PY_CATCH_OCC } PyObject* TopoShapePy::isInfinite(PyObject *args) { if (!PyArg_ParseTuple(args, "")) return nullptr; PY_TRY { return Py::new_reference_to(Py::Boolean(getTopoShapePtr()->isInfinite())); } PY_CATCH_OCC } PyObject* TopoShapePy::findPlane(PyObject *args) { double tol = -1; if (!PyArg_ParseTuple(args, "|d", &tol)) return nullptr; PY_TRY { gp_Pln pln; if (getTopoShapePtr()->findPlane(pln, tol)) return new PlanePy(new GeomPlane(new Geom_Plane(pln))); Py_Return; } PY_CATCH_OCC } PyObject* TopoShapePy::fix(PyObject *args) { double prec, mintol, maxtol; if (!PyArg_ParseTuple(args, "ddd", &prec, &mintol, &maxtol)) return nullptr; try { return Py_BuildValue("O", (getTopoShapePtr()->fix(prec, mintol, maxtol) ? Py_True : Py_False)); } catch (...) { PyErr_SetString(PyExc_RuntimeError, "check failed, shape may be empty"); return nullptr; } } PyObject* TopoShapePy::hashCode(PyObject *args) { int upper = IntegerLast(); if (!PyArg_ParseTuple(args, "|i",&upper)) return nullptr; int hc = ShapeMapHasher{}(getTopoShapePtr()->getShape()); return Py_BuildValue("i", hc); } PyObject* TopoShapePy::tessellate(PyObject *args) { double tolerance; PyObject* ok = Py_False; if (!PyArg_ParseTuple(args, "d|O!", &tolerance, &PyBool_Type, &ok)) return nullptr; try { std::vector Points; std::vector Facets; if (Base::asBoolean(ok)) BRepTools::Clean(getTopoShapePtr()->getShape()); getTopoShapePtr()->getFaces(Points, Facets,tolerance); 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 (const auto& it : Facets) { Py::Tuple f(3); f.setItem(0,Py::Long((long)it.I1)); f.setItem(1,Py::Long((long)it.I2)); f.setItem(2,Py::Long((long)it.I3)); facet.append(f); } tuple.setItem(1, facet); return Py::new_reference_to(tuple); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::project(PyObject *args) { PyObject *obj; BRepAlgo_NormalProjection algo; algo.Init(this->getTopoShapePtr()->getShape()); if (!PyArg_ParseTuple(args, "O", &obj)) return nullptr; try { Py::Sequence list(obj); for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { if (PyObject_TypeCheck((*it).ptr(), &(Part::TopoShapePy::Type))) { const TopoDS_Shape& shape = static_cast((*it).ptr())->getTopoShapePtr()->getShape(); algo.Add(shape); } } algo.Compute3d(Standard_True); algo.SetLimit(Standard_True); algo.SetParams(1.e-6, 1.e-6, GeomAbs_C1, 14, 10000); //algo.SetDefaultParams(); algo.Build(); return new TopoShapePy(new TopoShape(algo.Projection())); } catch (Standard_Failure&) { PyErr_SetString(PartExceptionOCCError, "Failed to project shape"); return nullptr; } } PyObject* TopoShapePy::makeParallelProjection(PyObject *args) { PyObject *pShape, *pDir; if (!PyArg_ParseTuple(args, "O!O!", &(Part::TopoShapePy::Type), &pShape, &Base::VectorPy::Type, &pDir)) return nullptr; try { const TopoDS_Shape& shape = this->getTopoShapePtr()->getShape(); const TopoDS_Shape& wire = static_cast(pShape)->getTopoShapePtr()->getShape(); Base::Vector3d vec = Py::Vector(pDir,false).toVector(); BRepProj_Projection proj(wire, shape, gp_Dir(vec.x,vec.y,vec.z)); TopoDS_Shape projected = proj.Shape(); return new TopoShapePy(new TopoShape(projected)); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::makePerspectiveProjection(PyObject *args) { PyObject *pShape, *pDir; if (!PyArg_ParseTuple(args, "O!O!", &(Part::TopoShapePy::Type), &pShape, &Base::VectorPy::Type, &pDir)) return nullptr; try { const TopoDS_Shape& shape = this->getTopoShapePtr()->getShape(); const TopoDS_Shape& wire = static_cast(pShape)->getTopoShapePtr()->getShape(); Base::Vector3d vec = Py::Vector(pDir,false).toVector(); BRepProj_Projection proj(wire, shape, gp_Pnt(vec.x,vec.y,vec.z)); TopoDS_Shape projected = proj.Shape(); return new TopoShapePy(new TopoShape(projected)); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } /*! from pivy import coin rot=Gui.ActiveDocument.ActiveView.getCameraOrientation() vdir=App.Vector(0,0,-1) vdir=rot.multVec(vdir) udir=App.Vector(0,1,0) udir=rot.multVec(udir) pos=Gui.ActiveDocument.ActiveView.getCameraNode().position.getValue().getValue() pos=App.Vector(*pos) shape=App.ActiveDocument.ActiveObject.Shape reflect=shape.reflectLines(ViewDir=vdir, ViewPos=pos, UpDir=udir, EdgeType="Sharp", Visible=True, OnShape=False) Part.show(reflect) */ PyObject* TopoShapePy::reflectLines(PyObject *args, PyObject *kwds) { static const std::array kwlist{"ViewDir", "ViewPos", "UpDir", "EdgeType", "Visible", "OnShape", nullptr}; const char* type="OutLine"; PyObject* vis = Py_True; PyObject* in3d = Py_False; PyObject* pPos = nullptr; PyObject* pUp = nullptr; PyObject *pView; if (!Base::Wrapped_ParseTupleAndKeywords(args, kwds, "O!|O!O!sO!O!", kwlist, &Base::VectorPy::Type, &pView, &Base::VectorPy::Type, &pPos, &Base::VectorPy::Type, &pUp, &type, &PyBool_Type, &vis, &PyBool_Type, &in3d)) { return nullptr; } try { HLRBRep_TypeOfResultingEdge t; std::string str = type; if (str == "IsoLine") t = HLRBRep_IsoLine; else if (str == "Rg1Line") t = HLRBRep_Rg1Line; else if (str == "RgNLine") t = HLRBRep_RgNLine; else if (str == "Sharp") t = HLRBRep_Sharp; else t = HLRBRep_OutLine; Base::Vector3d p(0.0, 0.0, 0.0); if (pPos) p = Py::Vector(pPos,false).toVector(); Base::Vector3d u(0.0, 1.0, 0.0); if (pUp) u = Py::Vector(pUp,false).toVector(); Base::Vector3d v = Py::Vector(pView,false).toVector(); const TopoDS_Shape& shape = this->getTopoShapePtr()->getShape(); HLRAppli_ReflectLines reflect(shape); reflect.SetAxes(v.x, v.y, v.z, p.x, p.y, p.z, u.x, u.y, u.z); reflect.Perform(); TopoDS_Shape lines = reflect.GetCompoundOf3dEdges(t, Base::asBoolean(vis), Base::asBoolean(in3d)); return new TopoShapePy(new TopoShape(lines)); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::makeShapeFromMesh(PyObject *args) { PyObject *tup; double tolerance = 1.0e-06; PyObject* sewShape = Py_True; if (!PyArg_ParseTuple(args, "O!|dO!",&PyTuple_Type, &tup, &tolerance, &PyBool_Type, &sewShape)) return nullptr; try { Py::Tuple tuple(tup); Py::Sequence vertex(tuple[0]); Py::Sequence facets(tuple[1]); std::vector Points; for (Py::Sequence::iterator it = vertex.begin(); it != vertex.end(); ++it) { Py::Vector vec(*it); Points.push_back(vec.toVector()); } std::vector Facets; for (Py::Sequence::iterator it = facets.begin(); it != facets.end(); ++it) { Data::ComplexGeoData::Facet face; Py::Tuple f(*it); face.I1 = (int)Py::Long(f[0]); face.I2 = (int)Py::Long(f[1]); face.I3 = (int)Py::Long(f[2]); Facets.push_back(face); } getTopoShapePtr()->setFaces(Points, Facets, tolerance); if (Base::asBoolean(sewShape)) getTopoShapePtr()->sewShape(tolerance); Py_Return; } PY_CATCH_OCC } PyObject* TopoShapePy::makeEvolved(PyObject *args, PyObject *kwds) { PyObject* Profile; PyObject* AxeProf = Py_True; PyObject* Solid = Py_False; PyObject* ProfOnSpine = Py_False; auto JoinType = JoinType::arc; double Tolerance = 0.0000001; static const std::array kwds_evolve{"Profile", "Join", "AxeProf", "Solid", "ProfOnSpine", "Tolerance", nullptr}; if (!Base::Wrapped_ParseTupleAndKeywords(args, kwds, "O!|iO!O!O!d", kwds_evolve, &TopoShapePy::Type, &Profile, &JoinType, &PyBool_Type, &AxeProf, &PyBool_Type, &Solid, &PyBool_Type, &ProfOnSpine, &Tolerance)) { return nullptr; } try { return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementEvolve( *static_cast(Profile)->getTopoShapePtr(), JoinType, PyObject_IsTrue(AxeProf) ? CoordinateSystem::global : CoordinateSystem::relativeToSpine, PyObject_IsTrue(Solid) ? MakeSolid::makeSolid : MakeSolid::noSolid, PyObject_IsTrue(ProfOnSpine) ? Spine::on : Spine::notOn, Tolerance))); } PY_CATCH_OCC } PyObject* TopoShapePy::makeWires(PyObject *args) { const char *op = nullptr; if (!PyArg_ParseTuple(args, "s", &op)) return nullptr; PY_TRY { return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeWires(op))); } PY_CATCH_OCC } PyObject* TopoShapePy::toNurbs(PyObject *args) { if (!PyArg_ParseTuple(args, "")) return nullptr; try { // Convert into nurbs TopoDS_Shape nurbs = this->getTopoShapePtr()->toNurbs(); return new TopoShapePy(new TopoShape(nurbs)); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::isInside(PyObject *args) { PyObject *point; double tolerance; PyObject* checkFace = Py_False; TopAbs_State stateIn = TopAbs_IN; if (!PyArg_ParseTuple(args, "O!dO!", &(Base::VectorPy::Type), &point, &tolerance, &PyBool_Type, &checkFace)) return nullptr; try { TopoDS_Shape shape = getTopoShapePtr()->getShape(); if (shape.IsNull()) { PyErr_SetString(PartExceptionOCCError, "Cannot handle null shape"); return nullptr; } Base::Vector3d pnt = static_cast(point)->value(); gp_Pnt vertex = gp_Pnt(pnt.x,pnt.y,pnt.z); if (shape.ShapeType() == TopAbs_VERTEX || shape.ShapeType() == TopAbs_EDGE || shape.ShapeType() == TopAbs_WIRE || shape.ShapeType() == TopAbs_FACE) { BRepBuilderAPI_MakeVertex mkVertex(vertex); BRepExtrema_DistShapeShape extss; extss.LoadS1(mkVertex.Vertex()); extss.LoadS2(shape); if (!extss.Perform()) { PyErr_SetString(PartExceptionOCCError, "Failed to determine distance to shape"); return nullptr; } Standard_Boolean test = (extss.Value() <= tolerance); return Py_BuildValue("O", (test ? Py_True : Py_False)); } else { BRepClass3d_SolidClassifier solidClassifier(shape); solidClassifier.Perform(vertex, tolerance); Standard_Boolean test = (solidClassifier.State() == stateIn); if (Base::asBoolean(checkFace) && solidClassifier.IsOnAFace()) test = Standard_True; return Py_BuildValue("O", (test ? Py_True : Py_False)); } } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } catch (const std::exception& e) { PyErr_SetString(PartExceptionOCCError, e.what()); return nullptr; } } PyObject* TopoShapePy::removeSplitter(PyObject *args) { if (!PyArg_ParseTuple(args, "")) return nullptr; try { return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementRefine())); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::getElement(PyObject *args) { char* input; PyObject* silent = Py_False; if (!PyArg_ParseTuple(args, "s|O", &input, &silent)) { return nullptr; } try { PyObject* res = getTopoShapePtr()->getPySubShape(input, PyObject_IsTrue(silent)); if (!res) { Py_Return; } return res; } PY_CATCH_OCC } PyObject* TopoShapePy::countElement(PyObject *args) { char* input; if (!PyArg_ParseTuple(args, "s", &input)) return nullptr; PY_TRY { return Py::new_reference_to(Py::Int((long)getTopoShapePtr()->countSubShapes(input))); } PY_CATCH_OCC } PyObject* TopoShapePy::getTolerance(PyObject *args) { int mode; PyObject* type = reinterpret_cast(&TopoShapePy::Type); if (!PyArg_ParseTuple(args, "i|O!", &mode, &PyType_Type, &type)) return nullptr; try { TopoDS_Shape shape = this->getTopoShapePtr()->getShape(); PyTypeObject* pyType = reinterpret_cast(type); TopAbs_ShapeEnum shapetype = ShapeTypeFromPyType(pyType); if (!PyType_IsSubtype(pyType, &TopoShapePy::Type) || (shapetype != TopAbs_SHAPE && shapetype != TopAbs_VERTEX && shapetype != TopAbs_EDGE && shapetype != TopAbs_FACE && shapetype != TopAbs_SHELL)) { PyErr_SetString(PyExc_TypeError, "shape type must be Shape, Vertex, Edge, Face or Shell"); return nullptr; } ShapeAnalysis_ShapeTolerance analysis; double tolerance = analysis.Tolerance(shape, mode, shapetype); return PyFloat_FromDouble(tolerance); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::overTolerance(PyObject *args) { double value; PyObject* type = reinterpret_cast(&TopoShapePy::Type); if (!PyArg_ParseTuple(args, "d|O!", &value, &PyType_Type, &type)) return nullptr; try { TopoDS_Shape shape = this->getTopoShapePtr()->getShape(); PyTypeObject* pyType = reinterpret_cast(type); TopAbs_ShapeEnum shapetype = ShapeTypeFromPyType(pyType); if (!PyType_IsSubtype(pyType, &TopoShapePy::Type) || (shapetype != TopAbs_SHAPE && shapetype != TopAbs_VERTEX && shapetype != TopAbs_EDGE && shapetype != TopAbs_FACE && shapetype != TopAbs_SHELL)) { PyErr_SetString(PyExc_TypeError, "shape type must be Shape, Vertex, Edge, Face or Shell"); return nullptr; } ShapeAnalysis_ShapeTolerance analysis; Handle(TopTools_HSequenceOfShape) seq = analysis.OverTolerance(shape, value, shapetype); Py::Tuple tuple(seq->Length()); std::size_t index=0; for (int i=1; i <= seq->Length(); i++) { TopoDS_Shape item = seq->Value(i); tuple.setItem(index++, shape2pyshape(item)); } return Py::new_reference_to(tuple); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::inTolerance(PyObject *args) { double valmin; double valmax; PyObject* type = reinterpret_cast(&TopoShapePy::Type); if (!PyArg_ParseTuple(args, "dd|O!", &valmin, &valmax, &PyType_Type, &type)) return nullptr; try { TopoDS_Shape shape = this->getTopoShapePtr()->getShape(); PyTypeObject* pyType = reinterpret_cast(type); TopAbs_ShapeEnum shapetype = ShapeTypeFromPyType(pyType); if (!PyType_IsSubtype(pyType, &TopoShapePy::Type) || (shapetype != TopAbs_SHAPE && shapetype != TopAbs_VERTEX && shapetype != TopAbs_EDGE && shapetype != TopAbs_FACE && shapetype != TopAbs_SHELL)) { PyErr_SetString(PyExc_TypeError, "shape type must be Shape, Vertex, Edge, Face or Shell"); return nullptr; } ShapeAnalysis_ShapeTolerance analysis; Handle(TopTools_HSequenceOfShape) seq = analysis.InTolerance(shape, valmin, valmax, shapetype); Py::Tuple tuple(seq->Length()); std::size_t index=0; for (int i=1; i <= seq->Length(); i++) { TopoDS_Shape item = seq->Value(i); tuple.setItem(index++, shape2pyshape(item)); } return Py::new_reference_to(tuple); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::globalTolerance(PyObject *args) { int mode; if (!PyArg_ParseTuple(args, "i", &mode)) return nullptr; try { TopoDS_Shape shape = this->getTopoShapePtr()->getShape(); ShapeAnalysis_ShapeTolerance analysis; analysis.Tolerance(shape, mode); double tolerance = analysis.GlobalTolerance(mode); return PyFloat_FromDouble(tolerance); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::fixTolerance(PyObject *args) { double value; PyObject* type = reinterpret_cast(&TopoShapePy::Type); if (!PyArg_ParseTuple(args, "d|O!", &value, &PyType_Type, &type)) return nullptr; try { TopoDS_Shape shape = this->getTopoShapePtr()->getShape(); PyTypeObject* pyType = reinterpret_cast(type); TopAbs_ShapeEnum shapetype = ShapeTypeFromPyType(pyType); if (!PyType_IsSubtype(pyType, &TopoShapePy::Type)) { PyErr_SetString(PyExc_TypeError, "type must be a Shape subtype"); return nullptr; } ShapeFix_ShapeTolerance fix; fix.SetTolerance(shape, value, shapetype); Py_Return; } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::limitTolerance(PyObject *args) { double tmin; double tmax=0; PyObject* type = reinterpret_cast(&TopoShapePy::Type); if (!PyArg_ParseTuple(args, "d|dO!", &tmin, &tmax, &PyType_Type, &type)) return nullptr; try { TopoDS_Shape shape = this->getTopoShapePtr()->getShape(); PyTypeObject* pyType = reinterpret_cast(type); TopAbs_ShapeEnum shapetype = ShapeTypeFromPyType(pyType); if (!PyType_IsSubtype(pyType, &TopoShapePy::Type)) { PyErr_SetString(PyExc_TypeError, "type must be a Shape subtype"); return nullptr; } ShapeFix_ShapeTolerance fix; Standard_Boolean ok = fix.LimitTolerance(shape, tmin, tmax, shapetype); return PyBool_FromLong(ok ? 1 : 0); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* _getSupportIndex(const char* suppStr, TopoShape* ts, TopoDS_Shape suppShape) { std::stringstream ss; TopoDS_Shape subShape; unsigned long nSubShapes = ts->countSubShapes(suppStr); long supportIndex = -1; for (unsigned long j=1; j<=nSubShapes; j++){ ss.str(""); ss << suppStr << j; subShape = ts->getSubShape(ss.str().c_str()); if (subShape.IsEqual(suppShape)) { supportIndex = j-1; break; } } return PyLong_FromLong(supportIndex); } PyObject* TopoShapePy::proximity(PyObject *args) { using BRepExtrema_OverlappedSubShapes = BRepExtrema_MapOfIntegerPackedMapOfInteger; PyObject* ps2; Standard_Real tol = Precision::Confusion(); if (!PyArg_ParseTuple(args, "O!|d",&(TopoShapePy::Type), &ps2, &tol)) return nullptr; const TopoDS_Shape& s1 = getTopoShapePtr()->getShape(); const TopoDS_Shape& s2 = static_cast(ps2)->getTopoShapePtr()->getShape(); if (s1.IsNull()) { PyErr_SetString(PyExc_ValueError, "proximity: Shape object is invalid"); return nullptr; } if (s2.IsNull()) { PyErr_SetString(PyExc_ValueError, "proximity: Shape parameter is invalid"); return nullptr; } BRepExtrema_ShapeProximity proximity; proximity.LoadShape1 (s1); proximity.LoadShape2 (s2); if (tol > 0.0) { proximity.SetTolerance (tol); } proximity.Perform(); if (!proximity.IsDone()) { PyErr_SetString(PartExceptionOCCError, "BRepExtrema_ShapeProximity failed, make sure the shapes are tessellated"); return nullptr; } Py::List overlappssindex1; Py::List overlappssindex2; for (BRepExtrema_OverlappedSubShapes::Iterator anIt1 (proximity.OverlapSubShapes1()); anIt1.More(); anIt1.Next()) { overlappssindex1.append(Py::Long(anIt1.Key() + 1)); } for (BRepExtrema_OverlappedSubShapes::Iterator anIt2 (proximity.OverlapSubShapes2()); anIt2.More(); anIt2.Next()) { overlappssindex2.append(Py::Long(anIt2.Key() + 1)); } Py::Tuple tuple(2); tuple.setItem(0, overlappssindex1); tuple.setItem(1, overlappssindex2); return Py::new_reference_to(tuple); //face indexes } PyObject* TopoShapePy::distToShape(PyObject *args) { PyObject* ps2; gp_Pnt P1, P2; BRepExtrema_SupportType supportType1, supportType2; TopoDS_Shape suppS1, suppS2; Standard_Real minDist = -1, t1, t2, u1, v1, u2, v2; Standard_Real tol = Precision::Confusion(); if (!PyArg_ParseTuple(args, "O!|d",&(TopoShapePy::Type), &ps2, &tol)) return nullptr; const TopoDS_Shape& s1 = getTopoShapePtr()->getShape(); TopoShape* ts1 = getTopoShapePtr(); const TopoDS_Shape& s2 = static_cast(ps2)->getTopoShapePtr()->getShape(); TopoShape* ts2 = static_cast(ps2)->getTopoShapePtr(); if (s2.IsNull()) { PyErr_SetString(PyExc_TypeError, "distToShape: Shape parameter is invalid"); return nullptr; } BRepExtrema_DistShapeShape extss; extss.SetDeflection(tol); #if OCC_VERSION_HEX >= 0x070600 extss.SetMultiThread(true); #endif extss.LoadS1(s1); extss.LoadS2(s2); try { extss.Perform(); } catch (const Standard_Failure& e) { PyErr_SetString(PyExc_RuntimeError, e.GetMessageString()); return nullptr; } if (!extss.IsDone()) { PyErr_SetString(PyExc_RuntimeError, "BRepExtrema_DistShapeShape failed"); return nullptr; } Py::List solnPts; Py::List solnGeom; int count = extss.NbSolution(); if (count != 0) { minDist = extss.Value(); //extss.Dump(std::cout); for (int i=1; i<= count; i++) { Py::Object pt1, pt2; Py::String suppType1, suppType2; Py::Long suppIndex1, suppIndex2; Py::Object param1, param2; P1 = extss.PointOnShape1(i); pt1 = Py::asObject(new Base::VectorPy(new Base::Vector3d(P1.X(), P1.Y(), P1.Z()))); supportType1 = extss.SupportTypeShape1(i); suppS1 = extss.SupportOnShape1(i); switch (supportType1) { case BRepExtrema_IsVertex: suppType1 = Py::String("Vertex"); suppIndex1 = Py::asObject(_getSupportIndex("Vertex", ts1, suppS1)); param1 = Py::None(); break; case BRepExtrema_IsOnEdge: suppType1 = Py::String("Edge"); suppIndex1 = Py::asObject(_getSupportIndex("Edge", ts1, suppS1)); extss.ParOnEdgeS1(i,t1); param1 = Py::Float(t1); break; case BRepExtrema_IsInFace: suppType1 = Py::String("Face"); suppIndex1 = Py::asObject(_getSupportIndex("Face", ts1, suppS1)); extss.ParOnFaceS1(i,u1,v1); { Py::Tuple tup(2); tup[0] = Py::Float(u1); tup[1] = Py::Float(v1); param1 = tup; } break; default: Base::Console().Message("distToShape: supportType1 is unknown: %d \n", static_cast(supportType1)); suppType1 = Py::String("Unknown"); suppIndex1 = -1; param1 = Py::None(); } P2 = extss.PointOnShape2(i); pt2 = Py::asObject(new Base::VectorPy(new Base::Vector3d(P2.X(), P2.Y(), P2.Z()))); supportType2 = extss.SupportTypeShape2(i); suppS2 = extss.SupportOnShape2(i); switch (supportType2) { case BRepExtrema_IsVertex: suppType2 = Py::String("Vertex"); suppIndex2 = Py::asObject(_getSupportIndex("Vertex", ts2, suppS2)); param2 = Py::None(); break; case BRepExtrema_IsOnEdge: suppType2 = Py::String("Edge"); suppIndex2 = Py::asObject(_getSupportIndex("Edge", ts2, suppS2)); extss.ParOnEdgeS2(i,t2); param2 = Py::Float(t2); break; case BRepExtrema_IsInFace: suppType2 = Py::String("Face"); suppIndex2 = Py::asObject(_getSupportIndex("Face", ts2, suppS2)); extss.ParOnFaceS2(i,u2,v2); { Py::Tuple tup(2); tup[0] = Py::Float(u2); tup[1] = Py::Float(v2); param2 = tup; } break; default: Base::Console().Message("distToShape: supportType2 is unknown: %d \n", static_cast(supportType2)); suppType2 = Py::String("Unknown"); suppIndex2 = -1; param2 = Py::None(); } Py::Tuple pts(2); pts[0] = pt1; pts[1] = pt2; solnPts.append(pts); Py::Tuple geom(6); geom[0] = suppType1; geom[1] = suppIndex1; geom[2] = param1; geom[3] = suppType2; geom[4] = suppIndex2; geom[5] = param2; solnGeom.append(geom); } } else { PyErr_SetString(PyExc_TypeError, "distToShape: No Solutions Found."); return nullptr; } Py::Tuple ret(3); ret[0] = Py::Float(minDist); ret[1] = solnPts; ret[2] = solnGeom; return Py::new_reference_to(ret); } PyObject* TopoShapePy::optimalBoundingBox(PyObject *args) { PyObject* useT = Py_True; PyObject* useS = Py_False; if (!PyArg_ParseTuple(args, "|O!O!", &PyBool_Type, &useT, &PyBool_Type, &useS)) { return nullptr; } try { TopoDS_Shape shape = this->getTopoShapePtr()->getShape(); Bnd_Box bounds; BRepBndLib::AddOptimal(shape, bounds, Base::asBoolean(useT), Base::asBoolean(useS)); bounds.SetGap(0.0); Standard_Real xMin, yMin, zMin, xMax, yMax, zMax; bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax); Base::BoundBox3d box; box.MinX = xMin; box.MaxX = xMax; box.MinY = yMin; box.MaxY = yMax; box.MinZ = zMin; box.MaxZ = zMax; Py::BoundingBox pybox(box); return Py::new_reference_to(pybox); } catch (const Standard_Failure& e) { throw Py::RuntimeError(e.GetMessageString()); } } PyObject* TopoShapePy::clearCache(PyObject* args) { if (!PyArg_ParseTuple(args, "")) { return 0; } getTopoShapePtr()->initCache(1); return IncRef(); } PyObject* TopoShapePy::defeaturing(PyObject *args) { PyObject *l; if (!PyArg_ParseTuple(args, "O",&l)) return nullptr; try { Py::Sequence list(l); std::vector shapes; for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { Py::TopoShape sh(*it); shapes.push_back( sh.extensionObject()->getTopoShapePtr()->getShape() ); } PyTypeObject* type = this->GetType(); PyObject* inst = type->tp_new(type, this, nullptr); static_cast(inst)->getTopoShapePtr()->setShape (this->getTopoShapePtr()->defeaturing(shapes)); return inst; } catch (const Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } } PyObject* TopoShapePy::findSubShape(PyObject* args) { PyObject* pyobj; if (!PyArg_ParseTuple(args, "O", &pyobj)) { return nullptr; } PY_TRY { Py::List res; for (auto& s : getPyShapes(pyobj)) { int index = getTopoShapePtr()->findShape(s.getShape()); if (index > 0) { res.append(Py::TupleN(Py::String(s.shapeName()), Py::Int(index))); } else { res.append(Py::TupleN(Py::Object(), Py::Int(0))); } } if (PySequence_Check(pyobj)) { return Py::new_reference_to(res); } return Py::new_reference_to(Py::Object(res[0].ptr())); } PY_CATCH_OCC } PyObject* TopoShapePy::findSubShapesWithSharedVertex(PyObject* args, PyObject* keywds) { static const std::array kwlist {"shape", "needName", "checkGeometry", "tol", "atol", "singleResult", nullptr}; PyObject* pyobj; PyObject* needName = Py_False; PyObject* checkGeometry = Py_True; PyObject* singleResult = Py_False; double tol = 1e-7; double atol = 1e-12; if (!Base::Wrapped_ParseTupleAndKeywords(args, keywds, "O!|OOdd", kwlist, &Type, &pyobj, &needName, &checkGeometry, &tol, &atol, &singleResult)) { return nullptr; } PY_TRY { Py::List res; const TopoShape& shape = *static_cast(pyobj)->getTopoShapePtr(); Data::SearchOptions options; if (PyObject_IsTrue(checkGeometry)) options.setFlag(Data::SearchOption::CheckGeometry); if (PyObject_IsTrue(singleResult)) options.setFlag(Data::SearchOption::SingleResult); if (PyObject_IsTrue(needName)) { std::vector names; auto shapes = getTopoShapePtr()->findSubShapesWithSharedVertex( shape, &names, options, tol, atol); for (std::size_t i = 0; i < shapes.size(); ++i) { res.append(Py::TupleN(Py::String(names[i]), shape2pyshape(shapes[i]))); } } else { for (auto& s : getTopoShapePtr()->findSubShapesWithSharedVertex( shape, nullptr, options, tol, atol)) { res.append(shape2pyshape(s)); } } return Py::new_reference_to(res); } PY_CATCH_OCC } // End of Methods, Start of Attributes Py::String TopoShapePy::getShapeType() const { TopoDS_Shape sh = getTopoShapePtr()->getShape(); if (sh.IsNull()) throw Py::Exception(Base::PyExc_FC_GeneralError, "cannot determine type of null shape"); TopAbs_ShapeEnum type = sh.ShapeType(); std::string name; switch (type) { case TopAbs_COMPOUND: name = "Compound"; break; case TopAbs_COMPSOLID: name = "CompSolid"; break; case TopAbs_SOLID: name = "Solid"; break; case TopAbs_SHELL: name = "Shell"; break; case TopAbs_FACE: name = "Face"; break; case TopAbs_WIRE: name = "Wire"; break; case TopAbs_EDGE: name = "Edge"; break; case TopAbs_VERTEX: name = "Vertex"; break; case TopAbs_SHAPE: name = "Shape"; break; } return Py::String(name); } Py::String TopoShapePy::getOrientation() const { TopoDS_Shape sh = getTopoShapePtr()->getShape(); if (sh.IsNull()) throw Py::Exception(Base::PyExc_FC_GeneralError, "cannot determine orientation of null shape"); TopAbs_Orientation type = sh.Orientation(); std::string name; switch (type) { case TopAbs_FORWARD: name = "Forward"; break; case TopAbs_REVERSED: name = "Reversed"; break; case TopAbs_INTERNAL: name = "Internal"; break; case TopAbs_EXTERNAL: name = "External"; break; } return Py::String(name); } void TopoShapePy::setOrientation(Py::String arg) { TopoDS_Shape sh = getTopoShapePtr()->getShape(); if (sh.IsNull()) throw Py::Exception(Base::PyExc_FC_GeneralError, "cannot determine orientation of null shape"); std::string name = static_cast(arg); TopAbs_Orientation type; if (name == "Forward") { type = TopAbs_FORWARD; } else if (name == "Reversed") { type = TopAbs_REVERSED; } else if (name == "Internal") { type = TopAbs_INTERNAL; } else if (name == "External") { type = TopAbs_EXTERNAL; } else { throw Py::AttributeError("Invalid orientation type"); } sh.Orientation(type); getTopoShapePtr()->setShape(sh); } static Py::List getElements(const TopoShape& sh, TopAbs_ShapeEnum type, TopAbs_ShapeEnum avoid = TopAbs_SHAPE) { Py::List ret; for (auto& shape : sh.getSubTopoShapes(type, avoid)) { ret.append(shape2pyshape(shape)); } return ret; } PyObject* TopoShapePy::getChildShapes(PyObject* args) { const char* type; const char* avoid = nullptr; if (!PyArg_ParseTuple(args, "s|s", &type, &avoid)) { return nullptr; } PY_TRY { return Py::new_reference_to( getElements(*getTopoShapePtr(), TopoShape::shapeType(type), avoid && avoid[0] ? TopoShape::shapeType(avoid) : TopAbs_SHAPE)); } PY_CATCH_OCC; } Py::List TopoShapePy::getSubShapes() const { return getElements(*getTopoShapePtr(), TopAbs_SHAPE); } Py::List TopoShapePy::getFaces() const { return getElements(*getTopoShapePtr(), TopAbs_FACE); } Py::List TopoShapePy::getVertexes() const { return getElements(*getTopoShapePtr(), TopAbs_VERTEX); } Py::List TopoShapePy::getShells() const { return getElements(*getTopoShapePtr(), TopAbs_SHELL); } Py::List TopoShapePy::getSolids() const { return getElements(*getTopoShapePtr(), TopAbs_SOLID); } Py::List TopoShapePy::getCompSolids() const { return getElements(*getTopoShapePtr(), TopAbs_COMPSOLID); } Py::List TopoShapePy::getEdges() const { return getElements(*getTopoShapePtr(), TopAbs_EDGE); } Py::List TopoShapePy::getWires() const { return getElements(*getTopoShapePtr(), TopAbs_WIRE); } Py::List TopoShapePy::getCompounds() const { return getElements(*getTopoShapePtr(), TopAbs_COMPOUND); } Py::Float TopoShapePy::getLength() const { const TopoDS_Shape& shape = getTopoShapePtr()->getShape(); if (shape.IsNull()) throw Py::RuntimeError("shape is invalid"); GProp_GProps props; BRepGProp::LinearProperties(shape, props); return Py::Float(props.Mass()); } Py::Float TopoShapePy::getArea() const { const TopoDS_Shape& shape = getTopoShapePtr()->getShape(); if (shape.IsNull()) throw Py::RuntimeError("shape is invalid"); GProp_GProps props; BRepGProp::SurfaceProperties(shape, props); return Py::Float(props.Mass()); } Py::Float TopoShapePy::getVolume() const { const TopoDS_Shape& shape = getTopoShapePtr()->getShape(); if (shape.IsNull()) throw Py::RuntimeError("shape is invalid"); GProp_GProps props; BRepGProp::VolumeProperties(shape, props); return Py::Float(props.Mass()); } PyObject* TopoShapePy::getElementHistory(PyObject* args) { const char* pyname; if (!PyArg_ParseTuple(args, "s", &pyname)) { return 0; } Data::MappedName name(pyname); PY_TRY { Data::MappedName original; std::vector history; long tag = getTopoShapePtr()->getElementHistory(name, &original, &history); if (!tag) { Py_Return; } Py::Tuple ret(3); ret.setItem(0, Py::Int(tag)); std::string tmp; ret.setItem(1, Py::String(original.appendToBuffer(tmp))); Py::List pyHistory; for (auto& h : history) { tmp.clear(); pyHistory.append(Py::String(h.appendToBuffer(tmp))); } ret.setItem(2, pyHistory); return Py::new_reference_to(ret); } PY_CATCH_OCC } struct PyShapeMapper: Part::ShapeMapper { bool populate(MappingStatus status, PyObject* pyobj) { if (!pyobj || pyobj == Py_None) { return true; } try { Py::Sequence seq(pyobj); for (size_t i = 0, count = seq.size(); i < count; ++i) { Py::Sequence item(seq[i].ptr()); if (item.size() != 2) { return false; } Part::ShapeMapper::populate(status, getPyShapes(item[0].ptr()), getPyShapes(item[1].ptr())); } } catch (Py::Exception&) { PyErr_Clear(); return false; } return true; } void init(PyObject* g, PyObject* m) { const char* msg = "Expect input mapping to be a list of tuple(srcShape|shapeList, dstShape|shapeList)"; if (!populate(MappingStatus::Generated, g) || !populate(MappingStatus::Modified, m)) { throw Py::TypeError(msg); } } }; PyObject* TopoShapePy::mapShapes(PyObject* args) { PyObject* generated; PyObject* modified; const char* op = nullptr; if (!PyArg_ParseTuple(args, "OO|s", &generated, &modified, &op)) { return 0; } PY_TRY { PyShapeMapper mapper; mapper.init(generated, modified); TopoShape& self = *getTopoShapePtr(); TopoShape s(self.Tag, self.Hasher); s.makeShapeWithElementMap(self.getShape(), mapper, mapper.shapes, op); self = s; return IncRef(); } PY_CATCH_OCC } PyObject* TopoShapePy::mapSubElement(PyObject* args) { const char* op = nullptr; PyObject* sh; if (!PyArg_ParseTuple(args, "O|s", &sh, &op)) { return 0; } PY_TRY { getTopoShapePtr()->mapSubElement(getPyShapes(sh), op); return IncRef(); } PY_CATCH_OCC } PyObject* TopoShapePy::getCustomAttributes(const char* attr) const { if (!attr) { return nullptr; } PY_TRY { TopoDS_Shape res = getTopoShapePtr()->getSubShape(attr, true); if (!res.IsNull()) { return Py::new_reference_to(shape2pyshape(res)); } } PY_CATCH_OCC return nullptr; } int TopoShapePy::setCustomAttributes(const char* , PyObject *) { return 0; }