Download src/Mod/Part/App/AppPartPy.cpp from AbdulElahGwaith/FreeCAD: direct link, hf CLI and curl.
- Browser
- Download file 104 kB
-
https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/Part/App/AppPartPy.cpp
- Command line
-
hf download hf://AbdulElahGwaith/FreeCAD/src/Mod/Part/App/AppPartPy.cpp
-
curl -L -o AppPartPy.cpp https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/Part/App/AppPartPy.cpp
104 kB
| // SPDX-License-Identifier: LGPL-2.1-or-later | |
| /*************************************************************************** | |
| * Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> * | |
| * * | |
| * 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 * | |
| * * | |
| ***************************************************************************/ | |
| FC_LOG_LEVEL_INIT("Part") | |
| extern const char* BRepBuilderAPI_FaceErrorText(BRepBuilderAPI_FaceError fe); | |
| namespace Part | |
| { | |
| PartExport void getPyShapes(PyObject* obj, std::vector<TopoShape>& shapes) | |
| { | |
| if (!obj) { | |
| return; | |
| } | |
| if (PyObject_TypeCheck(obj, &Part::TopoShapePy::Type)) { | |
| shapes.push_back(*static_cast<TopoShapePy*>(obj)->getTopoShapePtr()); | |
| } | |
| else if (PyObject_TypeCheck(obj, &GeometryPy::Type)) { | |
| shapes.emplace_back(static_cast<GeometryPy*>(obj)->getGeometryPtr()->toShape()); | |
| } | |
| 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))) { | |
| shapes.push_back(*static_cast<TopoShapePy*>((*it).ptr())->getTopoShapePtr()); | |
| } | |
| else if (PyObject_TypeCheck((*it).ptr(), &GeometryPy::Type)) { | |
| shapes.emplace_back(static_cast<GeometryPy*>((*it).ptr())->getGeometryPtr()->toShape()); | |
| } | |
| else { | |
| throw Py::TypeError("expect shape in sequence"); | |
| } | |
| } | |
| } | |
| else { | |
| throw Py::TypeError("expect shape or sequence of shapes"); | |
| } | |
| } | |
| PartExport std::vector<TopoShape> getPyShapes(PyObject* obj) | |
| { | |
| std::vector<TopoShape> ret; | |
| getPyShapes(obj, ret); | |
| return ret; | |
| } | |
| namespace | |
| { | |
| struct EdgePoints | |
| { | |
| gp_Pnt v1, v2; | |
| std::list<TopoDS_Edge>::iterator it; | |
| TopoDS_Edge edge; | |
| }; | |
| } // namespace | |
| PartExport std::list<TopoDS_Edge> sort_Edges(double tol3d, std::list<TopoDS_Edge>& edges) | |
| { | |
| tol3d = tol3d * tol3d; | |
| std::list<EdgePoints> edge_points; | |
| TopExp_Explorer xp; | |
| for (std::list<TopoDS_Edge>::iterator it = edges.begin(); it != edges.end(); ++it) { | |
| EdgePoints ep; | |
| xp.Init(*it, TopAbs_VERTEX); | |
| ep.v1 = BRep_Tool::Pnt(TopoDS::Vertex(xp.Current())); | |
| xp.Next(); | |
| ep.v2 = BRep_Tool::Pnt(TopoDS::Vertex(xp.Current())); | |
| ep.it = it; | |
| ep.edge = *it; | |
| edge_points.push_back(ep); | |
| } | |
| if (edge_points.empty()) { | |
| return {}; | |
| } | |
| std::list<TopoDS_Edge> sorted; | |
| gp_Pnt first, last; | |
| first = edge_points.front().v1; | |
| last = edge_points.front().v2; | |
| sorted.push_back(edge_points.front().edge); | |
| edges.erase(edge_points.front().it); | |
| edge_points.erase(edge_points.begin()); | |
| while (!edge_points.empty()) { | |
| // search for adjacent edge | |
| std::list<EdgePoints>::iterator pEI; | |
| for (pEI = edge_points.begin(); pEI != edge_points.end(); ++pEI) { | |
| if (pEI->v1.SquareDistance(last) <= tol3d) { | |
| last = pEI->v2; | |
| sorted.push_back(pEI->edge); | |
| edges.erase(pEI->it); | |
| edge_points.erase(pEI); | |
| pEI = edge_points.begin(); | |
| break; | |
| } | |
| else if (pEI->v2.SquareDistance(first) <= tol3d) { | |
| first = pEI->v1; | |
| sorted.push_front(pEI->edge); | |
| edges.erase(pEI->it); | |
| edge_points.erase(pEI); | |
| pEI = edge_points.begin(); | |
| break; | |
| } | |
| else if (pEI->v2.SquareDistance(last) <= tol3d) { | |
| last = pEI->v1; | |
| Standard_Real first, last; | |
| const Handle(Geom_Curve) & curve = BRep_Tool::Curve(pEI->edge, first, last); | |
| first = curve->ReversedParameter(first); | |
| last = curve->ReversedParameter(last); | |
| TopoDS_Edge edgeReversed = BRepBuilderAPI_MakeEdge(curve->Reversed(), last, first); | |
| sorted.push_back(edgeReversed); | |
| edges.erase(pEI->it); | |
| edge_points.erase(pEI); | |
| pEI = edge_points.begin(); | |
| break; | |
| } | |
| else if (pEI->v1.SquareDistance(first) <= tol3d) { | |
| first = pEI->v2; | |
| Standard_Real first, last; | |
| const Handle(Geom_Curve) & curve = BRep_Tool::Curve(pEI->edge, first, last); | |
| first = curve->ReversedParameter(first); | |
| last = curve->ReversedParameter(last); | |
| TopoDS_Edge edgeReversed = BRepBuilderAPI_MakeEdge(curve->Reversed(), last, first); | |
| sorted.push_front(edgeReversed); | |
| edges.erase(pEI->it); | |
| edge_points.erase(pEI); | |
| pEI = edge_points.begin(); | |
| break; | |
| } | |
| } | |
| if ((pEI == edge_points.end()) || (last.SquareDistance(first) <= tol3d)) { | |
| // no adjacent edge found or polyline is closed | |
| return sorted; | |
| } | |
| } | |
| return sorted; | |
| } | |
| } // namespace Part | |
| namespace Part | |
| { | |
| class BRepFeatModule: public Py::ExtensionModule<BRepFeatModule> | |
| { | |
| public: | |
| BRepFeatModule() | |
| : Py::ExtensionModule<BRepFeatModule>("BRepFeat") | |
| { | |
| initialize("This is a module working with the BRepFeat package."); // register with Python | |
| } | |
| }; | |
| class BRepOffsetAPIModule: public Py::ExtensionModule<BRepOffsetAPIModule> | |
| { | |
| public: | |
| BRepOffsetAPIModule() | |
| : Py::ExtensionModule<BRepOffsetAPIModule>("BRepOffsetAPI") | |
| { | |
| initialize("This is a module working with the BRepOffsetAPI package."); // register with Python | |
| } | |
| }; | |
| class Geom2dModule: public Py::ExtensionModule<Geom2dModule> | |
| { | |
| public: | |
| Geom2dModule() | |
| : Py::ExtensionModule<Geom2dModule>("Geom2d") | |
| { | |
| initialize("This is a module working with 2d geometries."); // register with Python | |
| } | |
| }; | |
| class GeomPlateModule: public Py::ExtensionModule<GeomPlateModule> | |
| { | |
| public: | |
| GeomPlateModule() | |
| : Py::ExtensionModule<GeomPlateModule>("GeomPlate") | |
| { | |
| initialize("This is a module working with the GeomPlate framework."); // register with Python | |
| } | |
| }; | |
| class HLRBRepModule: public Py::ExtensionModule<HLRBRepModule> | |
| { | |
| public: | |
| HLRBRepModule() | |
| : Py::ExtensionModule<HLRBRepModule>("HLRBRep") | |
| { | |
| initialize("This is a module working with the HLRBRep framework."); // register with Python | |
| } | |
| }; | |
| class ShapeFixModule: public Py::ExtensionModule<ShapeFixModule> | |
| { | |
| public: | |
| ShapeFixModule() | |
| : Py::ExtensionModule<ShapeFixModule>("ShapeFix") | |
| { | |
| add_varargs_method( | |
| "sameParameter", | |
| &ShapeFixModule::sameParameter, | |
| "sameParameter(shape, enforce, prec=0.0)" | |
| ); | |
| add_varargs_method( | |
| "encodeRegularity", | |
| &ShapeFixModule::encodeRegularity, | |
| "encodeRegularity(shape, tolerance = 1e-10)\n" | |
| ); | |
| add_varargs_method( | |
| "removeSmallEdges", | |
| &ShapeFixModule::removeSmallEdges, | |
| "removeSmallEdges(shape, tolerance, ReShapeContext)\n" | |
| "Removes edges which are less than given tolerance from shape" | |
| ); | |
| add_varargs_method( | |
| "fixVertexPosition", | |
| &ShapeFixModule::fixVertexPosition, | |
| "fixVertexPosition(shape, tolerance, ReShapeContext)\n" | |
| "Fix position of the vertices having tolerance more tnan specified one" | |
| ); | |
| add_varargs_method( | |
| "leastEdgeSize", | |
| &ShapeFixModule::leastEdgeSize, | |
| "leastEdgeSize(shape)\n" | |
| "Calculate size of least edge" | |
| ); | |
| initialize("This is a module working with the ShapeFix framework."); // register with Python | |
| } | |
| private: | |
| Py::Object sameParameter(const Py::Tuple& args) | |
| { | |
| PyObject* shape; | |
| PyObject* enforce; | |
| double prec = 0.0; | |
| if (!PyArg_ParseTuple( | |
| args.ptr(), | |
| "O!O!|d", | |
| &TopoShapePy::Type, | |
| &shape, | |
| &PyBool_Type, | |
| &enforce, | |
| &prec | |
| )) { | |
| throw Py::Exception(); | |
| } | |
| TopoDS_Shape sh = static_cast<TopoShapePy*>(shape)->getTopoShapePtr()->getShape(); | |
| bool ok = ShapeFix::SameParameter(sh, Base::asBoolean(enforce), prec); | |
| return Py::Boolean(ok); | |
| } | |
| Py::Object encodeRegularity(const Py::Tuple& args) | |
| { | |
| PyObject* shape; | |
| double tolang = 1.0e-10; | |
| if (!PyArg_ParseTuple(args.ptr(), "O!|d", &TopoShapePy::Type, &shape, &tolang)) { | |
| throw Py::Exception(); | |
| } | |
| TopoDS_Shape sh = static_cast<TopoShapePy*>(shape)->getTopoShapePtr()->getShape(); | |
| ShapeFix::EncodeRegularity(sh, tolang); | |
| return Py::None(); | |
| } | |
| Py::Object removeSmallEdges(const Py::Tuple& args) | |
| { | |
| PyObject* shape; | |
| double tol; | |
| if (!PyArg_ParseTuple(args.ptr(), "O!d", &TopoShapePy::Type, &shape, &tol)) { | |
| throw Py::Exception(); | |
| } | |
| TopoDS_Shape sh = static_cast<TopoShapePy*>(shape)->getTopoShapePtr()->getShape(); | |
| Handle(ShapeBuild_ReShape) reshape = new ShapeBuild_ReShape(); | |
| TopoShape res = ShapeFix::RemoveSmallEdges(sh, tol, reshape); | |
| return Py::asObject(res.getPyObject()); | |
| } | |
| Py::Object fixVertexPosition(const Py::Tuple& args) | |
| { | |
| PyObject* shape; | |
| double tol; | |
| if (!PyArg_ParseTuple(args.ptr(), "O!d", &TopoShapePy::Type, &shape, &tol)) { | |
| throw Py::Exception(); | |
| } | |
| TopoDS_Shape sh = static_cast<TopoShapePy*>(shape)->getTopoShapePtr()->getShape(); | |
| Handle(ShapeBuild_ReShape) reshape = new ShapeBuild_ReShape(); | |
| bool ok = ShapeFix::FixVertexPosition(sh, tol, reshape); | |
| return Py::Boolean(ok); | |
| } | |
| Py::Object leastEdgeSize(const Py::Tuple& args) | |
| { | |
| PyObject* shape; | |
| if (!PyArg_ParseTuple(args.ptr(), "O!", &TopoShapePy::Type, &shape)) { | |
| throw Py::Exception(); | |
| } | |
| TopoDS_Shape sh = static_cast<TopoShapePy*>(shape)->getTopoShapePtr()->getShape(); | |
| double len = ShapeFix::LeastEdgeSize(sh); | |
| return Py::Float(len); | |
| } | |
| }; | |
| class ShapeUpgradeModule: public Py::ExtensionModule<ShapeUpgradeModule> | |
| { | |
| public: | |
| ShapeUpgradeModule() | |
| : Py::ExtensionModule<ShapeUpgradeModule>("ShapeUpgrade") | |
| { | |
| initialize("This is a module working with the ShapeUpgrade framework."); // register with Python | |
| } | |
| }; | |
| class ChFi2dModule: public Py::ExtensionModule<ChFi2dModule> | |
| { | |
| public: | |
| ChFi2dModule() | |
| : Py::ExtensionModule<ChFi2dModule>("ChFi2d") | |
| { | |
| initialize("This is a module working with the ChFi2d framework."); // register with Python | |
| } | |
| }; | |
| class Module: public Py::ExtensionModule<Module> | |
| { | |
| BRepFeatModule brepFeat; | |
| BRepOffsetAPIModule brepOffsetApi; | |
| Geom2dModule geom2d; | |
| GeomPlateModule geomPlate; | |
| HLRBRepModule HLRBRep; | |
| ShapeFixModule shapeFix; | |
| ShapeUpgradeModule shapeUpgrade; | |
| ChFi2dModule chFi2d; | |
| public: | |
| Module() | |
| : Py::ExtensionModule<Module>("Part") | |
| { | |
| add_varargs_method( | |
| "open", | |
| &Module::open, | |
| "open(string) -- Create a new document and load the file into the document." | |
| ); | |
| add_varargs_method( | |
| "insert", | |
| &Module::insert, | |
| "insert(string,string) -- Insert the file into the given document." | |
| ); | |
| add_varargs_method( | |
| "export", | |
| &Module::exporter, | |
| "export(list,string) -- Export a list of objects into a single file." | |
| ); | |
| add_varargs_method("read", &Module::read, "read(string) -- Load the file and return the shape."); | |
| add_varargs_method( | |
| "show", | |
| &Module::show, | |
| "show(shape,[string]) -- Add the shape to the active document or create one if no " | |
| "document exists.\n" | |
| "Returns document object." | |
| ); | |
| add_varargs_method( | |
| "getFacets", | |
| &Module::getFacets, | |
| "getFacets(shape): simplified mesh generation" | |
| ); | |
| add_keyword_method( | |
| "makeCompound", | |
| &Module::makeCompound, | |
| "makeCompound(list) -- Create a compound out of a list of shapes." | |
| ); | |
| add_keyword_method( | |
| "makeShell", | |
| &Module::makeShell, | |
| "makeShell(list) -- Create a shell out of a list of faces." | |
| ); | |
| 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_keyword_method( | |
| "makeFilledSurface", | |
| &Module::makeFilledSurface, | |
| "makeFilledSurface(list of curves, tolerance) -- Create a surface out of a list of " | |
| "curves." | |
| ); | |
| add_keyword_method( | |
| "makeFilledFace", | |
| &Module::makeFilledFace, | |
| "makeFilledFace(list) -- Create a face out of a list of edges." | |
| ); | |
| 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, | |
| "makePlane(length,width,[pnt,dirZ,dirX]) -- Make a plane\n" | |
| "By default pnt=Vector(0,0,0) and dirZ=Vector(0,0,1), dirX is ignored in this case" | |
| ); | |
| add_varargs_method( | |
| "makeBox", | |
| &Module::makeBox, | |
| "makeBox(length,width,height,[pnt,dir]) -- Make a box located\n" | |
| "in pnt with the dimensions (length,width,height)\n" | |
| "By default pnt=Vector(0,0,0) and dir=Vector(0,0,1)" | |
| ); | |
| add_varargs_method( | |
| "makeWedge", | |
| &Module::makeWedge, | |
| "makeWedge(xmin, ymin, zmin, z2min, x2min,\n" | |
| "xmax, ymax, zmax, z2max, x2max,[pnt,dir])\n" | |
| " -- Make a wedge located in pnt\n" | |
| "By default pnt=Vector(0,0,0) and dir=Vector(0,0,1)" | |
| ); | |
| add_varargs_method( | |
| "makeLine", | |
| &Module::makeLine, | |
| "makeLine(startpnt,endpnt) -- Make a line between two points\n" | |
| "\n" | |
| "Args:\n" | |
| " startpnt (Vector or tuple): Vector or 3 element tuple \n" | |
| " containing the x,y and z coordinates of the start point,\n" | |
| " i.e. (x1,y1,z1).\n" | |
| " endpnt (Vector or tuple): Vector or 3 element tuple \n" | |
| " containing the x,y and z coordinates of the start point,\n" | |
| " i.e. (x1,y1,z1).\n" | |
| "\n" | |
| "Returns:\n" | |
| " Edge: Part.Edge object\n" | |
| ); | |
| add_varargs_method( | |
| "makePolygon", | |
| &Module::makePolygon, | |
| "makePolygon(pntslist) -- Make a polygon from a list of points\n" | |
| "\n" | |
| "Args:\n" | |
| " pntslist (list(Vector)): list of Vectors representing the \n" | |
| " points of the polygon.\n" | |
| "\n" | |
| "Returns:\n" | |
| " Wire: Part.Wire object. If the last point in the list is \n" | |
| " not the same as the first point, the Wire will not be \n" | |
| " closed and cannot be used to create a face.\n" | |
| ); | |
| add_varargs_method( | |
| "makeCircle", | |
| &Module::makeCircle, | |
| "makeCircle(radius,[pnt,dir,angle1,angle2]) -- Make a circle with a given radius\n" | |
| "By default pnt=Vector(0,0,0), dir=Vector(0,0,1), angle1=0 and angle2=360" | |
| ); | |
| add_varargs_method( | |
| "makeSphere", | |
| &Module::makeSphere, | |
| "makeSphere(radius,[pnt, dir, angle1,angle2,angle3]) -- Make a sphere with a given " | |
| "radius\n" | |
| "By default pnt=Vector(0,0,0), dir=Vector(0,0,1), angle1=0, angle2=90 and angle3=360" | |
| ); | |
| add_varargs_method( | |
| "makeCylinder", | |
| &Module::makeCylinder, | |
| "makeCylinder(radius,height,[pnt,dir,angle]) -- Make a cylinder with a given radius " | |
| "and height\n" | |
| "By default pnt=Vector(0,0,0),dir=Vector(0,0,1) and angle=360" | |
| ); | |
| add_varargs_method( | |
| "makeCone", | |
| &Module::makeCone, | |
| "makeCone(radius1,radius2,height,[pnt,dir,angle]) -- Make a cone with given radii and " | |
| "height\n" | |
| "By default pnt=Vector(0,0,0), dir=Vector(0,0,1) and angle=360" | |
| ); | |
| add_varargs_method( | |
| "makeTorus", | |
| &Module::makeTorus, | |
| "makeTorus(radius1,radius2,[pnt,dir,angle1,angle2,angle]) -- Make a torus with a given " | |
| "radii and angles\n" | |
| "By default pnt=Vector(0,0,0),dir=Vector(0,0,1),angle1=0,angle1=360 and angle=360" | |
| ); | |
| add_varargs_method( | |
| "makeHelix", | |
| &Module::makeHelix, | |
| "makeHelix(pitch,height,radius,[angle]) -- Make a helix with a given pitch, height and " | |
| "radius\n" | |
| "By default a cylindrical surface is used to create the helix. If the fourth parameter " | |
| "is set\n" | |
| "(the apex given in degree) a conical surface is used instead" | |
| ); | |
| add_varargs_method( | |
| "makeLongHelix", | |
| &Module::makeLongHelix, | |
| "makeLongHelix(pitch,height,radius,[angle],[hand]) -- Make a (multi-edge) helix with a " | |
| "given pitch, height and radius\n" | |
| "By default a cylindrical surface is used to create the helix. If the fourth parameter " | |
| "is set\n" | |
| "(the apex given in degree) a conical surface is used instead." | |
| ); | |
| add_varargs_method( | |
| "makeThread", | |
| &Module::makeThread, | |
| "makeThread(pitch,depth,height,radius) -- Make a thread with a given pitch, depth, " | |
| "height and radius" | |
| ); | |
| add_varargs_method( | |
| "makeRevolution", | |
| &Module::makeRevolution, | |
| "makeRevolution(Curve or Edge,[vmin,vmax,angle,pnt,dir,shapetype]) -- Make a revolved " | |
| "shape\n" | |
| "by rotating the curve or a portion of it around an axis given by (pnt,dir).\n" | |
| "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_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_keyword_method( | |
| "makeShellFromWires", | |
| &Module::makeShellFromWires, | |
| "makeShellFromWires(Wires) -- Make a shell from wires.\n" | |
| "The wires must have the same number of edges." | |
| ); | |
| 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( | |
| "makeTube", | |
| &Module::makeTube, | |
| "makeTube(edge,radius,[continuity,max degree,max segments]) -- Create a tube.\n" | |
| "continuity is a string which must be 'C0','C1','C2','C3','CN','G1' or 'G1'," | |
| ); | |
| add_varargs_method( | |
| "makeSweepSurface", | |
| &Module::makeSweepSurface, | |
| "makeSweepSurface(edge(path),edge(profile),[float]) -- Create a profile along a path." | |
| ); | |
| add_varargs_method( | |
| "makeWireString", | |
| &Module::makeWireString, | |
| "makeWireString(string,fontdir,fontfile,height,[track]) -- Make list of wires in the " | |
| "form of a string's characters." | |
| ); | |
| add_varargs_method( | |
| "makeSplitShape", | |
| &Module::makeSplitShape, | |
| "makeSplitShape(shape, list of shape pairs,[check Interior=True]) -> two lists of " | |
| "shapes.\n" | |
| "The following shape pairs are supported:\n" | |
| "* Wire, Face\n" | |
| "* Edge, Face\n" | |
| "* Compound, Face\n" | |
| "* Edge, Edge\n" | |
| "* The face must be part of the specified shape and the edge, wire or compound must\n" | |
| "lie on the face.\n" | |
| "Output:\n" | |
| "The first list contains the faces that are the left of the projected wires.\n" | |
| "The second list contains the left part on the shape.\n\n" | |
| "Example:\n" | |
| "face = ...\n" | |
| "edges = ...\n" | |
| "split = [(edges[0],face),(edges[1],face)]\n" | |
| "r = Part.makeSplitShape(face, split)\n" | |
| "Part.show(r[0][0])\n" | |
| "Part.show(r[1][0])\n" | |
| ); | |
| add_varargs_method( | |
| "exportUnits", | |
| &Module::exportUnits, | |
| "exportUnits([string=MM|M|INCH|FT|MI|KM|MIL|UM|CM|UIN]) -- Set units for exporting " | |
| "STEP/IGES files and returns the units." | |
| ); | |
| add_varargs_method( | |
| "setStaticValue", | |
| &Module::setStaticValue, | |
| "setStaticValue(string,string|int|float) -- Set a name to a value The value can be a " | |
| "string, int or float." | |
| ); | |
| add_varargs_method( | |
| "cast_to_shape", | |
| &Module::cast_to_shape, | |
| "cast_to_shape(shape) -- Cast to the actual shape type" | |
| ); | |
| add_varargs_method( | |
| "getSortedClusters", | |
| &Module::getSortedClusters, | |
| "getSortedClusters(list of edges) -- Helper method to sort and cluster a variety of " | |
| "edges" | |
| ); | |
| add_varargs_method( | |
| "__sortEdges__", | |
| &Module::sortEdges, | |
| "__sortEdges__(list of edges) -- list of edges\n" | |
| "Helper method to sort an unsorted list of edges so that afterwards\n" | |
| "the start and end vertex of two consecutive edges are geometrically coincident.\n" | |
| "It returns a single list of edges and the algorithm stops after the first set of\n" | |
| "connected edges which means that the output list can be smaller than the input list.\n" | |
| "The sorted list can be used to create a Wire." | |
| ); | |
| add_varargs_method( | |
| "sortEdges", | |
| &Module::sortEdges2, | |
| "sortEdges(list of edges, [tol3d]) -- list of lists of edges\n" | |
| "It does basically the same as __sortEdges__ but sorts all input edges and thus " | |
| "returns\n" | |
| "a list of lists of edges\n" | |
| "optional 3D tolerance defaults to Precision::Confusion" | |
| ); | |
| add_varargs_method( | |
| "__toPythonOCC__", | |
| &Module::toPythonOCC, | |
| "__toPythonOCC__(shape) -- Helper method to convert an internal shape to pythonocc " | |
| "shape" | |
| ); | |
| add_varargs_method( | |
| "__fromPythonOCC__", | |
| &Module::fromPythonOCC, | |
| "__fromPythonOCC__(occ) -- Helper method to convert a pythonocc shape to an internal " | |
| "shape" | |
| ); | |
| add_varargs_method( | |
| "clearShapeCache", | |
| &Module::clearShapeCache, | |
| "clearShapeCache() -- Clears internal shape cache" | |
| ); | |
| add_keyword_method( | |
| "getShape", | |
| &Module::getShape, | |
| "getShape(obj,subname=None,mat=None,needSubElement=False,transform=True,retType=0):\n" | |
| "Obtain the TopoShape of a given object with SubName reference\n\n" | |
| "* obj: the input object\n" | |
| "* subname: dot separated sub-object reference\n" | |
| "* mat: the current transformation matrix\n" | |
| "* needSubElement: if False, ignore the sub-element (e.g. Face1, Edge1) reference in " | |
| "'subname'\n" | |
| "* transform: if False, then skip obj's transformation. Use this if mat already " | |
| "include obj's\n" | |
| " transformation matrix\n" | |
| "* retType: 0: return TopoShape,\n" | |
| " 1: return (shape,mat,subObj), where subObj is the object referenced in " | |
| "'subname',\n" | |
| " and 'mat' is the accumulated transformation matrix of that sub-object.\n" | |
| " 2: same as 1, but make sure 'subObj' is resolved if it is a link.\n" | |
| "* refine: refine the returned shape" | |
| ); | |
| add_varargs_method( | |
| "splitSubname", | |
| &Module::splitSubname, | |
| "splitSubname(subname) -> list(sub,mapped,subElement)\n" | |
| "Split the given subname into a list\n\n" | |
| "sub: subname without any sub-element reference\n" | |
| "mapped: mapped element name, or '' if none\n" | |
| "subElement: old style element name, or '' if none" | |
| ); | |
| add_varargs_method( | |
| "joinSubname", | |
| &Module::joinSubname, | |
| "joinSubname(sub,mapped,subElement) -> subname\n" | |
| ); | |
| initialize("This is a module working with shapes."); // register with Python | |
| PyModule_AddObject(m_module, "BRepFeat", brepFeat.module().ptr()); | |
| PyModule_AddObject(m_module, "BRepOffsetAPI", brepOffsetApi.module().ptr()); | |
| PyModule_AddObject(m_module, "Geom2d", geom2d.module().ptr()); | |
| PyModule_AddObject(m_module, "GeomPlate", geomPlate.module().ptr()); | |
| PyModule_AddObject(m_module, "HLRBRep", HLRBRep.module().ptr()); | |
| PyModule_AddObject(m_module, "ShapeFix", shapeFix.module().ptr()); | |
| PyModule_AddObject(m_module, "ShapeUpgrade", shapeUpgrade.module().ptr()); | |
| PyModule_AddObject(m_module, "ChFi2d", chFi2d.module().ptr()); | |
| } | |
| private: | |
| Py::Object invoke_method_keyword(void* method_def, const Py::Tuple& args, const Py::Dict& keywords) override | |
| { | |
| try { | |
| return Py::ExtensionModule<Module>::invoke_method_keyword(method_def, args, keywords); | |
| } | |
| catch (const Standard_Failure& e) { | |
| std::string str; | |
| Standard_CString msg = e.GetMessageString(); | |
| str += typeid(e).name(); | |
| str += " "; | |
| if (msg) { | |
| str += msg; | |
| } | |
| else { | |
| str += "No OCCT Exception Message"; | |
| } | |
| Base::Console().error("%s\n", str.c_str()); | |
| throw Py::Exception(Part::PartExceptionOCCError, str); | |
| } | |
| catch (const Base::Exception& e) { | |
| std::string str; | |
| str += "FreeCAD exception thrown ("; | |
| str += e.what(); | |
| str += ")"; | |
| e.reportException(); | |
| throw Py::RuntimeError(str); | |
| } | |
| catch (const std::exception& e) { | |
| std::string str; | |
| str += "C++ exception thrown ("; | |
| str += e.what(); | |
| str += ")"; | |
| Base::Console().error("%s\n", str.c_str()); | |
| throw Py::RuntimeError(str); | |
| } | |
| } | |
| Py::Object invoke_method_varargs(void* method_def, const Py::Tuple& args) override | |
| { | |
| try { | |
| return Py::ExtensionModule<Module>::invoke_method_varargs(method_def, args); | |
| } | |
| catch (const Standard_Failure& e) { | |
| std::string str; | |
| Standard_CString msg = e.GetMessageString(); | |
| str += typeid(e).name(); | |
| str += " "; | |
| if (msg) { | |
| str += msg; | |
| } | |
| else { | |
| str += "No OCCT Exception Message"; | |
| } | |
| Base::Console().error("%s\n", str.c_str()); | |
| throw Py::Exception(Part::PartExceptionOCCError, str); | |
| } | |
| catch (const Base::Exception& e) { | |
| std::string str; | |
| str += "FreeCAD exception thrown ("; | |
| str += e.what(); | |
| str += ")"; | |
| e.reportException(); | |
| throw Py::RuntimeError(str); | |
| } | |
| catch (const std::exception& e) { | |
| std::string str; | |
| str += "C++ exception thrown ("; | |
| str += e.what(); | |
| str += ")"; | |
| Base::Console().error("%s\n", str.c_str()); | |
| throw Py::RuntimeError(str); | |
| } | |
| } | |
| Py::Object open(const Py::Tuple& args) | |
| { | |
| char* Name; | |
| if (!PyArg_ParseTuple(args.ptr(), "et", "utf-8", &Name)) { | |
| throw Py::Exception(); | |
| } | |
| std::string EncodedName = std::string(Name); | |
| PyMem_Free(Name); | |
| Base::FileInfo file(EncodedName.c_str()); | |
| // extract ending | |
| if (file.extension().empty()) { | |
| throw Py::RuntimeError("No file extension"); | |
| } | |
| if (file.hasExtension({"stp", "step"})) { | |
| // create new document and add Import feature | |
| App::Document* pcDoc = App::GetApplication().newDocument(); | |
| ImportStepParts(pcDoc, EncodedName.c_str()); | |
| pcDoc->recompute(); | |
| } | |
| else if (file.hasExtension({"igs", "iges"})) { | |
| App::Document* pcDoc = App::GetApplication().newDocument(); | |
| ImportIgesParts(pcDoc, EncodedName.c_str()); | |
| pcDoc->recompute(); | |
| } | |
| else { | |
| TopoShape shape; | |
| shape.read(EncodedName.c_str()); | |
| // create new document set loaded shape | |
| App::Document* pcDoc = App::GetApplication().newDocument(file.fileNamePure().c_str()); | |
| Part::Feature* object = static_cast<Part::Feature*>( | |
| pcDoc->addObject("Part::Feature", file.fileNamePure().c_str()) | |
| ); | |
| object->Shape.setValue(shape); | |
| pcDoc->recompute(); | |
| } | |
| return Py::None(); | |
| } | |
| Py::Object insert(const Py::Tuple& args) | |
| { | |
| char* Name; | |
| const char* DocName; | |
| if (!PyArg_ParseTuple(args.ptr(), "ets", "utf-8", &Name, &DocName)) { | |
| throw Py::Exception(); | |
| } | |
| std::string EncodedName = std::string(Name); | |
| PyMem_Free(Name); | |
| // Base::Console().log("Insert in Part with %s",Name); | |
| Base::FileInfo file(EncodedName.c_str()); | |
| // extract ending | |
| if (file.extension().empty()) { | |
| throw Py::RuntimeError("No file extension"); | |
| } | |
| App::Document* pcDoc = App::GetApplication().getDocument(DocName); | |
| if (!pcDoc) { | |
| pcDoc = App::GetApplication().newDocument(DocName); | |
| } | |
| if (file.hasExtension({"stp", "step"})) { | |
| ImportStepParts(pcDoc, EncodedName.c_str()); | |
| pcDoc->recompute(); | |
| } | |
| else if (file.hasExtension({"igs", "iges"})) { | |
| ImportIgesParts(pcDoc, EncodedName.c_str()); | |
| pcDoc->recompute(); | |
| } | |
| else { | |
| FC_WARN("Importing BREP via 'Part' is deprecated. Use 'ImportGui' instead."); | |
| TopoShape shape; | |
| shape.read(EncodedName.c_str()); | |
| Part::Feature* object = static_cast<Part::Feature*>( | |
| pcDoc->addObject("Part::Feature", file.fileNamePure().c_str()) | |
| ); | |
| object->Shape.setValue(shape); | |
| pcDoc->recompute(); | |
| } | |
| return Py::None(); | |
| } | |
| Py::Object exporter(const Py::Tuple& args) | |
| { | |
| PyObject* object; | |
| char* Name; | |
| if (!PyArg_ParseTuple(args.ptr(), "Oet", &object, "utf-8", &Name)) { | |
| throw Py::Exception(); | |
| } | |
| std::string EncodedName = std::string(Name); | |
| PyMem_Free(Name); | |
| BRep_Builder builder; | |
| TopoDS_Compound comp; | |
| builder.MakeCompound(comp); | |
| Py::Sequence list(object); | |
| for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { | |
| PyObject* item = (*it).ptr(); | |
| if (PyObject_TypeCheck(item, &(App::DocumentObjectPy::Type))) { | |
| App::DocumentObject* obj | |
| = static_cast<App::DocumentObjectPy*>(item)->getDocumentObjectPtr(); | |
| if (obj->isDerivedFrom<Part::Feature>()) { | |
| Part::Feature* part = static_cast<Part::Feature*>(obj); | |
| const TopoDS_Shape& shape = part->Shape.getValue(); | |
| if (!shape.IsNull()) { | |
| builder.Add(comp, shape); | |
| } | |
| } | |
| else { | |
| Base::Console().message( | |
| "'%s' is not a shape, export will be ignored.\n", | |
| obj->Label.getValue() | |
| ); | |
| } | |
| } | |
| } | |
| TopoShape shape(comp); | |
| shape.write(EncodedName.c_str()); | |
| return Py::None(); | |
| } | |
| Py::Object read(const Py::Tuple& args) | |
| { | |
| char* Name; | |
| if (!PyArg_ParseTuple(args.ptr(), "et", "utf-8", &Name)) { | |
| throw Py::Exception(); | |
| } | |
| std::string EncodedName = std::string(Name); | |
| PyMem_Free(Name); | |
| TopoShape* shape = new TopoShape(); | |
| shape->read(EncodedName.c_str()); | |
| return Py::asObject(new TopoShapePy(shape)); | |
| } | |
| Py::Object show(const Py::Tuple& args) | |
| { | |
| PyObject* pcObj = nullptr; | |
| const char* name = "Shape"; | |
| if (!PyArg_ParseTuple(args.ptr(), "O!|s", &(TopoShapePy::Type), &pcObj, &name)) { | |
| throw Py::Exception(); | |
| } | |
| App::Document* pcDoc = App::GetApplication().getActiveDocument(); | |
| if (!pcDoc) { | |
| pcDoc = App::GetApplication().newDocument(); | |
| } | |
| TopoShape shape; | |
| if (PyObject_TypeCheck(pcObj, &TopoShapePy::Type)) { | |
| shape = *static_cast<TopoShapePy*>(pcObj)->getTopoShapePtr(); | |
| } | |
| else if (PyObject_TypeCheck(pcObj, &GeometryPy::Type)) { | |
| shape = static_cast<GeometryPy*>(pcObj)->getGeometryPtr()->toShape(); | |
| } | |
| else if (PyObject_TypeCheck(pcObj, &App::DocumentObjectPy::Type)) { | |
| auto obj = static_cast<App::DocumentObjectPy*>(pcObj)->getDocumentObjectPtr(); | |
| shape = Feature::getTopoShape(obj, ShapeOption::ResolveLink | ShapeOption::Transform); | |
| } | |
| else { | |
| throw Py::TypeError("Expects argument of type DocumentObject, Shape, or Geometry"); | |
| } | |
| Part::Feature* pcFeature = pcDoc->addObject<Part::Feature>(name); | |
| // copy the data | |
| pcFeature->Shape.setValue(shape); | |
| pcFeature->purgeTouched(); | |
| return Py::asObject(pcFeature->getPyObject()); | |
| } | |
| Py::Object getFacets(const Py::Tuple& args) | |
| { | |
| PyObject* shape; | |
| Py::List list; | |
| if (!PyArg_ParseTuple(args.ptr(), "O", &shape)) { | |
| throw Py::Exception(); | |
| } | |
| auto theShape = static_cast<Part::TopoShapePy*>(shape)->getTopoShapePtr()->getShape(); | |
| for (TopExp_Explorer ex(theShape, TopAbs_FACE); ex.More(); ex.Next()) { | |
| TopoDS_Face currentFace = TopoDS::Face(ex.Current()); | |
| std::vector<gp_Pnt> points; | |
| std::vector<Poly_Triangle> facets; | |
| if (Tools::getTriangulation(currentFace, points, facets)) { | |
| for (const auto& it : facets) { | |
| Standard_Integer n1, n2, n3; | |
| it.Get(n1, n2, n3); | |
| gp_Pnt p1 = points[n1]; | |
| gp_Pnt p2 = points[n2]; | |
| gp_Pnt p3 = points[n3]; | |
| // TODO: verify if tolerance should be hard coded | |
| if (!p1.IsEqual(p2, 0.01) && !p2.IsEqual(p3, 0.01) && !p3.IsEqual(p1, 0.01)) { | |
| PyObject* t1 = PyTuple_Pack( | |
| 3, | |
| PyFloat_FromDouble(p1.X()), | |
| PyFloat_FromDouble(p1.Y()), | |
| PyFloat_FromDouble(p1.Z()) | |
| ); | |
| PyObject* t2 = PyTuple_Pack( | |
| 3, | |
| PyFloat_FromDouble(p2.X()), | |
| PyFloat_FromDouble(p2.Y()), | |
| PyFloat_FromDouble(p2.Z()) | |
| ); | |
| PyObject* t3 = PyTuple_Pack( | |
| 3, | |
| PyFloat_FromDouble(p3.X()), | |
| PyFloat_FromDouble(p3.Y()), | |
| PyFloat_FromDouble(p3.Z()) | |
| ); | |
| list.append(Py::asObject(PyTuple_Pack(3, t1, t2, t3))); | |
| } | |
| } | |
| } | |
| } | |
| return list; | |
| } | |
| Py::Object makeCompound(const Py::Tuple& args, const Py::Dict& kwds) | |
| { | |
| PyObject* pcObj; | |
| PyObject* force = Py_True; | |
| TopoShape::SingleShapeCompoundCreationPolicy | |
| policy; // = TopoShape::SingleShapeCompoundCreationPolicy::forceCompound; | |
| PyObject* module = PyImport_ImportModule("PartEnums"); | |
| PyObject* policyEnum | |
| = PyObject_GetAttrString(module, (char*)"SingleShapeCompoundCreationPolicy"); | |
| const char* op = nullptr; | |
| const std::array<const char*, 4> kwd_list = {"shapes", "force", "op", nullptr}; | |
| if (!Base::Wrapped_ParseTupleAndKeywords( | |
| args.ptr(), | |
| kwds.ptr(), | |
| "O|O!s", | |
| kwd_list, | |
| &pcObj, | |
| policyEnum, | |
| &force, | |
| &op | |
| )) { | |
| throw Py::Exception(); | |
| } | |
| policy = static_cast<TopoShape::SingleShapeCompoundCreationPolicy>(PyLong_AsLong(force)); | |
| Py_DECREF(policyEnum); | |
| return shape2pyshape(Part::TopoShape().makeElementCompound(getPyShapes(pcObj), op, policy)); | |
| } | |
| Py::Object makeShell(const Py::Tuple& args, const Py::Dict& kwds) | |
| { | |
| PyObject* obj; | |
| const char* op = nullptr; | |
| const std::array<const char*, 3> 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) | |
| ); | |
| } | |
| Py::Object makeFace(const Py::Tuple& args, const Py::Dict& kwds) | |
| { | |
| PyObject* obj; | |
| const char* className = nullptr; | |
| const char* op = nullptr; | |
| const std::array<const char*, 4> 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)); | |
| } | |
| template<class F> | |
| 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<TopoShapePy*>((*iter).ptr())->getTopoShapePtr()->getShape(); | |
| f(sh, (*iter).ptr(), err); | |
| } | |
| } | |
| } | |
| Py::Object makeFilledSurface(const Py::Tuple& args, const Py::Dict& kwds) | |
| { | |
| 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<const char*, 16> 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<TopoShapePy*>(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<TopoShapePy*>(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::Long(value); | |
| params.orders[s] = static_cast<TopoShape::Continuity>(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) | |
| ); | |
| } | |
| Py::Object makeFilledFace(const Py::Tuple& args, const Py::Dict& kwds) | |
| { | |
| 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<const char*, 16> 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<TopoShapePy*>(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<TopoShapePy*>(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::Long(value); | |
| params.orders[s] = static_cast<TopoShape::Continuity>(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) | |
| ); | |
| } | |
| Py::Object makeSolid(const Py::Tuple& args, const Py::Dict& kwds) | |
| { | |
| PyObject* obj; | |
| const char* op = nullptr; | |
| const std::array<const char*, 3> 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<TopoShapePy*>(obj)->getTopoShapePtr(), op) | |
| ); | |
| } | |
| Py::Object makePlane(const Py::Tuple& args) | |
| { | |
| double length, width; | |
| PyObject *pPnt = nullptr, *pDirZ = nullptr, *pDirX = nullptr; | |
| if (!PyArg_ParseTuple( | |
| args.ptr(), | |
| "dd|O!O!O!", | |
| &length, | |
| &width, | |
| &(Base::VectorPy::Type), | |
| &pPnt, | |
| &(Base::VectorPy::Type), | |
| &pDirZ, | |
| &(Base::VectorPy::Type), | |
| &pDirX | |
| )) { | |
| throw Py::Exception(); | |
| } | |
| if (length < Precision::Confusion()) { | |
| throw Py::ValueError("length of plane too small"); | |
| } | |
| if (width < Precision::Confusion()) { | |
| throw Py::ValueError("width of plane too small"); | |
| } | |
| try { | |
| gp_Pnt p(0, 0, 0); | |
| gp_Dir d(0, 0, 1); | |
| if (pPnt) { | |
| Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value(); | |
| p.SetCoord(pnt.x, pnt.y, pnt.z); | |
| } | |
| if (pDirZ) { | |
| Base::Vector3d vec = static_cast<Base::VectorPy*>(pDirZ)->value(); | |
| d.SetCoord(vec.x, vec.y, vec.z); | |
| } | |
| Handle(Geom_Plane) aPlane; | |
| if (pDirX) { | |
| Base::Vector3d vec = static_cast<Base::VectorPy*>(pDirX)->value(); | |
| gp_Dir dx; | |
| dx.SetCoord(vec.x, vec.y, vec.z); | |
| aPlane = new Geom_Plane(gp_Ax3(p, d, dx)); | |
| } | |
| else { | |
| aPlane = new Geom_Plane(p, d); | |
| } | |
| BRepBuilderAPI_MakeFace Face(aPlane, 0.0, length, 0.0, width, Precision::Confusion()); | |
| return Py::asObject(new TopoShapeFacePy(new TopoShape((Face.Face())))); | |
| } | |
| catch (Standard_DomainError&) { | |
| throw Py::Exception(PartExceptionOCCDomainError, "creation of plane failed"); | |
| } | |
| catch (Standard_Failure&) { | |
| throw Py::Exception(PartExceptionOCCError, "creation of plane failed"); | |
| } | |
| } | |
| Py::Object makeBox(const Py::Tuple& args) | |
| { | |
| double length, width, height; | |
| PyObject *pPnt = nullptr, *pDir = nullptr; | |
| if (!PyArg_ParseTuple( | |
| args.ptr(), | |
| "ddd|O!O!", | |
| &length, | |
| &width, | |
| &height, | |
| &(Base::VectorPy::Type), | |
| &pPnt, | |
| &(Base::VectorPy::Type), | |
| &pDir | |
| )) { | |
| throw Py::Exception(); | |
| } | |
| if (length < Precision::Confusion()) { | |
| throw Py::ValueError("length of box too small"); | |
| } | |
| if (width < Precision::Confusion()) { | |
| throw Py::ValueError("width of box too small"); | |
| } | |
| if (height < Precision::Confusion()) { | |
| throw Py::ValueError("height of box too small"); | |
| } | |
| try { | |
| gp_Pnt p(0, 0, 0); | |
| gp_Dir d(0, 0, 1); | |
| if (pPnt) { | |
| Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value(); | |
| p.SetCoord(pnt.x, pnt.y, pnt.z); | |
| } | |
| if (pDir) { | |
| Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value(); | |
| d.SetCoord(vec.x, vec.y, vec.z); | |
| } | |
| BRepPrimAPI_MakeBox mkBox(gp_Ax2(p, d), length, width, height); | |
| TopoDS_Shape ResultShape = mkBox.Shape(); | |
| return Py::asObject(new TopoShapeSolidPy(new TopoShape(ResultShape))); | |
| } | |
| catch (Standard_DomainError&) { | |
| throw Py::Exception(PartExceptionOCCDomainError, "creation of box failed"); | |
| } | |
| } | |
| Py::Object makeWedge(const Py::Tuple& args) | |
| { | |
| double xmin, ymin, zmin, z2min, x2min, xmax, ymax, zmax, z2max, x2max; | |
| PyObject *pPnt = nullptr, *pDir = nullptr; | |
| if (!PyArg_ParseTuple( | |
| args.ptr(), | |
| "dddddddddd|O!O!", | |
| &xmin, | |
| &ymin, | |
| &zmin, | |
| &z2min, | |
| &x2min, | |
| &xmax, | |
| &ymax, | |
| &zmax, | |
| &z2max, | |
| &x2max, | |
| &(Base::VectorPy::Type), | |
| &pPnt, | |
| &(Base::VectorPy::Type), | |
| &pDir | |
| )) { | |
| throw Py::Exception(); | |
| } | |
| double dx = xmax - xmin; | |
| double dy = ymax - ymin; | |
| double dz = zmax - zmin; | |
| double dz2 = z2max - z2min; | |
| double dx2 = x2max - x2min; | |
| if (dx < Precision::Confusion()) { | |
| throw Py::ValueError("delta x of wedge too small"); | |
| } | |
| if (dy < Precision::Confusion()) { | |
| throw Py::ValueError("delta y of wedge too small"); | |
| } | |
| if (dz < Precision::Confusion()) { | |
| throw Py::ValueError("delta z of wedge too small"); | |
| } | |
| if (dz2 < 0) { | |
| throw Py::ValueError("delta z2 of wedge is negative"); | |
| } | |
| if (dx2 < 0) { | |
| throw Py::ValueError("delta x2 of wedge is negative"); | |
| } | |
| try { | |
| gp_Pnt p(0, 0, 0); | |
| gp_Dir d(0, 0, 1); | |
| if (pPnt) { | |
| Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value(); | |
| p.SetCoord(pnt.x, pnt.y, pnt.z); | |
| } | |
| if (pDir) { | |
| Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value(); | |
| d.SetCoord(vec.x, vec.y, vec.z); | |
| } | |
| BRepPrim_Wedge | |
| mkWedge(gp_Ax2(p, d), xmin, ymin, zmin, z2min, x2min, xmax, ymax, zmax, z2max, x2max); | |
| BRepBuilderAPI_MakeSolid mkSolid; | |
| mkSolid.Add(mkWedge.Shell()); | |
| return Py::asObject(new TopoShapeSolidPy(new TopoShape(mkSolid.Solid()))); | |
| } | |
| catch (Standard_DomainError&) { | |
| throw Py::Exception(PartExceptionOCCDomainError, "creation of wedge failed"); | |
| } | |
| } | |
| Py::Object makeLine(const Py::Tuple& args) | |
| { | |
| PyObject *obj1, *obj2; | |
| if (!PyArg_ParseTuple(args.ptr(), "OO", &obj1, &obj2)) { | |
| throw Py::Exception(); | |
| } | |
| Base::Vector3d pnt1, pnt2; | |
| if (PyObject_TypeCheck(obj1, &(Base::VectorPy::Type))) { | |
| pnt1 = static_cast<Base::VectorPy*>(obj1)->value(); | |
| } | |
| else if (PyObject_TypeCheck(obj1, &PyTuple_Type)) { | |
| pnt1 = Base::getVectorFromTuple<double>(obj1); | |
| } | |
| else { | |
| throw Py::TypeError("first argument must either be vector or tuple"); | |
| } | |
| if (PyObject_TypeCheck(obj2, &(Base::VectorPy::Type))) { | |
| pnt2 = static_cast<Base::VectorPy*>(obj2)->value(); | |
| } | |
| else if (PyObject_TypeCheck(obj2, &PyTuple_Type)) { | |
| pnt2 = Base::getVectorFromTuple<double>(obj2); | |
| } | |
| else { | |
| throw Py::TypeError("second argument must either be vector or tuple"); | |
| } | |
| // Create directly the underlying line geometry | |
| BRepBuilderAPI_MakeEdge makeEdge(gp_Pnt(pnt1.x, pnt1.y, pnt1.z), gp_Pnt(pnt2.x, pnt2.y, pnt2.z)); | |
| const char* error = nullptr; | |
| switch (makeEdge.Error()) { | |
| case BRepBuilderAPI_EdgeDone: | |
| break; // ok | |
| case BRepBuilderAPI_PointProjectionFailed: | |
| error = "Point projection failed"; | |
| break; | |
| case BRepBuilderAPI_ParameterOutOfRange: | |
| error = "Parameter out of range"; | |
| break; | |
| case BRepBuilderAPI_DifferentPointsOnClosedCurve: | |
| error = "Different points on closed curve"; | |
| break; | |
| case BRepBuilderAPI_PointWithInfiniteParameter: | |
| error = "Point with infinite parameter"; | |
| break; | |
| case BRepBuilderAPI_DifferentsPointAndParameter: | |
| error = "Different point and parameter"; | |
| break; | |
| case BRepBuilderAPI_LineThroughIdenticPoints: | |
| error = "Line through identical points"; | |
| break; | |
| } | |
| // Error | |
| if (error) { | |
| throw Py::Exception(PartExceptionOCCError, error); | |
| } | |
| TopoDS_Edge edge = makeEdge.Edge(); | |
| return Py::asObject(new TopoShapeEdgePy(new TopoShape(edge))); | |
| } | |
| Py::Object makePolygon(const Py::Tuple& args) | |
| { | |
| PyObject* pcObj; | |
| PyObject* pclosed = Py_False; | |
| if (!PyArg_ParseTuple(args.ptr(), "O|O!", &pcObj, &(PyBool_Type), &pclosed)) { | |
| throw Py::Exception(); | |
| } | |
| BRepBuilderAPI_MakePolygon mkPoly; | |
| try { | |
| Py::Sequence list(pcObj); | |
| for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { | |
| if (PyObject_TypeCheck((*it).ptr(), &(Base::VectorPy::Type))) { | |
| Base::Vector3d v = static_cast<Base::VectorPy*>((*it).ptr())->value(); | |
| mkPoly.Add(gp_Pnt(v.x, v.y, v.z)); | |
| } | |
| else if (PyObject_TypeCheck((*it).ptr(), &PyTuple_Type)) { | |
| Base::Vector3d v = Base::getVectorFromTuple<double>((*it).ptr()); | |
| mkPoly.Add(gp_Pnt(v.x, v.y, v.z)); | |
| } | |
| } | |
| if (!mkPoly.IsDone()) { | |
| Standard_Failure::Raise( | |
| "Cannot create polygon because less than two vertices are given" | |
| ); | |
| } | |
| // if the polygon should be closed | |
| if (Base::asBoolean(pclosed)) { | |
| if (!mkPoly.FirstVertex().IsSame(mkPoly.LastVertex())) { | |
| mkPoly.Add(mkPoly.FirstVertex()); | |
| } | |
| } | |
| return Py::asObject(new TopoShapeWirePy(new TopoShape(mkPoly.Wire()))); | |
| } | |
| catch (Standard_Failure& e) { | |
| throw Py::Exception(PartExceptionOCCError, e.GetMessageString()); | |
| } | |
| } | |
| Py::Object makeCircle(const Py::Tuple& args) | |
| { | |
| double radius, angle1 = 0.0, angle2 = 360; | |
| PyObject *pPnt = nullptr, *pDir = nullptr; | |
| if (!PyArg_ParseTuple( | |
| args.ptr(), | |
| "d|O!O!dd", | |
| &radius, | |
| &(Base::VectorPy::Type), | |
| &pPnt, | |
| &(Base::VectorPy::Type), | |
| &pDir, | |
| &angle1, | |
| &angle2 | |
| )) { | |
| throw Py::Exception(); | |
| } | |
| try { | |
| gp_Pnt loc(0, 0, 0); | |
| gp_Dir dir(0, 0, 1); | |
| if (pPnt) { | |
| Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value(); | |
| loc.SetCoord(pnt.x, pnt.y, pnt.z); | |
| } | |
| if (pDir) { | |
| Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value(); | |
| dir.SetCoord(vec.x, vec.y, vec.z); | |
| } | |
| gp_Ax1 axis(loc, dir); | |
| gp_Circ circle; | |
| circle.SetAxis(axis); | |
| circle.SetRadius(radius); | |
| Handle(Geom_Circle) hCircle = new Geom_Circle(circle); | |
| BRepBuilderAPI_MakeEdge aMakeEdge( | |
| hCircle, | |
| Base::toRadians<double>(angle1), | |
| Base::toRadians<double>(angle2) | |
| ); | |
| TopoDS_Edge edge = aMakeEdge.Edge(); | |
| return Py::asObject(new TopoShapeEdgePy(new TopoShape(edge))); | |
| } | |
| catch (Standard_Failure&) { | |
| throw Py::Exception(PartExceptionOCCError, "creation of circle failed"); | |
| } | |
| } | |
| Py::Object makeSphere(const Py::Tuple& args) | |
| { | |
| double radius, angle1 = -90, angle2 = 90, angle3 = 360; | |
| PyObject *pPnt = nullptr, *pDir = nullptr; | |
| if (!PyArg_ParseTuple( | |
| args.ptr(), | |
| "d|O!O!ddd", | |
| &radius, | |
| &(Base::VectorPy::Type), | |
| &pPnt, | |
| &(Base::VectorPy::Type), | |
| &pDir, | |
| &angle1, | |
| &angle2, | |
| &angle3 | |
| )) { | |
| throw Py::Exception(); | |
| } | |
| try { | |
| gp_Pnt p(0, 0, 0); | |
| gp_Dir d(0, 0, 1); | |
| if (pPnt) { | |
| Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value(); | |
| p.SetCoord(pnt.x, pnt.y, pnt.z); | |
| } | |
| if (pDir) { | |
| Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value(); | |
| d.SetCoord(vec.x, vec.y, vec.z); | |
| } | |
| BRepPrimAPI_MakeSphere mkSphere( | |
| gp_Ax2(p, d), | |
| radius, | |
| Base::toRadians<double>(angle1), | |
| Base::toRadians<double>(angle2), | |
| Base::toRadians<double>(angle3) | |
| ); | |
| TopoDS_Shape shape = mkSphere.Shape(); | |
| return Py::asObject(new TopoShapeSolidPy(new TopoShape(shape))); | |
| } | |
| catch (Standard_DomainError&) { | |
| throw Py::Exception(PartExceptionOCCDomainError, "creation of sphere failed"); | |
| } | |
| } | |
| Py::Object makeCylinder(const Py::Tuple& args) | |
| { | |
| double radius, height, angle = 360; | |
| PyObject *pPnt = nullptr, *pDir = nullptr; | |
| if (!PyArg_ParseTuple( | |
| args.ptr(), | |
| "dd|O!O!d", | |
| &radius, | |
| &height, | |
| &(Base::VectorPy::Type), | |
| &pPnt, | |
| &(Base::VectorPy::Type), | |
| &pDir, | |
| &angle | |
| )) { | |
| throw Py::Exception(); | |
| } | |
| try { | |
| gp_Pnt p(0, 0, 0); | |
| gp_Dir d(0, 0, 1); | |
| if (pPnt) { | |
| Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value(); | |
| p.SetCoord(pnt.x, pnt.y, pnt.z); | |
| } | |
| if (pDir) { | |
| Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value(); | |
| d.SetCoord(vec.x, vec.y, vec.z); | |
| } | |
| BRepPrimAPI_MakeCylinder mkCyl(gp_Ax2(p, d), radius, height, Base::toRadians<double>(angle)); | |
| TopoDS_Shape shape = mkCyl.Shape(); | |
| return Py::asObject(new TopoShapeSolidPy(new TopoShape(shape))); | |
| } | |
| catch (Standard_DomainError&) { | |
| throw Py::Exception(PartExceptionOCCDomainError, "creation of cylinder failed"); | |
| } | |
| } | |
| Py::Object makeCone(const Py::Tuple& args) | |
| { | |
| double radius1, radius2, height, angle = 360; | |
| PyObject *pPnt = nullptr, *pDir = nullptr; | |
| if (!PyArg_ParseTuple( | |
| args.ptr(), | |
| "ddd|O!O!d", | |
| &radius1, | |
| &radius2, | |
| &height, | |
| &(Base::VectorPy::Type), | |
| &pPnt, | |
| &(Base::VectorPy::Type), | |
| &pDir, | |
| &angle | |
| )) { | |
| throw Py::Exception(); | |
| } | |
| try { | |
| gp_Pnt p(0, 0, 0); | |
| gp_Dir d(0, 0, 1); | |
| if (pPnt) { | |
| Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value(); | |
| p.SetCoord(pnt.x, pnt.y, pnt.z); | |
| } | |
| if (pDir) { | |
| Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value(); | |
| d.SetCoord(vec.x, vec.y, vec.z); | |
| } | |
| BRepPrimAPI_MakeCone | |
| mkCone(gp_Ax2(p, d), radius1, radius2, height, Base::toRadians<double>(angle)); | |
| TopoDS_Shape shape = mkCone.Shape(); | |
| return Py::asObject(new TopoShapeSolidPy(new TopoShape(shape))); | |
| } | |
| catch (Standard_DomainError&) { | |
| throw Py::Exception(PartExceptionOCCDomainError, "creation of cone failed"); | |
| } | |
| } | |
| Py::Object makeTorus(const Py::Tuple& args) | |
| { | |
| double radius1, radius2, angle1 = 0.0, angle2 = 360, angle = 360; | |
| PyObject *pPnt = nullptr, *pDir = nullptr; | |
| if (!PyArg_ParseTuple( | |
| args.ptr(), | |
| "dd|O!O!ddd", | |
| &radius1, | |
| &radius2, | |
| &(Base::VectorPy::Type), | |
| &pPnt, | |
| &(Base::VectorPy::Type), | |
| &pDir, | |
| &angle1, | |
| &angle2, | |
| &angle | |
| )) { | |
| throw Py::Exception(); | |
| } | |
| try { | |
| gp_Pnt p(0, 0, 0); | |
| gp_Dir d(0, 0, 1); | |
| if (pPnt) { | |
| Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value(); | |
| p.SetCoord(pnt.x, pnt.y, pnt.z); | |
| } | |
| if (pDir) { | |
| Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value(); | |
| d.SetCoord(vec.x, vec.y, vec.z); | |
| } | |
| BRepPrimAPI_MakeTorus mkTorus( | |
| gp_Ax2(p, d), | |
| radius1, | |
| radius2, | |
| Base::toRadians<double>(angle1), | |
| Base::toRadians<double>(angle2), | |
| Base::toRadians<double>(angle) | |
| ); | |
| const TopoDS_Shape& shape = mkTorus.Shape(); | |
| return Py::asObject(new TopoShapeSolidPy(new TopoShape(shape))); | |
| } | |
| catch (Standard_DomainError&) { | |
| throw Py::Exception(PartExceptionOCCDomainError, "creation of torus failed"); | |
| } | |
| } | |
| Py::Object makeHelix(const Py::Tuple& args) | |
| { | |
| double pitch, height, radius, angle = -1.0; | |
| PyObject* pleft = Py_False; | |
| PyObject* pvertHeight = Py_False; | |
| if (!PyArg_ParseTuple( | |
| args.ptr(), | |
| "ddd|dO!O!", | |
| &pitch, | |
| &height, | |
| &radius, | |
| &angle, | |
| &(PyBool_Type), | |
| &pleft, | |
| &(PyBool_Type), | |
| &pvertHeight | |
| )) { | |
| throw Py::Exception(); | |
| } | |
| try { | |
| TopoShape helix; | |
| Standard_Boolean anIsLeft = Base::asBoolean(pleft); | |
| Standard_Boolean anIsVertHeight = Base::asBoolean(pvertHeight); | |
| TopoDS_Shape wire = helix.makeHelix(pitch, height, radius, angle, anIsLeft, anIsVertHeight); | |
| return Py::asObject(new TopoShapeWirePy(new TopoShape(wire))); | |
| } | |
| catch (Standard_Failure& e) { | |
| throw Py::Exception(PartExceptionOCCError, e.GetMessageString()); | |
| } | |
| } | |
| Py::Object makeLongHelix(const Py::Tuple& args) | |
| { | |
| double pitch, height, radius, angle = -1.0; | |
| PyObject* pleft = Py_False; | |
| if (!PyArg_ParseTuple(args.ptr(), "ddd|dO!", &pitch, &height, &radius, &angle, &(PyBool_Type), &pleft)) { | |
| throw Py::RuntimeError("Part.makeLongHelix fails on parms"); | |
| } | |
| try { | |
| TopoShape helix; | |
| Standard_Boolean anIsLeft = Base::asBoolean(pleft); | |
| TopoDS_Shape wire = helix.makeLongHelix(pitch, height, radius, angle, anIsLeft); | |
| return Py::asObject(new TopoShapeWirePy(new TopoShape(wire))); | |
| } | |
| catch (Standard_Failure& e) { | |
| throw Py::Exception(PartExceptionOCCError, e.GetMessageString()); | |
| } | |
| } | |
| Py::Object makeThread(const Py::Tuple& args) | |
| { | |
| double pitch, depth, height, radius; | |
| if (!PyArg_ParseTuple(args.ptr(), "dddd", &pitch, &depth, &height, &radius)) { | |
| throw Py::Exception(); | |
| } | |
| try { | |
| TopoShape helix; | |
| TopoDS_Shape wire = helix.makeThread(pitch, depth, height, radius); | |
| return Py::asObject(new TopoShapeWirePy(new TopoShape(wire))); | |
| } | |
| catch (Standard_Failure& e) { | |
| throw Py::Exception(PartExceptionOCCError, e.GetMessageString()); | |
| } | |
| } | |
| Py::Object makeRevolution(const Py::Tuple& args) | |
| { | |
| constexpr double doubleMax = std::numeric_limits<double>::max(); | |
| double vmin = doubleMax, vmax = -doubleMax; | |
| double angle = 360; | |
| PyObject *pPnt = nullptr, *pDir = nullptr, *pCrv; | |
| Handle(Geom_Curve) curve; | |
| PyObject* defaultType = Base::getTypeAsObject(&Part::TopoShapeSolidPy::Type); | |
| PyObject* type = defaultType; | |
| do { | |
| if (PyArg_ParseTuple( | |
| args.ptr(), | |
| "O!|dddO!O!O!", | |
| &(GeometryPy::Type), | |
| &pCrv, | |
| &vmin, | |
| &vmax, | |
| &angle, | |
| &(Base::VectorPy::Type), | |
| &pPnt, | |
| &(Base::VectorPy::Type), | |
| &pDir, | |
| &(PyType_Type), | |
| &type | |
| )) { | |
| GeometryPy* pcGeo = static_cast<GeometryPy*>(pCrv); | |
| curve = Handle(Geom_Curve)::DownCast(pcGeo->getGeometryPtr()->handle()); | |
| if (curve.IsNull()) { | |
| throw Py::Exception(PyExc_TypeError, "geometry is not a curve"); | |
| } | |
| if (vmin == doubleMax) { | |
| vmin = curve->FirstParameter(); | |
| } | |
| if (vmax == -doubleMax) { | |
| vmax = curve->LastParameter(); | |
| } | |
| break; | |
| } | |
| PyErr_Clear(); | |
| if (PyArg_ParseTuple( | |
| args.ptr(), | |
| "O!|dddO!O!O!", | |
| &(TopoShapePy::Type), | |
| &pCrv, | |
| &vmin, | |
| &vmax, | |
| &angle, | |
| &(Base::VectorPy::Type), | |
| &pPnt, | |
| &(Base::VectorPy::Type), | |
| &pDir, | |
| &(PyType_Type), | |
| &type | |
| )) { | |
| const TopoDS_Shape& shape | |
| = static_cast<TopoShapePy*>(pCrv)->getTopoShapePtr()->getShape(); | |
| if (shape.IsNull()) { | |
| throw Py::Exception(PartExceptionOCCError, "shape is empty"); | |
| } | |
| if (shape.ShapeType() != TopAbs_EDGE) { | |
| throw Py::Exception(PartExceptionOCCError, "shape is not an edge"); | |
| } | |
| const TopoDS_Edge& edge = TopoDS::Edge(shape); | |
| BRepAdaptor_Curve adapt(edge); | |
| const Handle(Geom_Curve) & hCurve = adapt.Curve().Curve(); | |
| // Apply placement of the shape to the curve | |
| TopLoc_Location loc = edge.Location(); | |
| curve = Handle(Geom_Curve)::DownCast(hCurve->Transformed(loc.Transformation())); | |
| if (curve.IsNull()) { | |
| throw Py::Exception(PartExceptionOCCError, "invalid curve in edge"); | |
| } | |
| if (vmin == doubleMax) { | |
| vmin = adapt.FirstParameter(); | |
| } | |
| if (vmax == -doubleMax) { | |
| vmax = adapt.LastParameter(); | |
| } | |
| break; | |
| } | |
| // invalid arguments | |
| throw Py::TypeError( | |
| "Expected arguments are:\n" | |
| "Curve or Edge, [float, float, float, Vector, Vector, ShapeType]" | |
| ); | |
| } while (false); | |
| try { | |
| gp_Pnt p(0, 0, 0); | |
| gp_Dir d(0, 0, 1); | |
| if (pPnt) { | |
| Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value(); | |
| p.SetCoord(pnt.x, pnt.y, pnt.z); | |
| } | |
| if (pDir) { | |
| Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value(); | |
| d.SetCoord(vec.x, vec.y, vec.z); | |
| } | |
| PyObject* shellType = Base::getTypeAsObject(&Part::TopoShapeShellPy::Type); | |
| PyObject* faceType = Base::getTypeAsObject(&Part::TopoShapeFacePy::Type); | |
| BRepPrimAPI_MakeRevolution | |
| mkRev(gp_Ax2(p, d), curve, vmin, vmax, Base::toRadians<double>(angle)); | |
| if (type == defaultType) { | |
| TopoDS_Shape shape = mkRev.Solid(); | |
| return Py::asObject(new TopoShapeSolidPy(new TopoShape(shape))); | |
| } | |
| else if (type == shellType) { | |
| TopoDS_Shape shape = mkRev.Shell(); | |
| return Py::asObject(new TopoShapeShellPy(new TopoShape(shape))); | |
| } | |
| else if (type == faceType) { | |
| TopoDS_Shape shape = mkRev.Face(); | |
| return Py::asObject(new TopoShapeFacePy(new TopoShape(shape))); | |
| } | |
| else { | |
| TopoDS_Shape shape = mkRev.Shape(); | |
| return Py::asObject(new TopoShapePy(new TopoShape(shape))); | |
| } | |
| } | |
| catch (Standard_DomainError&) { | |
| throw Py::Exception(PartExceptionOCCDomainError, "creation of revolved shape failed"); | |
| } | |
| } | |
| Py::Object makeRuledSurface(const Py::Tuple& args, const Py::Dict& kwds) | |
| { | |
| const char* op = nullptr; | |
| int orientation = 0; | |
| PyObject *sh1, *sh2; | |
| const std::array<const char*, 5> 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<TopoShape> shapes; | |
| shapes.push_back(*static_cast<TopoShapePy*>(sh1)->getTopoShapePtr()); | |
| shapes.push_back(*static_cast<TopoShapePy*>(sh2)->getTopoShapePtr()); | |
| return shape2pyshape(TopoShape().makeElementRuledSurface(shapes, orientation, op)); | |
| } | |
| Py::Object makeShellFromWires(const Py::Tuple& args, const Py::Dict& kwds) | |
| { | |
| PyObject* pylist; | |
| const char* op = nullptr; | |
| const std::array<const char*, 3> 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"); | |
| } | |
| } | |
| Py::Object makeTube(const Py::Tuple& args) | |
| { | |
| PyObject* pshape; | |
| double radius; | |
| double tolerance = 0.001; | |
| const char* scont = "C0"; | |
| int maxdegree = 3; | |
| int maxsegment = 30; | |
| // Path + radius | |
| if (!PyArg_ParseTuple( | |
| args.ptr(), | |
| "O!d|sii", | |
| &(TopoShapePy::Type), | |
| &pshape, | |
| &radius, | |
| &scont, | |
| &maxdegree, | |
| &maxsegment | |
| )) { | |
| throw Py::Exception(); | |
| } | |
| std::string str_cont = scont; | |
| int cont; | |
| if (str_cont == "C0") { | |
| cont = (int)GeomAbs_C0; | |
| } | |
| else if (str_cont == "C1") { | |
| cont = (int)GeomAbs_C1; | |
| } | |
| else if (str_cont == "C2") { | |
| cont = (int)GeomAbs_C2; | |
| } | |
| else if (str_cont == "C3") { | |
| cont = (int)GeomAbs_C3; | |
| } | |
| else if (str_cont == "CN") { | |
| cont = (int)GeomAbs_CN; | |
| } | |
| else if (str_cont == "G1") { | |
| cont = (int)GeomAbs_G1; | |
| } | |
| else if (str_cont == "G2") { | |
| cont = (int)GeomAbs_G2; | |
| } | |
| else { | |
| cont = (int)GeomAbs_C0; | |
| } | |
| try { | |
| const TopoDS_Shape& path_shape | |
| = static_cast<TopoShapePy*>(pshape)->getTopoShapePtr()->getShape(); | |
| TopoShape myShape(path_shape); | |
| TopoDS_Shape face = myShape.makeTube(radius, tolerance, cont, maxdegree, maxsegment); | |
| return Py::asObject(new TopoShapeFacePy(new TopoShape(face))); | |
| } | |
| catch (Standard_Failure& e) { | |
| throw Py::Exception(PartExceptionOCCError, e.GetMessageString()); | |
| } | |
| } | |
| Py::Object makeSweepSurface(const Py::Tuple& args) | |
| { | |
| PyObject *path, *profile; | |
| double tolerance = 0.001; | |
| int fillMode = 0; | |
| // Path + profile | |
| if (!PyArg_ParseTuple( | |
| args.ptr(), | |
| "O!O!|di", | |
| &(TopoShapePy::Type), | |
| &path, | |
| &(TopoShapePy::Type), | |
| &profile, | |
| &tolerance, | |
| &fillMode | |
| )) { | |
| throw Py::Exception(); | |
| } | |
| try { | |
| TopoShape mShape = *static_cast<TopoShapePy*>(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<TopoShapePy*>(profile)->getTopoShapePtr()}, | |
| Part::MakeSolid::noSolid, | |
| Standard_False, | |
| TransitionMode::Transformed, | |
| nullptr, | |
| tolerance | |
| )); | |
| } | |
| catch (Standard_Failure& e) { | |
| throw Py::Exception(PartExceptionOCCError, e.GetMessageString()); | |
| } | |
| } | |
| 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; | |
| const char* op = nullptr; | |
| const std::array<const char*, 7> 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, | |
| &(PyList_Type), | |
| &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 | |
| ) | |
| ); | |
| } | |
| Py::Object makeSplitShape(const Py::Tuple& args) | |
| { | |
| PyObject* shape; | |
| PyObject* list; | |
| PyObject* checkInterior = Py_True; | |
| if (!PyArg_ParseTuple( | |
| args.ptr(), | |
| "O!O|O!", | |
| &(TopoShapePy::Type), | |
| &shape, | |
| &list, | |
| &PyBool_Type, | |
| &checkInterior | |
| )) { | |
| throw Py::Exception(); | |
| } | |
| try { | |
| std::vector<TopoShape> sources; | |
| sources.push_back(*static_cast<TopoShapePy*>(shape)->getTopoShapePtr()); | |
| TopoDS_Shape initShape = static_cast<TopoShapePy*>(shape)->getTopoShapePtr()->getShape(); | |
| BRepFeat_SplitShape splitShape(initShape); | |
| splitShape.SetCheckInterior(Base::asBoolean(checkInterior)); | |
| Py::Sequence seq(list); | |
| for (Py::Sequence::iterator it = seq.begin(); it != seq.end(); ++it) { | |
| 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()) { | |
| throw Py::RuntimeError("Cannot add null shape"); | |
| } | |
| if (shape2.ShapeType() == TopAbs_FACE) { | |
| if (shape1.ShapeType() == TopAbs_EDGE) { | |
| splitShape.Add(TopoDS::Edge(shape1), TopoDS::Face(shape2)); | |
| } | |
| else if (shape1.ShapeType() == TopAbs_WIRE) { | |
| splitShape.Add(TopoDS::Wire(shape1), TopoDS::Face(shape2)); | |
| } | |
| else if (shape1.ShapeType() == TopAbs_COMPOUND) { | |
| splitShape.Add(TopoDS::Compound(shape1), TopoDS::Face(shape2)); | |
| } | |
| else { | |
| throw Py::TypeError("First item in tuple must be Edge, Wire or Compound"); | |
| } | |
| } | |
| else if (shape2.ShapeType() == TopAbs_EDGE) { | |
| if (shape1.ShapeType() == TopAbs_EDGE) { | |
| splitShape.Add(TopoDS::Edge(shape1), TopoDS::Edge(shape2)); | |
| } | |
| else { | |
| throw Py::TypeError("First item in tuple must be Edge"); | |
| } | |
| } | |
| else { | |
| throw Py::TypeError("Second item in tuple must be Face or Edge"); | |
| } | |
| } | |
| splitShape.Build(); | |
| const TopTools_ListOfShape& d = splitShape.DirectLeft(); | |
| const TopTools_ListOfShape& l = splitShape.Left(); | |
| Py::List list1; | |
| Py::List list2; | |
| 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) | |
| )); | |
| } | |
| Py::Tuple tuple(2); | |
| tuple.setItem(0, list1); | |
| tuple.setItem(1, list2); | |
| return tuple; | |
| } | |
| catch (Standard_Failure& e) { | |
| throw Py::Exception(PartExceptionOCCError, e.GetMessageString()); | |
| } | |
| } | |
| Py::Object makeWireString(const Py::Tuple& args) | |
| { | |
| PyObject* intext; | |
| const char* dir; | |
| const char* fontfile; | |
| const char* fontspec; | |
| bool useFontSpec = false; | |
| double height; | |
| double track = 0; | |
| Py_UCS4* unichars = nullptr; | |
| Py_ssize_t pysize; | |
| PyObject* CharList; | |
| if (PyArg_ParseTuple( | |
| args.ptr(), | |
| "Ossd|d", | |
| &intext, // compatibility with old version | |
| &dir, | |
| &fontfile, | |
| &height, | |
| &track | |
| )) { | |
| useFontSpec = false; | |
| } | |
| else { | |
| PyErr_Clear(); | |
| if (PyArg_ParseTuple(args.ptr(), "Osd|d", &intext, &fontspec, &height, &track)) { | |
| useFontSpec = true; | |
| } | |
| else { | |
| throw Py::TypeError("** makeWireString bad args."); | |
| } | |
| } | |
| // FIXME: Test this! | |
| if (PyBytes_Check(intext)) { | |
| PyObject* p = Base::PyAsUnicodeObject(PyBytes_AsString(intext)); | |
| if (!p) { | |
| throw Py::TypeError("** makeWireString can't convert PyString."); | |
| } | |
| pysize = PyUnicode_GetLength(p); | |
| unichars = PyUnicode_AsUCS4Copy(p); | |
| } | |
| else if (PyUnicode_Check(intext)) { | |
| pysize = PyUnicode_GetLength(intext); | |
| unichars = PyUnicode_AsUCS4Copy(intext); | |
| } | |
| else { | |
| throw Py::TypeError("** makeWireString bad text parameter"); | |
| } | |
| try { | |
| if (useFontSpec) { | |
| CharList = FT2FC(unichars, pysize, fontspec, height, track); | |
| } | |
| else { | |
| CharList = FT2FC(unichars, pysize, dir, fontfile, height, track); | |
| } | |
| if (unichars) { | |
| PyMem_Free(unichars); | |
| } | |
| } | |
| catch (Standard_DomainError&) { // Standard_DomainError is OCC error. | |
| throw Py::Exception( | |
| PartExceptionOCCDomainError, | |
| "makeWireString failed - Standard_DomainError" | |
| ); | |
| } | |
| catch (std::runtime_error& e) { // FT2 or FT2FC errors | |
| throw Py::Exception(PartExceptionOCCError, e.what()); | |
| } | |
| return Py::asObject(CharList); | |
| throw Py::RuntimeError("FreeCAD compiled without FreeType support! This method is disabled..."); | |
| } | |
| Py::Object exportUnits(const Py::Tuple& args) | |
| { | |
| char* unit = nullptr; | |
| if (!PyArg_ParseTuple(args.ptr(), "|s", &unit)) { | |
| throw Py::Exception(); | |
| } | |
| if (unit) { | |
| if (!Interface::writeIgesUnit(unit)) { | |
| throw Py::RuntimeError("Failed to set 'write.iges.unit'"); | |
| } | |
| if (!Interface::writeStepUnit(unit)) { | |
| throw Py::RuntimeError("Failed to set 'write.step.unit'"); | |
| } | |
| } | |
| Py::Dict dict; | |
| dict.setItem("write.iges.unit", Py::String(Interface::writeIgesUnit())); | |
| dict.setItem("write.step.unit", Py::String(Interface::writeStepUnit())); | |
| return dict; | |
| } | |
| Py::Object setStaticValue(const Py::Tuple& args) | |
| { | |
| char *name, *cval; | |
| if (PyArg_ParseTuple(args.ptr(), "ss", &name, &cval)) { | |
| if (!Interface_Static::SetCVal(name, cval)) { | |
| std::stringstream str; | |
| str << "Failed to set '" << name << "'"; | |
| throw Py::RuntimeError(str.str()); | |
| } | |
| return Py::None(); | |
| } | |
| PyErr_Clear(); | |
| PyObject* index_or_value; | |
| if (PyArg_ParseTuple(args.ptr(), "sO", &name, &index_or_value)) { | |
| if (PyLong_Check(index_or_value)) { | |
| int ival = (int)PyLong_AsLong(index_or_value); | |
| if (!Interface_Static::SetIVal(name, ival)) { | |
| std::stringstream str; | |
| str << "Failed to set '" << name << "'"; | |
| throw Py::RuntimeError(str.str()); | |
| } | |
| return Py::None(); | |
| } | |
| else if (PyFloat_Check(index_or_value)) { | |
| double rval = PyFloat_AsDouble(index_or_value); | |
| if (!Interface_Static::SetRVal(name, rval)) { | |
| std::stringstream str; | |
| str << "Failed to set '" << name << "'"; | |
| throw Py::RuntimeError(str.str()); | |
| } | |
| return Py::None(); | |
| } | |
| } | |
| throw Py::TypeError("First argument must be string and must be either string, int or float"); | |
| } | |
| Py::Object cast_to_shape(const Py::Tuple& args) | |
| { | |
| PyObject* object; | |
| if (PyArg_ParseTuple(args.ptr(), "O!", &(Part::TopoShapePy::Type), &object)) { | |
| TopoShape* ptr = static_cast<TopoShapePy*>(object)->getTopoShapePtr(); | |
| return Py::asObject(ptr->getPyObject()); | |
| } | |
| throw Py::Exception(); | |
| } | |
| Py::Object getSortedClusters(const Py::Tuple& args) | |
| { | |
| PyObject* obj; | |
| if (!PyArg_ParseTuple(args.ptr(), "O", &obj)) { | |
| throw Py::Exception(PartExceptionOCCError, "list of edges expected"); | |
| } | |
| Py::Sequence list(obj); | |
| std::vector<TopoDS_Edge> edges; | |
| for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { | |
| PyObject* item = (*it).ptr(); | |
| if (PyObject_TypeCheck(item, &(Part::TopoShapePy::Type))) { | |
| const TopoDS_Shape& sh | |
| = static_cast<Part::TopoShapePy*>(item)->getTopoShapePtr()->getShape(); | |
| if (sh.ShapeType() == TopAbs_EDGE) { | |
| edges.push_back(TopoDS::Edge(sh)); | |
| } | |
| else { | |
| throw Py::TypeError("shape is not an edge"); | |
| } | |
| } | |
| else { | |
| throw Py::TypeError("item is not a shape"); | |
| } | |
| } | |
| Edgecluster acluster(edges); | |
| tEdgeClusterVector aclusteroutput = acluster.GetClusters(); | |
| Py::List root_list; | |
| for (const auto& it : aclusteroutput) { | |
| Py::List add_list; | |
| for (const auto& it1 : it) { | |
| add_list.append(Py::Object(new TopoShapeEdgePy(new TopoShape(it1)), true)); | |
| } | |
| root_list.append(add_list); | |
| } | |
| return root_list; | |
| } | |
| Py::Object sortEdges(const Py::Tuple& args) | |
| { | |
| PyObject* obj; | |
| if (!PyArg_ParseTuple(args.ptr(), "O", &obj)) { | |
| throw Py::TypeError("list of edges expected"); | |
| } | |
| Py::Sequence list(obj); | |
| std::list<TopoDS_Edge> edges; | |
| for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { | |
| PyObject* item = (*it).ptr(); | |
| if (PyObject_TypeCheck(item, &(Part::TopoShapePy::Type))) { | |
| const TopoDS_Shape& sh | |
| = static_cast<Part::TopoShapePy*>(item)->getTopoShapePtr()->getShape(); | |
| if (sh.ShapeType() == TopAbs_EDGE) { | |
| edges.push_back(TopoDS::Edge(sh)); | |
| } | |
| else { | |
| throw Py::TypeError("shape is not an edge"); | |
| } | |
| } | |
| else { | |
| throw Py::TypeError("item is not a shape"); | |
| } | |
| } | |
| std::list<TopoDS_Edge> sorted = sort_Edges(Precision::Confusion(), edges); | |
| Py::List sorted_list; | |
| for (const auto& it : sorted) { | |
| sorted_list.append(Py::Object(new TopoShapeEdgePy(new TopoShape(it)), true)); | |
| } | |
| return sorted_list; | |
| } | |
| Py::Object sortEdges2(const Py::Tuple& args) | |
| { | |
| PyObject* obj; | |
| double tol3d = Precision::Confusion(); | |
| if (!PyArg_ParseTuple(args.ptr(), "O|d", &obj, &tol3d)) { | |
| throw Py::Exception(PartExceptionOCCError, "list of edges expected"); | |
| } | |
| Py::Sequence list(obj); | |
| std::list<TopoDS_Edge> edges; | |
| for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { | |
| PyObject* item = (*it).ptr(); | |
| if (PyObject_TypeCheck(item, &(Part::TopoShapePy::Type))) { | |
| const TopoDS_Shape& sh | |
| = static_cast<Part::TopoShapePy*>(item)->getTopoShapePtr()->getShape(); | |
| if (sh.ShapeType() == TopAbs_EDGE) { | |
| edges.push_back(TopoDS::Edge(sh)); | |
| } | |
| else { | |
| throw Py::TypeError("shape is not an edge"); | |
| } | |
| } | |
| else { | |
| throw Py::TypeError("item is not a shape"); | |
| } | |
| } | |
| Py::List root_list; | |
| while (!edges.empty()) { | |
| std::list<TopoDS_Edge> sorted = sort_Edges(tol3d, edges); | |
| Py::List sorted_list; | |
| for (const auto& it : sorted) { | |
| sorted_list.append(Py::Object(new TopoShapeEdgePy(new TopoShape(it)), true)); | |
| } | |
| root_list.append(sorted_list); | |
| } | |
| return root_list; | |
| } | |
| Py::Object toPythonOCC(const Py::Tuple& args) | |
| { | |
| PyObject* pcObj; | |
| if (!PyArg_ParseTuple(args.ptr(), "O!", &(TopoShapePy::Type), &pcObj)) { | |
| throw Py::Exception(); | |
| } | |
| try { | |
| TopoDS_Shape* shape = new TopoDS_Shape(); | |
| (*shape) = static_cast<TopoShapePy*>(pcObj)->getTopoShapePtr()->getShape(); | |
| PyObject* proxy = nullptr; | |
| proxy = Base::Interpreter().createSWIGPointerObj( | |
| "OCC.TopoDS", | |
| "TopoDS_Shape *", | |
| static_cast<void*>(shape), | |
| 1 | |
| ); | |
| return Py::asObject(proxy); | |
| } | |
| catch (const Base::Exception& e) { | |
| throw Py::Exception(PartExceptionOCCError, e.what()); | |
| } | |
| } | |
| Py::Object fromPythonOCC(const Py::Tuple& args) | |
| { | |
| PyObject* proxy; | |
| if (!PyArg_ParseTuple(args.ptr(), "O", &proxy)) { | |
| throw Py::Exception(); | |
| } | |
| void* ptr; | |
| try { | |
| TopoShape* shape = new TopoShape(); | |
| Base::Interpreter().convertSWIGPointerObj("OCC.TopoDS", "TopoDS_Shape *", proxy, &ptr, 0); | |
| if (!ptr) { | |
| throw Py::RuntimeError("Conversion of OCC.TopoDS.TopoDS_Shape failed"); | |
| } | |
| TopoDS_Shape* s = static_cast<TopoDS_Shape*>(ptr); | |
| shape->setShape(*s); | |
| return Py::asObject(new TopoShapePy(shape)); | |
| } | |
| catch (const Base::Exception& e) { | |
| throw Py::Exception(PartExceptionOCCError, e.what()); | |
| } | |
| } | |
| Py::Object getShape(const Py::Tuple& args, const Py::Dict& kwds) | |
| { | |
| PyObject* pObj; | |
| const char* subname = nullptr; | |
| PyObject* pyMat = nullptr; | |
| PyObject* needSubElement = Py_False; | |
| PyObject* transform = Py_True; | |
| PyObject* noElementMap = Py_False; | |
| PyObject* refine = Py_False; | |
| short retType = 0; | |
| static const std::array<const char*, 9> kwd_list { | |
| "obj", | |
| "subname", | |
| "mat", | |
| "needSubElement", | |
| "transform", | |
| "retType", | |
| "noElementMap", | |
| "refine", | |
| nullptr | |
| }; | |
| if (!Base::Wrapped_ParseTupleAndKeywords( | |
| args.ptr(), | |
| kwds.ptr(), | |
| "O!|sO!O!O!hO!O!", | |
| kwd_list, | |
| &App::DocumentObjectPy::Type, | |
| &pObj, | |
| &subname, | |
| &Base::MatrixPy::Type, | |
| &pyMat, | |
| &PyBool_Type, | |
| &needSubElement, | |
| &PyBool_Type, | |
| &transform, | |
| &retType, | |
| &PyBool_Type, | |
| &noElementMap, | |
| &PyBool_Type, | |
| &refine | |
| )) { | |
| throw Py::Exception(); | |
| } | |
| App::DocumentObject* obj = static_cast<App::DocumentObjectPy*>(pObj)->getDocumentObjectPtr(); | |
| App::DocumentObject* subObj = nullptr; | |
| Base::Matrix4D mat; | |
| if (pyMat) { | |
| mat = *static_cast<Base::MatrixPy*>(pyMat)->getMatrixPtr(); | |
| } | |
| bool resolveLink = (retType == 2); | |
| auto shape = Feature::getTopoShape( | |
| obj, | |
| (resolveLink ? ShapeOption::ResolveLink : ShapeOption::NoFlag) | |
| | (Base::asBoolean(needSubElement) ? ShapeOption::NeedSubElement : ShapeOption::NoFlag) | |
| | (Base::asBoolean(transform) ? ShapeOption::Transform : ShapeOption::NoFlag) | |
| | (Base::asBoolean(noElementMap) ? ShapeOption::NoElementMap : ShapeOption::NoFlag), | |
| subname, | |
| &mat, | |
| &subObj | |
| ); | |
| if (Base::asBoolean(refine)) { | |
| shape = TopoShape(0, shape.Hasher).makeElementRefine(shape); | |
| } | |
| Py::Object sret(shape2pyshape(shape)); | |
| if (retType == 0) { | |
| return sret; | |
| } | |
| return Py::TupleN( | |
| sret, | |
| Py::asObject(new Base::MatrixPy(new Base::Matrix4D(mat))), | |
| subObj ? Py::Object(subObj->getPyObject(), true) : Py::Object() | |
| ); | |
| } | |
| Py::Object clearShapeCache(const Py::Tuple& args) | |
| { | |
| if (!PyArg_ParseTuple(args.ptr(), "")) { | |
| throw Py::Exception(); | |
| } | |
| Part::Feature::clearShapeCache(); | |
| return Py::Object(); | |
| } | |
| Py::Object splitSubname(const Py::Tuple& args) | |
| { | |
| const char* subname; | |
| if (!PyArg_ParseTuple(args.ptr(), "s", &subname)) { | |
| throw Py::Exception(); | |
| } | |
| auto element = Data::findElementName(subname); | |
| std::string sub(subname, element - subname); | |
| Py::List list; | |
| list.append(Py::String(sub)); | |
| const char* dot = strchr(element, '.'); | |
| if (!dot) { | |
| dot = element + strlen(element); | |
| } | |
| const char* mapped = Data::isMappedElement(element); | |
| if (mapped) { | |
| list.append(Py::String(std::string(mapped, dot - mapped))); | |
| } | |
| else { | |
| list.append(Py::String()); | |
| } | |
| if (*dot == '.') { | |
| list.append(Py::String(dot + 1)); | |
| } | |
| else if (!mapped) { | |
| list.append(Py::String(element)); | |
| } | |
| else { | |
| list.append(Py::String()); | |
| } | |
| return list; | |
| } | |
| Py::Object joinSubname(const Py::Tuple& args) | |
| { | |
| const char* sub; | |
| const char* mapped; | |
| const char* element; | |
| if (!PyArg_ParseTuple(args.ptr(), "sss", &sub, &mapped, &element)) { | |
| throw Py::Exception(); | |
| } | |
| std::string subname(sub); | |
| if (!subname.empty() && subname[subname.size() - 1] != '.') { | |
| subname += '.'; | |
| } | |
| if (!Base::Tools::isNullOrEmpty(mapped)) { | |
| if (!Data::isMappedElement(mapped)) { | |
| subname += Data::ELEMENT_MAP_PREFIX; | |
| } | |
| subname += mapped; | |
| } | |
| if (!Base::Tools::isNullOrEmpty(element)) { | |
| if (!subname.empty() && subname[subname.size() - 1] != '.') { | |
| subname += '.'; | |
| } | |
| subname += element; | |
| } | |
| return Py::String(subname); | |
| } | |
| }; | |
| PyObject* initModule() | |
| { | |
| return Base::Interpreter().addModule(new Module); | |
| } | |
| } // namespace Part | |