Skip to content

Commit 8156ff2

Browse files
committed
Part: python feature element map support
Python element mapping support is completely implemented in C++. No code change is required in existing python features.
1 parent 83a58cd commit 8156ff2

File tree

10 files changed

+568
-112
lines changed

10 files changed

+568
-112
lines changed

src/Mod/Part/App/AppPartPy.cpp

Lines changed: 125 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -129,17 +129,14 @@
129129
#include "FaceMaker.h"
130130
#include "PartFeature.h"
131131
#include "PartPyCXX.h"
132+
#include "TopoShapeOpCode.h"
132133

133134
#ifdef FCUseFreeType
134135
# include "FT2FC.h"
135136
#endif
136137

137138
extern const char* BRepBuilderAPI_FaceErrorText(BRepBuilderAPI_FaceError fe);
138139

139-
namespace Part {
140-
extern Py::Object shape2pyshape(const TopoDS_Shape &shape);
141-
}
142-
143140
#ifndef M_PI
144141
#define M_PI 3.14159265358979323846 /* pi */
145142
#endif
@@ -149,6 +146,28 @@ extern Py::Object shape2pyshape(const TopoDS_Shape &shape);
149146
#endif
150147

151148
namespace Part {
149+
150+
PartExport void getPyShapes(PyObject *obj, std::vector<TopoShape> &shapes) {
151+
if(PyObject_TypeCheck(obj,&Part::TopoShapePy::Type))
152+
shapes.push_back(*static_cast<TopoShapePy*>(obj)->getTopoShapePtr());
153+
else if(PySequence_Check(obj)) {
154+
Py::Sequence list(obj);
155+
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
156+
if (PyObject_TypeCheck((*it).ptr(), &(Part::TopoShapePy::Type)))
157+
shapes.push_back(*static_cast<TopoShapePy*>((*it).ptr())->getTopoShapePtr());
158+
else
159+
throw Py::TypeError("expect shape in sequence");
160+
}
161+
}else
162+
throw Py::TypeError("expect shape or sequence of shapes");
163+
}
164+
165+
PartExport std::vector<TopoShape> getPyShapes(PyObject *obj) {
166+
std::vector<TopoShape> ret;
167+
getPyShapes(obj,ret);
168+
return ret;
169+
}
170+
152171
struct EdgePoints {
153172
gp_Pnt v1, v2;
154173
std::list<TopoDS_Edge>::iterator it;
@@ -279,6 +298,9 @@ class Module : public Py::ExtensionModule<Module>
279298
add_varargs_method("makeShell",&Module::makeShell,
280299
"makeShell(list) -- Create a shell out of a list of faces."
281300
);
301+
add_varargs_method("makeWires",&Module::makeWires,
302+
"makeWires(list_of_shapes_or_compound) -- Create wires from a list of a unsorted edges."
303+
);
282304
add_varargs_method("makeFace",&Module::makeFace,
283305
"makeFace(list_of_shapes_or_compound, maker_class_name) -- Create a face (faces) using facemaker class.\n"
284306
"maker_class_name is a string like 'Part::FaceMakerSimple'."
@@ -644,13 +666,24 @@ class Module : public Py::ExtensionModule<Module>
644666
TopoShapePy* pShape = static_cast<TopoShapePy*>(pcObj);
645667
Part::Feature *pcFeature = static_cast<Part::Feature*>(pcDoc->addObject("Part::Feature", name));
646668
// copy the data
647-
pcFeature->Shape.setValue(pShape->getTopoShapePtr()->getShape());
669+
pcFeature->Shape.setValue(*pShape->getTopoShapePtr());
648670
pcDoc->recompute();
649671

650672
return Py::None();
651673
}
652674
Py::Object makeCompound(const Py::Tuple& args)
653675
{
676+
#ifndef FC_NO_ELEMENT_MAP
677+
PyObject *pcObj;
678+
PyObject *force = Py_True;
679+
const char *op = 0;
680+
PyObject *appendTag = Py_True;
681+
if (!PyArg_ParseTuple(args.ptr(), "O|OsO", &pcObj,&force,&op,&appendTag))
682+
throw Py::Exception();
683+
684+
return shape2pyshape(Part::TopoShape().makECompound(getPyShapes(pcObj),
685+
PyObject_IsTrue(appendTag), op, PyObject_IsTrue(force)));
686+
#else
654687
PyObject *pcObj;
655688
if (!PyArg_ParseTuple(args.ptr(), "O", &pcObj))
656689
throw Py::Exception();
@@ -675,9 +708,19 @@ class Module : public Py::ExtensionModule<Module>
675708
}
676709

677710
return Py::asObject(new TopoShapeCompoundPy(new TopoShape(Comp)));
711+
#endif
678712
}
679713
Py::Object makeShell(const Py::Tuple& args)
680714
{
715+
#ifndef FC_NO_ELEMENT_MAP
716+
PyObject *obj;
717+
const char *op = 0;
718+
PyObject *appendTag = Py_True;
719+
if (!PyArg_ParseTuple(args.ptr(), "O|sO", &obj,&op,&appendTag))
720+
throw Py::Exception();
721+
return shape2pyshape(Part::TopoShape().makEShape(
722+
TOPOP_SHELL,getPyShapes(obj),op,PyObject_IsTrue(appendTag)));
723+
#else
681724
PyObject *obj;
682725
if (!PyArg_ParseTuple(args.ptr(), "O", &obj))
683726
throw Py::Exception();
@@ -711,9 +754,26 @@ class Module : public Py::ExtensionModule<Module>
711754
}
712755

713756
return Py::asObject(new TopoShapeShellPy(new TopoShape(shape)));
757+
#endif
758+
}
759+
Py::Object makeWires(const Py::Tuple& args)
760+
{
761+
PyObject *obj;
762+
const char *op = 0;
763+
if(!PyArg_ParseTuple(args.ptr(), "O|s", &obj, &op))
764+
throw Py::Exception();
765+
return shape2pyshape(TopoShape().makEWires(getPyShapes(obj),op));
714766
}
715767
Py::Object makeFace(const Py::Tuple& args)
716768
{
769+
#ifndef FC_NO_ELEMENT_MAP
770+
PyObject *obj;
771+
const char *className = 0;
772+
const char *op = 0;
773+
if(!PyArg_ParseTuple(args.ptr(), "O|ss", &obj, &className,&op))
774+
throw Py::Exception();
775+
return shape2pyshape(TopoShape().makEFace(getPyShapes(obj),op,className));
776+
#else
717777
try {
718778
char* className = 0;
719779
PyObject* pcPyShapeOrList = nullptr;
@@ -767,9 +827,23 @@ class Module : public Py::ExtensionModule<Module>
767827
} catch (Base::Exception &e){
768828
throw Py::Exception(Base::BaseExceptionFreeCADError, e.what());
769829
}
830+
#endif
770831
}
771832
Py::Object makeFilledFace(const Py::Tuple& args)
772833
{
834+
#ifndef FC_NO_ELEMENT_MAP
835+
PyObject *obj;
836+
PyObject *surf=0;
837+
const char *op=0;
838+
PyObject *appendTag = Py_True;
839+
if (!PyArg_ParseTuple(args.ptr(), "O|O!sO", &obj, &TopoShapeFacePy::Type, &surf, &op, &appendTag))
840+
throw Py::Exception();
841+
TopoShape surface;
842+
if(surf)
843+
surface = *static_cast<TopoShapePy*>(surf)->getTopoShapePtr();
844+
return shape2pyshape(TopoShape().makEFilledFace(
845+
getPyShapes(obj),surface,op,PyObject_IsTrue(appendTag)));
846+
#else
773847
// TODO: BRepFeat_SplitShape
774848
PyObject *obj;
775849
PyObject *surf=0;
@@ -826,9 +900,19 @@ class Module : public Py::ExtensionModule<Module>
826900
catch (Standard_Failure& e) {
827901
throw Py::Exception(PartExceptionOCCError, e.GetMessageString());
828902
}
903+
#endif
829904
}
830905
Py::Object makeSolid(const Py::Tuple& args)
831906
{
907+
#ifndef FC_NO_ELEMENT_MAP
908+
PyObject *obj;
909+
const char *op = 0;
910+
PyObject *appendTag = Py_False;
911+
if (!PyArg_ParseTuple(args.ptr(), "O!|sO", &(TopoShapePy::Type), &obj,&op,&appendTag))
912+
throw Py::Exception();
913+
return shape2pyshape(TopoShape().makESolid(
914+
*static_cast<TopoShapePy*>(obj)->getTopoShapePtr(),op,PyObject_IsTrue(appendTag)));
915+
#else
832916
PyObject *obj;
833917
if (!PyArg_ParseTuple(args.ptr(), "O!", &(TopoShapePy::Type), &obj))
834918
throw Py::Exception();
@@ -876,6 +960,7 @@ class Module : public Py::ExtensionModule<Module>
876960
errmsg << "Creation of solid failed: " << err.GetMessageString();
877961
throw Py::Exception(PartExceptionOCCError, errmsg.str().c_str());
878962
}
963+
#endif
879964
}
880965
Py::Object makePlane(const Py::Tuple& args)
881966
{
@@ -1428,6 +1513,20 @@ class Module : public Py::ExtensionModule<Module>
14281513
}
14291514
Py::Object makeRuledSurface(const Py::Tuple& args)
14301515
{
1516+
#ifndef FC_NO_ELEMENT_MAP
1517+
const char *op=0;
1518+
PyObject *appendTag = Py_True;
1519+
int orientation = 0;
1520+
PyObject *sh1, *sh2;
1521+
if (!PyArg_ParseTuple(args.ptr(), "O!O!|isO", &(TopoShapePy::Type), &sh1,
1522+
&(TopoShapePy::Type), &sh2,&orientation,&op,&appendTag))
1523+
throw Py::Exception();
1524+
1525+
std::vector<TopoShape> shapes;
1526+
shapes.push_back(*static_cast<TopoShapePy*>(sh1)->getTopoShapePtr());
1527+
shapes.push_back(*static_cast<TopoShapePy*>(sh2)->getTopoShapePtr());
1528+
return shape2pyshape(TopoShape().makERuledSurface(shapes,orientation,op,appendTag));
1529+
#else
14311530
// http://opencascade.blogspot.com/2009/10/surface-modeling-part1.html
14321531
PyObject *sh1, *sh2;
14331532
if (!PyArg_ParseTuple(args.ptr(), "O!O!", &(TopoShapePy::Type), &sh1,
@@ -1453,6 +1552,7 @@ class Module : public Py::ExtensionModule<Module>
14531552
catch (Standard_Failure) {
14541553
throw Py::Exception(PartExceptionOCCError, "creation of ruled surface failed");
14551554
}
1555+
#endif
14561556
}
14571557
Py::Object makeTube(const Py::Tuple& args)
14581558
{
@@ -1571,6 +1671,23 @@ class Module : public Py::ExtensionModule<Module>
15711671
PyObject *pruled=Py_False;
15721672
PyObject *pclosed=Py_False;
15731673
int degMax = 5;
1674+
1675+
# ifndef FC_NO_ELEMENT_MAP
1676+
const char *op = 0;
1677+
PyObject *appendTag = Py_True;
1678+
if (!PyArg_ParseTuple(args.ptr(), "O|O!O!O!i|sO", &pcObj,
1679+
&(PyBool_Type), &psolid,
1680+
&(PyBool_Type), &pruled,
1681+
&(PyBool_Type), &pclosed,
1682+
&degMax,&op,&appendTag)) {
1683+
throw Py::Exception();
1684+
}
1685+
Standard_Boolean anIsSolid = PyObject_IsTrue(psolid) ? Standard_True : Standard_False;
1686+
Standard_Boolean anIsRuled = PyObject_IsTrue(pruled) ? Standard_True : Standard_False;
1687+
Standard_Boolean anIsClosed = PyObject_IsTrue(pclosed) ? Standard_True : Standard_False;
1688+
return shape2pyshape(TopoShape().makELoft(getPyShapes(pcObj),
1689+
anIsSolid,anIsRuled,anIsClosed,degMax,op,PyObject_IsTrue(appendTag)));
1690+
# else
15741691
if (!PyArg_ParseTuple(args.ptr(), "O|O!O!O!i", &pcObj,
15751692
&(PyBool_Type), &psolid,
15761693
&(PyBool_Type), &pruled,
@@ -1596,6 +1713,7 @@ class Module : public Py::ExtensionModule<Module>
15961713
Standard_Boolean anIsClosed = PyObject_IsTrue(pclosed) ? Standard_True : Standard_False;
15971714
TopoDS_Shape aResult = myShape.makeLoft(profiles, anIsSolid, anIsRuled, anIsClosed, degMax);
15981715
return Py::asObject(new TopoShapePy(new TopoShape(aResult)));
1716+
# endif
15991717
#endif
16001718
}
16011719
Py::Object makeSplitShape(const Py::Tuple& args)
@@ -2016,9 +2134,9 @@ class Module : public Py::ExtensionModule<Module>
20162134
Base::Matrix4D mat;
20172135
if(pyMat)
20182136
mat = *static_cast<Base::MatrixPy*>(pyMat)->getMatrixPtr();
2019-
auto shape = Feature::getShape(obj,subname,PyObject_IsTrue(needSubElement),
2137+
auto shape = Feature::getTopoShape(obj,subname,PyObject_IsTrue(needSubElement),
20202138
&mat,&subObj,retType==2,PyObject_IsTrue(transform));
2021-
Py::Object sret(new TopoShapePy(new TopoShape(shape)));
2139+
Py::Object sret(shape2pyshape(shape));
20222140
if(retType==0)
20232141
return sret;
20242142

src/Mod/Part/App/PartPyCXX.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ namespace Py {
3535
namespace Part {
3636
PartExport Py::Object shape2pyshape(const TopoShape &shape);
3737
PartExport Py::Object shape2pyshape(const TopoDS_Shape &shape);
38+
PartExport void getPyShapes(PyObject *obj, std::vector<TopoShape> &shapes);
39+
PartExport std::vector<TopoShape> getPyShapes(PyObject *obj);
3840
}
3941

4042
#endif //PART_PYCXX_H

src/Mod/Part/App/PropertyTopoShape.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,19 @@ PyObject *PropertyPartShape::getPyObject(void)
159159
void PropertyPartShape::setPyObject(PyObject *value)
160160
{
161161
if (PyObject_TypeCheck(value, &(TopoShapePy::Type))) {
162-
TopoShapePy *pcObject = static_cast<TopoShapePy*>(value);
163-
setValue(*pcObject->getTopoShapePtr());
162+
auto shape = *static_cast<TopoShapePy*>(value)->getTopoShapePtr();
163+
auto owner = dynamic_cast<App::DocumentObject*>(getContainer());
164+
if(owner && owner->getDocument() && !shape.Hasher) {
165+
auto hasher = owner->getDocument()->getStringHasher();
166+
if(hasher) {
167+
TopoShape tmp(shape);
168+
shape.Hasher = hasher;
169+
// copy element map with newly set hasher to hash every mapped
170+
// element names
171+
shape.copyElementMap(tmp);
172+
}
173+
}
174+
setValue(shape);
164175
}
165176
else {
166177
std::string error = std::string("type must be 'Shape', not ");

src/Mod/Part/App/TopoShapeCompSolidPyImp.cpp

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@
2828

2929
#include "OCCError.h"
3030
#include "TopoShape.h"
31+
#include "TopoShapeOpCode.h"
32+
#include "PartPyCXX.h"
3133

3234
// inclusion of the generated files (generated out of TopoShapeCompSolidPy.xml)
3335
#include "TopoShapeSolidPy.h"
3436
#include "TopoShapeCompSolidPy.h"
3537
#include "TopoShapeCompSolidPy.cpp"
38+
#include "TopoShapeOpCode.h"
3639

3740
using namespace Part;
3841

@@ -56,6 +59,11 @@ int TopoShapeCompSolidPy::PyInit(PyObject* args, PyObject* /*kwd*/)
5659
if (!PyArg_ParseTuple(args, "O", &pcObj))
5760
return -1;
5861

62+
#ifndef FC_NO_ELEMENT_MAP
63+
PY_TRY {
64+
getTopoShapePtr()->makEShape(TOPOP_COMPSOLID,getPyShapes(pcObj));
65+
}PY_CATCH_OCC
66+
#else
5967
BRep_Builder builder;
6068
TopoDS_CompSolid Comp;
6169
builder.MakeCompSolid(Comp);
@@ -78,6 +86,7 @@ int TopoShapeCompSolidPy::PyInit(PyObject* args, PyObject* /*kwd*/)
7886
}
7987

8088
getTopoShapePtr()->setShape(Comp);
89+
#endif
8190
return 0;
8291
}
8392

@@ -89,23 +98,33 @@ PyObject* TopoShapeCompSolidPy::add(PyObject *args)
8998

9099
BRep_Builder builder;
91100
TopoDS_Shape comp = getTopoShapePtr()->getShape();
101+
auto shapes = getPyShapes(obj);
92102

93103
try {
94-
const TopoDS_Shape& sh = static_cast<TopoShapePy*>(obj)->
95-
getTopoShapePtr()->getShape();
96-
if (!sh.IsNull())
97-
builder.Add(comp, sh);
98-
else
99-
Standard_Failure::Raise("Cannot empty shape to compound solid");
104+
for(auto &s : shapes) {
105+
if(!s.isNull())
106+
builder.Add(comp,s.getShape());
107+
else
108+
Standard_Failure::Raise("Cannot empty shape to compound solid");
109+
}
100110
}
101111
catch (Standard_Failure& e) {
102112

103113
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
104114
return 0;
105115
}
106116

117+
#ifndef FC_NO_ELEMENT_MAP
118+
PY_TRY {
119+
auto &self = *getTopoShapePtr();
120+
shapes.push_back(self);
121+
TopoShape tmp(self.Tag,self.Hasher,comp);
122+
tmp.mapSubElement(TopAbs_FACE,shapes);
123+
self = tmp;
124+
}PY_CATCH_OCC
125+
#else
107126
getTopoShapePtr()->setShape(comp);
108-
127+
#endif
109128
Py_Return;
110129
}
111130

0 commit comments

Comments
 (0)