FreeCAD

Форк
0
/
TopoShapePyImp.cpp 
2768 строк · 88.5 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2008 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 <sstream>
26
# include <boost/regex.hpp>
27

28
# include <BRep_Tool.hxx>
29
# include <BRepAlgo_NormalProjection.hxx>
30
# include <BRepBndLib.hxx>
31
# include <BRepBuilderAPI_Copy.hxx>
32
# include <BRepBuilderAPI_MakeVertex.hxx>
33
# include <BRepBuilderAPI_Transform.hxx>
34
# include <BRepClass3d_SolidClassifier.hxx>
35
# include <BRepExtrema_DistShapeShape.hxx>
36
# include <BRepExtrema_ShapeProximity.hxx>
37
# include <BRepExtrema_SupportType.hxx>
38
# include <BRepFilletAPI_MakeChamfer.hxx>
39
# include <BRepFilletAPI_MakeFillet.hxx>
40
# include <BRepGProp.hxx>
41
# include <BRepMesh_IncrementalMesh.hxx>
42
# include <BRepProj_Projection.hxx>
43
# include <BRepTools.hxx>
44
# include <Geom_Plane.hxx>
45
# include <gp_Ax1.hxx>
46
# include <gp_Ax2.hxx>
47
# include <gp_Dir.hxx>
48
# include <gp_Pln.hxx>
49
# include <gp_Pnt.hxx>
50
# include <gp_Trsf.hxx>
51
# include <GProp_GProps.hxx>
52
# include <HLRAppli_ReflectLines.hxx>
53
# include <Precision.hxx>
54
# include <Poly_Polygon3D.hxx>
55
# include <Poly_Triangulation.hxx>
56
# include <ShapeAnalysis_ShapeTolerance.hxx>
57
# include <ShapeFix_ShapeTolerance.hxx>
58
# include <Standard_Version.hxx>
59
# include <TopExp.hxx>
60
# include <TopExp_Explorer.hxx>
61
# include <TopLoc_Location.hxx>
62
# include <TopoDS.hxx>
63
# include <TopoDS_Iterator.hxx>
64
# include <TopTools_IndexedMapOfShape.hxx>
65
# include <TopTools_ListIteratorOfListOfShape.hxx>
66
# include <TopTools_ListOfShape.hxx>
67
#endif
68

69
#include <App/PropertyStandard.h>
70
#include <App/StringHasherPy.h>
71
#include <Base/FileInfo.h>
72
#include <Base/GeometryPyCXX.h>
73
#include <Base/MatrixPy.h>
74
#include <Base/PyWrapParseTupleAndKeywords.h>
75
#include <Base/Rotation.h>
76
#include <Base/Stream.h>
77
#include <Base/Vector3D.h>
78
#include <Base/VectorPy.h>
79

80
#include <Mod/Part/App/TopoShapePy.h>
81
#include <Mod/Part/App/TopoShapePy.cpp>
82

83
#include <Mod/Part/App/GeometryPy.h>
84
#include <Mod/Part/App/PlanePy.h>
85
#include <Mod/Part/App/TopoShapeCompoundPy.h>
86
#include <Mod/Part/App/TopoShapeCompSolidPy.h>
87
#include <Mod/Part/App/TopoShapeEdgePy.h>
88
#include <Mod/Part/App/TopoShapeFacePy.h>
89
#include <Mod/Part/App/TopoShapeOpCode.h>
90
#include <Mod/Part/App/TopoShapeShellPy.h>
91
#include <Mod/Part/App/TopoShapeSolidPy.h>
92
#include <Mod/Part/App/TopoShapeVertexPy.h>
93
#include <Mod/Part/App/TopoShapeWirePy.h>
94

95
#include "OCCError.h"
96
#include "PartPyCXX.h"
97
#include "ShapeMapHasher.h"
98
#include "TopoShapeMapper.h"
99

100

101
using namespace Part;
102

103
#ifndef M_PI
104
    #define M_PI    3.14159265358979323846 /* pi */
105
#endif
106

107
#ifndef M_PI_2
108
    #define M_PI_2  1.57079632679489661923 /* pi/2 */
109
#endif
110

111
static Py_hash_t _TopoShapeHash(PyObject* self)
112
{
113
    if (!self) {
114
        PyErr_SetString(PyExc_TypeError,
115
                        "descriptor 'hash' of 'Part.TopoShape' object needs an argument");
116
        return 0;
117
    }
118
    if (!static_cast<Base::PyObjectBase*>(self)->isValid()) {
119
        PyErr_SetString(PyExc_ReferenceError,
120
                        "This object is already deleted most likely through closing a document. "
121
                        "This reference is no longer valid!");
122
        return 0;
123
    }
124
#if OCC_VERSION_HEX >= 0x070800
125
    return std::hash<TopoDS_Shape> {}(static_cast<TopoShapePy*>(self)->getTopoShapePtr()->getShape());
126
#else
127
    return static_cast<TopoShapePy*>(self)->getTopoShapePtr()->getShape().HashCode(INT_MAX);
128
#endif
129
}
130

131
struct TopoShapePyInit
132
{
133
    TopoShapePyInit()
134
    {
135
        TopoShapePy::Type.tp_hash = _TopoShapeHash;
136
    }
137
} _TopoShapePyInit;
138

139
// returns a string which represents the object e.g. when printed in python
140
std::string TopoShapePy::representation() const
141
{
142
    std::stringstream str;
143
    str << "<Shape object at " << getTopoShapePtr() << ">";
144

145
    return str.str();
146
}
147

148
PyObject *TopoShapePy::PyMake(struct _typeobject *, PyObject *, PyObject *)  // Python wrapper
149
{
150
    // create a new instance of TopoShapePy and the Twin object
151
    return new TopoShapePy(new TopoShape);
152
}
153

154
int TopoShapePy::PyInit(PyObject* args, PyObject* keywds)
155
{
156
    static const std::array<const char*, 5> kwlist{ "shape",
157
                                                    "op",
158
                                                    "tag",
159
                                                    "hasher",
160
                                                    nullptr };
161
    long tag = 0;
162
    PyObject* pyHasher = nullptr;
163
    const char* op = nullptr;
164
    PyObject* pcObj = nullptr;
165
    if (!Base::Wrapped_ParseTupleAndKeywords(args,
166
                                             keywds,
167
                                             "|OsiO!",
168
                                             kwlist,
169
                                             &pcObj,
170
                                             &op,
171
                                             &tag,
172
                                             &App::StringHasherPy::Type,
173
                                             &pyHasher)) {
174
        return -1;
175
    }
176
    auto& self = *getTopoShapePtr();
177
    self.Tag = tag;
178
    if (pyHasher) {
179
        self.Hasher = static_cast<App::StringHasherPy*>(pyHasher)->getStringHasherPtr();
180
    }
181
    auto shapes = getPyShapes(pcObj);
182
    PY_TRY
183
    {
184
        if (shapes.size() == 1 && !op) {
185
            auto s = shapes.front();
186
            if (self.Tag) {
187
                if ((s.Tag && self.Tag != s.Tag)
188
                    || (self.Hasher && s.getElementMapSize() && self.Hasher != s.Hasher)) {
189
                    s.reTagElementMap(self.Tag, self.Hasher);
190
                }
191
                else {
192
                    s.Tag = self.Tag;
193
                    s.Hasher = self.Hasher;
194
                }
195
            }
196
            self = s;
197
        }
198
        else if (shapes.size()) {
199
            if (!op) {
200
                op = Part::OpCodes::Fuse;
201
            }
202
            self.makeElementBoolean(op, shapes);
203
        }
204
    }
205
    _PY_CATCH_OCC(return (-1))
206
    return 0;
207
}
208

209
PyObject* TopoShapePy::copy(PyObject *args)
210
{
211
    PyObject* copyGeom = Py_True;
212
    PyObject* copyMesh = Py_False;
213
    const char* op = nullptr;
214
    PyObject* pyHasher = nullptr;
215
    if (!PyArg_ParseTuple(args,
216
                          "|sO!O!O!",
217
                          &op,
218
                          &App::StringHasherPy::Type,
219
                          &pyHasher,
220
                          &PyBool_Type,
221
                          &copyGeom,
222
                          &PyBool_Type,
223
                          &copyMesh)) {
224
        PyErr_Clear();
225
        if (!PyArg_ParseTuple(args, "|O!O!", &PyBool_Type, &copyGeom, &PyBool_Type, &copyMesh)) {
226
            return 0;
227
        }
228
    }
229
    if (op && !op[0]) {
230
        op = nullptr;
231
    }
232
    App::StringHasherRef hasher;
233
    if (pyHasher) {
234
        hasher = static_cast<App::StringHasherPy*>(pyHasher)->getStringHasherPtr();
235
    }
236
    auto& self = *getTopoShapePtr();
237
    return Py::new_reference_to(shape2pyshape(
238
        TopoShape(self.Tag, hasher)
239
            .makeElementCopy(self, op, PyObject_IsTrue(copyGeom), PyObject_IsTrue(copyMesh))));
240
}
241

242
PyObject* TopoShapePy::cleaned(PyObject *args)
243
{
244
    if (!PyArg_ParseTuple(args, ""))
245
        return nullptr;
246
    auto& self = *getTopoShapePtr();
247
    TopoShape copy(self.makeElementCopy());
248
    if (!copy.isNull()) {
249
        BRepTools::Clean(copy.getShape());  // remove triangulation
250
    }
251
    return Py::new_reference_to(shape2pyshape(copy));
252
}
253

254
PyObject* TopoShapePy::replaceShape(PyObject *args)
255
{
256
    PyObject *l;
257
    if (!PyArg_ParseTuple(args, "O",&l))
258
        return nullptr;
259

260
    try {
261
        Py::Sequence list(l);
262
        std::vector<std::pair<TopoShape, TopoShape>> shapes;
263
        for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
264
            Py::Tuple tuple(*it);
265
            Py::TopoShape sh1(tuple[0]);
266
            Py::TopoShape sh2(tuple[1]);
267
            shapes.push_back(std::make_pair(*sh1.extensionObject()->getTopoShapePtr(),
268
                                            *sh2.extensionObject()->getTopoShapePtr()));
269
        }
270
        return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->replaceElementShape(shapes)));
271
    }
272
    catch (const Py::Exception&) {
273
        return nullptr;
274
    }
275
    catch (...) {
276
        PyErr_SetString(PartExceptionOCCError, "failed to replace shape");
277
        return nullptr;
278
    }
279
}
280

281
PyObject* TopoShapePy::removeShape(PyObject *args)
282
{
283
    PyObject *l;
284
    if (!PyArg_ParseTuple(args, "O",&l))
285
        return nullptr;
286

287
    try {
288
        return Py::new_reference_to(
289
            shape2pyshape(getTopoShapePtr()->removeElementShape(getPyShapes(l))));
290
    }
291
    catch (...) {
292
        PyErr_SetString(PartExceptionOCCError, "failed to remove shape");
293
        return nullptr;
294
    }
295
}
296

297
PyObject*  TopoShapePy::read(PyObject *args)
298
{
299
    char* Name;
300
    if (!PyArg_ParseTuple(args, "et","utf-8",&Name))
301
        return nullptr;
302

303
    std::string EncodedName = std::string(Name);
304
    PyMem_Free(Name);
305

306
    getTopoShapePtr()->read(EncodedName.c_str());
307
    Py_Return;
308
}
309

310
PyObject* TopoShapePy::writeInventor(PyObject * args, PyObject * keywds)
311
{
312
    static const std::array<const char *, 5> kwlist{"Mode", "Deviation", "Angle", "FaceColors", nullptr};
313

314
    double dev = 0.3, angle = 0.4;
315
    int mode = 2;
316
    PyObject *pylist = nullptr;
317
    if (!Base::Wrapped_ParseTupleAndKeywords(args, keywds, "|iddO", kwlist,
318
                                             &mode, &dev, &angle, &pylist)) {
319
        return nullptr;
320
    }
321

322
    std::vector<App::Color> faceColors;
323
    if (pylist) {
324
        App::PropertyColorList prop;
325
        prop.setPyObject(pylist);
326
        faceColors = prop.getValues();
327
    }
328

329
    std::stringstream result;
330
    BRepMesh_IncrementalMesh(getTopoShapePtr()->getShape(),dev);
331
    if (mode == 0) {
332
        getTopoShapePtr()->exportFaceSet(dev, angle, faceColors, result);
333
    }
334
    else if (mode == 1) {
335
        getTopoShapePtr()->exportLineSet(result);
336
    }
337
    else {
338
        getTopoShapePtr()->exportFaceSet(dev, angle, faceColors, result);
339
        getTopoShapePtr()->exportLineSet(result);
340
    }
341
    return Py::new_reference_to(Py::String(result.str()));
342
}
343

344
PyObject*  TopoShapePy::exportIges(PyObject *args)
345
{
346
    char* Name;
347
    if (!PyArg_ParseTuple(args, "et","utf-8",&Name))
348
        return nullptr;
349

350
    std::string EncodedName = std::string(Name);
351
    PyMem_Free(Name);
352

353
    try {
354
        // write iges file
355
        getTopoShapePtr()->exportIges(EncodedName.c_str());
356
    }
357
    catch (const Base::Exception& e) {
358
        PyErr_SetString(PartExceptionOCCError,e.what());
359
        return nullptr;
360
    }
361

362
    Py_Return;
363
}
364

365
PyObject*  TopoShapePy::exportStep(PyObject *args)
366
{
367
    char* Name;
368
    if (!PyArg_ParseTuple(args, "et","utf-8",&Name))
369
        return nullptr;
370

371
    std::string EncodedName = std::string(Name);
372
    PyMem_Free(Name);
373

374
    try {
375
        // write step file
376
        getTopoShapePtr()->exportStep(EncodedName.c_str());
377
    }
378
    catch (const Base::Exception& e) {
379
        PyErr_SetString(PartExceptionOCCError,e.what());
380
        return nullptr;
381
    }
382

383
    Py_Return;
384
}
385

386
PyObject*  TopoShapePy::exportBrep(PyObject *args)
387
{
388
    char* Name;
389
    if (PyArg_ParseTuple(args, "et","utf-8",&Name)) {
390
        std::string EncodedName = std::string(Name);
391
        PyMem_Free(Name);
392

393
        try {
394
            // write brep file
395
            getTopoShapePtr()->exportBrep(EncodedName.c_str());
396
        }
397
        catch (const Base::Exception& e) {
398
            PyErr_SetString(PartExceptionOCCError,e.what());
399
            return nullptr;
400
        }
401

402
        Py_Return;
403
    }
404

405
    PyErr_Clear();
406

407
    PyObject* input;
408
    if (PyArg_ParseTuple(args, "O", &input)) {
409
        try {
410
            // write brep
411
            Base::PyStreambuf buf(input);
412
            std::ostream str(nullptr);
413
            str.rdbuf(&buf);
414
            getTopoShapePtr()->exportBrep(str);
415
        }
416
        catch (const Base::Exception& e) {
417
            PyErr_SetString(PartExceptionOCCError,e.what());
418
            return nullptr;
419
        }
420

421
        Py_Return;
422
    }
423

424
    PyErr_SetString(PyExc_TypeError, "expect string or file object");
425
    return nullptr;
426
}
427

428
PyObject*  TopoShapePy::exportBinary(PyObject *args)
429
{
430
    char* input;
431
    if (!PyArg_ParseTuple(args, "s", &input))
432
        return nullptr;
433

434
    try {
435
        // read binary brep
436
        Base::FileInfo fi(input);
437
        Base::ofstream str(fi, std::ios::out | std::ios::binary);
438
        getTopoShapePtr()->exportBinary(str);
439
        str.close();
440
    }
441
    catch (const Base::Exception& e) {
442
        PyErr_SetString(PartExceptionOCCError,e.what());
443
        return nullptr;
444
    }
445

446
    Py_Return;
447
}
448

449
PyObject*  TopoShapePy::dumpToString(PyObject *args)
450
{
451
    if (!PyArg_ParseTuple(args, ""))
452
        return nullptr;
453

454
    try {
455
        std::stringstream str;
456
        getTopoShapePtr()->dump(str);
457
        return Py::new_reference_to(Py::String(str.str()));
458
    }
459
    catch (const Base::Exception& e) {
460
        PyErr_SetString(PartExceptionOCCError,e.what());
461
        return nullptr;
462
    }
463
    catch (const std::exception& e) {
464
        PyErr_SetString(PartExceptionOCCError,e.what());
465
        return nullptr;
466
    }
467
    catch (Standard_Failure& e) {
468

469
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
470
        return nullptr;
471
    }
472
}
473

474
PyObject*  TopoShapePy::exportBrepToString(PyObject *args)
475
{
476
    if (!PyArg_ParseTuple(args, ""))
477
        return nullptr;
478

479
    try {
480
        // write brep file
481
        std::stringstream str;
482
        getTopoShapePtr()->exportBrep(str);
483
        return Py::new_reference_to(Py::String(str.str()));
484
    }
485
    catch (const Base::Exception& e) {
486
        PyErr_SetString(PartExceptionOCCError,e.what());
487
        return nullptr;
488
    }
489
    catch (const std::exception& e) {
490
        PyErr_SetString(PartExceptionOCCError,e.what());
491
        return nullptr;
492
    }
493
    catch (Standard_Failure& e) {
494
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
495
        return nullptr;
496
    }
497
}
498

499
PyObject*  TopoShapePy::importBrep(PyObject *args)
500
{
501
    char* Name;
502
    if (PyArg_ParseTuple(args, "et","utf-8",&Name)) {
503
        std::string EncodedName = std::string(Name);
504
        PyMem_Free(Name);
505

506
        try {
507
            // write brep file
508
            getTopoShapePtr()->importBrep(EncodedName.c_str());
509
        }
510
        catch (const Base::Exception& e) {
511
            PyErr_SetString(PartExceptionOCCError,e.what());
512
            return nullptr;
513
        }
514

515
        Py_Return;
516
    }
517

518
    PyErr_Clear();
519
    PyObject* input;
520
    if (PyArg_ParseTuple(args, "O", &input)) {
521
        try {
522
            // read brep
523
            Base::PyStreambuf buf(input);
524
            std::istream str(nullptr);
525
            str.rdbuf(&buf);
526
            getTopoShapePtr()->importBrep(str);
527
        }
528
        catch (const Base::Exception& e) {
529
            PyErr_SetString(PartExceptionOCCError,e.what());
530
            return nullptr;
531
        }
532

533
        Py_Return;
534
    }
535

536
    PyErr_SetString(PyExc_TypeError, "expect string or file object");
537
    return nullptr;
538
}
539

540
PyObject*  TopoShapePy::importBinary(PyObject *args)
541
{
542
    char* input;
543
    if (!PyArg_ParseTuple(args, "s", &input))
544
        return nullptr;
545

546
    try {
547
        // read binary brep
548
        Base::FileInfo fi(input);
549
        Base::ifstream str(fi, std::ios::in | std::ios::binary);
550
        getTopoShapePtr()->importBinary(str);
551
        str.close();
552
    }
553
    catch (const Base::Exception& e) {
554
        PyErr_SetString(PartExceptionOCCError,e.what());
555
        return nullptr;
556
    }
557

558
    Py_Return;
559
}
560

561
PyObject*  TopoShapePy::importBrepFromString(PyObject *args)
562
{
563
    char* input;
564
    int indicator=1;
565
    if (!PyArg_ParseTuple(args, "s|i", &input, &indicator))
566
        return nullptr;
567

568
    try {
569
        // read brep
570
        std::stringstream str(input);
571
        getTopoShapePtr()->importBrep(str,indicator);
572
    }
573
    catch (const Base::Exception& e) {
574
        PyErr_SetString(PartExceptionOCCError,e.what());
575
        return nullptr;
576
    }
577
    catch (const std::exception& e) {
578
        PyErr_SetString(PartExceptionOCCError,e.what());
579
        return nullptr;
580
    }
581
    catch (Standard_Failure& e) {
582
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
583
        return nullptr;
584
    }
585

586
    Py_Return;
587
}
588

589
PyObject*  TopoShapePy::dumps(PyObject *args) {
590
    return exportBrepToString(args);
591
}
592

593

594
PyObject*  TopoShapePy::loads(PyObject *args) {
595
    if (! getTopoShapePtr()) {
596
        PyErr_SetString(Base::PyExc_FC_GeneralError,"no c++ object");
597
        return nullptr;
598
    }
599
    else {
600
        return importBrepFromString(args);
601
    }
602
}
603

604
PyObject*  TopoShapePy::exportStl(PyObject *args)
605
{
606
    double deflection = 0.01;
607
    char* Name;
608
    if (!PyArg_ParseTuple(args, "et|d","utf-8",&Name,&deflection))
609
        return nullptr;
610

611
    std::string EncodedName = std::string(Name);
612
    PyMem_Free(Name);
613

614
    try {
615
        // write stl file
616
        getTopoShapePtr()->exportStl(EncodedName.c_str(), deflection);
617
    }
618
    catch (const Base::Exception& e) {
619
        PyErr_SetString(PartExceptionOCCError,e.what());
620
        return nullptr;
621
    }
622
    catch (Standard_Failure& e) {
623
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
624
        return nullptr;
625
    }
626

627
    Py_Return;
628
}
629

630
PyObject* TopoShapePy::extrude(PyObject *args)
631
{
632
    PyObject *pVec;
633
    if (!PyArg_ParseTuple(args, "O!", &(Base::VectorPy::Type), &pVec))
634
        return nullptr;
635

636
    try {
637
        Base::Vector3d vec = static_cast<Base::VectorPy*>(pVec)->value();
638
        return Py::new_reference_to(
639
            shape2pyshape(getTopoShapePtr()->makeElementPrism(gp_Vec(vec.x, vec.y, vec.z))));
640
    }
641
    catch (Standard_Failure& e) {
642
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
643
        return nullptr;
644
    }
645
}
646

647
PyObject* TopoShapePy::revolve(PyObject *args)
648
{
649
    PyObject *pPos,*pDir;
650
    double d=360;
651
    if (!PyArg_ParseTuple(args, "O!O!|d", &(Base::VectorPy::Type), &pPos, &(Base::VectorPy::Type), &pDir,&d))
652
        return nullptr;
653
    Base::Vector3d pos = static_cast<Base::VectorPy*>(pPos)->value();
654
    Base::Vector3d dir = static_cast<Base::VectorPy*>(pDir)->value();
655
    try {
656
        return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementRevolve(
657
            gp_Ax1(gp_Pnt(pos.x, pos.y, pos.z), gp_Dir(dir.x, dir.y, dir.z)),
658
            d * (M_PI / 180))));
659
    }
660
    catch (Standard_Failure& e) {
661
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
662
        return nullptr;
663
    }
664
}
665

666
PyObject*  TopoShapePy::check(PyObject *args)
667
{
668
    PyObject* runBopCheck = Py_False;
669
    if (!PyArg_ParseTuple(args, "|O!", &(PyBool_Type), &runBopCheck))
670
        return nullptr;
671

672
    if (!getTopoShapePtr()->getShape().IsNull()) {
673
        std::stringstream str;
674
        if (!getTopoShapePtr()->analyze(Base::asBoolean(runBopCheck), str)) {
675
            PyErr_SetString(PyExc_ValueError, str.str().c_str());
676
            return nullptr;
677
        }
678
    }
679

680
    Py_Return;
681
}
682

683
static PyObject *makeShape(const char *op,const TopoShape &shape, PyObject *args) {
684
    double tol=0;
685
    PyObject *pcObj;
686
    if (!PyArg_ParseTuple(args, "O|d", &pcObj,&tol))
687
        return 0;
688
    PY_TRY {
689
        std::vector<TopoShape> shapes;
690
        shapes.push_back(shape);
691
        getPyShapes(pcObj,shapes);
692
        return Py::new_reference_to(shape2pyshape(TopoShape().makeElementBoolean(op,shapes,0,tol)));
693
    } PY_CATCH_OCC
694
}
695

696
PyObject*  TopoShapePy::fuse(PyObject *args)
697
{
698
    return makeShape(Part::OpCodes::Fuse, *getTopoShapePtr(), args);
699
}
700

701
PyObject*  TopoShapePy::multiFuse(PyObject *args)
702
{
703
    return makeShape(Part::OpCodes::Fuse, *getTopoShapePtr(), args);
704
}
705

706
PyObject*  TopoShapePy::oldFuse(PyObject *args)
707
{
708
    PyObject *pcObj;
709
    if (!PyArg_ParseTuple(args, "O!", &(TopoShapePy::Type), &pcObj))
710
        return nullptr;
711

712
    TopoDS_Shape shape = static_cast<TopoShapePy*>(pcObj)->getTopoShapePtr()->getShape();
713
    try {
714
        // Let's call algorithm computing a fuse operation:
715
        TopoDS_Shape fusShape = this->getTopoShapePtr()->oldFuse(shape);
716
        return new TopoShapePy(new TopoShape(fusShape));
717
    }
718
    catch (Standard_Failure& e) {
719
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
720
        return nullptr;
721
    }
722
    catch (const std::exception& e) {
723
        PyErr_SetString(PartExceptionOCCError, e.what());
724
        return nullptr;
725
    }
726
}
727

728
PyObject*  TopoShapePy::common(PyObject *args)
729
{
730
    return makeShape(Part::OpCodes::Common, *getTopoShapePtr(), args);
731
}
732

733
PyObject*  TopoShapePy::section(PyObject *args)
734
{
735
    return makeShape(Part::OpCodes::Section, *getTopoShapePtr(), args);
736
}
737

738
PyObject*  TopoShapePy::slice(PyObject *args)
739
{
740
    PyObject *dir;
741
    double d;
742
    if (!PyArg_ParseTuple(args, "O!d", &(Base::VectorPy::Type), &dir, &d))
743
        return nullptr;
744

745
    Base::Vector3d vec = Py::Vector(dir, false).toVector();
746

747
    try {
748
        Py::List wires;
749
        for (auto& w : getTopoShapePtr()->makeElementSlice(vec, d).getSubTopoShapes(TopAbs_WIRE)) {
750
            wires.append(shape2pyshape(w));
751
        }
752
        return Py::new_reference_to(wires);
753
    }
754
    catch (Standard_Failure& e) {
755

756
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
757
        return nullptr;
758
    }
759
    catch (const std::exception& e) {
760
        PyErr_SetString(PartExceptionOCCError, e.what());
761
        return nullptr;
762
    }
763
}
764

765
PyObject*  TopoShapePy::slices(PyObject *args)
766
{
767
    PyObject *dir, *dist;
768
    if (!PyArg_ParseTuple(args, "O!O", &(Base::VectorPy::Type), &dir, &dist))
769
        return nullptr;
770

771
    try {
772
        Base::Vector3d vec = Py::Vector(dir, false).toVector();
773
        Py::Sequence list(dist);
774
        std::vector<double> d;
775
        d.reserve(list.size());
776
        for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it)
777
            d.push_back((double)Py::Float(*it));
778
        return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementSlices(vec, d)));
779
    }
780
    catch (Standard_Failure& e) {
781
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
782
        return nullptr;
783
    }
784
    catch (const std::exception& e) {
785
        PyErr_SetString(PartExceptionOCCError, e.what());
786
        return nullptr;
787
    }
788
}
789

790
PyObject*  TopoShapePy::cut(PyObject *args)
791
{
792
    return makeShape(Part::OpCodes::Cut, *getTopoShapePtr(), args);
793
}
794

795
PyObject*  TopoShapePy::generalFuse(PyObject *args)
796
{
797
    double tolerance = 0.0;
798
    PyObject *pcObj;
799
    if (!PyArg_ParseTuple(args, "O|d", &pcObj, &tolerance))
800
        return nullptr;
801

802
    std::vector<std::vector<TopoShape>> modifies;
803
    std::vector<TopoShape> shapes;
804
    shapes.push_back(*getTopoShapePtr());
805
    try {
806
        getPyShapes(pcObj, shapes);
807
        TopoShape res;
808
        res.makeElementGeneralFuse(shapes, modifies, tolerance);
809
        Py::List mapPy;
810
        for (auto& mod : modifies) {
811
            Py::List shapesPy;
812
            for (auto& sh : mod) {
813
                shapesPy.append(shape2pyshape(sh));
814
            }
815
            mapPy.append(shapesPy);
816
        }
817
        Py::Tuple ret(2);
818
        ret[0] = shape2pyshape(res);
819
        ret[1] = mapPy;
820
        return Py::new_reference_to(ret);
821
    }
822
    PY_CATCH_OCC
823
}
824

825
PyObject*  TopoShapePy::sewShape(PyObject *args)
826
{
827
    double tolerance = 1.0e-06;
828
    if (!PyArg_ParseTuple(args, "|d", &tolerance))
829
        return nullptr;
830

831
    try {
832
        getTopoShapePtr()->sewShape();
833
        Py_Return;
834
    }
835
    catch (Standard_Failure& e) {
836
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
837
        return nullptr;
838
    }
839
}
840

841
PyObject* TopoShapePy::childShapes(PyObject *args)
842
{
843
    PyObject* cumOri = Py_True;
844
    PyObject* cumLoc = Py_True;
845
    if (!PyArg_ParseTuple(args, "|O!O!", &(PyBool_Type), &cumOri, &(PyBool_Type), &cumLoc))
846
        return nullptr;
847

848
    TopoShape shape = *getTopoShapePtr();
849
    if (!PyObject_IsTrue(cumOri)) {
850
        shape.setShape(shape.getShape().Oriented(TopAbs_FORWARD), false);
851
    }
852
    if (!PyObject_IsTrue(cumLoc)) {
853
        shape.setShape(shape.getShape().Located(TopLoc_Location()), false);
854
    }
855
    Py::List list;
856
    PY_TRY
857
    {
858
        for (auto& s : shape.getSubTopoShapes()) {
859
            list.append(shape2pyshape(s));
860
        }
861
        return Py::new_reference_to(list);
862
    }
863
    PY_CATCH_OCC
864
}
865

866
namespace Part {
867
// Containers to associate TopAbs_ShapeEnum values to each TopoShape*Py class
868
static const std::vector<std::pair<PyTypeObject*, TopAbs_ShapeEnum>> vecTypeShape = {
869
    {&TopoShapeCompoundPy::Type, TopAbs_COMPOUND},
870
    {&TopoShapeCompSolidPy::Type, TopAbs_COMPSOLID},
871
    {&TopoShapeSolidPy::Type, TopAbs_SOLID},
872
    {&TopoShapeShellPy::Type, TopAbs_SHELL},
873
    {&TopoShapeFacePy::Type, TopAbs_FACE},
874
    {&TopoShapeWirePy::Type, TopAbs_WIRE},
875
    {&TopoShapeEdgePy::Type, TopAbs_EDGE},
876
    {&TopoShapeVertexPy::Type, TopAbs_VERTEX},
877
    {&TopoShapePy::Type, TopAbs_SHAPE}
878
};
879

880
static const std::map<PyTypeObject*, TopAbs_ShapeEnum> mapTypeShape(
881
    vecTypeShape.begin(), vecTypeShape.end());
882

883
// Returns shape type of a Python type. Similar to TopAbs::ShapeTypeFromString.
884
// Returns TopAbs_SHAPE if pyType is not a subclass of any of the TopoShape*Py.
885
static TopAbs_ShapeEnum ShapeTypeFromPyType(PyTypeObject* pyType)
886
{
887
    for (const auto & it : vecTypeShape) {
888
        if (PyType_IsSubtype(pyType, it.first))
889
            return it.second;
890
    }
891
    return TopAbs_SHAPE;
892
}
893
}
894

895
PyObject*  TopoShapePy::ancestorsOfType(PyObject *args)
896
{
897
    PyObject *pcObj;
898
    PyObject *type;
899
    if (!PyArg_ParseTuple(args, "O!O!", &(TopoShapePy::Type), &pcObj, &PyType_Type, &type))
900
        return nullptr;
901

902
    try {
903
        const TopoDS_Shape& model = getTopoShapePtr()->getShape();
904
        const TopoDS_Shape& shape = static_cast<TopoShapePy*>(pcObj)->
905
                getTopoShapePtr()->getShape();
906
        if (model.IsNull() || shape.IsNull()) {
907
            PyErr_SetString(PyExc_ValueError, "Shape is null");
908
            return nullptr;
909
        }
910

911
        PyTypeObject* pyType = reinterpret_cast<PyTypeObject*>(type);
912
        TopAbs_ShapeEnum shapetype = ShapeTypeFromPyType(pyType);
913
        if (!PyType_IsSubtype(pyType, &TopoShapePy::Type)) {
914
            PyErr_SetString(PyExc_TypeError, "type must be a Shape subtype");
915
            return nullptr;
916
        }
917

918
        TopTools_IndexedDataMapOfShapeListOfShape mapOfShapeShape;
919
        TopExp::MapShapesAndAncestors(model, shape.ShapeType(), shapetype, mapOfShapeShape);
920
        const TopTools_ListOfShape& ancestors = mapOfShapeShape.FindFromKey(shape);
921

922
        Py::List list;
923
        std::set<Standard_Integer> hashes;
924
        TopTools_ListIteratorOfListOfShape it(ancestors);
925
        for (; it.More(); it.Next()) {
926
            // make sure to avoid duplicates
927
            Standard_Integer code = ShapeMapHasher{}(it.Value());
928
            if (hashes.find(code) == hashes.end()) {
929
                list.append(shape2pyshape(it.Value()));
930
                hashes.insert(code);
931
            }
932
        }
933

934
        return Py::new_reference_to(list);
935
    }
936
    catch (Standard_Failure& e) {
937
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
938
        return nullptr;
939
    }
940
}
941

942
PyObject*  TopoShapePy::removeInternalWires(PyObject *args)
943
{
944
    double minArea;
945
    if (!PyArg_ParseTuple(args, "d",&minArea))
946
        return nullptr;
947

948
    try {
949
        bool ok = getTopoShapePtr()->removeInternalWires(minArea);
950
        PyObject* ret = ok ? Py_True : Py_False;
951
        Py_INCREF(ret);
952
        return ret;
953
    }
954
    catch (Standard_Failure& e) {
955
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
956
        return nullptr;
957
    }
958
}
959

960
PyObject*  TopoShapePy::mirror(PyObject *args)
961
{
962
    PyObject *v1, *v2;
963
    if (!PyArg_ParseTuple(args, "O!O!", &(Base::VectorPy::Type),&v1, &(Base::VectorPy::Type),&v2))
964
        return nullptr;
965

966
    Base::Vector3d base = Py::Vector(v1,false).toVector();
967
    Base::Vector3d norm = Py::Vector(v2,false).toVector();
968

969
    try {
970
        gp_Ax2 ax2(gp_Pnt(base.x,base.y,base.z), gp_Dir(norm.x,norm.y,norm.z));
971
        return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementMirror(ax2)));
972
    }
973
    catch (Standard_Failure& e) {
974
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
975
        return nullptr;
976
    }
977
}
978

979
PyObject*  TopoShapePy::transformGeometry(PyObject *args)
980
{
981
    PyObject *obj;
982
    PyObject *cpy = Py_False;
983
    if (!PyArg_ParseTuple(args, "O!|O!", &(Base::MatrixPy::Type), &obj, &PyBool_Type, &cpy))
984
        return nullptr;
985

986
    try {
987
        Base::Matrix4D mat = static_cast<Base::MatrixPy*>(obj)->value();
988
        TopoDS_Shape shape = this->getTopoShapePtr()->transformGShape(mat, Base::asBoolean(cpy));
989
        return new TopoShapePy(new TopoShape(shape));
990
    }
991
    catch (Standard_Failure& e) {
992
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
993
        return nullptr;
994
    }
995
}
996

997
PyObject*  TopoShapePy::transformShape(PyObject *args)
998
{
999
    PyObject *obj;
1000
    PyObject *copy = Py_False;
1001
    PyObject *checkScale = Py_False;
1002
    if (!PyArg_ParseTuple(args, "O!|O!O!", &(Base::MatrixPy::Type),&obj,&(PyBool_Type), &copy, &(PyBool_Type), &checkScale))
1003
        return nullptr;
1004

1005
    Base::Matrix4D mat = static_cast<Base::MatrixPy*>(obj)->value();
1006
    PY_TRY {
1007
        this->getTopoShapePtr()->transformShape(mat, Base::asBoolean(copy), Base::asBoolean(checkScale));
1008
        return IncRef();
1009
    }
1010
    PY_CATCH_OCC
1011
}
1012

1013
PyObject* TopoShapePy::transformed(PyObject *args, PyObject *keywds)
1014
{
1015
    static const std::array<const char *, 5> kwlist{"matrix", "copy", "checkScale", "op", nullptr};
1016
    PyObject *pymat;
1017
    PyObject *copy = Py_False;
1018
    PyObject *checkScale = Py_False;
1019
    const char *op = nullptr;
1020
    if (!Base::Wrapped_ParseTupleAndKeywords(args, keywds, "O!|O!O!s", kwlist,
1021
                                             &Base::MatrixPy::Type, &pymat, &PyBool_Type, &copy, &PyBool_Type,
1022
                                             &checkScale, &op)) {
1023
        return nullptr;
1024
    }
1025

1026
    Base::Matrix4D mat = static_cast<Base::MatrixPy*>(pymat)->value();
1027
    (void)op;
1028
    PY_TRY {
1029
        TopoShape s(*getTopoShapePtr());
1030
        s.transformShape(mat,Base::asBoolean(copy), Base::asBoolean(checkScale));
1031
        return Py::new_reference_to(shape2pyshape(s));
1032
    }
1033
    PY_CATCH_OCC
1034
}
1035

1036
PyObject*  TopoShapePy::translate(PyObject *args)
1037
{
1038
    PyObject *obj;
1039
    if (!PyArg_ParseTuple(args, "O", &obj))
1040
        return nullptr;
1041

1042
    Base::Vector3d vec;
1043
    if (PyObject_TypeCheck(obj, &(Base::VectorPy::Type))) {
1044
        vec = static_cast<Base::VectorPy*>(obj)->value();
1045
    }
1046
    else if (PyObject_TypeCheck(obj, &PyTuple_Type)) {
1047
        vec = Base::getVectorFromTuple<double>(obj);
1048
    }
1049
    else {
1050
        PyErr_SetString(PyExc_TypeError, "either vector or tuple expected");
1051
        return nullptr;
1052
    }
1053

1054
    gp_Trsf mov;
1055
    mov.SetTranslation(gp_Vec(vec.x,vec.y,vec.z));
1056
    TopLoc_Location loc(mov);
1057
    TopoDS_Shape shape = getTopoShapePtr()->getShape();
1058
    shape.Move(loc);
1059
    getTopoShapePtr()->setShape(shape);
1060

1061
    return IncRef();
1062
}
1063

1064
PyObject*  TopoShapePy::rotate(PyObject *args)
1065
{
1066
    PyObject *obj1, *obj2;
1067
    double angle;
1068
    if (!PyArg_ParseTuple(args, "OOd", &obj1, &obj2, &angle))
1069
        return nullptr;
1070

1071
    PY_TRY {
1072
        // Vector also supports sequence
1073
        Py::Sequence p1(obj1), p2(obj2);
1074
        // Convert into OCC representation
1075
        gp_Pnt pos = gp_Pnt((double)Py::Float(p1[0]),
1076
                            (double)Py::Float(p1[1]),
1077
                            (double)Py::Float(p1[2]));
1078
        gp_Dir dir = gp_Dir((double)Py::Float(p2[0]),
1079
                            (double)Py::Float(p2[1]),
1080
                            (double)Py::Float(p2[2]));
1081

1082
        gp_Ax1 axis(pos, dir);
1083
        gp_Trsf mov;
1084
        mov.SetRotation(axis, angle*(M_PI/180));
1085
        TopLoc_Location loc(mov);
1086
        TopoDS_Shape shape = getTopoShapePtr()->getShape();
1087
        shape.Move(loc);
1088
        getTopoShapePtr()->setShape(shape);
1089

1090
        return IncRef();
1091
    }
1092
    PY_CATCH_OCC
1093
}
1094

1095
PyObject*  TopoShapePy::scale(PyObject *args)
1096
{
1097
    double factor;
1098
    PyObject* p=nullptr;
1099
    if (!PyArg_ParseTuple(args, "d|O!", &factor, &(Base::VectorPy::Type), &p))
1100
        return nullptr;
1101

1102
    gp_Pnt pos(0,0,0);
1103
    if (p) {
1104
        Base::Vector3d pnt = static_cast<Base::VectorPy*>(p)->value();
1105
        pos.SetX(pnt.x);
1106
        pos.SetY(pnt.y);
1107
        pos.SetZ(pnt.z);
1108
    }
1109
    if (fabs(factor) < Precision::Confusion()) {
1110
        PyErr_SetString(PyExc_ValueError, "scale factor too small");
1111
        return nullptr;
1112
    }
1113

1114
    PY_TRY {
1115
        const TopoDS_Shape& shape = getTopoShapePtr()->getShape();
1116
        if (!shape.IsNull()) {
1117
            gp_Trsf scl;
1118
            scl.SetScale(pos, factor);
1119
            BRepBuilderAPI_Transform BRepScale(scl);
1120
            bool bCopy = true;
1121
            BRepScale.Perform(shape, bCopy);
1122
            TopoShape copy(*getTopoShapePtr());
1123
            getTopoShapePtr()->makeElementShape(BRepScale, copy);
1124
        }
1125
        return IncRef();
1126
    }
1127
    PY_CATCH_OCC
1128
}
1129

1130
PyObject*  TopoShapePy::translated(PyObject *args)
1131
{
1132
    Py::Object pyobj(shape2pyshape(*getTopoShapePtr()));
1133
    return static_cast<TopoShapePy*>(pyobj.ptr())->translate(args);
1134
}
1135

1136
PyObject*  TopoShapePy::rotated(PyObject *args)
1137
{
1138
    Py::Object pyobj(shape2pyshape(*getTopoShapePtr()));
1139
    return static_cast<TopoShapePy*>(pyobj.ptr())->rotate(args);
1140
}
1141

1142
PyObject*  TopoShapePy::scaled(PyObject *args)
1143
{
1144
    Py::Object pyobj(shape2pyshape(*getTopoShapePtr()));
1145
    return static_cast<TopoShapePy*>(pyobj.ptr())->scale(args);
1146
}
1147

1148
PyObject* TopoShapePy::makeFillet(PyObject *args)
1149
{
1150
    // use two radii for all edges
1151
    double radius1, radius2;
1152
    PyObject *obj;
1153
    if (!PyArg_ParseTuple(args, "ddO", &radius1, &radius2, &obj)) {
1154
        PyErr_Clear();
1155
        if (!PyArg_ParseTuple(args, "dO", &radius1, &obj)) {
1156
            PyErr_SetString(PyExc_TypeError,
1157
                            "This method accepts:\n"
1158
                            "-- one radius and a list of edges\n"
1159
                            "-- two radii and a list of edges");
1160
            return 0;
1161
        }
1162
        radius2 = radius1;
1163
    }
1164
    PY_TRY
1165
    {
1166
        return Py::new_reference_to(shape2pyshape(
1167
            getTopoShapePtr()->makeElementFillet(getPyShapes(obj), radius1, radius2)));
1168
    }
1169
    PY_CATCH_OCC
1170
    PyErr_Clear();
1171
    // use one radius for all edges
1172
    double radius;
1173
    if (PyArg_ParseTuple(args, "dO", &radius, &obj)) {
1174
        try {
1175
            const TopoDS_Shape& shape = this->getTopoShapePtr()->getShape();
1176
            BRepFilletAPI_MakeFillet mkFillet(shape);
1177
            Py::Sequence list(obj);
1178
            for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
1179
                if (PyObject_TypeCheck((*it).ptr(), &(Part::TopoShapePy::Type))) {
1180
                    const TopoDS_Shape& edge = static_cast<TopoShapePy*>((*it).ptr())->getTopoShapePtr()->getShape();
1181
                    if (edge.ShapeType() == TopAbs_EDGE) {
1182
                        //Add edge to fillet algorithm
1183
                        mkFillet.Add(radius, TopoDS::Edge(edge));
1184
                    }
1185
                }
1186
            }
1187
            return new TopoShapePy(new TopoShape(mkFillet.Shape()));
1188
        }
1189
        catch (Standard_Failure& e) {
1190
            PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
1191
            return nullptr;
1192
        }
1193
    }
1194

1195
    PyErr_SetString(PyExc_TypeError, "This method accepts:\n"
1196
        "-- one radius and a list of edges\n"
1197
        "-- two radii and a list of edges");
1198
    return nullptr;
1199
}
1200

1201
// TODO:  Should this python interface support all three chamfer methods and not just two?
1202
PyObject* TopoShapePy::makeChamfer(PyObject *args)
1203
{
1204
    // use two radii for all edges
1205
    double radius1, radius2;
1206
    PyObject *obj;
1207
    if (!PyArg_ParseTuple(args, "ddO", &radius1, &radius2, &obj)) {
1208
        if (!PyArg_ParseTuple(args, "dO", &radius1, &obj)) {
1209
            PyErr_SetString(PyExc_TypeError,
1210
                            "This method accepts:\n"
1211
                            "-- one radius and a list of edges\n"
1212
                            "-- two radii and a list of edges");
1213
            return 0;
1214
        }
1215
        PyErr_Clear();
1216
        radius2 = radius1;
1217
    }
1218
    PY_TRY
1219
    {
1220
        return Py::new_reference_to(shape2pyshape(
1221
            getTopoShapePtr()->makeElementChamfer(getPyShapes(obj), Part::ChamferType::twoDistances, radius1, radius2)));
1222
    }
1223
    PY_CATCH_OCC
1224
    PyErr_Clear();
1225
    // use one radius for all edges
1226
    // TODO: Should this be using makeElementChamfer to support Toponaming fixes?
1227
    double radius;
1228
    if (PyArg_ParseTuple(args, "dO", &radius, &obj)) {
1229
        try {
1230
            const TopoDS_Shape& shape = this->getTopoShapePtr()->getShape();
1231
            BRepFilletAPI_MakeChamfer mkChamfer(shape);
1232
            TopTools_IndexedMapOfShape mapOfEdges;
1233
            TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace;
1234
            TopExp::MapShapesAndAncestors(shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace);
1235
            TopExp::MapShapes(shape, TopAbs_EDGE, mapOfEdges);
1236
            Py::Sequence list(obj);
1237
            for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
1238
                if (PyObject_TypeCheck((*it).ptr(), &(Part::TopoShapePy::Type))) {
1239
                    const TopoDS_Shape& edge = static_cast<TopoShapePy*>((*it).ptr())->getTopoShapePtr()->getShape();
1240
                    if (edge.ShapeType() == TopAbs_EDGE) {
1241
                        //Add edge to fillet algorithm
1242
                        const TopoDS_Face& face = TopoDS::Face(mapEdgeFace.FindFromKey(edge).First());
1243
                        mkChamfer.Add(radius, radius, TopoDS::Edge(edge), face);
1244
                    }
1245
                }
1246
            }
1247
            return new TopoShapePy(new TopoShape(mkChamfer.Shape()));
1248
        }
1249
        catch (Standard_Failure& e) {
1250
            PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
1251
            return nullptr;
1252
        }
1253
    }
1254

1255
    PyErr_SetString(PyExc_TypeError, "This method accepts:\n"
1256
        "-- one radius and a list of edges\n"
1257
        "-- two radii and a list of edges");
1258
    return nullptr;
1259
}
1260

1261
PyObject* TopoShapePy::makeThickness(PyObject *args)
1262
{
1263
    PyObject *obj;
1264
    double offset, tolerance;
1265
    PyObject* inter = Py_False;
1266
    PyObject* self_inter = Py_False;
1267
    short offsetMode = 0, join = 0;
1268
    if (!PyArg_ParseTuple(args, "Odd|O!O!hh", &obj, &offset, &tolerance,
1269
        &(PyBool_Type), &inter, &(PyBool_Type), &self_inter, &offsetMode, &join))
1270
        return nullptr;
1271

1272
    try {
1273
        return Py::new_reference_to(shape2pyshape(
1274
            getTopoShapePtr()->makeElementThickSolid(getPyShapes(obj),
1275
                                                     offset,
1276
                                                     tolerance,
1277
                                                     PyObject_IsTrue(inter) ? true : false,
1278
                                                     PyObject_IsTrue(self_inter) ? true : false,
1279
                                                     offsetMode,
1280
                                                     static_cast<JoinType>(join))));
1281
    }
1282
    catch (Standard_Failure& e) {
1283
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
1284
        return nullptr;
1285
    }
1286
}
1287

1288
PyObject* TopoShapePy::makeOffsetShape(PyObject *args, PyObject *keywds)
1289
{
1290
    static const std::array<const char *, 8> kwlist{"offset", "tolerance", "inter", "self_inter", "offsetMode", "join",
1291
                                                    "fill", nullptr};
1292
    double offset, tolerance;
1293
    PyObject *inter = Py_False;
1294
    PyObject *self_inter = Py_False;
1295
    PyObject *fill = Py_False;
1296
    short offsetMode = 0, join = 0;
1297
    if (!Base::Wrapped_ParseTupleAndKeywords(args, keywds, "dd|O!O!hhO!", kwlist, &offset, &tolerance,
1298
                                            &(PyBool_Type), &inter, &(PyBool_Type), &self_inter, &offsetMode, &join,
1299
                                            &(PyBool_Type), &fill)) {
1300
        return nullptr;
1301
    }
1302

1303
    try {
1304
        return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementOffset(
1305
            offset,
1306
            tolerance,
1307
            PyObject_IsTrue(inter) ? true : false,
1308
            PyObject_IsTrue(self_inter) ? true : false,
1309
            offsetMode,
1310
            static_cast<JoinType>(join),
1311
            PyObject_IsTrue(fill) ? FillType::fill : FillType::noFill)));
1312
    }
1313
    catch (Standard_Failure& e) {
1314
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
1315
        return nullptr;
1316
    }
1317
}
1318

1319
PyObject* TopoShapePy::makeOffset2D(PyObject *args, PyObject *keywds)
1320
{
1321
    static const std::array<const char *, 6> kwlist {"offset", "join", "fill", "openResult", "intersection", nullptr};
1322
    double offset;
1323
    PyObject* fill = Py_False;
1324
    PyObject* openResult = Py_False;
1325
    PyObject* inter = Py_False;
1326
    short join = 0;
1327
    if (!Base::Wrapped_ParseTupleAndKeywords(args, keywds, "d|hO!O!O!", kwlist, &offset, &join,
1328
                                             &(PyBool_Type), &fill, &(PyBool_Type), &openResult, &(PyBool_Type),
1329
                                             &inter)) {
1330
        return nullptr;
1331
    }
1332

1333
    try {
1334
        return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementOffset2D(
1335
            offset,
1336
            static_cast<JoinType>(join),
1337
            PyObject_IsTrue(fill) ? FillType::fill : FillType::noFill,
1338
            PyObject_IsTrue(openResult) ? OpenResult::allowOpenResult : OpenResult::noOpenResult,
1339
            PyObject_IsTrue(inter) ? true : false)));
1340
    }
1341
    PY_CATCH_OCC;
1342
}
1343

1344
PyObject*  TopoShapePy::reverse(PyObject *args)
1345
{
1346
    if (!PyArg_ParseTuple(args, ""))
1347
        return nullptr;
1348

1349
    TopoDS_Shape shape = getTopoShapePtr()->getShape();
1350
    shape.Reverse();
1351
    getTopoShapePtr()->setShape(shape);
1352

1353
    Py_Return;
1354
}
1355

1356
PyObject*  TopoShapePy::reversed(PyObject *args)
1357
{
1358
    if (!PyArg_ParseTuple(args, ""))
1359
        return nullptr;
1360

1361
    TopoDS_Shape shape = getTopoShapePtr()->getShape();
1362
    shape = shape.Reversed();
1363

1364
    PyTypeObject* type = this->GetType();
1365
    PyObject* cpy = nullptr;
1366

1367
    // let the type object decide
1368
    if (type->tp_new)
1369
        cpy = type->tp_new(type, this, nullptr);
1370
    if (!cpy) {
1371
        PyErr_SetString(PyExc_TypeError, "failed to create copy of shape");
1372
        return nullptr;
1373
    }
1374

1375
    if (!shape.IsNull()) {
1376
        static_cast<TopoShapePy*>(cpy)->getTopoShapePtr()->setShape(shape);
1377
    }
1378
    return cpy;
1379
}
1380

1381
PyObject*  TopoShapePy::complement(PyObject *args)
1382
{
1383
    if (!PyArg_ParseTuple(args, ""))
1384
        return nullptr;
1385

1386
    TopoDS_Shape shape = getTopoShapePtr()->getShape();
1387
    shape.Complement();
1388
    getTopoShapePtr()->setShape(shape);
1389

1390
    Py_Return;
1391
}
1392

1393
PyObject*  TopoShapePy::nullify(PyObject *args)
1394
{
1395
    if (!PyArg_ParseTuple(args, ""))
1396
        return nullptr;
1397

1398
    TopoDS_Shape shape = getTopoShapePtr()->getShape();
1399
    shape.Nullify();
1400
    getTopoShapePtr()->setShape(shape);
1401

1402
    Py_Return;
1403
}
1404

1405
PyObject*  TopoShapePy::isNull(PyObject *args)
1406
{
1407
    if (!PyArg_ParseTuple(args, ""))
1408
        return nullptr;
1409

1410
    bool null = getTopoShapePtr()->isNull();
1411
    return Py_BuildValue("O", (null ? Py_True : Py_False));
1412
}
1413

1414
PyObject*  TopoShapePy::isClosed(PyObject *args)
1415
{
1416
    if (!PyArg_ParseTuple(args, ""))
1417
        return nullptr;
1418

1419
    try {
1420
        if (getTopoShapePtr()->getShape().IsNull())
1421
            Standard_Failure::Raise("Cannot determine the 'Closed'' flag of an empty shape");
1422
        return Py_BuildValue("O", (getTopoShapePtr()->isClosed() ? Py_True : Py_False));
1423
    }
1424
    catch (...) {
1425
        PyErr_SetString(PyExc_RuntimeError, "check failed, shape may be empty");
1426
        return nullptr;
1427
    }
1428
}
1429

1430
PyObject*  TopoShapePy::isEqual(PyObject *args)
1431
{
1432
    PyObject *pcObj;
1433
    if (!PyArg_ParseTuple(args, "O!", &(TopoShapePy::Type), &pcObj))
1434
        return nullptr;
1435

1436
    TopoDS_Shape shape = static_cast<TopoShapePy*>(pcObj)->getTopoShapePtr()->getShape();
1437
    Standard_Boolean test = (getTopoShapePtr()->getShape().IsEqual(shape));
1438

1439
    return Py_BuildValue("O", (test ? Py_True : Py_False));
1440
}
1441

1442
PyObject*  TopoShapePy::isSame(PyObject *args)
1443
{
1444
    PyObject *pcObj;
1445
    if (!PyArg_ParseTuple(args, "O!", &(TopoShapePy::Type), &pcObj))
1446
        return nullptr;
1447

1448
    TopoDS_Shape shape = static_cast<TopoShapePy*>(pcObj)->getTopoShapePtr()->getShape();
1449
    Standard_Boolean test = getTopoShapePtr()->getShape().IsSame(shape);
1450

1451
    return Py_BuildValue("O", (test ? Py_True : Py_False));
1452
}
1453

1454
PyObject*  TopoShapePy::isPartner(PyObject *args)
1455
{
1456
    PyObject *pcObj;
1457
    if (!PyArg_ParseTuple(args, "O!", &(TopoShapePy::Type), &pcObj))
1458
        return nullptr;
1459

1460
    TopoDS_Shape shape = static_cast<TopoShapePy*>(pcObj)->getTopoShapePtr()->getShape();
1461
    Standard_Boolean test = getTopoShapePtr()->getShape().IsPartner(shape);
1462

1463
    return Py_BuildValue("O", (test ? Py_True : Py_False));
1464
}
1465

1466
PyObject*  TopoShapePy::isValid(PyObject *args)
1467
{
1468
    if (!PyArg_ParseTuple(args, ""))
1469
        return nullptr;
1470

1471
    PY_TRY {
1472
        return Py_BuildValue("O", (getTopoShapePtr()->isValid() ? Py_True : Py_False));
1473
    }
1474
    PY_CATCH_OCC
1475
}
1476

1477
PyObject*  TopoShapePy::isCoplanar(PyObject *args)
1478
{
1479
    PyObject *pyObj;
1480
    double tol = -1;
1481
    if (!PyArg_ParseTuple(args, "O!|d", &TopoShapePy::Type, &pyObj, &tol))
1482
        return nullptr;
1483

1484
    PY_TRY {
1485
        return Py::new_reference_to(Py::Boolean(getTopoShapePtr()->isCoplanar(
1486
                    *static_cast<TopoShapePy*>(pyObj)->getTopoShapePtr(),tol)));
1487
    }
1488
    PY_CATCH_OCC
1489
}
1490

1491
PyObject*  TopoShapePy::isInfinite(PyObject *args)
1492
{
1493
    if (!PyArg_ParseTuple(args, ""))
1494
        return nullptr;
1495

1496
    PY_TRY {
1497
        return Py::new_reference_to(Py::Boolean(getTopoShapePtr()->isInfinite()));
1498
    }
1499
    PY_CATCH_OCC
1500
}
1501

1502
PyObject*  TopoShapePy::findPlane(PyObject *args)
1503
{
1504
    double tol = -1;
1505
    if (!PyArg_ParseTuple(args, "|d", &tol))
1506
        return nullptr;
1507

1508
    PY_TRY {
1509
        gp_Pln pln;
1510
        if (getTopoShapePtr()->findPlane(pln, tol))
1511
            return new PlanePy(new GeomPlane(new Geom_Plane(pln)));
1512
        Py_Return;
1513
    }
1514
    PY_CATCH_OCC
1515
}
1516

1517
PyObject*  TopoShapePy::fix(PyObject *args)
1518
{
1519
    double prec, mintol, maxtol;
1520
    if (!PyArg_ParseTuple(args, "ddd", &prec, &mintol, &maxtol))
1521
        return nullptr;
1522

1523
    try {
1524
        return Py_BuildValue("O", (getTopoShapePtr()->fix(prec, mintol, maxtol) ? Py_True : Py_False));
1525
    }
1526
    catch (...) {
1527
        PyErr_SetString(PyExc_RuntimeError, "check failed, shape may be empty");
1528
        return nullptr;
1529
    }
1530
}
1531

1532
PyObject* TopoShapePy::hashCode(PyObject *args)
1533
{
1534
    int upper = IntegerLast();
1535
    if (!PyArg_ParseTuple(args, "|i",&upper))
1536
        return nullptr;
1537

1538
    int hc = ShapeMapHasher{}(getTopoShapePtr()->getShape());
1539
    return Py_BuildValue("i", hc);
1540
}
1541

1542
PyObject* TopoShapePy::tessellate(PyObject *args)
1543
{
1544
    double tolerance;
1545
    PyObject* ok = Py_False;
1546
    if (!PyArg_ParseTuple(args, "d|O!", &tolerance, &PyBool_Type, &ok))
1547
        return nullptr;
1548

1549
    try {
1550
        std::vector<Base::Vector3d> Points;
1551
        std::vector<Data::ComplexGeoData::Facet> Facets;
1552
        if (Base::asBoolean(ok))
1553
            BRepTools::Clean(getTopoShapePtr()->getShape());
1554
        getTopoShapePtr()->getFaces(Points, Facets,tolerance);
1555
        Py::Tuple tuple(2);
1556
        Py::List vertex;
1557
        for (const auto & Point : Points)
1558
            vertex.append(Py::asObject(new Base::VectorPy(Point)));
1559
        tuple.setItem(0, vertex);
1560
        Py::List facet;
1561
        for (const auto& it : Facets) {
1562
            Py::Tuple f(3);
1563
            f.setItem(0,Py::Long((long)it.I1));
1564
            f.setItem(1,Py::Long((long)it.I2));
1565
            f.setItem(2,Py::Long((long)it.I3));
1566
            facet.append(f);
1567
        }
1568
        tuple.setItem(1, facet);
1569
        return Py::new_reference_to(tuple);
1570
    }
1571
    catch (Standard_Failure& e) {
1572
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
1573
        return nullptr;
1574
    }
1575
}
1576

1577
PyObject* TopoShapePy::project(PyObject *args)
1578
{
1579
    PyObject *obj;
1580

1581
    BRepAlgo_NormalProjection algo;
1582
    algo.Init(this->getTopoShapePtr()->getShape());
1583
    if (!PyArg_ParseTuple(args, "O", &obj))
1584
        return nullptr;
1585

1586
    try {
1587
        Py::Sequence list(obj);
1588
        for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
1589
            if (PyObject_TypeCheck((*it).ptr(), &(Part::TopoShapePy::Type))) {
1590
                const TopoDS_Shape& shape = static_cast<TopoShapePy*>((*it).ptr())->getTopoShapePtr()->getShape();
1591
                algo.Add(shape);
1592
            }
1593
        }
1594

1595
        algo.Compute3d(Standard_True);
1596
        algo.SetLimit(Standard_True);
1597
        algo.SetParams(1.e-6, 1.e-6, GeomAbs_C1, 14, 10000);
1598
        //algo.SetDefaultParams();
1599
        algo.Build();
1600
        return new TopoShapePy(new TopoShape(algo.Projection()));
1601
    }
1602
    catch (Standard_Failure&) {
1603
        PyErr_SetString(PartExceptionOCCError, "Failed to project shape");
1604
        return nullptr;
1605
    }
1606
}
1607

1608
PyObject* TopoShapePy::makeParallelProjection(PyObject *args)
1609
{
1610
    PyObject *pShape, *pDir;
1611
    if (!PyArg_ParseTuple(args, "O!O!", &(Part::TopoShapePy::Type), &pShape, &Base::VectorPy::Type, &pDir))
1612
        return nullptr;
1613

1614
    try {
1615
        const TopoDS_Shape& shape = this->getTopoShapePtr()->getShape();
1616
        const TopoDS_Shape& wire = static_cast<TopoShapePy*>(pShape)->getTopoShapePtr()->getShape();
1617
        Base::Vector3d vec = Py::Vector(pDir,false).toVector();
1618
        BRepProj_Projection proj(wire, shape, gp_Dir(vec.x,vec.y,vec.z));
1619
        TopoDS_Shape projected = proj.Shape();
1620
        return new TopoShapePy(new TopoShape(projected));
1621
    }
1622
    catch (Standard_Failure& e) {
1623
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
1624
        return nullptr;
1625
    }
1626
}
1627

1628
PyObject* TopoShapePy::makePerspectiveProjection(PyObject *args)
1629
{
1630
    PyObject *pShape, *pDir;
1631
    if (!PyArg_ParseTuple(args, "O!O!", &(Part::TopoShapePy::Type), &pShape, &Base::VectorPy::Type, &pDir))
1632
        return nullptr;
1633

1634
    try {
1635
        const TopoDS_Shape& shape = this->getTopoShapePtr()->getShape();
1636
        const TopoDS_Shape& wire = static_cast<TopoShapePy*>(pShape)->getTopoShapePtr()->getShape();
1637
        Base::Vector3d vec = Py::Vector(pDir,false).toVector();
1638
        BRepProj_Projection proj(wire, shape, gp_Pnt(vec.x,vec.y,vec.z));
1639
        TopoDS_Shape projected = proj.Shape();
1640
        return new TopoShapePy(new TopoShape(projected));
1641
    }
1642
    catch (Standard_Failure& e) {
1643
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
1644
        return nullptr;
1645
    }
1646
}
1647

1648
/*!
1649
from pivy import coin
1650

1651
rot=Gui.ActiveDocument.ActiveView.getCameraOrientation()
1652
vdir=App.Vector(0,0,-1)
1653
vdir=rot.multVec(vdir)
1654
udir=App.Vector(0,1,0)
1655
udir=rot.multVec(udir)
1656

1657
pos=Gui.ActiveDocument.ActiveView.getCameraNode().position.getValue().getValue()
1658
pos=App.Vector(*pos)
1659

1660
shape=App.ActiveDocument.ActiveObject.Shape
1661
reflect=shape.reflectLines(ViewDir=vdir, ViewPos=pos, UpDir=udir, EdgeType="Sharp", Visible=True, OnShape=False)
1662
Part.show(reflect)
1663
 */
1664
PyObject* TopoShapePy::reflectLines(PyObject *args, PyObject *kwds)
1665
{
1666
    static const std::array<const char *, 7> kwlist{"ViewDir", "ViewPos", "UpDir", "EdgeType", "Visible", "OnShape",
1667
                                                    nullptr};
1668

1669
    const char* type="OutLine";
1670
    PyObject* vis = Py_True;
1671
    PyObject* in3d = Py_False;
1672
    PyObject* pPos = nullptr;
1673
    PyObject* pUp = nullptr;
1674
    PyObject *pView;
1675
    if (!Base::Wrapped_ParseTupleAndKeywords(args, kwds, "O!|O!O!sO!O!", kwlist,
1676
                                             &Base::VectorPy::Type, &pView, &Base::VectorPy::Type, &pPos,
1677
                                             &Base::VectorPy::Type,
1678
                                             &pUp, &type, &PyBool_Type, &vis, &PyBool_Type, &in3d)) {
1679
        return nullptr;
1680
    }
1681

1682
    try {
1683
        HLRBRep_TypeOfResultingEdge t;
1684
        std::string str = type;
1685
        if (str == "IsoLine")
1686
            t = HLRBRep_IsoLine;
1687
        else if (str == "Rg1Line")
1688
            t = HLRBRep_Rg1Line;
1689
        else if (str == "RgNLine")
1690
            t = HLRBRep_RgNLine;
1691
        else if (str == "Sharp")
1692
            t = HLRBRep_Sharp;
1693
        else
1694
            t = HLRBRep_OutLine;
1695

1696
        Base::Vector3d p(0.0, 0.0, 0.0);
1697
        if (pPos)
1698
            p = Py::Vector(pPos,false).toVector();
1699
        Base::Vector3d u(0.0, 1.0, 0.0);
1700
        if (pUp)
1701
            u = Py::Vector(pUp,false).toVector();
1702

1703
        Base::Vector3d v = Py::Vector(pView,false).toVector();
1704
        const TopoDS_Shape& shape = this->getTopoShapePtr()->getShape();
1705
        HLRAppli_ReflectLines reflect(shape);
1706
        reflect.SetAxes(v.x, v.y, v.z, p.x, p.y, p.z, u.x, u.y, u.z);
1707
        reflect.Perform();
1708
        TopoDS_Shape lines = reflect.GetCompoundOf3dEdges(t, Base::asBoolean(vis), Base::asBoolean(in3d));
1709
        return new TopoShapePy(new TopoShape(lines));
1710
    }
1711
    catch (Standard_Failure& e) {
1712
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
1713
        return nullptr;
1714
    }
1715
}
1716

1717
PyObject* TopoShapePy::makeShapeFromMesh(PyObject *args)
1718
{
1719
    PyObject *tup;
1720
    double tolerance = 1.0e-06;
1721
    PyObject* sewShape = Py_True;
1722
    if (!PyArg_ParseTuple(args, "O!|dO!",&PyTuple_Type, &tup, &tolerance, &PyBool_Type, &sewShape))
1723
        return nullptr;
1724

1725
    try {
1726
        Py::Tuple tuple(tup);
1727
        Py::Sequence vertex(tuple[0]);
1728
        Py::Sequence facets(tuple[1]);
1729

1730
        std::vector<Base::Vector3d> Points;
1731
        for (Py::Sequence::iterator it = vertex.begin(); it != vertex.end(); ++it) {
1732
            Py::Vector vec(*it);
1733
            Points.push_back(vec.toVector());
1734
        }
1735
        std::vector<Data::ComplexGeoData::Facet> Facets;
1736
        for (Py::Sequence::iterator it = facets.begin(); it != facets.end(); ++it) {
1737
            Data::ComplexGeoData::Facet face;
1738
            Py::Tuple f(*it);
1739
            face.I1 = (int)Py::Long(f[0]);
1740
            face.I2 = (int)Py::Long(f[1]);
1741
            face.I3 = (int)Py::Long(f[2]);
1742
            Facets.push_back(face);
1743
        }
1744

1745
        getTopoShapePtr()->setFaces(Points, Facets, tolerance);
1746
        if (Base::asBoolean(sewShape))
1747
            getTopoShapePtr()->sewShape(tolerance);
1748

1749
        Py_Return;
1750
    }
1751
    PY_CATCH_OCC
1752
}
1753

1754
PyObject* TopoShapePy::makeEvolved(PyObject *args, PyObject *kwds)
1755
{
1756
    PyObject* Profile;
1757
    PyObject* AxeProf = Py_True;
1758
    PyObject* Solid = Py_False;
1759
    PyObject* ProfOnSpine = Py_False;
1760
    auto JoinType = JoinType::arc;
1761
    double Tolerance = 0.0000001;
1762

1763
    static const std::array<const char*, 7> kwds_evolve{"Profile", "Join", "AxeProf", "Solid", "ProfOnSpine", "Tolerance", nullptr};
1764
    if (!Base::Wrapped_ParseTupleAndKeywords(args, kwds, "O!|iO!O!O!d", kwds_evolve,
1765
        &TopoShapePy::Type, &Profile, &JoinType,
1766
        &PyBool_Type, &AxeProf, &PyBool_Type, &Solid,
1767
        &PyBool_Type, &ProfOnSpine, &Tolerance)) {
1768
        return nullptr;
1769
    }
1770
    try {
1771
        return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementEvolve(
1772
            *static_cast<TopoShapePy*>(Profile)->getTopoShapePtr(), JoinType,
1773
            PyObject_IsTrue(AxeProf) ? CoordinateSystem::global : CoordinateSystem::relativeToSpine,
1774
            PyObject_IsTrue(Solid) ? MakeSolid::makeSolid : MakeSolid::noSolid,
1775
            PyObject_IsTrue(ProfOnSpine) ? Spine::on : Spine::notOn,
1776
            Tolerance)));
1777
    } PY_CATCH_OCC
1778
}
1779

1780
PyObject* TopoShapePy::makeWires(PyObject *args) {
1781
    const char *op = nullptr;
1782
    if (!PyArg_ParseTuple(args, "s", &op))
1783
        return nullptr;
1784

1785
    PY_TRY {
1786
        return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeWires(op)));
1787
    }
1788
    PY_CATCH_OCC
1789
}
1790

1791
PyObject* TopoShapePy::toNurbs(PyObject *args)
1792
{
1793
    if (!PyArg_ParseTuple(args, ""))
1794
        return nullptr;
1795

1796
    try {
1797
        // Convert into nurbs
1798
        TopoDS_Shape nurbs = this->getTopoShapePtr()->toNurbs();
1799
        return new TopoShapePy(new TopoShape(nurbs));
1800
    }
1801
    catch (Standard_Failure& e) {
1802
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
1803
        return nullptr;
1804
    }
1805
}
1806

1807
PyObject*  TopoShapePy::isInside(PyObject *args)
1808
{
1809
    PyObject *point;
1810
    double tolerance;
1811
    PyObject* checkFace = Py_False;
1812
    TopAbs_State stateIn = TopAbs_IN;
1813
    if (!PyArg_ParseTuple(args, "O!dO!", &(Base::VectorPy::Type), &point, &tolerance,  &PyBool_Type, &checkFace))
1814
        return nullptr;
1815

1816
    try {
1817
        TopoDS_Shape shape = getTopoShapePtr()->getShape();
1818
        if (shape.IsNull()) {
1819
            PyErr_SetString(PartExceptionOCCError, "Cannot handle null shape");
1820
            return nullptr;
1821
        }
1822

1823
        Base::Vector3d pnt = static_cast<Base::VectorPy*>(point)->value();
1824
        gp_Pnt vertex = gp_Pnt(pnt.x,pnt.y,pnt.z);
1825
        if (shape.ShapeType() == TopAbs_VERTEX ||
1826
            shape.ShapeType() == TopAbs_EDGE ||
1827
            shape.ShapeType() == TopAbs_WIRE ||
1828
            shape.ShapeType() == TopAbs_FACE) {
1829

1830
            BRepBuilderAPI_MakeVertex mkVertex(vertex);
1831
            BRepExtrema_DistShapeShape extss;
1832
            extss.LoadS1(mkVertex.Vertex());
1833
            extss.LoadS2(shape);
1834
            if (!extss.Perform()) {
1835
                PyErr_SetString(PartExceptionOCCError, "Failed to determine distance to shape");
1836
                return nullptr;
1837
            }
1838
            Standard_Boolean test = (extss.Value() <= tolerance);
1839
            return Py_BuildValue("O", (test ? Py_True : Py_False));
1840
        }
1841
        else {
1842
            BRepClass3d_SolidClassifier solidClassifier(shape);
1843
            solidClassifier.Perform(vertex, tolerance);
1844
            Standard_Boolean test = (solidClassifier.State() == stateIn);
1845

1846
            if (Base::asBoolean(checkFace) && solidClassifier.IsOnAFace())
1847
                test = Standard_True;
1848
            return Py_BuildValue("O", (test ? Py_True : Py_False));
1849
        }
1850
    }
1851
    catch (Standard_Failure& e) {
1852
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
1853
        return nullptr;
1854
    }
1855
    catch (const std::exception& e) {
1856
        PyErr_SetString(PartExceptionOCCError, e.what());
1857
        return nullptr;
1858
    }
1859
}
1860

1861
PyObject* TopoShapePy::removeSplitter(PyObject *args)
1862
{
1863
    if (!PyArg_ParseTuple(args, ""))
1864
        return nullptr;
1865

1866
    try {
1867
        return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementRefine()));
1868
    }
1869
    catch (Standard_Failure& e) {
1870
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
1871
        return nullptr;
1872
    }
1873
}
1874

1875
PyObject* TopoShapePy::getElement(PyObject *args)
1876
{
1877
    char* input;
1878
    PyObject* silent = Py_False;
1879
    if (!PyArg_ParseTuple(args, "s|O", &input, &silent)) {
1880
        return nullptr;
1881
    }
1882
    try {
1883
        PyObject* res = getTopoShapePtr()->getPySubShape(input, PyObject_IsTrue(silent));
1884
        if (!res) {
1885
            Py_Return;
1886
        }
1887
        return res;
1888
    }
1889
    PY_CATCH_OCC
1890
}
1891

1892
PyObject* TopoShapePy::countElement(PyObject *args)
1893
{
1894
    char* input;
1895
    if (!PyArg_ParseTuple(args, "s", &input))
1896
        return nullptr;
1897

1898
    PY_TRY {
1899
        return Py::new_reference_to(Py::Int((long)getTopoShapePtr()->countSubShapes(input)));
1900
    }
1901
    PY_CATCH_OCC
1902
}
1903

1904
PyObject* TopoShapePy::getTolerance(PyObject *args)
1905
{
1906
    int mode;
1907
    PyObject* type = reinterpret_cast<PyObject*>(&TopoShapePy::Type);
1908
    if (!PyArg_ParseTuple(args, "i|O!", &mode, &PyType_Type, &type))
1909
        return nullptr;
1910

1911
    try {
1912
        TopoDS_Shape shape = this->getTopoShapePtr()->getShape();
1913
        PyTypeObject* pyType = reinterpret_cast<PyTypeObject*>(type);
1914
        TopAbs_ShapeEnum shapetype = ShapeTypeFromPyType(pyType);
1915
        if (!PyType_IsSubtype(pyType, &TopoShapePy::Type) ||
1916
            (shapetype != TopAbs_SHAPE && shapetype != TopAbs_VERTEX &&
1917
            shapetype != TopAbs_EDGE && shapetype != TopAbs_FACE && shapetype != TopAbs_SHELL)) {
1918
            PyErr_SetString(PyExc_TypeError, "shape type must be Shape, Vertex, Edge, Face or Shell");
1919
            return nullptr;
1920
        }
1921

1922
        ShapeAnalysis_ShapeTolerance analysis;
1923
        double tolerance = analysis.Tolerance(shape, mode, shapetype);
1924
        return PyFloat_FromDouble(tolerance);
1925
    }
1926
    catch (Standard_Failure& e) {
1927
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
1928
        return nullptr;
1929
    }
1930
}
1931

1932
PyObject* TopoShapePy::overTolerance(PyObject *args)
1933
{
1934
    double value;
1935
    PyObject* type = reinterpret_cast<PyObject*>(&TopoShapePy::Type);
1936
    if (!PyArg_ParseTuple(args, "d|O!", &value, &PyType_Type, &type))
1937
        return nullptr;
1938

1939
    try {
1940
        TopoDS_Shape shape = this->getTopoShapePtr()->getShape();
1941
        PyTypeObject* pyType = reinterpret_cast<PyTypeObject*>(type);
1942
        TopAbs_ShapeEnum shapetype = ShapeTypeFromPyType(pyType);
1943
        if (!PyType_IsSubtype(pyType, &TopoShapePy::Type) ||
1944
            (shapetype != TopAbs_SHAPE && shapetype != TopAbs_VERTEX &&
1945
            shapetype != TopAbs_EDGE && shapetype != TopAbs_FACE && shapetype != TopAbs_SHELL)) {
1946
            PyErr_SetString(PyExc_TypeError, "shape type must be Shape, Vertex, Edge, Face or Shell");
1947
            return nullptr;
1948
        }
1949

1950
        ShapeAnalysis_ShapeTolerance analysis;
1951
        Handle(TopTools_HSequenceOfShape) seq = analysis.OverTolerance(shape, value, shapetype);
1952
        Py::Tuple tuple(seq->Length());
1953
        std::size_t index=0;
1954
        for (int i=1; i <= seq->Length(); i++) {
1955
            TopoDS_Shape item = seq->Value(i);
1956
            tuple.setItem(index++, shape2pyshape(item));
1957
        }
1958
        return Py::new_reference_to(tuple);
1959
    }
1960
    catch (Standard_Failure& e) {
1961
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
1962
        return nullptr;
1963
    }
1964
}
1965

1966
PyObject* TopoShapePy::inTolerance(PyObject *args)
1967
{
1968
    double valmin;
1969
    double valmax;
1970
    PyObject* type = reinterpret_cast<PyObject*>(&TopoShapePy::Type);
1971
    if (!PyArg_ParseTuple(args, "dd|O!", &valmin, &valmax, &PyType_Type, &type))
1972
        return nullptr;
1973

1974
    try {
1975
        TopoDS_Shape shape = this->getTopoShapePtr()->getShape();
1976
        PyTypeObject* pyType = reinterpret_cast<PyTypeObject*>(type);
1977
        TopAbs_ShapeEnum shapetype = ShapeTypeFromPyType(pyType);
1978
        if (!PyType_IsSubtype(pyType, &TopoShapePy::Type) ||
1979
            (shapetype != TopAbs_SHAPE && shapetype != TopAbs_VERTEX &&
1980
            shapetype != TopAbs_EDGE && shapetype != TopAbs_FACE && shapetype != TopAbs_SHELL)) {
1981
            PyErr_SetString(PyExc_TypeError, "shape type must be Shape, Vertex, Edge, Face or Shell");
1982
            return nullptr;
1983
        }
1984

1985
        ShapeAnalysis_ShapeTolerance analysis;
1986
        Handle(TopTools_HSequenceOfShape) seq = analysis.InTolerance(shape, valmin, valmax, shapetype);
1987
        Py::Tuple tuple(seq->Length());
1988
        std::size_t index=0;
1989
        for (int i=1; i <= seq->Length(); i++) {
1990
            TopoDS_Shape item = seq->Value(i);
1991
            tuple.setItem(index++, shape2pyshape(item));
1992
        }
1993
        return Py::new_reference_to(tuple);
1994
    }
1995
    catch (Standard_Failure& e) {
1996
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
1997
        return nullptr;
1998
    }
1999
}
2000

2001
PyObject* TopoShapePy::globalTolerance(PyObject *args)
2002
{
2003
    int mode;
2004
    if (!PyArg_ParseTuple(args, "i", &mode))
2005
        return nullptr;
2006

2007
    try {
2008
        TopoDS_Shape shape = this->getTopoShapePtr()->getShape();
2009
        ShapeAnalysis_ShapeTolerance analysis;
2010
        analysis.Tolerance(shape, mode);
2011
        double tolerance = analysis.GlobalTolerance(mode);
2012

2013
        return PyFloat_FromDouble(tolerance);
2014
    }
2015
    catch (Standard_Failure& e) {
2016
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
2017
        return nullptr;
2018
    }
2019
}
2020

2021
PyObject* TopoShapePy::fixTolerance(PyObject *args)
2022
{
2023
    double value;
2024
    PyObject* type = reinterpret_cast<PyObject*>(&TopoShapePy::Type);
2025
    if (!PyArg_ParseTuple(args, "d|O!", &value, &PyType_Type, &type))
2026
        return nullptr;
2027

2028
    try {
2029
        TopoDS_Shape shape = this->getTopoShapePtr()->getShape();
2030
        PyTypeObject* pyType = reinterpret_cast<PyTypeObject*>(type);
2031
        TopAbs_ShapeEnum shapetype = ShapeTypeFromPyType(pyType);
2032
        if (!PyType_IsSubtype(pyType, &TopoShapePy::Type)) {
2033
            PyErr_SetString(PyExc_TypeError, "type must be a Shape subtype");
2034
            return nullptr;
2035
        }
2036

2037
        ShapeFix_ShapeTolerance fix;
2038
        fix.SetTolerance(shape, value, shapetype);
2039
        Py_Return;
2040
    }
2041
    catch (Standard_Failure& e) {
2042
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
2043
        return nullptr;
2044
    }
2045
}
2046

2047
PyObject* TopoShapePy::limitTolerance(PyObject *args)
2048
{
2049
    double tmin;
2050
    double tmax=0;
2051
    PyObject* type = reinterpret_cast<PyObject*>(&TopoShapePy::Type);
2052
    if (!PyArg_ParseTuple(args, "d|dO!", &tmin, &tmax, &PyType_Type, &type))
2053
        return nullptr;
2054

2055
    try {
2056
        TopoDS_Shape shape = this->getTopoShapePtr()->getShape();
2057
        PyTypeObject* pyType = reinterpret_cast<PyTypeObject*>(type);
2058
        TopAbs_ShapeEnum shapetype = ShapeTypeFromPyType(pyType);
2059
        if (!PyType_IsSubtype(pyType, &TopoShapePy::Type)) {
2060
            PyErr_SetString(PyExc_TypeError, "type must be a Shape subtype");
2061
            return nullptr;
2062
        }
2063

2064
        ShapeFix_ShapeTolerance fix;
2065
        Standard_Boolean ok = fix.LimitTolerance(shape, tmin, tmax, shapetype);
2066
        return PyBool_FromLong(ok ? 1 : 0);
2067
    }
2068
    catch (Standard_Failure& e) {
2069
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
2070
        return nullptr;
2071
    }
2072
}
2073

2074
PyObject* _getSupportIndex(const char* suppStr, TopoShape* ts, TopoDS_Shape suppShape) {
2075
    std::stringstream ss;
2076
    TopoDS_Shape subShape;
2077

2078
    unsigned long nSubShapes = ts->countSubShapes(suppStr);
2079
    long supportIndex = -1;
2080
    for (unsigned long j=1; j<=nSubShapes; j++){
2081
        ss.str("");
2082
        ss << suppStr << j;
2083
        subShape = ts->getSubShape(ss.str().c_str());
2084
        if (subShape.IsEqual(suppShape)) {
2085
            supportIndex = j-1;
2086
            break;
2087
        }
2088
    }
2089
    return PyLong_FromLong(supportIndex);
2090
}
2091

2092
PyObject* TopoShapePy::proximity(PyObject *args)
2093
{
2094
    using BRepExtrema_OverlappedSubShapes = BRepExtrema_MapOfIntegerPackedMapOfInteger;
2095

2096
    PyObject* ps2;
2097
    Standard_Real tol = Precision::Confusion();
2098
    if (!PyArg_ParseTuple(args, "O!|d",&(TopoShapePy::Type), &ps2, &tol))
2099
        return nullptr;
2100

2101
    const TopoDS_Shape& s1 = getTopoShapePtr()->getShape();
2102
    const TopoDS_Shape& s2 = static_cast<Part::TopoShapePy*>(ps2)->getTopoShapePtr()->getShape();
2103
    if (s1.IsNull()) {
2104
        PyErr_SetString(PyExc_ValueError, "proximity: Shape object is invalid");
2105
        return nullptr;
2106
    }
2107
    if (s2.IsNull()) {
2108
        PyErr_SetString(PyExc_ValueError, "proximity: Shape parameter is invalid");
2109
        return nullptr;
2110
    }
2111

2112
    BRepExtrema_ShapeProximity proximity;
2113
    proximity.LoadShape1 (s1);
2114
    proximity.LoadShape2 (s2);
2115
    if (tol > 0.0) {
2116
        proximity.SetTolerance (tol);
2117
    }
2118

2119
    proximity.Perform();
2120
    if (!proximity.IsDone()) {
2121
        PyErr_SetString(PartExceptionOCCError, "BRepExtrema_ShapeProximity failed, make sure the shapes are tessellated");
2122
        return nullptr;
2123
    }
2124

2125
    Py::List overlappssindex1;
2126
    Py::List overlappssindex2;
2127

2128
    for (BRepExtrema_OverlappedSubShapes::Iterator anIt1 (proximity.OverlapSubShapes1()); anIt1.More(); anIt1.Next()) {
2129
        overlappssindex1.append(Py::Long(anIt1.Key() + 1));
2130
    }
2131
    for (BRepExtrema_OverlappedSubShapes::Iterator anIt2 (proximity.OverlapSubShapes2()); anIt2.More(); anIt2.Next()) {
2132
        overlappssindex2.append(Py::Long(anIt2.Key() + 1));
2133
    }
2134

2135
    Py::Tuple tuple(2);
2136
    tuple.setItem(0, overlappssindex1);
2137
    tuple.setItem(1, overlappssindex2);
2138
    return Py::new_reference_to(tuple); //face indexes
2139

2140
}
2141

2142
PyObject* TopoShapePy::distToShape(PyObject *args)
2143
{
2144
    PyObject* ps2;
2145
    gp_Pnt P1, P2;
2146
    BRepExtrema_SupportType supportType1, supportType2;
2147
    TopoDS_Shape suppS1, suppS2;
2148
    Standard_Real minDist = -1, t1, t2, u1, v1, u2, v2;
2149
    Standard_Real tol = Precision::Confusion();
2150

2151
    if (!PyArg_ParseTuple(args, "O!|d",&(TopoShapePy::Type), &ps2, &tol))
2152
        return nullptr;
2153

2154
    const TopoDS_Shape& s1 = getTopoShapePtr()->getShape();
2155
    TopoShape* ts1 = getTopoShapePtr();
2156
    const TopoDS_Shape& s2 = static_cast<Part::TopoShapePy*>(ps2)->getTopoShapePtr()->getShape();
2157
    TopoShape* ts2 = static_cast<Part::TopoShapePy*>(ps2)->getTopoShapePtr();
2158

2159
    if (s2.IsNull()) {
2160
        PyErr_SetString(PyExc_TypeError, "distToShape: Shape parameter is invalid");
2161
        return nullptr;
2162
    }
2163
    BRepExtrema_DistShapeShape extss;
2164
    extss.SetDeflection(tol);
2165
#if OCC_VERSION_HEX >= 0x070600
2166
    extss.SetMultiThread(true);
2167
#endif
2168
    extss.LoadS1(s1);
2169
    extss.LoadS2(s2);
2170
    try {
2171
        extss.Perform();
2172
    }
2173
    catch (const Standard_Failure& e) {
2174
        PyErr_SetString(PyExc_RuntimeError, e.GetMessageString());
2175
        return nullptr;
2176
    }
2177
    if (!extss.IsDone()) {
2178
        PyErr_SetString(PyExc_RuntimeError, "BRepExtrema_DistShapeShape failed");
2179
        return nullptr;
2180
    }
2181
    Py::List solnPts;
2182
    Py::List solnGeom;
2183
    int count = extss.NbSolution();
2184
    if (count != 0) {
2185
        minDist = extss.Value();
2186
        //extss.Dump(std::cout);
2187
        for (int i=1; i<= count; i++) {
2188
            Py::Object pt1, pt2;
2189
            Py::String suppType1, suppType2;
2190
            Py::Long suppIndex1, suppIndex2;
2191
            Py::Object param1, param2;
2192

2193
            P1 = extss.PointOnShape1(i);
2194
            pt1 = Py::asObject(new Base::VectorPy(new Base::Vector3d(P1.X(), P1.Y(), P1.Z())));
2195
            supportType1 = extss.SupportTypeShape1(i);
2196
            suppS1 = extss.SupportOnShape1(i);
2197
            switch (supportType1) {
2198
                case BRepExtrema_IsVertex:
2199
                    suppType1 = Py::String("Vertex");
2200
                    suppIndex1 = Py::asObject(_getSupportIndex("Vertex", ts1, suppS1));
2201
                    param1 = Py::None();
2202
                    break;
2203
                case BRepExtrema_IsOnEdge:
2204
                    suppType1 = Py::String("Edge");
2205
                    suppIndex1 = Py::asObject(_getSupportIndex("Edge", ts1, suppS1));
2206
                    extss.ParOnEdgeS1(i,t1);
2207
                    param1 = Py::Float(t1);
2208
                    break;
2209
                case BRepExtrema_IsInFace:
2210
                    suppType1 = Py::String("Face");
2211
                    suppIndex1 = Py::asObject(_getSupportIndex("Face", ts1, suppS1));
2212
                    extss.ParOnFaceS1(i,u1,v1);
2213
                    {
2214
                        Py::Tuple tup(2);
2215
                        tup[0] = Py::Float(u1);
2216
                        tup[1] = Py::Float(v1);
2217
                        param1 = tup;
2218
                    }
2219
                    break;
2220
                default:
2221
                    Base::Console().Message("distToShape: supportType1 is unknown: %d \n",
2222
                                            static_cast<int>(supportType1));
2223
                    suppType1 = Py::String("Unknown");
2224
                    suppIndex1 = -1;
2225
                    param1 = Py::None();
2226
            }
2227

2228
            P2 = extss.PointOnShape2(i);
2229
            pt2 = Py::asObject(new Base::VectorPy(new Base::Vector3d(P2.X(), P2.Y(), P2.Z())));
2230
            supportType2 = extss.SupportTypeShape2(i);
2231
            suppS2 = extss.SupportOnShape2(i);
2232
            switch (supportType2) {
2233
                case BRepExtrema_IsVertex:
2234
                    suppType2 = Py::String("Vertex");
2235
                    suppIndex2 = Py::asObject(_getSupportIndex("Vertex", ts2, suppS2));
2236
                    param2 = Py::None();
2237
                    break;
2238
                case BRepExtrema_IsOnEdge:
2239
                    suppType2 = Py::String("Edge");
2240
                    suppIndex2 = Py::asObject(_getSupportIndex("Edge", ts2, suppS2));
2241
                    extss.ParOnEdgeS2(i,t2);
2242
                    param2 = Py::Float(t2);
2243
                    break;
2244
                case BRepExtrema_IsInFace:
2245
                    suppType2 = Py::String("Face");
2246
                    suppIndex2 = Py::asObject(_getSupportIndex("Face", ts2, suppS2));
2247
                    extss.ParOnFaceS2(i,u2,v2);
2248
                    {
2249
                        Py::Tuple tup(2);
2250
                        tup[0] = Py::Float(u2);
2251
                        tup[1] = Py::Float(v2);
2252
                        param2 = tup;
2253
                    }
2254
                    break;
2255
                default:
2256
                    Base::Console().Message("distToShape: supportType2 is unknown: %d \n",
2257
                                            static_cast<int>(supportType2));
2258
                    suppType2 = Py::String("Unknown");
2259
                    suppIndex2 = -1;
2260
                    param2 = Py::None();
2261
            }
2262
            Py::Tuple pts(2);
2263
            pts[0] = pt1;
2264
            pts[1] = pt2;
2265
            solnPts.append(pts);
2266

2267
            Py::Tuple geom(6);
2268
            geom[0] = suppType1;
2269
            geom[1] = suppIndex1;
2270
            geom[2] = param1;
2271
            geom[3] = suppType2;
2272
            geom[4] = suppIndex2;
2273
            geom[5] = param2;
2274

2275
            solnGeom.append(geom);
2276
        }
2277
    }
2278
    else {
2279
        PyErr_SetString(PyExc_TypeError, "distToShape: No Solutions Found.");
2280
        return nullptr;
2281
    }
2282
    Py::Tuple ret(3);
2283
    ret[0] = Py::Float(minDist);
2284
    ret[1] = solnPts;
2285
    ret[2] = solnGeom;
2286
    return Py::new_reference_to(ret);
2287
}
2288

2289
PyObject* TopoShapePy::optimalBoundingBox(PyObject *args)
2290
{
2291
    PyObject* useT = Py_True;
2292
    PyObject* useS = Py_False;
2293
    if (!PyArg_ParseTuple(args, "|O!O!", &PyBool_Type, &useT, &PyBool_Type, &useS)) {
2294
        return nullptr;
2295
    }
2296

2297
    try {
2298
        TopoDS_Shape shape = this->getTopoShapePtr()->getShape();
2299
        Bnd_Box bounds;
2300
        BRepBndLib::AddOptimal(shape, bounds,
2301
                               Base::asBoolean(useT),
2302
                               Base::asBoolean(useS));
2303
        bounds.SetGap(0.0);
2304
        Standard_Real xMin, yMin, zMin, xMax, yMax, zMax;
2305
        bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax);
2306

2307
        Base::BoundBox3d box;
2308
        box.MinX = xMin;
2309
        box.MaxX = xMax;
2310
        box.MinY = yMin;
2311
        box.MaxY = yMax;
2312
        box.MinZ = zMin;
2313
        box.MaxZ = zMax;
2314

2315
        Py::BoundingBox pybox(box);
2316
        return Py::new_reference_to(pybox);
2317
    }
2318
    catch (const Standard_Failure& e) {
2319
        throw Py::RuntimeError(e.GetMessageString());
2320
    }
2321
}
2322

2323
PyObject* TopoShapePy::clearCache(PyObject* args)
2324
{
2325
    if (!PyArg_ParseTuple(args, "")) {
2326
        return 0;
2327
    }
2328
    getTopoShapePtr()->initCache(1);
2329
    return IncRef();
2330
}
2331

2332
PyObject* TopoShapePy::defeaturing(PyObject *args)
2333
{
2334
    PyObject *l;
2335
    if (!PyArg_ParseTuple(args, "O",&l))
2336
        return nullptr;
2337

2338
    try {
2339
        Py::Sequence list(l);
2340
        std::vector<TopoDS_Shape> shapes;
2341
        for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
2342
            Py::TopoShape sh(*it);
2343
            shapes.push_back(
2344
                sh.extensionObject()->getTopoShapePtr()->getShape()
2345
            );
2346
        }
2347
        PyTypeObject* type = this->GetType();
2348
        PyObject* inst = type->tp_new(type, this, nullptr);
2349
        static_cast<TopoShapePy*>(inst)->getTopoShapePtr()->setShape
2350
            (this->getTopoShapePtr()->defeaturing(shapes));
2351
        return inst;
2352
    }
2353
    catch (const Standard_Failure& e) {
2354
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
2355
        return nullptr;
2356
    }
2357
}
2358

2359
PyObject* TopoShapePy::findSubShape(PyObject* args)
2360
{
2361
    PyObject* pyobj;
2362
    if (!PyArg_ParseTuple(args, "O", &pyobj)) {
2363
        return nullptr;
2364
    }
2365

2366
    PY_TRY
2367
    {
2368
        Py::List res;
2369
        for (auto& s : getPyShapes(pyobj)) {
2370
            int index = getTopoShapePtr()->findShape(s.getShape());
2371
            if (index > 0) {
2372
                res.append(Py::TupleN(Py::String(s.shapeName()), Py::Int(index)));
2373
            }
2374
            else {
2375
                res.append(Py::TupleN(Py::Object(), Py::Int(0)));
2376
            }
2377
        }
2378
        if (PySequence_Check(pyobj)) {
2379
            return Py::new_reference_to(res);
2380
        }
2381
        return Py::new_reference_to(Py::Object(res[0].ptr()));
2382
    }
2383
    PY_CATCH_OCC
2384
}
2385

2386
PyObject* TopoShapePy::findSubShapesWithSharedVertex(PyObject* args, PyObject* keywds)
2387
{
2388
    static const std::array<const char*, 7> kwlist {"shape", "needName", "checkGeometry", "tol", "atol", "singleResult", nullptr};
2389
    PyObject* pyobj;
2390
    PyObject* needName = Py_False;
2391
    PyObject* checkGeometry = Py_True;
2392
    PyObject* singleResult = Py_False;
2393
    double tol = 1e-7;
2394
    double atol = 1e-12;
2395
    if (!Base::Wrapped_ParseTupleAndKeywords(args,
2396
                                             keywds,
2397
                                             "O!|OOdd",
2398
                                             kwlist,
2399
                                             &Type,
2400
                                             &pyobj,
2401
                                             &needName,
2402
                                             &checkGeometry,
2403
                                             &tol,
2404
                                             &atol,
2405
                                             &singleResult)) {
2406
        return nullptr;
2407
    }
2408

2409
    PY_TRY
2410
    {
2411
        Py::List res;
2412
        const TopoShape& shape = *static_cast<TopoShapePy*>(pyobj)->getTopoShapePtr();
2413
        Data::SearchOptions options;
2414
        if (PyObject_IsTrue(checkGeometry))
2415
            options.setFlag(Data::SearchOption::CheckGeometry);
2416
        if (PyObject_IsTrue(singleResult))
2417
            options.setFlag(Data::SearchOption::SingleResult);
2418
        if (PyObject_IsTrue(needName)) {
2419
            std::vector<std::string> names;
2420
            auto shapes = getTopoShapePtr()->findSubShapesWithSharedVertex(
2421
                shape,
2422
                &names,
2423
                options,
2424
                tol,
2425
                atol);
2426
            for (std::size_t i = 0; i < shapes.size(); ++i) {
2427
                res.append(Py::TupleN(Py::String(names[i]), shape2pyshape(shapes[i])));
2428
            }
2429
        }
2430
        else {
2431
            for (auto& s : getTopoShapePtr()->findSubShapesWithSharedVertex(
2432
                     shape,
2433
                     nullptr,
2434
                     options,
2435
                     tol,
2436
                     atol)) {
2437
                res.append(shape2pyshape(s));
2438
            }
2439
        }
2440
        return Py::new_reference_to(res);
2441
    }
2442
    PY_CATCH_OCC
2443
}
2444

2445
// End of Methods, Start of Attributes
2446

2447
Py::String TopoShapePy::getShapeType() const
2448
{
2449
    TopoDS_Shape sh = getTopoShapePtr()->getShape();
2450
    if (sh.IsNull())
2451
        throw Py::Exception(Base::PyExc_FC_GeneralError, "cannot determine type of null shape");
2452

2453
    TopAbs_ShapeEnum type = sh.ShapeType();
2454
    std::string name;
2455
    switch (type) {
2456
        case TopAbs_COMPOUND:
2457
            name = "Compound";
2458
            break;
2459
        case TopAbs_COMPSOLID:
2460
            name = "CompSolid";
2461
            break;
2462
        case TopAbs_SOLID:
2463
            name = "Solid";
2464
            break;
2465
        case TopAbs_SHELL:
2466
            name = "Shell";
2467
            break;
2468
        case TopAbs_FACE:
2469
            name = "Face";
2470
            break;
2471
        case TopAbs_WIRE:
2472
            name = "Wire";
2473
            break;
2474
        case TopAbs_EDGE:
2475
            name = "Edge";
2476
            break;
2477
        case TopAbs_VERTEX:
2478
            name = "Vertex";
2479
            break;
2480
        case TopAbs_SHAPE:
2481
            name = "Shape";
2482
            break;
2483
    }
2484

2485
    return Py::String(name);
2486
}
2487

2488
Py::String TopoShapePy::getOrientation() const
2489
{
2490
    TopoDS_Shape sh = getTopoShapePtr()->getShape();
2491
    if (sh.IsNull())
2492
        throw Py::Exception(Base::PyExc_FC_GeneralError, "cannot determine orientation of null shape");
2493

2494
    TopAbs_Orientation type = sh.Orientation();
2495
    std::string name;
2496
    switch (type) {
2497
        case TopAbs_FORWARD:
2498
            name = "Forward";
2499
            break;
2500
        case TopAbs_REVERSED:
2501
            name = "Reversed";
2502
            break;
2503
        case TopAbs_INTERNAL:
2504
            name = "Internal";
2505
            break;
2506
        case TopAbs_EXTERNAL:
2507
            name = "External";
2508
            break;
2509
    }
2510

2511
    return Py::String(name);
2512
}
2513

2514
void TopoShapePy::setOrientation(Py::String arg)
2515
{
2516
    TopoDS_Shape sh = getTopoShapePtr()->getShape();
2517
    if (sh.IsNull())
2518
        throw Py::Exception(Base::PyExc_FC_GeneralError, "cannot determine orientation of null shape");
2519

2520
    std::string name = static_cast<std::string>(arg);
2521
    TopAbs_Orientation type;
2522
    if (name == "Forward") {
2523
        type = TopAbs_FORWARD;
2524
    }
2525
    else if (name == "Reversed") {
2526
        type = TopAbs_REVERSED;
2527
    }
2528
    else if (name == "Internal") {
2529
        type = TopAbs_INTERNAL;
2530
    }
2531
    else if (name == "External") {
2532
        type = TopAbs_EXTERNAL;
2533
    }
2534
    else {
2535
        throw Py::AttributeError("Invalid orientation type");
2536
    }
2537

2538
    sh.Orientation(type);
2539
    getTopoShapePtr()->setShape(sh);
2540
}
2541

2542
static Py::List
2543
getElements(const TopoShape& sh, TopAbs_ShapeEnum type, TopAbs_ShapeEnum avoid = TopAbs_SHAPE)
2544
{
2545
    Py::List ret;
2546
    for (auto& shape : sh.getSubTopoShapes(type, avoid)) {
2547
        ret.append(shape2pyshape(shape));
2548
    }
2549
    return ret;
2550
}
2551

2552
PyObject* TopoShapePy::getChildShapes(PyObject* args)
2553
{
2554
    const char* type;
2555
    const char* avoid = nullptr;
2556
    if (!PyArg_ParseTuple(args, "s|s", &type, &avoid)) {
2557
        return nullptr;
2558
    }
2559

2560
    PY_TRY
2561
    {
2562
        return Py::new_reference_to(
2563
            getElements(*getTopoShapePtr(),
2564
                        TopoShape::shapeType(type),
2565
                        avoid && avoid[0] ? TopoShape::shapeType(avoid) : TopAbs_SHAPE));
2566
    }
2567
    PY_CATCH_OCC;
2568
}
2569

2570
Py::List TopoShapePy::getSubShapes() const
2571
{
2572
    return getElements(*getTopoShapePtr(), TopAbs_SHAPE);
2573
}
2574

2575
Py::List TopoShapePy::getFaces() const
2576
{
2577
    return getElements(*getTopoShapePtr(), TopAbs_FACE);
2578
}
2579

2580
Py::List TopoShapePy::getVertexes() const
2581
{
2582
    return getElements(*getTopoShapePtr(), TopAbs_VERTEX);
2583
}
2584

2585
Py::List TopoShapePy::getShells() const
2586
{
2587
    return getElements(*getTopoShapePtr(), TopAbs_SHELL);
2588
}
2589

2590
Py::List TopoShapePy::getSolids() const
2591
{
2592
    return getElements(*getTopoShapePtr(), TopAbs_SOLID);
2593
}
2594

2595
Py::List TopoShapePy::getCompSolids() const
2596
{
2597
    return getElements(*getTopoShapePtr(), TopAbs_COMPSOLID);
2598
}
2599

2600
Py::List TopoShapePy::getEdges() const
2601
{
2602
    return getElements(*getTopoShapePtr(), TopAbs_EDGE);
2603
}
2604

2605
Py::List TopoShapePy::getWires() const
2606
{
2607
    return getElements(*getTopoShapePtr(), TopAbs_WIRE);
2608
}
2609

2610
Py::List TopoShapePy::getCompounds() const
2611
{
2612
    return getElements(*getTopoShapePtr(), TopAbs_COMPOUND);
2613
}
2614

2615
Py::Float TopoShapePy::getLength() const
2616
{
2617
    const TopoDS_Shape& shape = getTopoShapePtr()->getShape();
2618
    if (shape.IsNull())
2619
        throw Py::RuntimeError("shape is invalid");
2620
    GProp_GProps props;
2621
    BRepGProp::LinearProperties(shape, props);
2622
    return Py::Float(props.Mass());
2623
}
2624

2625
Py::Float TopoShapePy::getArea() const
2626
{
2627
    const TopoDS_Shape& shape = getTopoShapePtr()->getShape();
2628
    if (shape.IsNull())
2629
        throw Py::RuntimeError("shape is invalid");
2630
    GProp_GProps props;
2631
    BRepGProp::SurfaceProperties(shape, props);
2632
    return Py::Float(props.Mass());
2633
}
2634

2635
Py::Float TopoShapePy::getVolume() const
2636
{
2637
    const TopoDS_Shape& shape = getTopoShapePtr()->getShape();
2638
    if (shape.IsNull())
2639
        throw Py::RuntimeError("shape is invalid");
2640
    GProp_GProps props;
2641
    BRepGProp::VolumeProperties(shape, props);
2642
    return Py::Float(props.Mass());
2643
}
2644

2645
PyObject* TopoShapePy::getElementHistory(PyObject* args)
2646
{
2647
    const char* pyname;
2648
    if (!PyArg_ParseTuple(args, "s", &pyname)) {
2649
        return 0;
2650
    }
2651

2652
    Data::MappedName name(pyname);
2653
    PY_TRY
2654
    {
2655
        Data::MappedName original;
2656
        std::vector<Data::MappedName> history;
2657
        long tag = getTopoShapePtr()->getElementHistory(name, &original, &history);
2658
        if (!tag) {
2659
            Py_Return;
2660
        }
2661
        Py::Tuple ret(3);
2662
        ret.setItem(0, Py::Int(tag));
2663
        std::string tmp;
2664
        ret.setItem(1, Py::String(original.appendToBuffer(tmp)));
2665
        Py::List pyHistory;
2666
        for (auto& h : history) {
2667
            tmp.clear();
2668
            pyHistory.append(Py::String(h.appendToBuffer(tmp)));
2669
        }
2670
        ret.setItem(2, pyHistory);
2671
        return Py::new_reference_to(ret);
2672
    }
2673
    PY_CATCH_OCC
2674
}
2675

2676
struct PyShapeMapper: Part::ShapeMapper
2677
{
2678
    bool populate(MappingStatus status, PyObject* pyobj)
2679
    {
2680
        if (!pyobj || pyobj == Py_None) {
2681
            return true;
2682
        }
2683
        try {
2684
            Py::Sequence seq(pyobj);
2685
            for (size_t i = 0, count = seq.size(); i < count; ++i) {
2686
                Py::Sequence item(seq[i].ptr());
2687
                if (item.size() != 2) {
2688
                    return false;
2689
                }
2690

2691
                Part::ShapeMapper::populate(status,
2692
                                            getPyShapes(item[0].ptr()),
2693
                                            getPyShapes(item[1].ptr()));
2694
            }
2695
        }
2696
        catch (Py::Exception&) {
2697
            PyErr_Clear();
2698
            return false;
2699
        }
2700
        return true;
2701
    }
2702

2703
    void init(PyObject* g, PyObject* m)
2704
    {
2705
        const char* msg =
2706
            "Expect input mapping to be a list of tuple(srcShape|shapeList, dstShape|shapeList)";
2707
        if (!populate(MappingStatus::Generated, g) || !populate(MappingStatus::Modified, m)) {
2708
            throw Py::TypeError(msg);
2709
        }
2710
    }
2711
};
2712

2713
PyObject* TopoShapePy::mapShapes(PyObject* args)
2714
{
2715
    PyObject* generated;
2716
    PyObject* modified;
2717
    const char* op = nullptr;
2718
    if (!PyArg_ParseTuple(args, "OO|s", &generated, &modified, &op)) {
2719
        return 0;
2720
    }
2721
    PY_TRY
2722
    {
2723
        PyShapeMapper mapper;
2724
        mapper.init(generated, modified);
2725
        TopoShape& self = *getTopoShapePtr();
2726
        TopoShape s(self.Tag, self.Hasher);
2727
        s.makeShapeWithElementMap(self.getShape(), mapper, mapper.shapes, op);
2728
        self = s;
2729
        return IncRef();
2730
    }
2731
    PY_CATCH_OCC
2732
}
2733

2734
PyObject* TopoShapePy::mapSubElement(PyObject* args)
2735
{
2736
    const char* op = nullptr;
2737
    PyObject* sh;
2738
    if (!PyArg_ParseTuple(args, "O|s", &sh, &op)) {
2739
        return 0;
2740
    }
2741
    PY_TRY
2742
    {
2743
        getTopoShapePtr()->mapSubElement(getPyShapes(sh), op);
2744
        return IncRef();
2745
    }
2746
    PY_CATCH_OCC
2747
}
2748

2749
PyObject* TopoShapePy::getCustomAttributes(const char* attr) const
2750
{
2751
    if (!attr) {
2752
        return nullptr;
2753
    }
2754
    PY_TRY
2755
    {
2756
        TopoDS_Shape res = getTopoShapePtr()->getSubShape(attr, true);
2757
        if (!res.IsNull()) {
2758
            return Py::new_reference_to(shape2pyshape(res));
2759
        }
2760
    }
2761
    PY_CATCH_OCC
2762
    return nullptr;
2763
}
2764

2765
int TopoShapePy::setCustomAttributes(const char* , PyObject *)
2766
{
2767
    return 0;
2768
}
2769

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

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

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

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