From 5663ecfd8656f109fc1cc233a53a581d266601c6 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Wed, 20 Mar 2024 17:04:56 -0400 Subject: [PATCH] Transfer in makeCompound python interface and other tnp clauses into AppPartPy --- src/Mod/Part/App/AppPartPy.cpp | 265 ++++++++++++++++++++++++++++++--- 1 file changed, 245 insertions(+), 20 deletions(-) diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index 367b7d8bc1..6d223f886f 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -106,6 +106,8 @@ #ifdef FCUseFreeType # include "FT2FC.h" +#include "TopoShapeOpCode.h" +#include "TopoShapeMapper.h" #endif extern const char* BRepBuilderAPI_FaceErrorText(BRepBuilderAPI_FaceError fe); @@ -424,20 +426,20 @@ public: add_varargs_method("makeCompound",&Module::makeCompound, "makeCompound(list) -- Create a compound out of a list of shapes." ); - add_varargs_method("makeShell",&Module::makeShell, + add_keyword_method("makeShell",&Module::makeShell, "makeShell(list) -- Create a shell out of a list of faces." ); - add_varargs_method("makeFace",&Module::makeFace, + add_keyword_method("makeFace",&Module::makeFace, "makeFace(list_of_shapes_or_compound, maker_class_name) -- Create a face (faces) using facemaker class.\n" "maker_class_name is a string like 'Part::FaceMakerSimple'." ); - add_varargs_method("makeFilledSurface",&Module::makeFilledSurface, + add_keyword_method("makeFilledSurface",&Module::makeFilledSurface, "makeFilledSurface(list of curves, tolerance) -- Create a surface out of a list of curves." ); - add_varargs_method("makeFilledFace",&Module::makeFilledFace, + add_keyword_method("makeFilledFace",&Module::makeFilledFace, "makeFilledFace(list) -- Create a face out of a list of edges." ); - add_varargs_method("makeSolid",&Module::makeSolid, + add_keyword_method("makeSolid",&Module::makeSolid, "makeSolid(shape): Create a solid out of shells of shape. If shape is a compsolid, the overall volume solid is created." ); add_varargs_method("makePlane",&Module::makePlane, @@ -520,12 +522,12 @@ public: "By default vmin/vmax=bounds of the curve, angle=360, pnt=Vector(0,0,0),\n" "dir=Vector(0,0,1) and shapetype=Part.Solid" ); - add_varargs_method("makeRuledSurface",&Module::makeRuledSurface, + add_keyword_method("makeRuledSurface",&Module::makeRuledSurface, "makeRuledSurface(Edge|Wire,Edge|Wire) -- Make a ruled surface\n" "Create a ruled surface out of two edges or wires. If wires are used then" "these must have the same number of edges." ); - add_varargs_method("makeShellFromWires",&Module::makeShellFromWires, + add_keyword_method("makeShellFromWires",&Module::makeShellFromWires, "makeShellFromWires(Wires) -- Make a shell from wires.\n" "The wires must have the same number of edges." ); @@ -536,7 +538,7 @@ public: add_varargs_method("makeSweepSurface",&Module::makeSweepSurface, "makeSweepSurface(edge(path),edge(profile),[float]) -- Create a profile along a path." ); - add_varargs_method("makeLoft",&Module::makeLoft, + add_keyword_method("makeLoft",&Module::makeLoft, "makeLoft(list of wires,[solid=False,ruled=False,closed=False,maxDegree=5]) -- Create a loft shape." ); add_varargs_method("makeWireString",&Module::makeWireString, @@ -887,6 +889,16 @@ private: } Py::Object makeCompound(const Py::Tuple& args) { +#ifndef FC_USE_TNP_FIX + PyObject *pcObj; + PyObject *force = Py_True; + const char *op = nullptr; + static char* kwd_list[] = {"shapes", "force", "op", nullptr}; + if(!PyArg_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "O|O!s", kwd_list, &pcObj, &PyBool_Type, &force, &op)) + throw Py::Exception(); + + return shape2pyshape(Part::TopoShape().makECompound(getPyShapes(pcObj), op, PyObject_IsTrue(force))); +#else PyObject *pcObj; if (!PyArg_ParseTuple(args.ptr(), "O", &pcObj)) throw Py::Exception(); @@ -903,9 +915,18 @@ private: } } _PY_CATCH_OCC(throw Py::Exception()) return Py::asObject(new TopoShapeCompoundPy(new TopoShape(Comp))); +#endif } - Py::Object makeShell(const Py::Tuple& args) + Py::Object makeShell(const Py::Tuple& args, const Py::Dict &kwds) { +#ifdef FC_USE_TNP_FIX + PyObject *obj; + const char *op = nullptr; + const std::array kwd_list = {"shapes", "op", nullptr}; + if(!Base::Wrapped_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "O|s", kwd_list, &obj, &op)) + throw Py::Exception(); + return shape2pyshape(Part::TopoShape().makeElementBoolean(Part::OpCodes::Shell,getPyShapes(obj),op)); +#else PyObject *obj; if (!PyArg_ParseTuple(args.ptr(), "O", &obj)) throw Py::Exception(); @@ -939,9 +960,20 @@ private: } return Py::asObject(new TopoShapeShellPy(new TopoShape(shape))); +#endif } - Py::Object makeFace(const Py::Tuple& args) + Py::Object makeFace(const Py::Tuple& args, const Py::Dict &kwds) { +#ifdef FC_USE_TNP_FIX + PyObject *obj; + const char *className = nullptr; + const char *op = nullptr; + const std::array kwd_list = {"shapes", "class_name", "op", nullptr}; + if(!Base::Wrapped_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "O|ss", kwd_list, + &obj, &className, &op)) + throw Py::Exception(); + return shape2pyshape(TopoShape().makeElementFace(getPyShapes(obj),op,className)); +#else try { char* className = nullptr; PyObject* pcPyShapeOrList = nullptr; @@ -987,9 +1019,73 @@ private: e.setPyException(); throw Py::Exception(); } +#endif } - Py::Object makeFilledSurface(const Py::Tuple &args) + + template + void parseSequence(PyObject *pyObj, const char *err, F f) { + if (pyObj != Py_None) { + if (!PySequence_Check(pyObj)) + throw Py::TypeError(err); + Py::Sequence seq(pyObj); + for (Py::Sequence::iterator it = seq.begin(); it != seq.end(); ++it) { + if (!PySequence_Check((*it).ptr())) + throw Py::TypeError(err); + Py::Sequence tuple((*it).ptr()); + if (tuple.size() != 2) + throw Py::TypeError(err); + auto iter = tuple.begin(); + if (!PyObject_TypeCheck((*iter).ptr(), &(Part::TopoShapePy::Type))) + throw Py::TypeError(err); + const TopoDS_Shape& sh = static_cast((*iter).ptr())->getTopoShapePtr()->getShape(); + f(sh, (*iter).ptr(), err); + } + } + } + + + Py::Object makeFilledSurface(const Py::Tuple &args, const Py::Dict &kwds) + { +#ifdef FC_USE_TNP_FIX + TopoShape::BRepFillingParams params; + PyObject *obj = nullptr; + PyObject *pySurface = Py_None; + PyObject *supports = Py_None; + PyObject *orders = Py_None; + PyObject *anisotropy = params.anisotropy ? Py_True : Py_False; + const char *op = nullptr; + const std::array kwd_list = {"shapes", "surface", "supports", + "orders","degree","ptsOnCurve","numIter","anisotropy", + "tol2d", "tol3d", "tolG1", "tolG2", "maxDegree", "maxSegments", "op", nullptr}; + if(!Base::Wrapped_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "O|O!OOIIIOddddIIs", kwd_list, + &obj, &pySurface, &orders, ¶ms.degree, ¶ms.ptsoncurve, + ¶ms.numiter, &anisotropy, ¶ms.tol2d, ¶ms.tol3d, + ¶ms.tolG1, ¶ms.tolG2, ¶ms.maxdeg, ¶ms.maxseg, &op)) + throw Py::Exception(); + params.anisotropy = PyObject_IsTrue(anisotropy); + TopoShape surface; + if(pySurface != Py_None) + surface = *static_cast(pySurface)->getTopoShapePtr(); + parseSequence(supports, "Expects 'supports' to be a sequence of tuple(shape, shape)", + [&](const TopoDS_Shape &s, PyObject *value, const char *err) { + if (!PyObject_TypeCheck(value, &(Part::TopoShapePy::Type))) + throw Py::TypeError(err); + params.supports[s] = static_cast(value)->getTopoShapePtr()->getShape(); + }); + parseSequence(orders, "Expects 'orders' to be a sequence of tuple(shape, PartEnums.Shape)", + [&](const TopoDS_Shape &s, PyObject *value, const char *err) { + if (!PyLong_Check(value)) + throw Py::ValueError(err); + int order = Py::Int(value); + params.orders[s] = static_cast(order); + return; + }); + auto shapes = getPyShapes(obj); + if (shapes.empty()) + throw Py::ValueError("No input shape"); + return shape2pyshape(TopoShape(0, shapes.front().Hasher).makeElementFilledFace(shapes,params,op)); +#else PyObject *obj; double tolerance; if (!PyArg_ParseTuple(args.ptr(), "Od", &obj, &tolerance)) @@ -1019,9 +1115,49 @@ private: catch (Standard_Failure& e) { throw Py::Exception(PartExceptionOCCError, e.GetMessageString()); } +#endif } - Py::Object makeFilledFace(const Py::Tuple& args) + Py::Object makeFilledFace(const Py::Tuple& args, const Py::Dict &kwds) { +#ifdef FC_USE_TNP_FIX + TopoShape::BRepFillingParams params; + PyObject *obj = nullptr; + PyObject *pySurface = Py_None; + PyObject *supports = Py_None; + PyObject *orders = Py_None; + PyObject *anisotropy = params.anisotropy ? Py_True : Py_False; + const char *op = nullptr; + const std::array kwd_list = {"shapes", "surface", "supports", + "orders","degree","ptsOnCurve","numIter","anisotropy", + "tol2d", "tol3d", "tolG1", "tolG2", "maxDegree", "maxSegments", "op", nullptr}; + if(!Base::Wrapped_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "O|O!OOIIIOddddIIs", kwd_list, + &obj, &pySurface, &orders, ¶ms.degree, ¶ms.ptsoncurve, + ¶ms.numiter, &anisotropy, ¶ms.tol2d, ¶ms.tol3d, + ¶ms.tolG1, ¶ms.tolG2, ¶ms.maxdeg, ¶ms.maxseg, &op)) + throw Py::Exception(); + params.anisotropy = PyObject_IsTrue(anisotropy); + TopoShape surface; + if(pySurface != Py_None) + surface = *static_cast(pySurface)->getTopoShapePtr(); + parseSequence(supports, "Expects 'supports' to be a sequence of tuple(shape, shape)", + [&](const TopoDS_Shape &s, PyObject *value, const char *err) { + if (!PyObject_TypeCheck(value, &(Part::TopoShapePy::Type))) + throw Py::TypeError(err); + params.supports[s] = static_cast(value)->getTopoShapePtr()->getShape(); + }); + parseSequence(orders, "Expects 'orders' to be a sequence of tuple(shape, PartEnums.Shape)", + [&](const TopoDS_Shape &s, PyObject *value, const char *err) { + if (!PyLong_Check(value)) + throw Py::ValueError(err); + int order = Py::Int(value); + params.orders[s] = static_cast(order); + return; + }); + auto shapes = getPyShapes(obj); + if (shapes.empty()) + throw Py::ValueError("No input shape"); + return shape2pyshape(TopoShape(0, shapes.front().Hasher).makeElementFilledFace(shapes,params,op)); +#else // TODO: BRepFeat_SplitShape PyObject *obj; PyObject *surf=nullptr; @@ -1078,9 +1214,19 @@ private: catch (Standard_Failure& e) { throw Py::Exception(PartExceptionOCCError, e.GetMessageString()); } +#endif } - Py::Object makeSolid(const Py::Tuple& args) + Py::Object makeSolid(const Py::Tuple& args, const Py::Dict &kwds) { +#ifndef FC_NO_ELEMENT_MAP + PyObject *obj; + const char *op = nullptr; + const std::array kwd_list = {"shape", "op", nullptr}; + if(!Base::Wrapped_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "O!|s", + kwd_list, &(TopoShapePy::Type), &obj, &op)) + throw Py::Exception(); + return shape2pyshape(TopoShape().makeElementSolid(*static_cast(obj)->getTopoShapePtr(),op)); +#else PyObject *obj; if (!PyArg_ParseTuple(args.ptr(), "O!", &(TopoShapePy::Type), &obj)) throw Py::Exception(); @@ -1128,6 +1274,7 @@ private: errmsg << "Creation of solid failed: " << err.GetMessageString(); throw Py::Exception(PartExceptionOCCError, errmsg.str().c_str()); } +#endif } Py::Object makePlane(const Py::Tuple& args) { @@ -1684,8 +1831,25 @@ private: throw Py::Exception(PartExceptionOCCDomainError, "creation of revolved shape failed"); } } - Py::Object makeRuledSurface(const Py::Tuple& args) + Py::Object makeRuledSurface(const Py::Tuple& args, const Py::Dict &kwds) { +#ifdef FC_USE_TNP_FIX + const char *op=nullptr; + int orientation = 0; + PyObject *sh1, *sh2; + const std::array kwd_list = {"path", "profile", "orientation", "op", nullptr}; + if(!Base::Wrapped_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "O!O!|is", kwd_list, + &(TopoShapePy::Type), &sh1, + &(TopoShapePy::Type), &sh2, + &orientation, + &op)) + throw Py::Exception(); + + std::vector shapes; + shapes.push_back(*static_cast(sh1)->getTopoShapePtr()); + shapes.push_back(*static_cast(sh2)->getTopoShapePtr()); + return shape2pyshape(TopoShape().makeElementRuledSurface(shapes,orientation,op)); +#else // http://opencascade.blogspot.com/2009/10/surface-modeling-part1.html PyObject *sh1, *sh2; if (!PyArg_ParseTuple(args.ptr(), "O!O!", &(TopoShapePy::Type), &sh1, @@ -1711,10 +1875,22 @@ private: catch (Standard_Failure&) { throw Py::Exception(PartExceptionOCCError, "creation of ruled surface failed"); } +#endif } - Py::Object makeShellFromWires(const Py::Tuple& args) + Py::Object makeShellFromWires(const Py::Tuple& args, const Py::Dict &kwds) { PyObject *pylist; +#ifdef FC_USE_TNP_FIX + const char *op = nullptr; + const std::array kwd_list = {"shape", "op", nullptr}; + if(!Base::Wrapped_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "O|s", kwd_list, &pylist, &op)) + throw Py::Exception(); + try { + return shape2pyshape(TopoShape().makeElementShellFromWires(getPyShapes(pylist), /*silent*/false, op)); + } catch (Standard_Failure&) { + throw Py::Exception(PartExceptionOCCError, "creation of shell failed"); + } +#else if (!PyArg_ParseTuple(args.ptr(), "O", &pylist)) throw Py::Exception(); @@ -1735,6 +1911,7 @@ private: catch (Standard_Failure&) { throw Py::Exception(PartExceptionOCCError, "creation of shell failed"); } +#endif } Py::Object makeTube(const Py::Tuple& args) { @@ -1791,24 +1968,55 @@ private: throw Py::Exception(); try { +#ifndef FC_NO_ELEMENT_MAP + TopoShape mShape = *static_cast(path)->getTopoShapePtr(); + // makeSweep uses GeomFill_Pipe which does not support shape + // history. So use makEPipeShell() as a replacement + return shape2pyshape(TopoShape(0, mShape.Hasher).makeElementPipeShell( + {mShape, *static_cast(profile)->getTopoShapePtr()}, + Part::MakeSolid::noSolid, Standard_False, TransitionMode::Transformed, + nullptr, tolerance)); +#else const TopoDS_Shape& path_shape = static_cast(path)->getTopoShapePtr()->getShape(); const TopoDS_Shape& prof_shape = static_cast(profile)->getTopoShapePtr()->getShape(); TopoShape myShape(path_shape); TopoDS_Shape face = myShape.makeSweep(prof_shape, tolerance, fillMode); return Py::asObject(new TopoShapeFacePy(new TopoShape(face))); +#endif } catch (Standard_Failure& e) { throw Py::Exception(PartExceptionOCCError, e.GetMessageString()); } } - Py::Object makeLoft(const Py::Tuple& args) + Py::Object makeLoft(const Py::Tuple& args, const Py::Dict &kwds) { PyObject *pcObj; PyObject *psolid=Py_False; PyObject *pruled=Py_False; PyObject *pclosed=Py_False; int degMax = 5; +# ifdef FC_USE_TNP_FIX + const char *op = nullptr; + const std::array kwd_list = {"shapes", "solid", "ruled", "closed", "max_degree", "op", nullptr}; + if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "O!|O!O!O!is", kwd_list, + &pcObj, + &(PyBool_Type), &psolid, + &(PyBool_Type), &pruled, + &(PyBool_Type), &pclosed, + °Max, &op)) + { + throw Py::Exception(); + } + Standard_Boolean anIsSolid = PyObject_IsTrue(psolid) ? Standard_True : Standard_False; + Standard_Boolean anIsRuled = PyObject_IsTrue(pruled) ? Standard_True : Standard_False; + Standard_Boolean anIsClosed = PyObject_IsTrue(pclosed) ? Standard_True : Standard_False; + return shape2pyshape(TopoShape().makeElementLoft(getPyShapes(pcObj), + anIsSolid ? Part::IsSolid::solid : Part::IsSolid::notSolid, + anIsRuled ? Part::IsRuled::ruled : Part::IsRuled::notRuled, + anIsClosed ? Part::IsClosed::closed : Part::IsClosed::notClosed, + degMax,op)); +# else if (!PyArg_ParseTuple(args.ptr(), "O|O!O!O!i", &pcObj, &(PyBool_Type), &psolid, &(PyBool_Type), &pruled, @@ -1834,7 +2042,7 @@ private: Standard_Boolean anIsClosed = Base::asBoolean(pclosed); TopoDS_Shape aResult = myShape.makeLoft(profiles, anIsSolid, anIsRuled, anIsClosed, degMax); return Py::asObject(new TopoShapePy(new TopoShape(aResult))); - +#endif } Py::Object makeSplitShape(const Py::Tuple& args) { @@ -1846,6 +2054,8 @@ private: throw Py::Exception(); try { + std::vector sources; + sources.push_back(*static_cast(shape)->getTopoShapePtr()); TopoDS_Shape initShape = static_cast (shape)->getTopoShapePtr()->getShape(); BRepFeat_SplitShape splitShape(initShape); @@ -1856,6 +2066,7 @@ private: Py::Tuple tuple(*it); Py::TopoShape sh1(tuple[0]); Py::TopoShape sh2(tuple[1]); + sources.push_back(*sh1.extensionObject()->getTopoShapePtr()); const TopoDS_Shape& shape1= sh1.extensionObject()->getTopoShapePtr()->getShape(); const TopoDS_Shape& shape2= sh2.extensionObject()->getTopoShapePtr()->getShape(); if (shape1.IsNull() || shape2.IsNull()) @@ -1892,15 +2103,26 @@ private: const TopTools_ListOfShape& l = splitShape.Left(); Py::List list1; + Py::List list2; +#ifdef FC_USE_TNP_FIX + MapperMaker mapper(splitShape); + for (TopTools_ListIteratorOfListOfShape it(d); it.More(); it.Next()) { + TopoShape s(0, sources.front().Hasher); + list1.append(shape2pyshape(s.makeShapeWithElementMap(it.Value(), mapper, sources, Part::OpCodes::Split))); + } + for (TopTools_ListIteratorOfListOfShape it(l); it.More(); it.Next()) { + TopoShape s(0, sources.front().Hasher); + list2.append(shape2pyshape(s.makeShapeWithElementMap(it.Value(), mapper, sources, Part::OpCodes::Split))); + } +#else for (TopTools_ListIteratorOfListOfShape it(d); it.More(); it.Next()) { list1.append(shape2pyshape(it.Value())); } - Py::List list2; for (TopTools_ListIteratorOfListOfShape it(l); it.More(); it.Next()) { list2.append(shape2pyshape(it.Value())); } - +#endif Py::Tuple tuple(2); tuple.setItem(0, list1); tuple.setItem(1, list2); @@ -2251,9 +2473,12 @@ private: &mat,&subObj,retType==2,Base::asBoolean(transform), Base::asBoolean(noElementMap)); if (Base::asBoolean(refine)) { - // shape = TopoShape(0,shape.Hasher).makERefine(shape); +#ifndef FC_NO_ELEMENT_MAP + shape = TopoShape(0,shape.Hasher).makeElementRefine(shape); +#else BRepBuilderAPI_RefineModel mkRefine(shape.getShape()); shape.setShape(mkRefine.Shape()); +#endif } Py::Object sret(shape2pyshape(shape)); if(retType==0)