FreeCAD

Форк
0
/
AppPartPy.cpp 
2377 строк · 100.0 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de>              *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
6
 *   This library is free software; you can redistribute it and/or         *
7
 *   modify it under the terms of the GNU Library General Public           *
8
 *   License as published by the Free Software Foundation; either          *
9
 *   version 2 of the License, or (at your option) any later version.      *
10
 *                                                                         *
11
 *   This library  is distributed in the hope that it will be useful,      *
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14
 *   GNU Library General Public License for more details.                  *
15
 *                                                                         *
16
 *   You should have received a copy of the GNU Library General Public     *
17
 *   License along with this library; see the file COPYING.LIB. If not,    *
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23
#include "PreCompiled.h"
24
#ifndef _PreComp_
25
# include <BRep_Builder.hxx>
26
# include <BRep_Tool.hxx>
27
# include <BRepAdaptor_Curve.hxx>
28
# include <BRepBuilderAPI_MakeEdge.hxx>
29
# include <BRepBuilderAPI_MakeFace.hxx>
30
# include <BRepBuilderAPI_MakePolygon.hxx>
31
# include <BRepBuilderAPI_MakeSolid.hxx>
32
# include <BRepCheck_Analyzer.hxx>
33
# include <BRepFeat_SplitShape.hxx>
34
# include <BRepOffsetAPI_Sewing.hxx>
35
# include <BRepPrim_Wedge.hxx>
36
# include <BRepPrimAPI_MakeBox.hxx>
37
# include <BRepPrimAPI_MakeCone.hxx>
38
# include <BRepPrimAPI_MakeCylinder.hxx>
39
# include <BRepPrimAPI_MakeRevolution.hxx>
40
# include <BRepPrimAPI_MakeSphere.hxx>
41
# include <BRepPrimAPI_MakeTorus.hxx>
42
# include <BRepFill.hxx>
43
# include <BRepFill_Filling.hxx>
44
# include <BRepLib.hxx>
45
# include <BSplCLib.hxx>
46
# include <gp_Ax3.hxx>
47
# include <gp_Circ.hxx>
48
# include <gp_Pnt.hxx>
49
# include <Geom_BSplineSurface.hxx>
50
# include <Geom_Circle.hxx>
51
# include <Geom_Plane.hxx>
52
# include <GeomFill_AppSurf.hxx>
53
# include <GeomFill_Generator.hxx>
54
# include <GeomFill_Line.hxx>
55
# include <GeomFill_SectionGenerator.hxx>
56
# include <Interface_Static.hxx>
57
# include <NCollection_List.hxx>
58
# include <Precision.hxx>
59
# include <ShapeFix.hxx>
60
# include <ShapeBuild_ReShape.hxx>
61
# include <ShapeUpgrade_ShellSewing.hxx>
62
# include <Standard_DomainError.hxx>
63
# include <Standard_Version.hxx>
64
# include <TopExp_Explorer.hxx>
65
# include <TopoDS_Compound.hxx>
66
# include <TopoDS_Edge.hxx>
67
# include <TopoDS_Face.hxx>
68
# include <TopoDS_Shell.hxx>
69
# include <TopoDS_Solid.hxx>
70
# include <TopTools_ListIteratorOfListOfShape.hxx>
71
#endif
72
# include <BRepFill_Generator.hxx>
73

74
#include <App/Application.h>
75
#include <App/Document.h>
76
#include <App/DocumentObjectPy.h>
77
#include <App/ElementNamingUtils.h>
78
#include <Base/Console.h>
79
#include <Base/Exception.h>
80
#include <Base/FileInfo.h>
81
#include <Base/GeometryPyCXX.h>
82
#include <Base/Interpreter.h>
83
#include <Base/PyWrapParseTupleAndKeywords.h>
84
#include <Base/VectorPy.h>
85

86
#include "BSplineSurfacePy.h"
87
#include "edgecluster.h"
88
#include "FaceMaker.h"
89
#include "GeometryCurvePy.h"
90
#include "GeometryPy.h"
91
#include "ImportIges.h"
92
#include "ImportStep.h"
93
#include "Interface.h"
94
#include "modelRefine.h"
95
#include "OCCError.h"
96
#include "PartFeature.h"
97
#include "PartPyCXX.h"
98
#include "Tools.h"
99
#include "TopoShapeCompoundPy.h"
100
#include "TopoShapePy.h"
101
#include "TopoShapeEdgePy.h"
102
#include "TopoShapeFacePy.h"
103
#include "TopoShapeShellPy.h"
104
#include "TopoShapeSolidPy.h"
105
#include "TopoShapeWirePy.h"
106
#include "TopoShapeOpCode.h"
107
#include "TopoShapeMapper.h"
108

109
#ifdef FCUseFreeType
110
#  include "FT2FC.h"
111
#endif
112

113
extern const char* BRepBuilderAPI_FaceErrorText(BRepBuilderAPI_FaceError fe);
114

115
#ifndef M_PI
116
#define M_PI    3.14159265358979323846 /* pi */
117
#endif
118

119
#ifndef M_PI_2
120
#define M_PI_2  1.57079632679489661923 /* pi/2 */
121
#endif
122

123
namespace Part {
124

125
PartExport void getPyShapes(PyObject* obj, std::vector<TopoShape>& shapes)
126
{
127
    if (!obj) {
128
        return;
129
    }
130
    if (PyObject_TypeCheck(obj, &Part::TopoShapePy::Type)) {
131
        shapes.push_back(*static_cast<TopoShapePy*>(obj)->getTopoShapePtr());
132
    }
133
    else if (PyObject_TypeCheck(obj, &GeometryPy::Type)) {
134
        shapes.emplace_back(static_cast<GeometryPy*>(obj)->getGeometryPtr()->toShape());
135
    }
136
    else if (PySequence_Check(obj)) {
137
        Py::Sequence list(obj);
138
        for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
139
            if (PyObject_TypeCheck((*it).ptr(), &(Part::TopoShapePy::Type))) {
140
                shapes.push_back(*static_cast<TopoShapePy*>((*it).ptr())->getTopoShapePtr());
141
            }
142
            else if (PyObject_TypeCheck((*it).ptr(), &GeometryPy::Type)) {
143
                shapes.emplace_back(
144
                    static_cast<GeometryPy*>((*it).ptr())->getGeometryPtr()->toShape());
145
            }
146
            else {
147
                throw Py::TypeError("expect shape in sequence");
148
            }
149
        }
150
    }
151
    else {
152
        throw Py::TypeError("expect shape or sequence of shapes");
153
    }
154
}
155

156
PartExport std::vector<TopoShape> getPyShapes(PyObject *obj) {
157
    std::vector<TopoShape> ret;
158
    getPyShapes(obj,ret);
159
    return ret;
160
}
161

162
struct EdgePoints {
163
    gp_Pnt v1, v2;
164
    std::list<TopoDS_Edge>::iterator it;
165
    TopoDS_Edge edge;
166
};
167

168
PartExport std::list<TopoDS_Edge> sort_Edges(double tol3d, std::list<TopoDS_Edge>& edges)
169
{
170
    tol3d = tol3d * tol3d;
171
    std::list<EdgePoints>  edge_points;
172
    TopExp_Explorer xp;
173
    for (std::list<TopoDS_Edge>::iterator it = edges.begin(); it != edges.end(); ++it) {
174
        EdgePoints ep;
175
        xp.Init(*it,TopAbs_VERTEX);
176
        ep.v1 = BRep_Tool::Pnt(TopoDS::Vertex(xp.Current()));
177
        xp.Next();
178
        ep.v2 = BRep_Tool::Pnt(TopoDS::Vertex(xp.Current()));
179
        ep.it = it;
180
        ep.edge = *it;
181
        edge_points.push_back(ep);
182
    }
183

184
    if (edge_points.empty())
185
        return {};
186

187
    std::list<TopoDS_Edge> sorted;
188
    gp_Pnt first, last;
189
    first = edge_points.front().v1;
190
    last  = edge_points.front().v2;
191

192
    sorted.push_back(edge_points.front().edge);
193
    edges.erase(edge_points.front().it);
194
    edge_points.erase(edge_points.begin());
195

196
    while (!edge_points.empty()) {
197
        // search for adjacent edge
198
        std::list<EdgePoints>::iterator pEI;
199
        for (pEI = edge_points.begin(); pEI != edge_points.end(); ++pEI) {
200
            if (pEI->v1.SquareDistance(last) <= tol3d) {
201
                last = pEI->v2;
202
                sorted.push_back(pEI->edge);
203
                edges.erase(pEI->it);
204
                edge_points.erase(pEI);
205
                pEI = edge_points.begin();
206
                break;
207
            }
208
            else if (pEI->v2.SquareDistance(first) <= tol3d) {
209
                first = pEI->v1;
210
                sorted.push_front(pEI->edge);
211
                edges.erase(pEI->it);
212
                edge_points.erase(pEI);
213
                pEI = edge_points.begin();
214
                break;
215
            }
216
            else if (pEI->v2.SquareDistance(last) <= tol3d) {
217
                last = pEI->v1;
218
                Standard_Real first, last;
219
                const Handle(Geom_Curve) & curve = BRep_Tool::Curve(pEI->edge, first, last);
220
                first = curve->ReversedParameter(first);
221
                last = curve->ReversedParameter(last);
222
                TopoDS_Edge edgeReversed = BRepBuilderAPI_MakeEdge(curve->Reversed(), last, first);
223
                sorted.push_back(edgeReversed);
224
                edges.erase(pEI->it);
225
                edge_points.erase(pEI);
226
                pEI = edge_points.begin();
227
                break;
228
            }
229
            else if (pEI->v1.SquareDistance(first) <= tol3d) {
230
                first = pEI->v2;
231
                Standard_Real first, last;
232
                const Handle(Geom_Curve) & curve = BRep_Tool::Curve(pEI->edge, first, last);
233
                first = curve->ReversedParameter(first);
234
                last = curve->ReversedParameter(last);
235
                TopoDS_Edge edgeReversed = BRepBuilderAPI_MakeEdge(curve->Reversed(), last, first);
236
                sorted.push_front(edgeReversed);
237
                edges.erase(pEI->it);
238
                edge_points.erase(pEI);
239
                pEI = edge_points.begin();
240
                break;
241
            }
242
        }
243

244
        if ((pEI == edge_points.end()) || (last.SquareDistance(first) <= tol3d)) {
245
            // no adjacent edge found or polyline is closed
246
            return sorted;
247
        }
248
    }
249

250
    return sorted;
251
}
252
}
253

254
namespace Part {
255
class BRepFeatModule : public Py::ExtensionModule<BRepFeatModule>
256
{
257
public:
258
    BRepFeatModule() : Py::ExtensionModule<BRepFeatModule>("BRepFeat")
259
    {
260
        initialize("This is a module working with the BRepFeat package."); // register with Python
261
    }
262
};
263

264
class BRepOffsetAPIModule : public Py::ExtensionModule<BRepOffsetAPIModule>
265
{
266
public:
267
    BRepOffsetAPIModule() : Py::ExtensionModule<BRepOffsetAPIModule>("BRepOffsetAPI")
268
    {
269
        initialize("This is a module working with the BRepOffsetAPI package."); // register with Python
270
    }
271
};
272

273
class Geom2dModule : public Py::ExtensionModule<Geom2dModule>
274
{
275
public:
276
    Geom2dModule() : Py::ExtensionModule<Geom2dModule>("Geom2d")
277
    {
278
        initialize("This is a module working with 2d geometries."); // register with Python
279
    }
280
};
281

282
class GeomPlateModule : public Py::ExtensionModule<GeomPlateModule>
283
{
284
public:
285
    GeomPlateModule() : Py::ExtensionModule<GeomPlateModule>("GeomPlate")
286
    {
287
        initialize("This is a module working with the GeomPlate framework."); // register with Python
288
    }
289
};
290

291
class HLRBRepModule : public Py::ExtensionModule<HLRBRepModule>
292
{
293
public:
294
    HLRBRepModule() : Py::ExtensionModule<HLRBRepModule>("HLRBRep")
295
    {
296
        initialize("This is a module working with the HLRBRep framework."); // register with Python
297
    }
298
};
299

300
class ShapeFixModule : public Py::ExtensionModule<ShapeFixModule>
301
{
302
public:
303
    ShapeFixModule() : Py::ExtensionModule<ShapeFixModule>("ShapeFix")
304
    {
305
        add_varargs_method("sameParameter",&ShapeFixModule::sameParameter,
306
            "sameParameter(shape, enforce, prec=0.0)"
307
        );
308
        add_varargs_method("encodeRegularity",&ShapeFixModule::encodeRegularity,
309
            "encodeRegularity(shape, tolerance = 1e-10)\n"
310
        );
311
        add_varargs_method("removeSmallEdges",&ShapeFixModule::removeSmallEdges,
312
            "removeSmallEdges(shape, tolerance, ReShapeContext)\n"
313
            "Removes edges which are less than given tolerance from shape"
314
        );
315
        add_varargs_method("fixVertexPosition",&ShapeFixModule::fixVertexPosition,
316
            "fixVertexPosition(shape, tolerance, ReShapeContext)\n"
317
            "Fix position of the vertices having tolerance more tnan specified one"
318
        );
319
        add_varargs_method("leastEdgeSize",&ShapeFixModule::leastEdgeSize,
320
            "leastEdgeSize(shape)\n"
321
            "Calculate size of least edge"
322
        );
323
        initialize("This is a module working with the ShapeFix framework."); // register with Python
324
    }
325

326
private:
327
    Py::Object sameParameter(const Py::Tuple& args)
328
    {
329
        PyObject* shape;
330
        PyObject* enforce;
331
        double prec = 0.0;
332
        if (!PyArg_ParseTuple(args.ptr(), "O!O!|d", &TopoShapePy::Type, &shape, &PyBool_Type, &enforce, &prec))
333
            throw Py::Exception();
334

335
        TopoDS_Shape sh = static_cast<TopoShapePy*>(shape)->getTopoShapePtr()->getShape();
336
        bool ok = ShapeFix::SameParameter(sh, Base::asBoolean(enforce), prec);
337
        return Py::Boolean(ok);
338
    }
339
    Py::Object encodeRegularity(const Py::Tuple& args)
340
    {
341
        PyObject* shape;
342
        double tolang = 1.0e-10;
343
        if (!PyArg_ParseTuple(args.ptr(), "O!|d", &TopoShapePy::Type, &shape, &tolang))
344
            throw Py::Exception();
345

346
        TopoDS_Shape sh = static_cast<TopoShapePy*>(shape)->getTopoShapePtr()->getShape();
347
        ShapeFix::EncodeRegularity(sh, tolang);
348
        return Py::None();
349
    }
350
    Py::Object removeSmallEdges(const Py::Tuple& args)
351
    {
352
        PyObject* shape;
353
        double tol;
354
        if (!PyArg_ParseTuple(args.ptr(), "O!d", &TopoShapePy::Type, &shape, &tol))
355
            throw Py::Exception();
356

357
        TopoDS_Shape sh = static_cast<TopoShapePy*>(shape)->getTopoShapePtr()->getShape();
358
        Handle(ShapeBuild_ReShape) reshape = new ShapeBuild_ReShape();
359
        TopoShape res = ShapeFix::RemoveSmallEdges(sh, tol, reshape);
360
        return Py::asObject(res.getPyObject());
361
    }
362
    Py::Object fixVertexPosition(const Py::Tuple& args)
363
    {
364
        PyObject* shape;
365
        double tol;
366
        if (!PyArg_ParseTuple(args.ptr(), "O!d", &TopoShapePy::Type, &shape, &tol))
367
            throw Py::Exception();
368

369
        TopoDS_Shape sh = static_cast<TopoShapePy*>(shape)->getTopoShapePtr()->getShape();
370
        Handle(ShapeBuild_ReShape) reshape = new ShapeBuild_ReShape();
371
        bool ok = ShapeFix::FixVertexPosition(sh, tol, reshape);
372
        return Py::Boolean(ok);
373
    }
374
    Py::Object leastEdgeSize(const Py::Tuple& args)
375
    {
376
        PyObject* shape;
377
        if (!PyArg_ParseTuple(args.ptr(), "O!", &TopoShapePy::Type, &shape))
378
            throw Py::Exception();
379

380
        TopoDS_Shape sh = static_cast<TopoShapePy*>(shape)->getTopoShapePtr()->getShape();
381
        double len = ShapeFix::LeastEdgeSize(sh);
382
        return Py::Float(len);
383
    }
384
};
385

386
class ShapeUpgradeModule : public Py::ExtensionModule<ShapeUpgradeModule>
387
{
388
public:
389
    ShapeUpgradeModule() : Py::ExtensionModule<ShapeUpgradeModule>("ShapeUpgrade")
390
    {
391
        initialize("This is a module working with the ShapeUpgrade framework."); // register with Python
392
    }
393
};
394

395
class ChFi2dModule : public Py::ExtensionModule<ChFi2dModule>
396
{
397
public:
398
    ChFi2dModule() : Py::ExtensionModule<ChFi2dModule>("ChFi2d")
399
    {
400
        initialize("This is a module working with the ChFi2d framework."); // register with Python
401
    }
402
};
403

404
class Module : public Py::ExtensionModule<Module>
405
{
406
    BRepFeatModule brepFeat;
407
    BRepOffsetAPIModule brepOffsetApi;
408
    Geom2dModule geom2d;
409
    GeomPlateModule geomPlate;
410
    HLRBRepModule HLRBRep;
411
    ShapeFixModule shapeFix;
412
    ShapeUpgradeModule shapeUpgrade;
413
    ChFi2dModule chFi2d;
414
public:
415
    Module() : Py::ExtensionModule<Module>("Part")
416
    {
417
        add_varargs_method("open",&Module::open,
418
            "open(string) -- Create a new document and load the file into the document."
419
        );
420
        add_varargs_method("insert",&Module::insert,
421
            "insert(string,string) -- Insert the file into the given document."
422
        );
423
        add_varargs_method("export",&Module::exporter,
424
            "export(list,string) -- Export a list of objects into a single file."
425
        );
426
        add_varargs_method("read",&Module::read,
427
            "read(string) -- Load the file and return the shape."
428
        );
429
        add_varargs_method("show",&Module::show,
430
            "show(shape,[string]) -- Add the shape to the active document or create one if no document exists."
431
        );
432
        add_varargs_method("getFacets",&Module::getFacets,
433
            "getFacets(shape): simplified mesh generation"
434
        );
435
        add_keyword_method("makeCompound",&Module::makeCompound,
436
            "makeCompound(list) -- Create a compound out of a list of shapes."
437
        );
438
        add_keyword_method("makeShell",&Module::makeShell,
439
            "makeShell(list) -- Create a shell out of a list of faces."
440
        );
441
        add_keyword_method("makeFace",&Module::makeFace,
442
            "makeFace(list_of_shapes_or_compound, maker_class_name) -- Create a face (faces) using facemaker class.\n"
443
            "maker_class_name is a string like 'Part::FaceMakerSimple'."
444
        );
445
        add_keyword_method("makeFilledSurface",&Module::makeFilledSurface,
446
            "makeFilledSurface(list of curves, tolerance) -- Create a surface out of a list of curves."
447
        );
448
        add_keyword_method("makeFilledFace",&Module::makeFilledFace,
449
            "makeFilledFace(list) -- Create a face out of a list of edges."
450
        );
451
        add_keyword_method("makeSolid",&Module::makeSolid,
452
            "makeSolid(shape): Create a solid out of shells of shape. If shape is a compsolid, the overall volume solid is created."
453
        );
454
        add_varargs_method("makePlane",&Module::makePlane,
455
            "makePlane(length,width,[pnt,dirZ,dirX]) -- Make a plane\n"
456
            "By default pnt=Vector(0,0,0) and dirZ=Vector(0,0,1), dirX is ignored in this case"
457
        );
458
        add_varargs_method("makeBox",&Module::makeBox,
459
            "makeBox(length,width,height,[pnt,dir]) -- Make a box located\n"
460
            "in pnt with the dimensions (length,width,height)\n"
461
            "By default pnt=Vector(0,0,0) and dir=Vector(0,0,1)"
462
        );
463
        add_varargs_method("makeWedge",&Module::makeWedge,
464
            "makeWedge(xmin, ymin, zmin, z2min, x2min,\n"
465
            "xmax, ymax, zmax, z2max, x2max,[pnt,dir])\n"
466
            " -- Make a wedge located in pnt\n"
467
            "By default pnt=Vector(0,0,0) and dir=Vector(0,0,1)"
468
        );
469
        add_varargs_method("makeLine",&Module::makeLine,
470
            "makeLine(startpnt,endpnt) -- Make a line between two points\n"
471
            "\n"
472
            "Args:\n"
473
            "    startpnt (Vector or tuple): Vector or 3 element tuple \n"
474
            "        containing the x,y and z coordinates of the start point,\n"
475
            "        i.e. (x1,y1,z1).\n"
476
            "    endpnt (Vector or tuple): Vector or 3 element tuple \n"
477
            "        containing the x,y and z coordinates of the start point,\n"
478
            "        i.e. (x1,y1,z1).\n"
479
            "\n"
480
            "Returns:\n"
481
            "    Edge: Part.Edge object\n"
482
        );
483
        add_varargs_method("makePolygon",&Module::makePolygon,
484
            "makePolygon(pntslist) -- Make a polygon from a list of points\n"
485
            "\n"
486
            "Args:\n"
487
            "    pntslist (list(Vector)): list of Vectors representing the \n"
488
            "        points of the polygon.\n"
489
            "\n"
490
            "Returns:\n"
491
            "    Wire: Part.Wire object. If the last point in the list is \n"
492
            "        not the same as the first point, the Wire will not be \n"
493
            "        closed and cannot be used to create a face.\n"
494
        );
495
        add_varargs_method("makeCircle",&Module::makeCircle,
496
            "makeCircle(radius,[pnt,dir,angle1,angle2]) -- Make a circle with a given radius\n"
497
            "By default pnt=Vector(0,0,0), dir=Vector(0,0,1), angle1=0 and angle2=360"
498
        );
499
        add_varargs_method("makeSphere",&Module::makeSphere,
500
            "makeSphere(radius,[pnt, dir, angle1,angle2,angle3]) -- Make a sphere with a given radius\n"
501
            "By default pnt=Vector(0,0,0), dir=Vector(0,0,1), angle1=0, angle2=90 and angle3=360"
502
        );
503
        add_varargs_method("makeCylinder",&Module::makeCylinder,
504
            "makeCylinder(radius,height,[pnt,dir,angle]) -- Make a cylinder with a given radius and height\n"
505
            "By default pnt=Vector(0,0,0),dir=Vector(0,0,1) and angle=360"
506
        );
507
        add_varargs_method("makeCone",&Module::makeCone,
508
            "makeCone(radius1,radius2,height,[pnt,dir,angle]) -- Make a cone with given radii and height\n"
509
            "By default pnt=Vector(0,0,0), dir=Vector(0,0,1) and angle=360"
510
        );
511
        add_varargs_method("makeTorus",&Module::makeTorus,
512
            "makeTorus(radius1,radius2,[pnt,dir,angle1,angle2,angle]) -- Make a torus with a given radii and angles\n"
513
            "By default pnt=Vector(0,0,0),dir=Vector(0,0,1),angle1=0,angle1=360 and angle=360"
514
        );
515
        add_varargs_method("makeHelix",&Module::makeHelix,
516
            "makeHelix(pitch,height,radius,[angle]) -- Make a helix with a given pitch, height and radius\n"
517
            "By default a cylindrical surface is used to create the helix. If the fourth parameter is set\n"
518
            "(the apex given in degree) a conical surface is used instead"
519
        );
520
        add_varargs_method("makeLongHelix",&Module::makeLongHelix,
521
            "makeLongHelix(pitch,height,radius,[angle],[hand]) -- Make a (multi-edge) helix with a given pitch, height and radius\n"
522
            "By default a cylindrical surface is used to create the helix. If the fourth parameter is set\n"
523
            "(the apex given in degree) a conical surface is used instead."
524
        );
525
        add_varargs_method("makeThread",&Module::makeThread,
526
            "makeThread(pitch,depth,height,radius) -- Make a thread with a given pitch, depth, height and radius"
527
        );
528
        add_varargs_method("makeRevolution",&Module::makeRevolution,
529
            "makeRevolution(Curve or Edge,[vmin,vmax,angle,pnt,dir,shapetype]) -- Make a revolved shape\n"
530
            "by rotating the curve or a portion of it around an axis given by (pnt,dir).\n"
531
            "By default vmin/vmax=bounds of the curve, angle=360, pnt=Vector(0,0,0),\n"
532
            "dir=Vector(0,0,1) and shapetype=Part.Solid"
533
        );
534
        add_keyword_method("makeRuledSurface",&Module::makeRuledSurface,
535
            "makeRuledSurface(Edge|Wire,Edge|Wire) -- Make a ruled surface\n"
536
            "Create a ruled surface out of two edges or wires. If wires are used then"
537
            "these must have the same number of edges."
538
        );
539
        add_keyword_method("makeShellFromWires",&Module::makeShellFromWires,
540
            "makeShellFromWires(Wires) -- Make a shell from wires.\n"
541
            "The wires must have the same number of edges."
542
        );
543
        add_keyword_method("makeLoft",&Module::makeLoft,
544
                           "makeLoft(list of wires,[solid=False,ruled=False,closed=False,maxDegree=5]) -- Create a loft shape."
545
        );
546
        add_varargs_method("makeTube",&Module::makeTube,
547
            "makeTube(edge,radius,[continuity,max degree,max segments]) -- Create a tube.\n"
548
            "continuity is a string which must be 'C0','C1','C2','C3','CN','G1' or 'G1',"
549
        );
550
        add_varargs_method("makeSweepSurface",&Module::makeSweepSurface,
551
            "makeSweepSurface(edge(path),edge(profile),[float]) -- Create a profile along a path."
552
        );
553
        add_varargs_method("makeWireString",&Module::makeWireString,
554
            "makeWireString(string,fontdir,fontfile,height,[track]) -- Make list of wires in the form of a string's characters."
555
        );
556
        add_varargs_method("makeSplitShape",&Module::makeSplitShape,
557
            "makeSplitShape(shape, list of shape pairs,[check Interior=True]) -> two lists of shapes.\n"
558
            "The following shape pairs are supported:\n"
559
            "* Wire, Face\n"
560
            "* Edge, Face\n"
561
            "* Compound, Face\n"
562
            "* Edge, Edge\n"
563
            "* The face must be part of the specified shape and the edge, wire or compound must\n"
564
            "lie on the face.\n"
565
            "Output:\n"
566
            "The first list contains the faces that are the left of the projected wires.\n"
567
            "The second list contains the left part on the shape.\n\n"
568
            "Example:\n"
569
            "face = ...\n"
570
            "edges = ...\n"
571
            "split = [(edges[0],face),(edges[1],face)]\n"
572
            "r = Part.makeSplitShape(face, split)\n"
573
            "Part.show(r[0][0])\n"
574
            "Part.show(r[1][0])\n"
575
        );
576
        add_varargs_method("exportUnits",&Module::exportUnits,
577
            "exportUnits([string=MM|M|INCH|FT|MI|KM|MIL|UM|CM|UIN]) -- Set units for exporting STEP/IGES files and returns the units."
578
        );
579
        add_varargs_method("setStaticValue",&Module::setStaticValue,
580
            "setStaticValue(string,string|int|float) -- Set a name to a value The value can be a string, int or float."
581
        );
582
        add_varargs_method("cast_to_shape",&Module::cast_to_shape,
583
            "cast_to_shape(shape) -- Cast to the actual shape type"
584
        );
585
        add_varargs_method("getSortedClusters",&Module::getSortedClusters,
586
            "getSortedClusters(list of edges) -- Helper method to sort and cluster a variety of edges"
587
        );
588
        add_varargs_method("__sortEdges__",&Module::sortEdges,
589
            "__sortEdges__(list of edges) -- list of edges\n"
590
            "Helper method to sort an unsorted list of edges so that afterwards\n"
591
            "the start and end vertex of two consecutive edges are geometrically coincident.\n"
592
            "It returns a single list of edges and the algorithm stops after the first set of\n"
593
            "connected edges which means that the output list can be smaller than the input list.\n"
594
            "The sorted list can be used to create a Wire."
595
        );
596
        add_varargs_method("sortEdges",&Module::sortEdges2,
597
            "sortEdges(list of edges, [tol3d]) -- list of lists of edges\n"
598
            "It does basically the same as __sortEdges__ but sorts all input edges and thus returns\n"
599
            "a list of lists of edges\n"
600
            "optional 3D tolerance defaults to Precision::Confusion"
601
        );
602
        add_varargs_method("__toPythonOCC__",&Module::toPythonOCC,
603
            "__toPythonOCC__(shape) -- Helper method to convert an internal shape to pythonocc shape"
604
        );
605
        add_varargs_method("__fromPythonOCC__",&Module::fromPythonOCC,
606
            "__fromPythonOCC__(occ) -- Helper method to convert a pythonocc shape to an internal shape"
607
        );
608
        add_varargs_method("clearShapeCache",&Module::clearShapeCache,
609
            "clearShapeCache() -- Clears internal shape cache"
610
        );
611
        add_keyword_method("getShape",&Module::getShape,
612
            "getShape(obj,subname=None,mat=None,needSubElement=False,transform=True,retType=0):\n"
613
            "Obtain the TopoShape of a given object with SubName reference\n\n"
614
            "* obj: the input object\n"
615
            "* subname: dot separated sub-object reference\n"
616
            "* mat: the current transformation matrix\n"
617
            "* needSubElement: if False, ignore the sub-element (e.g. Face1, Edge1) reference in 'subname'\n"
618
            "* transform: if False, then skip obj's transformation. Use this if mat already include obj's\n"
619
            "             transformation matrix\n"
620
            "* retType: 0: return TopoShape,\n"
621
            "           1: return (shape,mat,subObj), where subObj is the object referenced in 'subname',\n"
622
            "              and 'mat' is the accumulated transformation matrix of that sub-object.\n"
623
            "           2: same as 1, but make sure 'subObj' is resolved if it is a link.\n"
624
            "* refine: refine the returned shape"
625
        );
626
        add_varargs_method("splitSubname",&Module::splitSubname,
627
            "splitSubname(subname) -> list(sub,mapped,subElement)\n"
628
            "Split the given subname into a list\n\n"
629
            "sub: subname without any sub-element reference\n"
630
            "mapped: mapped element name, or '' if none\n"
631
            "subElement: old style element name, or '' if none"
632
        );
633
        add_varargs_method("joinSubname",&Module::joinSubname,
634
            "joinSubname(sub,mapped,subElement) -> subname\n"
635
        );
636
        initialize("This is a module working with shapes."); // register with Python
637

638
        PyModule_AddObject(m_module, "BRepFeat", brepFeat.module().ptr());
639
        PyModule_AddObject(m_module, "BRepOffsetAPI", brepOffsetApi.module().ptr());
640
        PyModule_AddObject(m_module, "Geom2d", geom2d.module().ptr());
641
        PyModule_AddObject(m_module, "GeomPlate", geomPlate.module().ptr());
642
        PyModule_AddObject(m_module, "HLRBRep", HLRBRep.module().ptr());
643
        PyModule_AddObject(m_module, "ShapeFix", shapeFix.module().ptr());
644
        PyModule_AddObject(m_module, "ShapeUpgrade", shapeUpgrade.module().ptr());
645
        PyModule_AddObject(m_module, "ChFi2d", chFi2d.module().ptr());
646
    }
647

648
private:
649
    Py::Object invoke_method_keyword( void *method_def,
650
            const Py::Tuple &args, const Py::Dict &keywords ) override
651
    {
652
        try {
653
            return Py::ExtensionModule<Module>::invoke_method_keyword(method_def, args, keywords);
654
        }
655
        catch (const Standard_Failure &e) {
656
            std::string str;
657
            Standard_CString msg = e.GetMessageString();
658
            str += typeid(e).name();
659
            str += " ";
660
            if (msg) {str += msg;}
661
            else     {str += "No OCCT Exception Message";}
662
            Base::Console().Error("%s\n", str.c_str());
663
            throw Py::Exception(Part::PartExceptionOCCError, str);
664
        }
665
        catch (const Base::Exception &e) {
666
            std::string str;
667
            str += "FreeCAD exception thrown (";
668
            str += e.what();
669
            str += ")";
670
            e.ReportException();
671
            throw Py::RuntimeError(str);
672
        }
673
        catch (const std::exception &e) {
674
            std::string str;
675
            str += "C++ exception thrown (";
676
            str += e.what();
677
            str += ")";
678
            Base::Console().Error("%s\n", str.c_str());
679
            throw Py::RuntimeError(str);
680
        }
681
    }
682

683
    Py::Object invoke_method_varargs(void *method_def, const Py::Tuple &args) override
684
    {
685
        try {
686
            return Py::ExtensionModule<Module>::invoke_method_varargs(method_def, args);
687
        }
688
        catch (const Standard_Failure &e) {
689
            std::string str;
690
            Standard_CString msg = e.GetMessageString();
691
            str += typeid(e).name();
692
            str += " ";
693
            if (msg) {str += msg;}
694
            else     {str += "No OCCT Exception Message";}
695
            Base::Console().Error("%s\n", str.c_str());
696
            throw Py::Exception(Part::PartExceptionOCCError, str);
697
        }
698
        catch (const Base::Exception &e) {
699
            std::string str;
700
            str += "FreeCAD exception thrown (";
701
            str += e.what();
702
            str += ")";
703
            e.ReportException();
704
            throw Py::RuntimeError(str);
705
        }
706
        catch (const std::exception &e) {
707
            std::string str;
708
            str += "C++ exception thrown (";
709
            str += e.what();
710
            str += ")";
711
            Base::Console().Error("%s\n", str.c_str());
712
            throw Py::RuntimeError(str);
713
        }
714
    }
715

716
    Py::Object open(const Py::Tuple& args)
717
    {
718
        char* Name;
719
        if (!PyArg_ParseTuple(args.ptr(), "et","utf-8",&Name))
720
            throw Py::Exception();
721
        std::string EncodedName = std::string(Name);
722
        PyMem_Free(Name);
723

724
        //Base::Console().Log("Open in Part with %s",Name);
725
        Base::FileInfo file(EncodedName.c_str());
726

727
        // extract ending
728
        if (file.extension().empty())
729
            throw Py::RuntimeError("No file extension");
730

731
        if (file.hasExtension({"stp", "step"})) {
732
            // create new document and add Import feature
733
            App::Document *pcDoc = App::GetApplication().newDocument();
734
            ImportStepParts(pcDoc,EncodedName.c_str());
735

736
            pcDoc->recompute();
737
        }
738
        else if (file.hasExtension({"igs", "iges"})) {
739
            App::Document *pcDoc = App::GetApplication().newDocument();
740
            ImportIgesParts(pcDoc,EncodedName.c_str());
741
            pcDoc->recompute();
742
        }
743
        else {
744
            TopoShape shape;
745
            shape.read(EncodedName.c_str());
746

747
            // create new document set loaded shape
748
            App::Document *pcDoc = App::GetApplication().newDocument(file.fileNamePure().c_str());
749
            Part::Feature *object = static_cast<Part::Feature *>(pcDoc->addObject
750
                ("Part::Feature",file.fileNamePure().c_str()));
751
            object->Shape.setValue(shape);
752
            pcDoc->recompute();
753
        }
754

755
        return Py::None();
756
    }
757
    Py::Object insert(const Py::Tuple& args)
758
    {
759
        char* Name;
760
        const char* DocName;
761
        if (!PyArg_ParseTuple(args.ptr(), "ets","utf-8",&Name,&DocName))
762
            throw Py::Exception();
763

764
        std::string EncodedName = std::string(Name);
765
        PyMem_Free(Name);
766

767
        //Base::Console().Log("Insert in Part with %s",Name);
768
        Base::FileInfo file(EncodedName.c_str());
769

770
        // extract ending
771
        if (file.extension().empty())
772
            throw Py::RuntimeError("No file extension");
773

774
        App::Document *pcDoc = App::GetApplication().getDocument(DocName);
775
        if (!pcDoc) {
776
            pcDoc = App::GetApplication().newDocument(DocName);
777
        }
778

779
        if (file.hasExtension({"stp", "step"})) {
780
            ImportStepParts(pcDoc,EncodedName.c_str());
781

782
            pcDoc->recompute();
783
        }
784
        else if (file.hasExtension({"igs", "iges"})) {
785
            ImportIgesParts(pcDoc,EncodedName.c_str());
786
            pcDoc->recompute();
787
        }
788
        else {
789
            TopoShape shape;
790
            shape.read(EncodedName.c_str());
791

792
            Part::Feature *object = static_cast<Part::Feature *>(pcDoc->addObject
793
                ("Part::Feature",file.fileNamePure().c_str()));
794
            object->Shape.setValue(shape);
795
            pcDoc->recompute();
796
        }
797

798
        return Py::None();
799
    }
800
    Py::Object exporter(const Py::Tuple& args)
801
    {
802
        PyObject* object;
803
        char* Name;
804
        if (!PyArg_ParseTuple(args.ptr(), "Oet",&object,"utf-8",&Name))
805
            throw Py::Exception();
806

807
        std::string EncodedName = std::string(Name);
808
        PyMem_Free(Name);
809

810
        BRep_Builder builder;
811
        TopoDS_Compound comp;
812
        builder.MakeCompound(comp);
813

814
        Py::Sequence list(object);
815
        for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
816
            PyObject* item = (*it).ptr();
817
            if (PyObject_TypeCheck(item, &(App::DocumentObjectPy::Type))) {
818
                App::DocumentObject* obj = static_cast<App::DocumentObjectPy*>(item)->getDocumentObjectPtr();
819
                if (obj->isDerivedFrom<Part::Feature>()) {
820
                    Part::Feature* part = static_cast<Part::Feature*>(obj);
821
                    const TopoDS_Shape& shape = part->Shape.getValue();
822
                    if (!shape.IsNull())
823
                        builder.Add(comp, shape);
824
                }
825
                else {
826
                    Base::Console().Message("'%s' is not a shape, export will be ignored.\n", obj->Label.getValue());
827
                }
828
            }
829
        }
830

831
        TopoShape shape(comp);
832
        shape.write(EncodedName.c_str());
833

834
        return Py::None();
835
    }
836
    Py::Object read(const Py::Tuple& args)
837
    {
838
        char* Name;
839
        if (!PyArg_ParseTuple(args.ptr(), "et","utf-8",&Name))
840
            throw Py::Exception();
841

842
        std::string EncodedName = std::string(Name);
843
        PyMem_Free(Name);
844

845
        TopoShape* shape = new TopoShape();
846
        shape->read(EncodedName.c_str());
847
        return Py::asObject(new TopoShapePy(shape));
848
    }
849
    Py::Object show(const Py::Tuple& args)
850
    {
851
        PyObject *pcObj = nullptr;
852
        const char *name = "Shape";
853
        if (!PyArg_ParseTuple(args.ptr(), "O!|s", &(TopoShapePy::Type), &pcObj, &name))
854
            throw Py::Exception();
855

856
        App::Document *pcDoc = App::GetApplication().getActiveDocument();
857
        if (!pcDoc)
858
            pcDoc = App::GetApplication().newDocument();
859
        TopoShape shape;
860
        if (PyObject_TypeCheck(pcObj, &TopoShapePy::Type))
861
            shape = *static_cast<TopoShapePy *>(pcObj)->getTopoShapePtr();
862
        else if (PyObject_TypeCheck(pcObj, &GeometryPy::Type))
863
            shape = static_cast<GeometryPy *>(pcObj)->getGeometryPtr()->toShape();
864
        else if (PyObject_TypeCheck(pcObj, &App::DocumentObjectPy::Type)) {
865
            auto obj = static_cast<App::DocumentObjectPy *>(pcObj)->getDocumentObjectPtr();
866
            shape = Feature::getTopoShape(obj);
867
        } else {
868
            throw Py::TypeError("Expects argument of type DocumentObject, Shape, or Geometry");
869
        }
870
        Part::Feature *pcFeature = static_cast<Part::Feature*>(pcDoc->addObject("Part::Feature", name));
871
        // copy the data
872
        pcFeature->Shape.setValue(shape);
873
        pcFeature->purgeTouched();
874
        return Py::asObject(pcFeature->getPyObject());
875
    }
876
    Py::Object getFacets(const Py::Tuple& args)
877
    {
878
        PyObject *shape;
879
        Py::List list;
880
        if (!PyArg_ParseTuple(args.ptr(), "O", &shape))
881
            throw Py::Exception();
882
        auto theShape = static_cast<Part::TopoShapePy*>(shape)->getTopoShapePtr()->getShape();
883
        for (TopExp_Explorer ex(theShape, TopAbs_FACE); ex.More(); ex.Next()) {
884
            TopoDS_Face currentFace = TopoDS::Face(ex.Current());
885

886
            std::vector<gp_Pnt> points;
887
            std::vector<Poly_Triangle> facets;
888
            if (Tools::getTriangulation(currentFace, points, facets)) {
889
                for (const auto& it : facets) {
890
                    Standard_Integer n1,n2,n3;
891
                    it.Get(n1, n2, n3);
892

893
                    gp_Pnt p1 = points[n1];
894
                    gp_Pnt p2 = points[n2];
895
                    gp_Pnt p3 = points[n3];
896

897
                    // TODO: verify if tolerance should be hard coded
898
                    if (!p1.IsEqual(p2, 0.01) && !p2.IsEqual(p3, 0.01) && !p3.IsEqual(p1, 0.01)) {
899
                        PyObject *t1 = PyTuple_Pack(3, PyFloat_FromDouble(p1.X()), PyFloat_FromDouble(p1.Y()), PyFloat_FromDouble(p1.Z()));
900
                        PyObject *t2 = PyTuple_Pack(3, PyFloat_FromDouble(p2.X()), PyFloat_FromDouble(p2.Y()), PyFloat_FromDouble(p2.Z()));
901
                        PyObject *t3 = PyTuple_Pack(3, PyFloat_FromDouble(p3.X()), PyFloat_FromDouble(p3.Y()), PyFloat_FromDouble(p3.Z()));
902
                        list.append(Py::asObject(PyTuple_Pack(3, t1, t2, t3)));
903
                    }
904
                }
905
            }
906
        }
907
        return list;
908
    }
909
    Py::Object makeCompound(const Py::Tuple& args, const Py::Dict &kwds)
910
    {
911
        PyObject* pcObj;
912
        PyObject* force = Py_True;
913
        TopoShape::SingleShapeCompoundCreationPolicy
914
            policy;  // = TopoShape::SingleShapeCompoundCreationPolicy::forceCompound;
915
        PyObject* module = PyImport_ImportModule("PartEnums");
916
        PyObject* policyEnum =
917
            PyObject_GetAttrString(module, (char*)"SingleShapeCompoundCreationPolicy");
918
        const char* op = nullptr;
919
        const std::array<const char*, 4> kwd_list = {"shapes", "force", "op", nullptr};
920
        if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(),
921
                                                 kwds.ptr(),
922
                                                 "O|O!s",
923
                                                 kwd_list,
924
                                                 &pcObj,
925
                                                 policyEnum,
926
                                                 &force,
927
                                                 &op)) {
928
            throw Py::Exception();
929
        }
930

931
        policy = static_cast<TopoShape::SingleShapeCompoundCreationPolicy>(PyLong_AsLong(force));
932
        Py_DECREF(policyEnum);
933

934
        return shape2pyshape(Part::TopoShape().makeElementCompound(getPyShapes(pcObj), op, policy));
935
    }
936
    Py::Object makeShell(const Py::Tuple& args, const Py::Dict &kwds)
937
    {
938
        PyObject* obj;
939
        const char* op = nullptr;
940
        const std::array<const char*, 3> kwd_list = {"shapes", "op", nullptr};
941
        if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(),
942
                                                 kwds.ptr(),
943
                                                 "O|s",
944
                                                 kwd_list,
945
                                                 &obj,
946
                                                 &op)) {
947
            throw Py::Exception();
948
        }
949
        return shape2pyshape(
950
            Part::TopoShape().makeElementBoolean(Part::OpCodes::Shell, getPyShapes(obj), op));
951
    }
952
    Py::Object makeFace(const Py::Tuple& args, const Py::Dict &kwds)
953
    {
954
        PyObject* obj;
955
        const char* className = nullptr;
956
        const char* op = nullptr;
957
        const std::array<const char*, 4> kwd_list = {"shapes", "class_name", "op", nullptr};
958
        if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(),
959
                                                 kwds.ptr(),
960
                                                 "O|ss",
961
                                                 kwd_list,
962
                                                 &obj,
963
                                                 &className,
964
                                                 &op)) {
965
            throw Py::Exception();
966
        }
967
        return shape2pyshape(TopoShape().makeElementFace(getPyShapes(obj), op, className));
968
    }
969

970
    template<class F>
971
    void parseSequence(PyObject *pyObj, const char *err, F f)
972
    {
973
        if (pyObj != Py_None) {
974
            if (!PySequence_Check(pyObj))
975
                throw Py::TypeError(err);
976
            Py::Sequence seq(pyObj);
977
            for (Py::Sequence::iterator it = seq.begin(); it != seq.end(); ++it) {
978
                if (!PySequence_Check((*it).ptr()))
979
                    throw Py::TypeError(err);
980
                Py::Sequence tuple((*it).ptr());
981
                if (tuple.size() != 2)
982
                    throw Py::TypeError(err);
983
                auto iter = tuple.begin();
984
                if (!PyObject_TypeCheck((*iter).ptr(), &(Part::TopoShapePy::Type)))
985
                    throw Py::TypeError(err);
986
                const TopoDS_Shape& sh = static_cast<TopoShapePy*>((*iter).ptr())->getTopoShapePtr()->getShape();
987
                f(sh, (*iter).ptr(), err);
988
            }
989
        }
990
    }
991

992

993
    Py::Object makeFilledSurface(const Py::Tuple &args, const Py::Dict &kwds)
994
    {
995
        TopoShape::BRepFillingParams params;
996
        PyObject* obj = nullptr;
997
        PyObject* pySurface = Py_None;
998
        PyObject* supports = Py_None;
999
        PyObject* orders = Py_None;
1000
        PyObject* anisotropy = params.anisotropy ? Py_True : Py_False;
1001
        const char* op = nullptr;
1002
        const std::array<const char*, 16> kwd_list = {"shapes",
1003
                                                      "surface",
1004
                                                      "supports",
1005
                                                      "orders",
1006
                                                      "degree",
1007
                                                      "ptsOnCurve",
1008
                                                      "numIter",
1009
                                                      "anisotropy",
1010
                                                      "tol2d",
1011
                                                      "tol3d",
1012
                                                      "tolG1",
1013
                                                      "tolG2",
1014
                                                      "maxDegree",
1015
                                                      "maxSegments",
1016
                                                      "op",
1017
                                                      nullptr};
1018
        if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(),
1019
                                                 kwds.ptr(),
1020
                                                 "O|O!OOIIIOddddIIs",
1021
                                                 kwd_list,
1022
                                                 &obj,
1023
                                                 &pySurface,
1024
                                                 &orders,
1025
                                                 &params.degree,
1026
                                                 &params.ptsoncurve,
1027
                                                 &params.numiter,
1028
                                                 &anisotropy,
1029
                                                 &params.tol2d,
1030
                                                 &params.tol3d,
1031
                                                 &params.tolG1,
1032
                                                 &params.tolG2,
1033
                                                 &params.maxdeg,
1034
                                                 &params.maxseg,
1035
                                                 &op)) {
1036
            throw Py::Exception();
1037
        }
1038
        params.anisotropy = PyObject_IsTrue(anisotropy);
1039
        TopoShape surface;
1040
        if (pySurface != Py_None) {
1041
            surface = *static_cast<TopoShapePy*>(pySurface)->getTopoShapePtr();
1042
        }
1043
        parseSequence(supports,
1044
                      "Expects 'supports' to be a sequence of tuple(shape, shape)",
1045
                      [&](const TopoDS_Shape& s, PyObject* value, const char* err) {
1046
                          if (!PyObject_TypeCheck(value, &(Part::TopoShapePy::Type))) {
1047
                              throw Py::TypeError(err);
1048
                          }
1049
                          params.supports[s] =
1050
                              static_cast<TopoShapePy*>(value)->getTopoShapePtr()->getShape();
1051
                      });
1052
        parseSequence(orders,
1053
                      "Expects 'orders' to be a sequence of tuple(shape, PartEnums.Shape)",
1054
                      [&](const TopoDS_Shape& s, PyObject* value, const char* err) {
1055
                          if (!PyLong_Check(value)) {
1056
                              throw Py::ValueError(err);
1057
                          }
1058
                          int order = Py::Int(value);
1059
                          params.orders[s] = static_cast<TopoShape::Continuity>(order);
1060
                          return;
1061
                      });
1062
        auto shapes = getPyShapes(obj);
1063
        if (shapes.empty()) {
1064
            throw Py::ValueError("No input shape");
1065
        }
1066
        return shape2pyshape(
1067
            TopoShape(0, shapes.front().Hasher).makeElementFilledFace(shapes, params, op));
1068
    }
1069

1070
    Py::Object makeFilledFace(const Py::Tuple& args, const Py::Dict &kwds)
1071
    {
1072
        TopoShape::BRepFillingParams params;
1073
        PyObject* obj = nullptr;
1074
        PyObject* pySurface = Py_None;
1075
        PyObject* supports = Py_None;
1076
        PyObject* orders = Py_None;
1077
        PyObject* anisotropy = params.anisotropy ? Py_True : Py_False;
1078
        const char* op = nullptr;
1079
        const std::array<const char*, 16> kwd_list = {"shapes",
1080
                                                      "surface",
1081
                                                      "supports",
1082
                                                      "orders",
1083
                                                      "degree",
1084
                                                      "ptsOnCurve",
1085
                                                      "numIter",
1086
                                                      "anisotropy",
1087
                                                      "tol2d",
1088
                                                      "tol3d",
1089
                                                      "tolG1",
1090
                                                      "tolG2",
1091
                                                      "maxDegree",
1092
                                                      "maxSegments",
1093
                                                      "op",
1094
                                                      nullptr};
1095
        if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(),
1096
                                                 kwds.ptr(),
1097
                                                 "O|O!OOIIIOddddIIs",
1098
                                                 kwd_list,
1099
                                                 &obj,
1100
                                                 &pySurface,
1101
                                                 &orders,
1102
                                                 &params.degree,
1103
                                                 &params.ptsoncurve,
1104
                                                 &params.numiter,
1105
                                                 &anisotropy,
1106
                                                 &params.tol2d,
1107
                                                 &params.tol3d,
1108
                                                 &params.tolG1,
1109
                                                 &params.tolG2,
1110
                                                 &params.maxdeg,
1111
                                                 &params.maxseg,
1112
                                                 &op)) {
1113
            throw Py::Exception();
1114
        }
1115
        params.anisotropy = PyObject_IsTrue(anisotropy);
1116
        TopoShape surface;
1117
        if (pySurface != Py_None) {
1118
            surface = *static_cast<TopoShapePy*>(pySurface)->getTopoShapePtr();
1119
        }
1120
        parseSequence(supports,
1121
                      "Expects 'supports' to be a sequence of tuple(shape, shape)",
1122
                      [&](const TopoDS_Shape& s, PyObject* value, const char* err) {
1123
                          if (!PyObject_TypeCheck(value, &(Part::TopoShapePy::Type))) {
1124
                              throw Py::TypeError(err);
1125
                          }
1126
                          params.supports[s] =
1127
                              static_cast<TopoShapePy*>(value)->getTopoShapePtr()->getShape();
1128
                      });
1129
        parseSequence(orders,
1130
                      "Expects 'orders' to be a sequence of tuple(shape, PartEnums.Shape)",
1131
                      [&](const TopoDS_Shape& s, PyObject* value, const char* err) {
1132
                          if (!PyLong_Check(value)) {
1133
                              throw Py::ValueError(err);
1134
                          }
1135
                          int order = Py::Int(value);
1136
                          params.orders[s] = static_cast<TopoShape::Continuity>(order);
1137
                          return;
1138
                      });
1139
        auto shapes = getPyShapes(obj);
1140
        if (shapes.empty()) {
1141
            throw Py::ValueError("No input shape");
1142
        }
1143
        return shape2pyshape(
1144
            TopoShape(0, shapes.front().Hasher).makeElementFilledFace(shapes, params, op));
1145
    }
1146

1147
    Py::Object makeSolid(const Py::Tuple& args, const Py::Dict &kwds)
1148
    {
1149
        PyObject* obj;
1150
        const char* op = nullptr;
1151
        const std::array<const char*, 3> kwd_list = {"shape", "op", nullptr};
1152
        if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(),
1153
                                                 kwds.ptr(),
1154
                                                 "O!|s",
1155
                                                 kwd_list,
1156
                                                 &(TopoShapePy::Type),
1157
                                                 &obj,
1158
                                                 &op)) {
1159
            throw Py::Exception();
1160
        }
1161
        return shape2pyshape(
1162
            TopoShape().makeElementSolid(*static_cast<TopoShapePy*>(obj)->getTopoShapePtr(), op));
1163
    }
1164

1165
    Py::Object makePlane(const Py::Tuple& args)
1166
    {
1167
        double length, width;
1168
        PyObject *pPnt=nullptr, *pDirZ=nullptr, *pDirX=nullptr;
1169
        if (!PyArg_ParseTuple(args.ptr(), "dd|O!O!O!", &length, &width,
1170
                                                 &(Base::VectorPy::Type), &pPnt,
1171
                                                 &(Base::VectorPy::Type), &pDirZ,
1172
                                                 &(Base::VectorPy::Type), &pDirX))
1173
            throw Py::Exception();
1174

1175
        if (length < Precision::Confusion()) {
1176
            throw Py::ValueError("length of plane too small");
1177
        }
1178
        if (width < Precision::Confusion()) {
1179
            throw Py::ValueError("width of plane too small");
1180
        }
1181

1182
        try {
1183
            gp_Pnt p(0,0,0);
1184
            gp_Dir d(0,0,1);
1185
            if (pPnt) {
1186
                Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value();
1187
                p.SetCoord(pnt.x, pnt.y, pnt.z);
1188
            }
1189
            if (pDirZ) {
1190
                Base::Vector3d vec = static_cast<Base::VectorPy*>(pDirZ)->value();
1191
                d.SetCoord(vec.x, vec.y, vec.z);
1192
            }
1193
            Handle(Geom_Plane) aPlane;
1194
            if (pDirX) {
1195
                Base::Vector3d vec = static_cast<Base::VectorPy*>(pDirX)->value();
1196
                gp_Dir dx;
1197
                dx.SetCoord(vec.x, vec.y, vec.z);
1198
                aPlane = new Geom_Plane(gp_Ax3(p, d, dx));
1199
            }
1200
            else {
1201
                aPlane = new Geom_Plane(p, d);
1202
            }
1203

1204
            BRepBuilderAPI_MakeFace Face(aPlane, 0.0, length, 0.0, width, Precision::Confusion() );
1205
            return Py::asObject(new TopoShapeFacePy(new TopoShape((Face.Face()))));
1206
        }
1207
        catch (Standard_DomainError&) {
1208
            throw Py::Exception(PartExceptionOCCDomainError, "creation of plane failed");
1209
        }
1210
        catch (Standard_Failure&) {
1211
            throw Py::Exception(PartExceptionOCCError, "creation of plane failed");
1212
        }
1213
    }
1214
    Py::Object makeBox(const Py::Tuple& args)
1215
    {
1216
        double length, width, height;
1217
        PyObject *pPnt=nullptr, *pDir=nullptr;
1218
        if (!PyArg_ParseTuple(args.ptr(), "ddd|O!O!",
1219
            &length, &width, &height,
1220
            &(Base::VectorPy::Type), &pPnt,
1221
            &(Base::VectorPy::Type), &pDir))
1222
            throw Py::Exception();
1223

1224
        if (length < Precision::Confusion()) {
1225
            throw Py::ValueError("length of box too small");
1226
        }
1227
        if (width < Precision::Confusion()) {
1228
            throw Py::ValueError("width of box too small");
1229
        }
1230
        if (height < Precision::Confusion()) {
1231
            throw Py::ValueError("height of box too small");
1232
        }
1233

1234
        try {
1235
            gp_Pnt p(0,0,0);
1236
            gp_Dir d(0,0,1);
1237
            if (pPnt) {
1238
                Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value();
1239
                p.SetCoord(pnt.x, pnt.y, pnt.z);
1240
            }
1241
            if (pDir) {
1242
                Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value();
1243
                d.SetCoord(vec.x, vec.y, vec.z);
1244
            }
1245
            BRepPrimAPI_MakeBox mkBox(gp_Ax2(p,d), length, width, height);
1246
            TopoDS_Shape ResultShape = mkBox.Shape();
1247
            return Py::asObject(new TopoShapeSolidPy(new TopoShape(ResultShape)));
1248
        }
1249
        catch (Standard_DomainError&) {
1250
            throw Py::Exception(PartExceptionOCCDomainError, "creation of box failed");
1251
        }
1252
    }
1253
    Py::Object makeWedge(const Py::Tuple& args)
1254
    {
1255
        double xmin, ymin, zmin, z2min, x2min, xmax, ymax, zmax, z2max, x2max;
1256
        PyObject *pPnt=nullptr, *pDir=nullptr;
1257
        if (!PyArg_ParseTuple(args.ptr(), "dddddddddd|O!O!",
1258
            &xmin, &ymin, &zmin, &z2min, &x2min, &xmax, &ymax, &zmax, &z2max, &x2max,
1259
            &(Base::VectorPy::Type), &pPnt, &(Base::VectorPy::Type), &pDir))
1260
            throw Py::Exception();
1261

1262
        double dx = xmax-xmin;
1263
        double dy = ymax-ymin;
1264
        double dz = zmax-zmin;
1265
        double dz2 = z2max-z2min;
1266
        double dx2 = x2max-x2min;
1267
        if (dx < Precision::Confusion()) {
1268
            throw Py::ValueError("delta x of wedge too small");
1269
        }
1270
        if (dy < Precision::Confusion()) {
1271
            throw Py::ValueError("delta y of wedge too small");
1272
        }
1273
        if (dz < Precision::Confusion()) {
1274
            throw Py::ValueError("delta z of wedge too small");
1275
        }
1276
        if (dz2 < 0) {
1277
            throw Py::ValueError("delta z2 of wedge is negative");
1278
        }
1279
        if (dx2 < 0) {
1280
            throw Py::ValueError("delta x2 of wedge is negative");
1281
        }
1282

1283
        try {
1284
            gp_Pnt p(0,0,0);
1285
            gp_Dir d(0,0,1);
1286
            if (pPnt) {
1287
                Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value();
1288
                p.SetCoord(pnt.x, pnt.y, pnt.z);
1289
            }
1290
            if (pDir) {
1291
                Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value();
1292
                d.SetCoord(vec.x, vec.y, vec.z);
1293
            }
1294
            BRepPrim_Wedge mkWedge(gp_Ax2(p,d), xmin, ymin, zmin, z2min, x2min, xmax, ymax, zmax, z2max, x2max);
1295
            BRepBuilderAPI_MakeSolid mkSolid;
1296
            mkSolid.Add(mkWedge.Shell());
1297
            return Py::asObject(new TopoShapeSolidPy(new TopoShape(mkSolid.Solid())));
1298
        }
1299
        catch (Standard_DomainError&) {
1300
            throw Py::Exception(PartExceptionOCCDomainError, "creation of wedge failed");
1301
        }
1302
    }
1303
    Py::Object makeLine(const Py::Tuple& args)
1304
    {
1305
        PyObject *obj1, *obj2;
1306
        if (!PyArg_ParseTuple(args.ptr(), "OO", &obj1, &obj2))
1307
            throw Py::Exception();
1308

1309
        Base::Vector3d pnt1, pnt2;
1310
        if (PyObject_TypeCheck(obj1, &(Base::VectorPy::Type))) {
1311
            pnt1 = static_cast<Base::VectorPy*>(obj1)->value();
1312
        }
1313
        else if (PyObject_TypeCheck(obj1, &PyTuple_Type)) {
1314
            pnt1 = Base::getVectorFromTuple<double>(obj1);
1315
        }
1316
        else {
1317
            throw Py::TypeError("first argument must either be vector or tuple");
1318
        }
1319
        if (PyObject_TypeCheck(obj2, &(Base::VectorPy::Type))) {
1320
            pnt2 = static_cast<Base::VectorPy*>(obj2)->value();
1321
        }
1322
        else if (PyObject_TypeCheck(obj2, &PyTuple_Type)) {
1323
            pnt2 = Base::getVectorFromTuple<double>(obj2);
1324
        }
1325
        else {
1326
            throw Py::TypeError("second argument must either be vector or tuple");
1327
        }
1328

1329
        // Create directly the underlying line geometry
1330
        BRepBuilderAPI_MakeEdge makeEdge(gp_Pnt(pnt1.x, pnt1.y, pnt1.z),
1331
                                         gp_Pnt(pnt2.x, pnt2.y, pnt2.z));
1332

1333
        const char *error=nullptr;
1334
        switch (makeEdge.Error())
1335
        {
1336
        case BRepBuilderAPI_EdgeDone:
1337
            break; // ok
1338
        case BRepBuilderAPI_PointProjectionFailed:
1339
            error = "Point projection failed";
1340
            break;
1341
        case BRepBuilderAPI_ParameterOutOfRange:
1342
            error = "Parameter out of range";
1343
            break;
1344
        case BRepBuilderAPI_DifferentPointsOnClosedCurve:
1345
            error = "Different points on closed curve";
1346
            break;
1347
        case BRepBuilderAPI_PointWithInfiniteParameter:
1348
            error = "Point with infinite parameter";
1349
            break;
1350
        case BRepBuilderAPI_DifferentsPointAndParameter:
1351
            error = "Different point and parameter";
1352
            break;
1353
        case BRepBuilderAPI_LineThroughIdenticPoints:
1354
            error = "Line through identical points";
1355
            break;
1356
        }
1357
        // Error
1358
        if (error) {
1359
            throw Py::Exception(PartExceptionOCCError, error);
1360
        }
1361

1362
        TopoDS_Edge edge = makeEdge.Edge();
1363
        return Py::asObject(new TopoShapeEdgePy(new TopoShape(edge)));
1364
    }
1365
    Py::Object makePolygon(const Py::Tuple& args)
1366
    {
1367
        PyObject *pcObj;
1368
        PyObject *pclosed=Py_False;
1369
        if (!PyArg_ParseTuple(args.ptr(), "O|O!", &pcObj, &(PyBool_Type), &pclosed))
1370
            throw Py::Exception();
1371

1372
        BRepBuilderAPI_MakePolygon mkPoly;
1373
        try {
1374
            Py::Sequence list(pcObj);
1375
            for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
1376
                if (PyObject_TypeCheck((*it).ptr(), &(Base::VectorPy::Type))) {
1377
                    Base::Vector3d v = static_cast<Base::VectorPy*>((*it).ptr())->value();
1378
                    mkPoly.Add(gp_Pnt(v.x,v.y,v.z));
1379
                }
1380
                else if (PyObject_TypeCheck((*it).ptr(), &PyTuple_Type)) {
1381
                    Base::Vector3d v = Base::getVectorFromTuple<double>((*it).ptr());
1382
                    mkPoly.Add(gp_Pnt(v.x,v.y,v.z));
1383
                }
1384
            }
1385

1386
            if (!mkPoly.IsDone())
1387
                Standard_Failure::Raise("Cannot create polygon because less than two vertices are given");
1388

1389
            // if the polygon should be closed
1390
            if (Base::asBoolean(pclosed)) {
1391
                if (!mkPoly.FirstVertex().IsSame(mkPoly.LastVertex())) {
1392
                    mkPoly.Add(mkPoly.FirstVertex());
1393
                }
1394
            }
1395

1396
            return Py::asObject(new TopoShapeWirePy(new TopoShape(mkPoly.Wire())));
1397
        }
1398
        catch (Standard_Failure& e) {
1399
            throw Py::Exception(PartExceptionOCCError, e.GetMessageString());
1400
        }
1401
    }
1402
    Py::Object makeCircle(const Py::Tuple& args)
1403
    {
1404
        double radius, angle1=0.0, angle2=360;
1405
        PyObject *pPnt=nullptr, *pDir=nullptr;
1406
        if (!PyArg_ParseTuple(args.ptr(), "d|O!O!dd",
1407
            &radius,
1408
            &(Base::VectorPy::Type), &pPnt,
1409
            &(Base::VectorPy::Type), &pDir,
1410
            &angle1, &angle2))
1411
            throw Py::Exception();
1412

1413
        try {
1414
            gp_Pnt loc(0,0,0);
1415
            gp_Dir dir(0,0,1);
1416
            if (pPnt) {
1417
                Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value();
1418
                loc.SetCoord(pnt.x, pnt.y, pnt.z);
1419
            }
1420
            if (pDir) {
1421
                Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value();
1422
                dir.SetCoord(vec.x, vec.y, vec.z);
1423
            }
1424
            gp_Ax1 axis(loc, dir);
1425
            gp_Circ circle;
1426
            circle.SetAxis(axis);
1427
            circle.SetRadius(radius);
1428

1429
            Handle(Geom_Circle) hCircle = new Geom_Circle (circle);
1430
            BRepBuilderAPI_MakeEdge aMakeEdge(hCircle, angle1*(M_PI/180), angle2*(M_PI/180));
1431
            TopoDS_Edge edge = aMakeEdge.Edge();
1432
            return Py::asObject(new TopoShapeEdgePy(new TopoShape(edge)));
1433
        }
1434
        catch (Standard_Failure&) {
1435
            throw Py::Exception(PartExceptionOCCError, "creation of circle failed");
1436
        }
1437
    }
1438
    Py::Object makeSphere(const Py::Tuple& args)
1439
    {
1440
        double radius, angle1=-90, angle2=90, angle3=360;
1441
        PyObject *pPnt=nullptr, *pDir=nullptr;
1442
        if (!PyArg_ParseTuple(args.ptr(), "d|O!O!ddd",
1443
            &radius,
1444
            &(Base::VectorPy::Type), &pPnt,
1445
            &(Base::VectorPy::Type), &pDir,
1446
            &angle1, &angle2, &angle3))
1447
            throw Py::Exception();
1448

1449
        try {
1450
            gp_Pnt p(0,0,0);
1451
            gp_Dir d(0,0,1);
1452
            if (pPnt) {
1453
                Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value();
1454
                p.SetCoord(pnt.x, pnt.y, pnt.z);
1455
            }
1456
            if (pDir) {
1457
                Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value();
1458
                d.SetCoord(vec.x, vec.y, vec.z);
1459
            }
1460
            BRepPrimAPI_MakeSphere mkSphere(gp_Ax2(p,d), radius, angle1*(M_PI/180), angle2*(M_PI/180), angle3*(M_PI/180));
1461
            TopoDS_Shape shape = mkSphere.Shape();
1462
            return Py::asObject(new TopoShapeSolidPy(new TopoShape(shape)));
1463
        }
1464
        catch (Standard_DomainError&) {
1465
            throw Py::Exception(PartExceptionOCCDomainError, "creation of sphere failed");
1466
        }
1467
    }
1468
    Py::Object makeCylinder(const Py::Tuple& args)
1469
    {
1470
        double radius, height, angle=360;
1471
        PyObject *pPnt=nullptr, *pDir=nullptr;
1472
        if (!PyArg_ParseTuple(args.ptr(), "dd|O!O!d",
1473
            &radius, &height,
1474
            &(Base::VectorPy::Type), &pPnt,
1475
            &(Base::VectorPy::Type), &pDir,
1476
            &angle))
1477
            throw Py::Exception();
1478

1479
        try {
1480
            gp_Pnt p(0,0,0);
1481
            gp_Dir d(0,0,1);
1482
            if (pPnt) {
1483
                Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value();
1484
                p.SetCoord(pnt.x, pnt.y, pnt.z);
1485
            }
1486
            if (pDir) {
1487
                Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value();
1488
                d.SetCoord(vec.x, vec.y, vec.z);
1489
            }
1490
            BRepPrimAPI_MakeCylinder mkCyl(gp_Ax2(p,d),radius, height, angle*(M_PI/180));
1491
            TopoDS_Shape shape = mkCyl.Shape();
1492
            return Py::asObject(new TopoShapeSolidPy(new TopoShape(shape)));
1493
        }
1494
        catch (Standard_DomainError&) {
1495
            throw Py::Exception(PartExceptionOCCDomainError, "creation of cylinder failed");
1496
        }
1497
    }
1498
    Py::Object makeCone(const Py::Tuple& args)
1499
    {
1500
        double radius1, radius2,  height, angle=360;
1501
        PyObject *pPnt=nullptr, *pDir=nullptr;
1502
        if (!PyArg_ParseTuple(args.ptr(), "ddd|O!O!d",
1503
            &radius1, &radius2, &height,
1504
            &(Base::VectorPy::Type), &pPnt,
1505
            &(Base::VectorPy::Type), &pDir,
1506
            &angle))
1507
            throw Py::Exception();
1508

1509
        try {
1510
            gp_Pnt p(0,0,0);
1511
            gp_Dir d(0,0,1);
1512
            if (pPnt) {
1513
                Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value();
1514
                p.SetCoord(pnt.x, pnt.y, pnt.z);
1515
            }
1516
            if (pDir) {
1517
                Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value();
1518
                d.SetCoord(vec.x, vec.y, vec.z);
1519
            }
1520
            BRepPrimAPI_MakeCone mkCone(gp_Ax2(p,d),radius1, radius2, height, angle*(M_PI/180));
1521
            TopoDS_Shape shape = mkCone.Shape();
1522
            return Py::asObject(new TopoShapeSolidPy(new TopoShape(shape)));
1523
        }
1524
        catch (Standard_DomainError&) {
1525
            throw Py::Exception(PartExceptionOCCDomainError, "creation of cone failed");
1526
        }
1527
    }
1528
    Py::Object makeTorus(const Py::Tuple& args)
1529
    {
1530
        double radius1, radius2, angle1=0.0, angle2=360, angle=360;
1531
        PyObject *pPnt=nullptr, *pDir=nullptr;
1532
        if (!PyArg_ParseTuple(args.ptr(), "dd|O!O!ddd",
1533
            &radius1, &radius2,
1534
            &(Base::VectorPy::Type), &pPnt,
1535
            &(Base::VectorPy::Type), &pDir,
1536
            &angle1, &angle2, &angle))
1537
            throw Py::Exception();
1538

1539
        try {
1540
            gp_Pnt p(0,0,0);
1541
            gp_Dir d(0,0,1);
1542
            if (pPnt) {
1543
                Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value();
1544
                p.SetCoord(pnt.x, pnt.y, pnt.z);
1545
            }
1546
            if (pDir) {
1547
                Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value();
1548
                d.SetCoord(vec.x, vec.y, vec.z);
1549
            }
1550
            BRepPrimAPI_MakeTorus mkTorus(gp_Ax2(p,d), radius1, radius2, angle1*(M_PI/180), angle2*(M_PI/180), angle*(M_PI/180));
1551
            const TopoDS_Shape& shape = mkTorus.Shape();
1552
            return Py::asObject(new TopoShapeSolidPy(new TopoShape(shape)));
1553
        }
1554
        catch (Standard_DomainError&) {
1555
            throw Py::Exception(PartExceptionOCCDomainError, "creation of torus failed");
1556
        }
1557
    }
1558
    Py::Object makeHelix(const Py::Tuple& args)
1559
    {
1560
        double pitch, height, radius, angle=-1.0;
1561
        PyObject *pleft=Py_False;
1562
        PyObject *pvertHeight=Py_False;
1563
        if (!PyArg_ParseTuple(args.ptr(), "ddd|dO!O!",
1564
            &pitch, &height, &radius, &angle,
1565
            &(PyBool_Type), &pleft,
1566
            &(PyBool_Type), &pvertHeight))
1567
            throw Py::Exception();
1568

1569
        try {
1570
            TopoShape helix;
1571
            Standard_Boolean anIsLeft = Base::asBoolean(pleft);
1572
            Standard_Boolean anIsVertHeight = Base::asBoolean(pvertHeight);
1573
            TopoDS_Shape wire = helix.makeHelix(pitch, height, radius, angle,
1574
                                                anIsLeft, anIsVertHeight);
1575
            return Py::asObject(new TopoShapeWirePy(new TopoShape(wire)));
1576
        }
1577
        catch (Standard_Failure& e) {
1578
            throw Py::Exception(PartExceptionOCCError, e.GetMessageString());
1579
        }
1580
    }
1581
    Py::Object makeLongHelix(const Py::Tuple& args)
1582
    {
1583
        double pitch, height, radius, angle=-1.0;
1584
        PyObject *pleft=Py_False;
1585
        if (!PyArg_ParseTuple(args.ptr(), "ddd|dO!", &pitch, &height, &radius, &angle,
1586
                                               &(PyBool_Type), &pleft)) {
1587
            throw Py::RuntimeError("Part.makeLongHelix fails on parms");
1588
        }
1589

1590
        try {
1591
            TopoShape helix;
1592
            Standard_Boolean anIsLeft = Base::asBoolean(pleft);
1593
            TopoDS_Shape wire = helix.makeLongHelix(pitch, height, radius, angle, anIsLeft);
1594
            return Py::asObject(new TopoShapeWirePy(new TopoShape(wire)));
1595
        }
1596
        catch (Standard_Failure& e) {
1597
            throw Py::Exception(PartExceptionOCCError, e.GetMessageString());
1598
        }
1599
    }
1600
    Py::Object makeThread(const Py::Tuple& args)
1601
    {
1602
        double pitch, depth, height, radius;
1603
        if (!PyArg_ParseTuple(args.ptr(), "dddd", &pitch, &depth, &height, &radius))
1604
            throw Py::Exception();
1605

1606
        try {
1607
            TopoShape helix;
1608
            TopoDS_Shape wire = helix.makeThread(pitch, depth, height, radius);
1609
            return Py::asObject(new TopoShapeWirePy(new TopoShape(wire)));
1610
        }
1611
        catch (Standard_Failure& e) {
1612
            throw Py::Exception(PartExceptionOCCError, e.GetMessageString());
1613
        }
1614
    }
1615
    Py::Object makeRevolution(const Py::Tuple& args)
1616
    {
1617
        double vmin = DBL_MAX, vmax=-DBL_MAX;
1618
        double angle=360;
1619
        PyObject *pPnt=nullptr, *pDir=nullptr, *pCrv;
1620
        Handle(Geom_Curve) curve;
1621
        PyObject* defaultType = Base::getTypeAsObject(&Part::TopoShapeSolidPy::Type);
1622
        PyObject* type = defaultType;
1623

1624
        do {
1625
            if (PyArg_ParseTuple(args.ptr(), "O!|dddO!O!O!", &(GeometryPy::Type), &pCrv,
1626
                                                       &vmin, &vmax, &angle,
1627
                                                       &(Base::VectorPy::Type), &pPnt,
1628
                                                       &(Base::VectorPy::Type), &pDir,
1629
                                                       &(PyType_Type), &type)) {
1630
                GeometryPy* pcGeo = static_cast<GeometryPy*>(pCrv);
1631
                curve = Handle(Geom_Curve)::DownCast
1632
                    (pcGeo->getGeometryPtr()->handle());
1633
                if (curve.IsNull()) {
1634
                    throw Py::Exception(PyExc_TypeError, "geometry is not a curve");
1635
                }
1636
                if (vmin == DBL_MAX)
1637
                    vmin = curve->FirstParameter();
1638

1639
                if (vmax == -DBL_MAX)
1640
                    vmax = curve->LastParameter();
1641
                break;
1642
            }
1643

1644
            PyErr_Clear();
1645
            if (PyArg_ParseTuple(args.ptr(), "O!|dddO!O!O!", &(TopoShapePy::Type), &pCrv,
1646
                                                       &vmin, &vmax, &angle,
1647
                                                       &(Base::VectorPy::Type), &pPnt,
1648
                                                       &(Base::VectorPy::Type), &pDir,
1649
                                                       &(PyType_Type), &type)) {
1650
                const TopoDS_Shape& shape = static_cast<TopoShapePy*>(pCrv)->getTopoShapePtr()->getShape();
1651
                if (shape.IsNull()) {
1652
                    throw Py::Exception(PartExceptionOCCError, "shape is empty");
1653
                }
1654

1655
                if (shape.ShapeType() != TopAbs_EDGE) {
1656
                    throw Py::Exception(PartExceptionOCCError, "shape is not an edge");
1657
                }
1658

1659
                const TopoDS_Edge& edge = TopoDS::Edge(shape);
1660
                BRepAdaptor_Curve adapt(edge);
1661

1662
                const Handle(Geom_Curve)& hCurve = adapt.Curve().Curve();
1663
                // Apply placement of the shape to the curve
1664
                TopLoc_Location loc = edge.Location();
1665
                curve = Handle(Geom_Curve)::DownCast(hCurve->Transformed(loc.Transformation()));
1666
                if (curve.IsNull()) {
1667
                    throw Py::Exception(PartExceptionOCCError, "invalid curve in edge");
1668
                }
1669

1670
                if (vmin == DBL_MAX)
1671
                    vmin = adapt.FirstParameter();
1672
                if (vmax == -DBL_MAX)
1673
                    vmax = adapt.LastParameter();
1674
                break;
1675
            }
1676

1677
            // invalid arguments
1678
            throw Py::TypeError("Expected arguments are:\n"
1679
                                "Curve or Edge, [float, float, float, Vector, Vector, ShapeType]");
1680
        }
1681
        while(false);
1682

1683
        try {
1684
            gp_Pnt p(0,0,0);
1685
            gp_Dir d(0,0,1);
1686
            if (pPnt) {
1687
                Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value();
1688
                p.SetCoord(pnt.x, pnt.y, pnt.z);
1689
            }
1690
            if (pDir) {
1691
                Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value();
1692
                d.SetCoord(vec.x, vec.y, vec.z);
1693
            }
1694

1695
            PyObject* shellType = Base::getTypeAsObject(&Part::TopoShapeShellPy::Type);
1696
            PyObject* faceType = Base::getTypeAsObject(&Part::TopoShapeFacePy::Type);
1697

1698
            BRepPrimAPI_MakeRevolution mkRev(gp_Ax2(p,d),curve, vmin, vmax, angle*(M_PI/180));
1699
            if (type == defaultType) {
1700
                TopoDS_Shape shape = mkRev.Solid();
1701
                return Py::asObject(new TopoShapeSolidPy(new TopoShape(shape)));
1702
            }
1703
            else if (type == shellType) {
1704
                TopoDS_Shape shape = mkRev.Shell();
1705
                return Py::asObject(new TopoShapeShellPy(new TopoShape(shape)));
1706
            }
1707
            else if (type == faceType) {
1708
                TopoDS_Shape shape = mkRev.Face();
1709
                return Py::asObject(new TopoShapeFacePy(new TopoShape(shape)));
1710
            }
1711
            else {
1712
                TopoDS_Shape shape = mkRev.Shape();
1713
                return Py::asObject(new TopoShapePy(new TopoShape(shape)));
1714
            }
1715
        }
1716
        catch (Standard_DomainError&) {
1717
            throw Py::Exception(PartExceptionOCCDomainError, "creation of revolved shape failed");
1718
        }
1719
    }
1720

1721
    Py::Object makeRuledSurface(const Py::Tuple& args, const Py::Dict &kwds)
1722
    {
1723
        const char* op = nullptr;
1724
        int orientation = 0;
1725
        PyObject *sh1, *sh2;
1726
        const std::array<const char*, 5> kwd_list = {"path",
1727
                                                     "profile",
1728
                                                     "orientation",
1729
                                                     "op",
1730
                                                     nullptr};
1731
        if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(),
1732
                                                 kwds.ptr(),
1733
                                                 "O!O!|is",
1734
                                                 kwd_list,
1735
                                                 &(TopoShapePy::Type),
1736
                                                 &sh1,
1737
                                                 &(TopoShapePy::Type),
1738
                                                 &sh2,
1739
                                                 &orientation,
1740
                                                 &op)) {
1741
            throw Py::Exception();
1742
        }
1743

1744
        std::vector<TopoShape> shapes;
1745
        shapes.push_back(*static_cast<TopoShapePy*>(sh1)->getTopoShapePtr());
1746
        shapes.push_back(*static_cast<TopoShapePy*>(sh2)->getTopoShapePtr());
1747
        return shape2pyshape(TopoShape().makeElementRuledSurface(shapes, orientation, op));
1748
    }
1749

1750
    Py::Object makeShellFromWires(const Py::Tuple& args, const Py::Dict &kwds)
1751
    {
1752
        PyObject *pylist;
1753
        const char* op = nullptr;
1754
        const std::array<const char*, 3> kwd_list = {"shape", "op", nullptr};
1755
        if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(),
1756
                                                 kwds.ptr(),
1757
                                                 "O|s",
1758
                                                 kwd_list,
1759
                                                 &pylist,
1760
                                                 &op)) {
1761
            throw Py::Exception();
1762
        }
1763
        try {
1764
            return shape2pyshape(
1765
                TopoShape().makeElementShellFromWires(getPyShapes(pylist), /*silent*/ false, op));
1766
        }
1767
        catch (Standard_Failure&) {
1768
            throw Py::Exception(PartExceptionOCCError, "creation of shell failed");
1769
        }
1770
    }
1771

1772
    Py::Object makeTube(const Py::Tuple& args)
1773
    {
1774
        PyObject *pshape;
1775
        double radius;
1776
        double tolerance=0.001;
1777
        const char* scont = "C0";
1778
        int maxdegree = 3;
1779
        int maxsegment = 30;
1780

1781
        // Path + radius
1782
        if (!PyArg_ParseTuple(args.ptr(), "O!d|sii", &(TopoShapePy::Type), &pshape, &radius, &scont, &maxdegree, &maxsegment))
1783
            throw Py::Exception();
1784

1785
        std::string str_cont = scont;
1786
        int cont;
1787
        if (str_cont == "C0")
1788
            cont = (int)GeomAbs_C0;
1789
        else if (str_cont == "C1")
1790
            cont = (int)GeomAbs_C1;
1791
        else if (str_cont == "C2")
1792
            cont = (int)GeomAbs_C2;
1793
        else if (str_cont == "C3")
1794
            cont = (int)GeomAbs_C3;
1795
        else if (str_cont == "CN")
1796
            cont = (int)GeomAbs_CN;
1797
        else if (str_cont == "G1")
1798
            cont = (int)GeomAbs_G1;
1799
        else if (str_cont == "G2")
1800
            cont = (int)GeomAbs_G2;
1801
        else
1802
            cont = (int)GeomAbs_C0;
1803

1804
        try {
1805
            const TopoDS_Shape& path_shape = static_cast<TopoShapePy*>(pshape)->getTopoShapePtr()->getShape();
1806
            TopoShape myShape(path_shape);
1807
            TopoDS_Shape face = myShape.makeTube(radius, tolerance, cont, maxdegree, maxsegment);
1808
            return Py::asObject(new TopoShapeFacePy(new TopoShape(face)));
1809
        }
1810
        catch (Standard_Failure& e) {
1811
            throw Py::Exception(PartExceptionOCCError, e.GetMessageString());
1812
        }
1813
    }
1814
    Py::Object makeSweepSurface(const Py::Tuple& args)
1815
    {
1816
        PyObject *path, *profile;
1817
        double tolerance=0.001;
1818
        int fillMode = 0;
1819

1820
        // Path + profile
1821
        if (!PyArg_ParseTuple(args.ptr(), "O!O!|di", &(TopoShapePy::Type), &path,
1822
                                               &(TopoShapePy::Type), &profile,
1823
                                               &tolerance, &fillMode))
1824
            throw Py::Exception();
1825

1826
        try {
1827
            TopoShape mShape = *static_cast<TopoShapePy*>(path)->getTopoShapePtr();
1828
            // makeSweep uses GeomFill_Pipe which does not support shape
1829
            // history. So use makEPipeShell() as a replacement
1830
            return shape2pyshape(
1831
                TopoShape(0, mShape.Hasher)
1832
                    .makeElementPipeShell(
1833
                        {mShape, *static_cast<TopoShapePy*>(profile)->getTopoShapePtr()},
1834
                        Part::MakeSolid::noSolid,
1835
                        Standard_False,
1836
                        TransitionMode::Transformed,
1837
                        nullptr,
1838
                        tolerance));
1839
        }
1840
        catch (Standard_Failure& e) {
1841
            throw Py::Exception(PartExceptionOCCError, e.GetMessageString());
1842
        }
1843
    }
1844

1845
    Py::Object makeLoft(const Py::Tuple& args, const Py::Dict &kwds)
1846
    {
1847
        PyObject *pcObj;
1848
        PyObject *psolid=Py_False;
1849
        PyObject *pruled=Py_False;
1850
        PyObject *pclosed=Py_False;
1851
        int degMax = 5;
1852

1853
        const char* op = nullptr;
1854
        const std::array<const char*, 7> kwd_list =
1855
            {"shapes", "solid", "ruled", "closed", "max_degree", "op", nullptr};
1856
        if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(),
1857
                                                 kwds.ptr(),
1858
                                                 "O!|O!O!O!is",
1859
                                                 kwd_list,
1860
                                                 &(PyList_Type),
1861
                                                 &pcObj,
1862
                                                 &(PyBool_Type),
1863
                                                 &psolid,
1864
                                                 &(PyBool_Type),
1865
                                                 &pruled,
1866
                                                 &(PyBool_Type),
1867
                                                 &pclosed,
1868
                                                 &degMax,
1869
                                                 &op)) {
1870
            throw Py::Exception();
1871
        }
1872
        Standard_Boolean anIsSolid = PyObject_IsTrue(psolid) ? Standard_True : Standard_False;
1873
        Standard_Boolean anIsRuled = PyObject_IsTrue(pruled) ? Standard_True : Standard_False;
1874
        Standard_Boolean anIsClosed = PyObject_IsTrue(pclosed) ? Standard_True : Standard_False;
1875
        return shape2pyshape(TopoShape().makeElementLoft(
1876
            getPyShapes(pcObj),
1877
            anIsSolid ? Part::IsSolid::solid : Part::IsSolid::notSolid,
1878
            anIsRuled ? Part::IsRuled::ruled : Part::IsRuled::notRuled,
1879
            anIsClosed ? Part::IsClosed::closed : Part::IsClosed::notClosed,
1880
            degMax,
1881
            op));
1882
    }
1883

1884
    Py::Object makeSplitShape(const Py::Tuple& args)
1885
    {
1886
        PyObject* shape;
1887
        PyObject* list;
1888
        PyObject* checkInterior = Py_True;
1889
        if (!PyArg_ParseTuple(args.ptr(), "O!O|O!", &(TopoShapePy::Type), &shape, &list,
1890
                                                    &PyBool_Type, &checkInterior))
1891
            throw Py::Exception();
1892

1893
        try {
1894
            std::vector<TopoShape> sources;
1895
            sources.push_back(*static_cast<TopoShapePy*>(shape)->getTopoShapePtr());
1896
            TopoDS_Shape initShape = static_cast<TopoShapePy*>
1897
                    (shape)->getTopoShapePtr()->getShape();
1898
            BRepFeat_SplitShape splitShape(initShape);
1899
            splitShape.SetCheckInterior(Base::asBoolean(checkInterior));
1900

1901
            Py::Sequence seq(list);
1902
            for (Py::Sequence::iterator it = seq.begin(); it != seq.end(); ++it) {
1903
                Py::Tuple tuple(*it);
1904
                Py::TopoShape sh1(tuple[0]);
1905
                Py::TopoShape sh2(tuple[1]);
1906
                sources.push_back(*sh1.extensionObject()->getTopoShapePtr());
1907
                const TopoDS_Shape& shape1= sh1.extensionObject()->getTopoShapePtr()->getShape();
1908
                const TopoDS_Shape& shape2= sh2.extensionObject()->getTopoShapePtr()->getShape();
1909
                if (shape1.IsNull() || shape2.IsNull())
1910
                    throw Py::RuntimeError("Cannot add null shape");
1911
                if (shape2.ShapeType() == TopAbs_FACE) {
1912
                    if (shape1.ShapeType() == TopAbs_EDGE) {
1913
                        splitShape.Add(TopoDS::Edge(shape1), TopoDS::Face(shape2));
1914
                    }
1915
                    else if (shape1.ShapeType() == TopAbs_WIRE) {
1916
                        splitShape.Add(TopoDS::Wire(shape1), TopoDS::Face(shape2));
1917
                    }
1918
                    else if (shape1.ShapeType() == TopAbs_COMPOUND) {
1919
                        splitShape.Add(TopoDS::Compound(shape1), TopoDS::Face(shape2));
1920
                    }
1921
                    else {
1922
                        throw Py::TypeError("First item in tuple must be Edge, Wire or Compound");
1923
                    }
1924
                }
1925
                else if (shape2.ShapeType() == TopAbs_EDGE) {
1926
                    if (shape1.ShapeType() == TopAbs_EDGE) {
1927
                        splitShape.Add(TopoDS::Edge(shape1), TopoDS::Edge(shape2));
1928
                    }
1929
                    else {
1930
                        throw Py::TypeError("First item in tuple must be Edge");
1931
                    }
1932
                }
1933
                else {
1934
                    throw Py::TypeError("Second item in tuple must be Face or Edge");
1935
                }
1936
            }
1937

1938
            splitShape.Build();
1939
            const TopTools_ListOfShape& d = splitShape.DirectLeft();
1940
            const TopTools_ListOfShape& l = splitShape.Left();
1941

1942
            Py::List list1;
1943
            Py::List list2;
1944
            MapperMaker mapper(splitShape);
1945
            for (TopTools_ListIteratorOfListOfShape it(d); it.More(); it.Next()) {
1946
                TopoShape s(0, sources.front().Hasher);
1947
                list1.append(shape2pyshape(
1948
                    s.makeShapeWithElementMap(it.Value(), mapper, sources, Part::OpCodes::Split)));
1949
            }
1950
            for (TopTools_ListIteratorOfListOfShape it(l); it.More(); it.Next()) {
1951
                TopoShape s(0, sources.front().Hasher);
1952
                list2.append(shape2pyshape(
1953
                    s.makeShapeWithElementMap(it.Value(), mapper, sources, Part::OpCodes::Split)));
1954
            }
1955
            Py::Tuple tuple(2);
1956
            tuple.setItem(0, list1);
1957
            tuple.setItem(1, list2);
1958
            return tuple;
1959
        }
1960
        catch (Standard_Failure& e) {
1961
            throw Py::Exception(PartExceptionOCCError, e.GetMessageString());
1962
        }
1963
    }
1964
    Py::Object makeWireString(const Py::Tuple& args)
1965
    {
1966
#ifdef FCUseFreeType
1967
        PyObject *intext;
1968
        const char* dir;
1969
        const char* fontfile;
1970
        const char* fontspec;
1971
        bool useFontSpec = false;
1972
        double height;
1973
        double track = 0;
1974

1975
        Py_UNICODE *unichars = nullptr;
1976
        Py_ssize_t pysize;
1977

1978
        PyObject *CharList;
1979

1980
        if (PyArg_ParseTuple(args.ptr(), "Ossd|d", &intext,                               // compatibility with old version
1981
                                         &dir,
1982
                                         &fontfile,
1983
                                         &height,
1984
                                         &track)) {
1985
            useFontSpec = false;
1986
        }
1987
        else {
1988
            PyErr_Clear();
1989
            if (PyArg_ParseTuple(args.ptr(), "Osd|d", &intext,
1990
                                            &fontspec,
1991
                                            &height,
1992
                                            &track)) {
1993
                useFontSpec = true;
1994
            }
1995
            else {
1996
                throw Py::TypeError("** makeWireString bad args.");
1997
            }
1998
        }
1999

2000
        //FIXME: Test this!
2001
        if (PyBytes_Check(intext)) {
2002
            PyObject *p = Base::PyAsUnicodeObject(PyBytes_AsString(intext));
2003
            if (!p) {
2004
                throw Py::TypeError("** makeWireString can't convert PyString.");
2005
            }
2006

2007
            pysize = PyUnicode_GetLength(p);
2008
#if PY_VERSION_HEX < 0x03090000
2009
            unichars = PyUnicode_AS_UNICODE(p);
2010
#else
2011
#ifdef FC_OS_WIN32
2012
            //PyUNICODE is only 16 bits on Windows (wchar_t), so passing 32 bit UCS4
2013
            //will result in unknown glyph in even positions, and wrong characters in
2014
            //odd positions.
2015
            unichars = (Py_UNICODE*)PyUnicode_AsWideCharString(p, &pysize);
2016
#else
2017
            unichars = (Py_UNICODE *)PyUnicode_AsUCS4Copy(p);
2018
#endif
2019
#endif
2020
        }
2021
        else if (PyUnicode_Check(intext)) {
2022
            pysize = PyUnicode_GetLength(intext);
2023

2024
#if PY_VERSION_HEX < 0x03090000
2025
            unichars = PyUnicode_AS_UNICODE(intext);
2026
#else
2027
#ifdef FC_OS_WIN32
2028
            //PyUNICODE is only 16 bits on Windows (wchar_t), so passing 32 bit UCS4
2029
            //will result in unknown glyph in even positions, and wrong characters in
2030
            //odd positions.
2031
            unichars = (Py_UNICODE*)PyUnicode_AsWideCharString(intext, &pysize);
2032
#else
2033
            unichars = (Py_UNICODE *)PyUnicode_AsUCS4Copy(intext);
2034
#endif
2035
#endif
2036
        }
2037
        else {
2038
            throw Py::TypeError("** makeWireString bad text parameter");
2039
        }
2040

2041
        try {
2042
            if (useFontSpec) {
2043
                CharList = FT2FC(unichars,pysize,fontspec,height,track);
2044
            }
2045
            else {
2046
                CharList = FT2FC(unichars,pysize,dir,fontfile,height,track);
2047
            }
2048
#if PY_VERSION_HEX >= 0x03090000
2049
            if (unichars) {
2050
                PyMem_Free(unichars);
2051
            }
2052
#endif
2053
        }
2054
        catch (Standard_DomainError&) {                                      // Standard_DomainError is OCC error.
2055
            throw Py::Exception(PartExceptionOCCDomainError, "makeWireString failed - Standard_DomainError");
2056
        }
2057
        catch (std::runtime_error& e) {                                     // FT2 or FT2FC errors
2058
            throw Py::Exception(PartExceptionOCCError, e.what());
2059
        }
2060

2061
        return Py::asObject(CharList);
2062
#else
2063
        throw Py::RuntimeError("FreeCAD compiled without FreeType support! This method is disabled...");
2064
#endif
2065
    }
2066
    Py::Object exportUnits(const Py::Tuple& args)
2067
    {
2068
        char* unit=nullptr;
2069
        if (!PyArg_ParseTuple(args.ptr(), "|s", &unit))
2070
            throw Py::Exception();
2071

2072
        if (unit) {
2073
            if (!Interface::writeIgesUnit(unit)) {
2074
                throw Py::RuntimeError("Failed to set 'write.iges.unit'");
2075
            }
2076
            if (!Interface::writeStepUnit(unit)) {
2077
                throw Py::RuntimeError("Failed to set 'write.step.unit'");
2078
            }
2079
        }
2080

2081
        Py::Dict dict;
2082
        dict.setItem("write.iges.unit", Py::String(Interface::writeIgesUnit()));
2083
        dict.setItem("write.step.unit", Py::String(Interface::writeStepUnit()));
2084
        return dict;
2085
    }
2086
    Py::Object setStaticValue(const Py::Tuple& args)
2087
    {
2088
        char *name, *cval;
2089
        if (PyArg_ParseTuple(args.ptr(), "ss", &name, &cval)) {
2090
            if (!Interface_Static::SetCVal(name, cval)) {
2091
                std::stringstream str;
2092
                str << "Failed to set '" << name << "'";
2093
                throw Py::RuntimeError(str.str());
2094
            }
2095
            return Py::None();
2096
        }
2097

2098
        PyErr_Clear();
2099
        PyObject* index_or_value;
2100
        if (PyArg_ParseTuple(args.ptr(), "sO", &name, &index_or_value)) {
2101
            if (PyLong_Check(index_or_value)) {
2102
                int ival = (int)PyLong_AsLong(index_or_value);
2103
                if (!Interface_Static::SetIVal(name, ival)) {
2104
                    std::stringstream str;
2105
                    str << "Failed to set '" << name << "'";
2106
                    throw Py::RuntimeError(str.str());
2107
                }
2108
                return Py::None();
2109
            }
2110
            else if (PyFloat_Check(index_or_value)) {
2111
                double rval = PyFloat_AsDouble(index_or_value);
2112
                if (!Interface_Static::SetRVal(name, rval)) {
2113
                    std::stringstream str;
2114
                    str << "Failed to set '" << name << "'";
2115
                    throw Py::RuntimeError(str.str());
2116
                }
2117
                return Py::None();
2118
            }
2119
        }
2120

2121
        throw Py::TypeError("First argument must be string and must be either string, int or float");
2122
    }
2123
    Py::Object cast_to_shape(const Py::Tuple& args)
2124
    {
2125
        PyObject *object;
2126
        if (PyArg_ParseTuple(args.ptr(),"O!",&(Part::TopoShapePy::Type), &object)) {
2127
            TopoShape* ptr = static_cast<TopoShapePy*>(object)->getTopoShapePtr();
2128
            return Py::asObject(ptr->getPyObject());
2129
        }
2130

2131
        throw Py::Exception();
2132
    }
2133
    Py::Object getSortedClusters(const Py::Tuple& args)
2134
    {
2135
        PyObject *obj;
2136
        if (!PyArg_ParseTuple(args.ptr(), "O", &obj)) {
2137
            throw Py::Exception(PartExceptionOCCError, "list of edges expected");
2138
        }
2139

2140
        Py::Sequence list(obj);
2141
        std::vector<TopoDS_Edge> edges;
2142
        for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
2143
            PyObject* item = (*it).ptr();
2144
            if (PyObject_TypeCheck(item, &(Part::TopoShapePy::Type))) {
2145
                const TopoDS_Shape& sh = static_cast<Part::TopoShapePy*>(item)->getTopoShapePtr()->getShape();
2146
                if (sh.ShapeType() == TopAbs_EDGE)
2147
                    edges.push_back(TopoDS::Edge(sh));
2148
                else {
2149
                    throw Py::TypeError("shape is not an edge");
2150
                }
2151
            }
2152
            else {
2153
                throw Py::TypeError("item is not a shape");
2154
            }
2155
        }
2156

2157
        Edgecluster acluster(edges);
2158
        tEdgeClusterVector aclusteroutput = acluster.GetClusters();
2159

2160
        Py::List root_list;
2161
        for (const auto & it : aclusteroutput) {
2162
            Py::List add_list;
2163
            for (const auto& it1 : it) {
2164
                add_list.append(Py::Object(new TopoShapeEdgePy(new TopoShape(it1)),true));
2165
            }
2166
            root_list.append(add_list);
2167
        }
2168

2169
        return root_list;
2170
    }
2171
    Py::Object sortEdges(const Py::Tuple& args)
2172
    {
2173
        PyObject *obj;
2174
        if (!PyArg_ParseTuple(args.ptr(), "O", &obj)) {
2175
            throw Py::TypeError("list of edges expected");
2176
        }
2177

2178
        Py::Sequence list(obj);
2179
        std::list<TopoDS_Edge> edges;
2180
        for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
2181
            PyObject* item = (*it).ptr();
2182
            if (PyObject_TypeCheck(item, &(Part::TopoShapePy::Type))) {
2183
                const TopoDS_Shape& sh = static_cast<Part::TopoShapePy*>(item)->getTopoShapePtr()->getShape();
2184
                if (sh.ShapeType() == TopAbs_EDGE)
2185
                    edges.push_back(TopoDS::Edge(sh));
2186
                else {
2187
                    throw Py::TypeError("shape is not an edge");
2188
                }
2189
            }
2190
            else {
2191
                throw Py::TypeError("item is not a shape");
2192
            }
2193
        }
2194

2195
        std::list<TopoDS_Edge> sorted = sort_Edges(Precision::Confusion(), edges);
2196
        Py::List sorted_list;
2197
        for (const auto & it : sorted) {
2198
            sorted_list.append(Py::Object(new TopoShapeEdgePy(new TopoShape(it)),true));
2199
        }
2200

2201
        return sorted_list;
2202
    }
2203
    Py::Object sortEdges2(const Py::Tuple& args)
2204
    {
2205
        PyObject *obj;
2206
        double tol3d = Precision::Confusion();
2207
        if (!PyArg_ParseTuple(args.ptr(), "O|d", &obj, &tol3d)) {
2208
            throw Py::Exception(PartExceptionOCCError, "list of edges expected");
2209
        }
2210

2211
        Py::Sequence list(obj);
2212
        std::list<TopoDS_Edge> edges;
2213
        for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
2214
            PyObject* item = (*it).ptr();
2215
            if (PyObject_TypeCheck(item, &(Part::TopoShapePy::Type))) {
2216
                const TopoDS_Shape& sh = static_cast<Part::TopoShapePy*>(item)->getTopoShapePtr()->getShape();
2217
                if (sh.ShapeType() == TopAbs_EDGE)
2218
                    edges.push_back(TopoDS::Edge(sh));
2219
                else {
2220
                    throw Py::TypeError("shape is not an edge");
2221
                }
2222
            }
2223
            else {
2224
                throw Py::TypeError("item is not a shape");
2225
            }
2226
        }
2227

2228
        Py::List root_list;
2229
        while(!edges.empty()) {
2230
            std::list<TopoDS_Edge> sorted = sort_Edges(tol3d, edges);
2231
            Py::List sorted_list;
2232
            for (const auto & it : sorted) {
2233
                sorted_list.append(Py::Object(new TopoShapeEdgePy(new TopoShape(it)),true));
2234
            }
2235
            root_list.append(sorted_list);
2236
        }
2237
        return root_list;
2238
    }
2239
    Py::Object toPythonOCC(const Py::Tuple& args)
2240
    {
2241
        PyObject *pcObj;
2242
        if (!PyArg_ParseTuple(args.ptr(), "O!", &(TopoShapePy::Type), &pcObj))
2243
            throw Py::Exception();
2244

2245
        try {
2246
            TopoDS_Shape* shape = new TopoDS_Shape();
2247
            (*shape) = static_cast<TopoShapePy*>(pcObj)->getTopoShapePtr()->getShape();
2248
            PyObject* proxy = nullptr;
2249
            proxy = Base::Interpreter().createSWIGPointerObj("OCC.TopoDS", "TopoDS_Shape *", static_cast<void*>(shape), 1);
2250
            return Py::asObject(proxy);
2251
        }
2252
        catch (const Base::Exception& e) {
2253
            throw Py::Exception(PartExceptionOCCError, e.what());
2254
        }
2255
    }
2256
    Py::Object fromPythonOCC(const Py::Tuple& args)
2257
    {
2258
        PyObject *proxy;
2259
        if (!PyArg_ParseTuple(args.ptr(), "O", &proxy))
2260
            throw Py::Exception();
2261

2262
        void* ptr;
2263
        try {
2264
            TopoShape* shape = new TopoShape();
2265
            Base::Interpreter().convertSWIGPointerObj("OCC.TopoDS","TopoDS_Shape *", proxy, &ptr, 0);
2266
            TopoDS_Shape* s = static_cast<TopoDS_Shape*>(ptr);
2267
            shape->setShape(*s);
2268
            return Py::asObject(new TopoShapePy(shape));
2269
        }
2270
        catch (const Base::Exception& e) {
2271
            throw Py::Exception(PartExceptionOCCError, e.what());
2272
        }
2273
    }
2274

2275
    Py::Object getShape(const Py::Tuple& args, const Py::Dict &kwds) {
2276
        PyObject *pObj;
2277
        const char *subname = nullptr;
2278
        PyObject *pyMat = nullptr;
2279
        PyObject *needSubElement = Py_False;
2280
        PyObject *transform = Py_True;
2281
        PyObject *noElementMap = Py_False;
2282
        PyObject *refine = Py_False;
2283
        short retType = 0;
2284
        static const std::array<const char *, 9> kwd_list{"obj", "subname", "mat",
2285
                                                          "needSubElement", "transform", "retType", "noElementMap",
2286
                                                          "refine", nullptr};
2287
        if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "O!|sO!O!O!hO!O!", kwd_list,
2288
                                                 &App::DocumentObjectPy::Type, &pObj, &subname,
2289
                                                 &Base::MatrixPy::Type, &pyMat,
2290
                                                 &PyBool_Type, &needSubElement,
2291
                                                 &PyBool_Type, &transform, &retType,
2292
                                                 &PyBool_Type, &noElementMap,
2293
                                                 &PyBool_Type, &refine)) {
2294
            throw Py::Exception();
2295
        }
2296

2297
        App::DocumentObject *obj =
2298
            static_cast<App::DocumentObjectPy*>(pObj)->getDocumentObjectPtr();
2299
        App::DocumentObject *subObj = nullptr;
2300
        Base::Matrix4D mat;
2301
        if(pyMat)
2302
            mat = *static_cast<Base::MatrixPy*>(pyMat)->getMatrixPtr();
2303
        auto shape = Feature::getTopoShape(obj,subname,Base::asBoolean(needSubElement),
2304
                &mat,&subObj,retType==2,Base::asBoolean(transform),
2305
                Base::asBoolean(noElementMap));
2306
        if (Base::asBoolean(refine)) {
2307
            shape = TopoShape(0, shape.Hasher).makeElementRefine(shape);
2308
        }
2309
        Py::Object sret(shape2pyshape(shape));
2310
        if(retType==0)
2311
            return sret;
2312

2313
        return Py::TupleN(sret,Py::asObject(new Base::MatrixPy(new Base::Matrix4D(mat))),
2314
                subObj?Py::Object(subObj->getPyObject(),true):Py::Object());
2315
    }
2316

2317
    Py::Object clearShapeCache(const Py::Tuple &args) {
2318
        if (!PyArg_ParseTuple(args.ptr(),""))
2319
            throw Py::Exception();
2320
        Part::Feature::clearShapeCache();
2321
        return Py::Object();
2322
    }
2323

2324
    Py::Object splitSubname(const Py::Tuple& args) {
2325
        const char *subname;
2326
        if (!PyArg_ParseTuple(args.ptr(), "s",&subname))
2327
            throw Py::Exception();
2328
        auto element = Data::findElementName(subname);
2329
        std::string sub(subname,element-subname);
2330
        Py::List list;
2331
        list.append(Py::String(sub));
2332
        const char *dot = strchr(element,'.');
2333
        if(!dot)
2334
            dot = element+strlen(element);
2335
        const char *mapped = Data::isMappedElement(element);
2336
        if(mapped)
2337
            list.append(Py::String(std::string(mapped,dot-mapped)));
2338
        else
2339
            list.append(Py::String());
2340
        if(*dot=='.')
2341
            list.append(Py::String(dot+1));
2342
        else if(!mapped)
2343
            list.append(Py::String(element));
2344
        else
2345
            list.append(Py::String());
2346
        return list;
2347
    }
2348

2349
    Py::Object joinSubname(const Py::Tuple& args) {
2350
        const char *sub;
2351
        const char *mapped;
2352
        const char *element;
2353
        if (!PyArg_ParseTuple(args.ptr(), "sss",&sub,&mapped,&element))
2354
            throw Py::Exception();
2355
        std::string subname(sub);
2356
        if (!subname.empty() && subname[subname.size()-1]!='.')
2357
            subname += '.';
2358
        if (mapped && mapped[0]) {
2359
            if (!Data::isMappedElement(mapped))
2360
                subname += Data::ELEMENT_MAP_PREFIX;
2361
            subname += mapped;
2362
        }
2363
        if (element && element[0]) {
2364
            if (!subname.empty() && subname[subname.size()-1]!='.')
2365
                subname += '.';
2366
            subname += element;
2367
        }
2368
        return Py::String(subname);
2369
    }
2370
};
2371

2372
PyObject* initModule()
2373
{
2374
    return Base::Interpreter().addModule(new Module);
2375
}
2376

2377
} // namespace Part
2378

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.