diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index 83246b9ecc..92bd1030bb 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -122,26 +122,35 @@ extern const char* BRepBuilderAPI_FaceErrorText(BRepBuilderAPI_FaceError fe); namespace Part { -PartExport void getPyShapes(PyObject *obj, std::vector &shapes) { - if(!obj) +PartExport void getPyShapes(PyObject* obj, std::vector& shapes) +{ + if (!obj) { return; - if(PyObject_TypeCheck(obj,&Part::TopoShapePy::Type)) + } + if (PyObject_TypeCheck(obj, &Part::TopoShapePy::Type)) { shapes.push_back(*static_cast(obj)->getTopoShapePtr()); - else if (PyObject_TypeCheck(obj, &GeometryPy::Type)) + } + else if (PyObject_TypeCheck(obj, &GeometryPy::Type)) { shapes.emplace_back(static_cast(obj)->getGeometryPtr()->toShape()); - else if(PySequence_Check(obj)) { + } + else if (PySequence_Check(obj)) { Py::Sequence list(obj); for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { - if (PyObject_TypeCheck((*it).ptr(), &(Part::TopoShapePy::Type))) + if (PyObject_TypeCheck((*it).ptr(), &(Part::TopoShapePy::Type))) { shapes.push_back(*static_cast((*it).ptr())->getTopoShapePtr()); - else if (PyObject_TypeCheck((*it).ptr(), &GeometryPy::Type)) - shapes.emplace_back(static_cast( - (*it).ptr())->getGeometryPtr()->toShape()); - else + } + else if (PyObject_TypeCheck((*it).ptr(), &GeometryPy::Type)) { + shapes.emplace_back( + static_cast((*it).ptr())->getGeometryPtr()->toShape()); + } + else { throw Py::TypeError("expect shape in sequence"); + } } - }else + } + else { throw Py::TypeError("expect shape or sequence of shapes"); + } } PartExport std::vector getPyShapes(PyObject *obj) { @@ -952,8 +961,8 @@ private: return shape2pyshape(Part::TopoShape().makeElementCompound(getPyShapes(pcObj), op, policy)); #else -Py::Object makeCompound(const Py::Tuple& args) -{ + Py::Object makeCompound(const Py::Tuple& args) + { PyObject *pcObj; if (!PyArg_ParseTuple(args.ptr(), "O", &pcObj)) throw Py::Exception(); @@ -989,8 +998,8 @@ Py::Object makeCompound(const Py::Tuple& args) return shape2pyshape( Part::TopoShape().makeElementBoolean(Part::OpCodes::Shell, getPyShapes(obj), op)); #else -Py::Object makeShell(const Py::Tuple& args) -{ + Py::Object makeShell(const Py::Tuple& args) + { PyObject *obj; if (!PyArg_ParseTuple(args.ptr(), "O", &obj)) throw Py::Exception(); @@ -1044,8 +1053,8 @@ Py::Object makeShell(const Py::Tuple& args) } return shape2pyshape(TopoShape().makeElementFace(getPyShapes(obj), op, className)); #else -Py::Object makeFace(const Py::Tuple& args) -{ + Py::Object makeFace(const Py::Tuple& args) + { try { char* className = nullptr; PyObject* pcPyShapeOrList = nullptr; @@ -1194,8 +1203,8 @@ Py::Object makeFace(const Py::Tuple& args) return shape2pyshape( TopoShape(0, shapes.front().Hasher).makeElementFilledFace(shapes, params, op)); #else -Py::Object makeFilledSurface(const Py::Tuple &args) -{ + Py::Object makeFilledSurface(const Py::Tuple &args) + { PyObject *obj; double tolerance; if (!PyArg_ParseTuple(args.ptr(), "Od", &obj, &tolerance)) @@ -1304,8 +1313,8 @@ Py::Object makeFilledSurface(const Py::Tuple &args) return shape2pyshape( TopoShape(0, shapes.front().Hasher).makeElementFilledFace(shapes, params, op)); #else -Py::Object makeFilledFace(const Py::Tuple& args) -{ + Py::Object makeFilledFace(const Py::Tuple& args) + { // TODO: BRepFeat_SplitShape PyObject *obj; PyObject *surf=nullptr; @@ -1382,8 +1391,8 @@ Py::Object makeFilledFace(const Py::Tuple& args) return shape2pyshape( TopoShape().makeElementSolid(*static_cast(obj)->getTopoShapePtr(), op)); #else -Py::Object makeSolid(const Py::Tuple& args) -{ + Py::Object makeSolid(const Py::Tuple& args) + { PyObject *obj; if (!PyArg_ParseTuple(args.ptr(), "O!", &(TopoShapePy::Type), &obj)) throw Py::Exception(); @@ -2017,8 +2026,8 @@ Py::Object makeSolid(const Py::Tuple& args) shapes.push_back(*static_cast(sh2)->getTopoShapePtr()); return shape2pyshape(TopoShape().makeElementRuledSurface(shapes, orientation, op)); #else -Py::Object makeRuledSurface(const Py::Tuple& args) -{ + Py::Object makeRuledSurface(const Py::Tuple& args) + { // http://opencascade.blogspot.com/2009/10/surface-modeling-part1.html PyObject *sh1, *sh2; if (!PyArg_ParseTuple(args.ptr(), "O!O!", &(TopoShapePy::Type), &sh1, @@ -2068,9 +2077,9 @@ Py::Object makeRuledSurface(const Py::Tuple& args) throw Py::Exception(PartExceptionOCCError, "creation of shell failed"); } #else -Py::Object makeShellFromWires(const Py::Tuple& args) -{ - PyObject *pylist; + Py::Object makeShellFromWires(const Py::Tuple& args) + { + PyObject *pylist; if (!PyArg_ParseTuple(args.ptr(), "O", &pylist)) throw Py::Exception(); @@ -2162,6 +2171,8 @@ Py::Object makeShellFromWires(const Py::Tuple& args) nullptr, tolerance)); #else + if (tolerance == 0.0) + tolerance=0.001; const TopoDS_Shape& path_shape = static_cast(path)->getTopoShapePtr()->getShape(); const TopoDS_Shape& prof_shape = static_cast(profile)->getTopoShapePtr()->getShape(); @@ -2182,6 +2193,7 @@ Py::Object makeShellFromWires(const Py::Tuple& args) PyObject *pruled=Py_False; PyObject *pclosed=Py_False; int degMax = 5; + const char* op = nullptr; const std::array kwd_list = {"shapes", "solid", "ruled", "closed", "max_degree", "op", nullptr}; @@ -2212,13 +2224,14 @@ Py::Object makeShellFromWires(const Py::Tuple& args) degMax, op)); #else -Py::Object makeLoft(const Py::Tuple& args) -{ - PyObject *pcObj; - PyObject *psolid=Py_False; - PyObject *pruled=Py_False; - PyObject *pclosed=Py_False; - int degMax = 5; + Py::Object makeLoft(const Py::Tuple& args) + { + PyObject *pcObj; + PyObject *psolid=Py_False; + PyObject *pruled=Py_False; + PyObject *pclosed=Py_False; + int degMax = 5; + if (!PyArg_ParseTuple(args.ptr(), "O|O!O!O!i", &pcObj, &(PyBool_Type), &psolid, &(PyBool_Type), &pruled, diff --git a/src/Mod/Part/App/TopoShapeCompSolidPyImp.cpp b/src/Mod/Part/App/TopoShapeCompSolidPyImp.cpp index cf2f42c20d..201c693441 100644 --- a/src/Mod/Part/App/TopoShapeCompSolidPyImp.cpp +++ b/src/Mod/Part/App/TopoShapeCompSolidPyImp.cpp @@ -29,11 +29,13 @@ #endif #include "OCCError.h" +#include "PartPyCXX.h" // inclusion of the generated files (generated out of TopoShapeCompSolidPy.xml) #include "TopoShapeCompSolidPy.h" #include "TopoShapeCompSolidPy.cpp" #include "TopoShapeSolidPy.h" +#include "TopoShapeOpCode.h" using namespace Part; @@ -61,10 +63,16 @@ int TopoShapeCompSolidPy::PyInit(PyObject* args, PyObject* /*kwd*/) } PyErr_Clear(); - PyObject *pcObj; - if (!PyArg_ParseTuple(args, "O", &pcObj)) + PyObject* pcObj; + if (!PyArg_ParseTuple(args, "O", &pcObj)) { return -1; - + } +#ifdef FC_USE_TNP_FIX + try { + getTopoShapePtr()->makeElementBoolean(Part::OpCodes::Compsolid, getPyShapes(pcObj)); + } + _PY_CATCH_OCC(return (-1)) +#else BRep_Builder builder; TopoDS_CompSolid Comp; builder.MakeCompSolid(Comp); @@ -73,10 +81,11 @@ int TopoShapeCompSolidPy::PyInit(PyObject* args, PyObject* /*kwd*/) Py::Sequence list(pcObj); for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { if (PyObject_TypeCheck((*it).ptr(), &(Part::TopoShapeSolidPy::Type))) { - const TopoDS_Shape& sh = static_cast((*it).ptr())-> - getTopoShapePtr()->getShape(); - if (!sh.IsNull()) + const TopoDS_Shape& sh = + static_cast((*it).ptr())->getTopoShapePtr()->getShape(); + if (!sh.IsNull()) { builder.Add(Comp, sh); + } } } } @@ -87,35 +96,46 @@ int TopoShapeCompSolidPy::PyInit(PyObject* args, PyObject* /*kwd*/) } getTopoShapePtr()->setShape(Comp); +#endif return 0; } -PyObject* TopoShapeCompSolidPy::add(PyObject *args) +PyObject* TopoShapeCompSolidPy::add(PyObject* args) { - PyObject *obj; - if (!PyArg_ParseTuple(args, "O!", &(Part::TopoShapeSolidPy::Type), &obj)) + PyObject* obj; + if (!PyArg_ParseTuple(args, "O!", &(Part::TopoShapeSolidPy::Type), &obj)) { return nullptr; + } BRep_Builder builder; TopoDS_Shape comp = getTopoShapePtr()->getShape(); + auto shapes = getPyShapes(obj); try { - const TopoDS_Shape& sh = static_cast(obj)-> - getTopoShapePtr()->getShape(); - if (!sh.IsNull()) - builder.Add(comp, sh); - else - Standard_Failure::Raise("Cannot empty shape to compound solid"); + for (auto& ts : shapes) { + if (!ts.isNull()) { + builder.Add(comp, ts.getShape()); + } + else { + Standard_Failure::Raise("Cannot empty shape to compound solid"); + } + } +#ifdef FC_USE_TNP_FIX + auto& self = *getTopoShapePtr(); + shapes.push_back(self); + TopoShape tmp(self.Tag, self.Hasher, comp); + tmp.mapSubElement(shapes); + self = tmp; +#else + getTopoShapePtr()->setShape(comp); +#endif + Py_Return; } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } - - getTopoShapePtr()->setShape(comp); - - Py_Return; } PyObject *TopoShapeCompSolidPy::getCustomAttributes(const char* /*attr*/) const diff --git a/src/Mod/Part/App/TopoShapeFacePyImp.cpp b/src/Mod/Part/App/TopoShapeFacePyImp.cpp index eb452b1092..17621f6105 100644 --- a/src/Mod/Part/App/TopoShapeFacePyImp.cpp +++ b/src/Mod/Part/App/TopoShapeFacePyImp.cpp @@ -88,6 +88,7 @@ #include "FaceMaker.h" #include "Geometry2d.h" #include "OCCError.h" +#include "PartPyCXX.h" #include "Tools.h" @@ -324,6 +325,9 @@ int TopoShapeFacePy::PyInit(PyObject* args, PyObject* /*kwd*/) PyErr_Clear(); if (PyArg_ParseTuple(args, "Os", &pcPyShapeOrList, &className)) { try { +#ifdef FC_USE_TNP_FIX + getTopoShapePtr()->makeElementFace(getPyShapes(pcPyShapeOrList),0,className); +#else std::unique_ptr fm = Part::FaceMaker::ConstructFromType(className); //dump all supplied shapes to facemaker, no matter what type (let facemaker decide). @@ -355,6 +359,7 @@ int TopoShapeFacePy::PyInit(PyObject* args, PyObject* /*kwd*/) fm->Build(); getTopoShapePtr()->setShape(fm->Face()); +#endif return 0; } catch (Base::Exception &e) { e.setPyException(); @@ -420,6 +425,10 @@ PyObject* TopoShapeFacePy::addWire(PyObject *args) PyObject* TopoShapeFacePy::makeOffset(PyObject *args) { +#ifdef FC_USE_TNP_FIX + Py::Dict dict; + return TopoShapePy::makeOffset2D(args, dict.ptr()); +#else double dist; if (!PyArg_ParseTuple(args, "d",&dist)) return nullptr; @@ -434,6 +443,7 @@ PyObject* TopoShapeFacePy::makeOffset(PyObject *args) mkOffset.Perform(dist); return new TopoShapePy(new TopoShape(mkOffset.Shape())); +#endif } /* @@ -445,6 +455,9 @@ evolve = spine.makeEvolved(Profile=profile, Join=PartEnums.JoinType.Arc) */ PyObject* TopoShapeFacePy::makeEvolved(PyObject *args, PyObject *kwds) { +#ifdef FC_USE_TNP_FIX + return TopoShapePy::makeEvolved(args, kwds); +#else PyObject* Profile; PyObject* AxeProf = Py_True; PyObject* Solid = Py_False; @@ -496,6 +509,7 @@ PyObject* TopoShapeFacePy::makeEvolved(PyObject *args, PyObject *kwds) PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); return nullptr; } +#endif } PyObject* TopoShapeFacePy::valueAt(PyObject *args) diff --git a/src/Mod/Part/App/TopoShapePy.xml b/src/Mod/Part/App/TopoShapePy.xml index cdac9edc92..357a7be4cf 100644 --- a/src/Mod/Part/App/TopoShapePy.xml +++ b/src/Mod/Part/App/TopoShapePy.xml @@ -511,6 +511,11 @@ Returns: result of offsetting (wire or face or compound of those). Compounding structure follows that of source shape. + + + Profile along the spine + + make wire(s) using the edges of this shape @@ -820,6 +825,45 @@ countElement(type) -> int + + + + mapSubElement(shape|[shape...], op='') - maps the sub element of other shape + + shape: other shape or sequence of shapes to map the sub-elements + op: optional string prefix to append before the mapped sub element names + + + + + + + mapShapes(generated, modified, op='') + + generate element names with user defined mapping + + generated: a list of tuple(src, dst) that indicating src shape or shapes + generates dst shape or shapes. Note that the dst shape or shapes + must be sub-shapes of this shape. + modified: a list of tuple(src, dst) that indicating src shape or shapes + modifies into dst shape or shapes. Note that the dst shape or + shapes must be sub-shapes of this shape. + op: optional string prefix to append before the mapped sub element names + + + + + + + getElementHistory(name) - returns the element mapped name history + + name: mapped element name belonging to this shape + + Returns tuple(sourceShapeTag, sourceName, [intermediateNames...]), + or None if no history. + + + Determines a tolerance from the ones stored in a shape @@ -906,6 +950,55 @@ optimalBoundingBox([useTriangulation = True, useShapeTolerance = False]) -> boun + + + Clear internal sub-shape cache + + + + + + findSubShape(shape) -> (type_name, index) + + Find sub shape and return the shape type name and index. If not found, + then return (None, 0) + + + + + + + findSubShapesWithSharedVertex(shape, needName=False, checkGeometry=True, tol=1e-7, atol=1e-12) -> Shape + + shape: input elementary shape, currently only support Face, Edge, or Vertex + + needName: if True, return a list of tuple(name, shape), or else return a list + of shapes. + + checkGeometry: whether to compare geometry + + tol: distance tolerance + + atol: angular tolerance + + Search sub shape by checking vertex coordinates and comparing the underlying + geometries, This can find shapes that are copied. It currently only works with + elementary shapes, Face, Edge, Vertex. + + + + + + + getChildShapes(shapetype, avoidtype='') -> list(Shape) + + Return a list of child sub-shapes of given type. + + shapetype: the type of requesting sub shapes + avoidtype: optional shape type to skip when exploring + + +