Merge pull request #13196 from bgbsww/bgbsww-toponamingCompSolidPyImp
Toponaming/Part move in PyImps
This commit is contained in:
@@ -122,26 +122,35 @@ extern const char* BRepBuilderAPI_FaceErrorText(BRepBuilderAPI_FaceError fe);
|
||||
|
||||
namespace Part {
|
||||
|
||||
PartExport void getPyShapes(PyObject *obj, std::vector<TopoShape> &shapes) {
|
||||
if(!obj)
|
||||
PartExport void getPyShapes(PyObject* obj, std::vector<TopoShape>& shapes)
|
||||
{
|
||||
if (!obj) {
|
||||
return;
|
||||
if(PyObject_TypeCheck(obj,&Part::TopoShapePy::Type))
|
||||
}
|
||||
if (PyObject_TypeCheck(obj, &Part::TopoShapePy::Type)) {
|
||||
shapes.push_back(*static_cast<TopoShapePy*>(obj)->getTopoShapePtr());
|
||||
else if (PyObject_TypeCheck(obj, &GeometryPy::Type))
|
||||
}
|
||||
else if (PyObject_TypeCheck(obj, &GeometryPy::Type)) {
|
||||
shapes.emplace_back(static_cast<GeometryPy*>(obj)->getGeometryPtr()->toShape());
|
||||
else if(PySequence_Check(obj)) {
|
||||
}
|
||||
else if (PySequence_Check(obj)) {
|
||||
Py::Sequence list(obj);
|
||||
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
|
||||
if (PyObject_TypeCheck((*it).ptr(), &(Part::TopoShapePy::Type)))
|
||||
if (PyObject_TypeCheck((*it).ptr(), &(Part::TopoShapePy::Type))) {
|
||||
shapes.push_back(*static_cast<TopoShapePy*>((*it).ptr())->getTopoShapePtr());
|
||||
else if (PyObject_TypeCheck((*it).ptr(), &GeometryPy::Type))
|
||||
shapes.emplace_back(static_cast<GeometryPy*>(
|
||||
(*it).ptr())->getGeometryPtr()->toShape());
|
||||
else
|
||||
}
|
||||
else if (PyObject_TypeCheck((*it).ptr(), &GeometryPy::Type)) {
|
||||
shapes.emplace_back(
|
||||
static_cast<GeometryPy*>((*it).ptr())->getGeometryPtr()->toShape());
|
||||
}
|
||||
else {
|
||||
throw Py::TypeError("expect shape in sequence");
|
||||
}
|
||||
}
|
||||
}else
|
||||
}
|
||||
else {
|
||||
throw Py::TypeError("expect shape or sequence of shapes");
|
||||
}
|
||||
}
|
||||
|
||||
PartExport std::vector<TopoShape> getPyShapes(PyObject *obj) {
|
||||
@@ -952,8 +961,8 @@ private:
|
||||
|
||||
return shape2pyshape(Part::TopoShape().makeElementCompound(getPyShapes(pcObj), op, policy));
|
||||
#else
|
||||
Py::Object makeCompound(const Py::Tuple& args)
|
||||
{
|
||||
Py::Object makeCompound(const Py::Tuple& args)
|
||||
{
|
||||
PyObject *pcObj;
|
||||
if (!PyArg_ParseTuple(args.ptr(), "O", &pcObj))
|
||||
throw Py::Exception();
|
||||
@@ -989,8 +998,8 @@ Py::Object makeCompound(const Py::Tuple& args)
|
||||
return shape2pyshape(
|
||||
Part::TopoShape().makeElementBoolean(Part::OpCodes::Shell, getPyShapes(obj), op));
|
||||
#else
|
||||
Py::Object makeShell(const Py::Tuple& args)
|
||||
{
|
||||
Py::Object makeShell(const Py::Tuple& args)
|
||||
{
|
||||
PyObject *obj;
|
||||
if (!PyArg_ParseTuple(args.ptr(), "O", &obj))
|
||||
throw Py::Exception();
|
||||
@@ -1044,8 +1053,8 @@ Py::Object makeShell(const Py::Tuple& args)
|
||||
}
|
||||
return shape2pyshape(TopoShape().makeElementFace(getPyShapes(obj), op, className));
|
||||
#else
|
||||
Py::Object makeFace(const Py::Tuple& args)
|
||||
{
|
||||
Py::Object makeFace(const Py::Tuple& args)
|
||||
{
|
||||
try {
|
||||
char* className = nullptr;
|
||||
PyObject* pcPyShapeOrList = nullptr;
|
||||
@@ -1194,8 +1203,8 @@ Py::Object makeFace(const Py::Tuple& args)
|
||||
return shape2pyshape(
|
||||
TopoShape(0, shapes.front().Hasher).makeElementFilledFace(shapes, params, op));
|
||||
#else
|
||||
Py::Object makeFilledSurface(const Py::Tuple &args)
|
||||
{
|
||||
Py::Object makeFilledSurface(const Py::Tuple &args)
|
||||
{
|
||||
PyObject *obj;
|
||||
double tolerance;
|
||||
if (!PyArg_ParseTuple(args.ptr(), "Od", &obj, &tolerance))
|
||||
@@ -1304,8 +1313,8 @@ Py::Object makeFilledSurface(const Py::Tuple &args)
|
||||
return shape2pyshape(
|
||||
TopoShape(0, shapes.front().Hasher).makeElementFilledFace(shapes, params, op));
|
||||
#else
|
||||
Py::Object makeFilledFace(const Py::Tuple& args)
|
||||
{
|
||||
Py::Object makeFilledFace(const Py::Tuple& args)
|
||||
{
|
||||
// TODO: BRepFeat_SplitShape
|
||||
PyObject *obj;
|
||||
PyObject *surf=nullptr;
|
||||
@@ -1382,8 +1391,8 @@ Py::Object makeFilledFace(const Py::Tuple& args)
|
||||
return shape2pyshape(
|
||||
TopoShape().makeElementSolid(*static_cast<TopoShapePy*>(obj)->getTopoShapePtr(), op));
|
||||
#else
|
||||
Py::Object makeSolid(const Py::Tuple& args)
|
||||
{
|
||||
Py::Object makeSolid(const Py::Tuple& args)
|
||||
{
|
||||
PyObject *obj;
|
||||
if (!PyArg_ParseTuple(args.ptr(), "O!", &(TopoShapePy::Type), &obj))
|
||||
throw Py::Exception();
|
||||
@@ -2017,8 +2026,8 @@ Py::Object makeSolid(const Py::Tuple& args)
|
||||
shapes.push_back(*static_cast<TopoShapePy*>(sh2)->getTopoShapePtr());
|
||||
return shape2pyshape(TopoShape().makeElementRuledSurface(shapes, orientation, op));
|
||||
#else
|
||||
Py::Object makeRuledSurface(const Py::Tuple& args)
|
||||
{
|
||||
Py::Object makeRuledSurface(const Py::Tuple& args)
|
||||
{
|
||||
// http://opencascade.blogspot.com/2009/10/surface-modeling-part1.html
|
||||
PyObject *sh1, *sh2;
|
||||
if (!PyArg_ParseTuple(args.ptr(), "O!O!", &(TopoShapePy::Type), &sh1,
|
||||
@@ -2068,9 +2077,9 @@ Py::Object makeRuledSurface(const Py::Tuple& args)
|
||||
throw Py::Exception(PartExceptionOCCError, "creation of shell failed");
|
||||
}
|
||||
#else
|
||||
Py::Object makeShellFromWires(const Py::Tuple& args)
|
||||
{
|
||||
PyObject *pylist;
|
||||
Py::Object makeShellFromWires(const Py::Tuple& args)
|
||||
{
|
||||
PyObject *pylist;
|
||||
if (!PyArg_ParseTuple(args.ptr(), "O", &pylist))
|
||||
throw Py::Exception();
|
||||
|
||||
@@ -2162,6 +2171,8 @@ Py::Object makeShellFromWires(const Py::Tuple& args)
|
||||
nullptr,
|
||||
tolerance));
|
||||
#else
|
||||
if (tolerance == 0.0)
|
||||
tolerance=0.001;
|
||||
const TopoDS_Shape& path_shape = static_cast<TopoShapePy*>(path)->getTopoShapePtr()->getShape();
|
||||
const TopoDS_Shape& prof_shape = static_cast<TopoShapePy*>(profile)->getTopoShapePtr()->getShape();
|
||||
|
||||
@@ -2182,6 +2193,7 @@ Py::Object makeShellFromWires(const Py::Tuple& args)
|
||||
PyObject *pruled=Py_False;
|
||||
PyObject *pclosed=Py_False;
|
||||
int degMax = 5;
|
||||
|
||||
const char* op = nullptr;
|
||||
const std::array<const char*, 7> kwd_list =
|
||||
{"shapes", "solid", "ruled", "closed", "max_degree", "op", nullptr};
|
||||
@@ -2212,13 +2224,14 @@ Py::Object makeShellFromWires(const Py::Tuple& args)
|
||||
degMax,
|
||||
op));
|
||||
#else
|
||||
Py::Object makeLoft(const Py::Tuple& args)
|
||||
{
|
||||
PyObject *pcObj;
|
||||
PyObject *psolid=Py_False;
|
||||
PyObject *pruled=Py_False;
|
||||
PyObject *pclosed=Py_False;
|
||||
int degMax = 5;
|
||||
Py::Object makeLoft(const Py::Tuple& args)
|
||||
{
|
||||
PyObject *pcObj;
|
||||
PyObject *psolid=Py_False;
|
||||
PyObject *pruled=Py_False;
|
||||
PyObject *pclosed=Py_False;
|
||||
int degMax = 5;
|
||||
|
||||
if (!PyArg_ParseTuple(args.ptr(), "O|O!O!O!i", &pcObj,
|
||||
&(PyBool_Type), &psolid,
|
||||
&(PyBool_Type), &pruled,
|
||||
|
||||
@@ -29,11 +29,13 @@
|
||||
#endif
|
||||
|
||||
#include "OCCError.h"
|
||||
#include "PartPyCXX.h"
|
||||
|
||||
// inclusion of the generated files (generated out of TopoShapeCompSolidPy.xml)
|
||||
#include "TopoShapeCompSolidPy.h"
|
||||
#include "TopoShapeCompSolidPy.cpp"
|
||||
#include "TopoShapeSolidPy.h"
|
||||
#include "TopoShapeOpCode.h"
|
||||
|
||||
|
||||
using namespace Part;
|
||||
@@ -61,10 +63,16 @@ int TopoShapeCompSolidPy::PyInit(PyObject* args, PyObject* /*kwd*/)
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
PyObject *pcObj;
|
||||
if (!PyArg_ParseTuple(args, "O", &pcObj))
|
||||
PyObject* pcObj;
|
||||
if (!PyArg_ParseTuple(args, "O", &pcObj)) {
|
||||
return -1;
|
||||
|
||||
}
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
try {
|
||||
getTopoShapePtr()->makeElementBoolean(Part::OpCodes::Compsolid, getPyShapes(pcObj));
|
||||
}
|
||||
_PY_CATCH_OCC(return (-1))
|
||||
#else
|
||||
BRep_Builder builder;
|
||||
TopoDS_CompSolid Comp;
|
||||
builder.MakeCompSolid(Comp);
|
||||
@@ -73,10 +81,11 @@ int TopoShapeCompSolidPy::PyInit(PyObject* args, PyObject* /*kwd*/)
|
||||
Py::Sequence list(pcObj);
|
||||
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
|
||||
if (PyObject_TypeCheck((*it).ptr(), &(Part::TopoShapeSolidPy::Type))) {
|
||||
const TopoDS_Shape& sh = static_cast<TopoShapePy*>((*it).ptr())->
|
||||
getTopoShapePtr()->getShape();
|
||||
if (!sh.IsNull())
|
||||
const TopoDS_Shape& sh =
|
||||
static_cast<TopoShapePy*>((*it).ptr())->getTopoShapePtr()->getShape();
|
||||
if (!sh.IsNull()) {
|
||||
builder.Add(Comp, sh);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,35 +96,46 @@ int TopoShapeCompSolidPy::PyInit(PyObject* args, PyObject* /*kwd*/)
|
||||
}
|
||||
|
||||
getTopoShapePtr()->setShape(Comp);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* TopoShapeCompSolidPy::add(PyObject *args)
|
||||
PyObject* TopoShapeCompSolidPy::add(PyObject* args)
|
||||
{
|
||||
PyObject *obj;
|
||||
if (!PyArg_ParseTuple(args, "O!", &(Part::TopoShapeSolidPy::Type), &obj))
|
||||
PyObject* obj;
|
||||
if (!PyArg_ParseTuple(args, "O!", &(Part::TopoShapeSolidPy::Type), &obj)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BRep_Builder builder;
|
||||
TopoDS_Shape comp = getTopoShapePtr()->getShape();
|
||||
auto shapes = getPyShapes(obj);
|
||||
|
||||
try {
|
||||
const TopoDS_Shape& sh = static_cast<TopoShapePy*>(obj)->
|
||||
getTopoShapePtr()->getShape();
|
||||
if (!sh.IsNull())
|
||||
builder.Add(comp, sh);
|
||||
else
|
||||
Standard_Failure::Raise("Cannot empty shape to compound solid");
|
||||
for (auto& ts : shapes) {
|
||||
if (!ts.isNull()) {
|
||||
builder.Add(comp, ts.getShape());
|
||||
}
|
||||
else {
|
||||
Standard_Failure::Raise("Cannot empty shape to compound solid");
|
||||
}
|
||||
}
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
auto& self = *getTopoShapePtr();
|
||||
shapes.push_back(self);
|
||||
TopoShape tmp(self.Tag, self.Hasher, comp);
|
||||
tmp.mapSubElement(shapes);
|
||||
self = tmp;
|
||||
#else
|
||||
getTopoShapePtr()->setShape(comp);
|
||||
#endif
|
||||
Py_Return;
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
|
||||
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
getTopoShapePtr()->setShape(comp);
|
||||
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject *TopoShapeCompSolidPy::getCustomAttributes(const char* /*attr*/) const
|
||||
|
||||
@@ -88,6 +88,7 @@
|
||||
#include "FaceMaker.h"
|
||||
#include "Geometry2d.h"
|
||||
#include "OCCError.h"
|
||||
#include "PartPyCXX.h"
|
||||
#include "Tools.h"
|
||||
|
||||
|
||||
@@ -324,6 +325,9 @@ int TopoShapeFacePy::PyInit(PyObject* args, PyObject* /*kwd*/)
|
||||
PyErr_Clear();
|
||||
if (PyArg_ParseTuple(args, "Os", &pcPyShapeOrList, &className)) {
|
||||
try {
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
getTopoShapePtr()->makeElementFace(getPyShapes(pcPyShapeOrList),0,className);
|
||||
#else
|
||||
std::unique_ptr<FaceMaker> fm = Part::FaceMaker::ConstructFromType(className);
|
||||
|
||||
//dump all supplied shapes to facemaker, no matter what type (let facemaker decide).
|
||||
@@ -355,6 +359,7 @@ int TopoShapeFacePy::PyInit(PyObject* args, PyObject* /*kwd*/)
|
||||
fm->Build();
|
||||
|
||||
getTopoShapePtr()->setShape(fm->Face());
|
||||
#endif
|
||||
return 0;
|
||||
} catch (Base::Exception &e) {
|
||||
e.setPyException();
|
||||
@@ -420,6 +425,10 @@ PyObject* TopoShapeFacePy::addWire(PyObject *args)
|
||||
|
||||
PyObject* TopoShapeFacePy::makeOffset(PyObject *args)
|
||||
{
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
Py::Dict dict;
|
||||
return TopoShapePy::makeOffset2D(args, dict.ptr());
|
||||
#else
|
||||
double dist;
|
||||
if (!PyArg_ParseTuple(args, "d",&dist))
|
||||
return nullptr;
|
||||
@@ -434,6 +443,7 @@ PyObject* TopoShapeFacePy::makeOffset(PyObject *args)
|
||||
mkOffset.Perform(dist);
|
||||
|
||||
return new TopoShapePy(new TopoShape(mkOffset.Shape()));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -445,6 +455,9 @@ evolve = spine.makeEvolved(Profile=profile, Join=PartEnums.JoinType.Arc)
|
||||
*/
|
||||
PyObject* TopoShapeFacePy::makeEvolved(PyObject *args, PyObject *kwds)
|
||||
{
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
return TopoShapePy::makeEvolved(args, kwds);
|
||||
#else
|
||||
PyObject* Profile;
|
||||
PyObject* AxeProf = Py_True;
|
||||
PyObject* Solid = Py_False;
|
||||
@@ -496,6 +509,7 @@ PyObject* TopoShapeFacePy::makeEvolved(PyObject *args, PyObject *kwds)
|
||||
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
PyObject* TopoShapeFacePy::valueAt(PyObject *args)
|
||||
|
||||
@@ -511,6 +511,11 @@ Returns: result of offsetting (wire or face or compound of those). Compounding
|
||||
structure follows that of source shape.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="makeEvolved" Const="true" Keyword="true">
|
||||
<Documentation>
|
||||
<UserDocu>Profile along the spine</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="makeWires" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>make wire(s) using the edges of this shape
|
||||
@@ -820,6 +825,45 @@ countElement(type) -> int
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="mapSubElement">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
mapSubElement(shape|[shape...], op='') - maps the sub element of other shape
|
||||
|
||||
shape: other shape or sequence of shapes to map the sub-elements
|
||||
op: optional string prefix to append before the mapped sub element names
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="mapShapes">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
mapShapes(generated, modified, op='')
|
||||
|
||||
generate element names with user defined mapping
|
||||
|
||||
generated: a list of tuple(src, dst) that indicating src shape or shapes
|
||||
generates dst shape or shapes. Note that the dst shape or shapes
|
||||
must be sub-shapes of this shape.
|
||||
modified: a list of tuple(src, dst) that indicating src shape or shapes
|
||||
modifies into dst shape or shapes. Note that the dst shape or
|
||||
shapes must be sub-shapes of this shape.
|
||||
op: optional string prefix to append before the mapped sub element names
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getElementHistory" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
getElementHistory(name) - returns the element mapped name history
|
||||
|
||||
name: mapped element name belonging to this shape
|
||||
|
||||
Returns tuple(sourceShapeTag, sourceName, [intermediateNames...]),
|
||||
or None if no history.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getTolerance" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>Determines a tolerance from the ones stored in a shape
|
||||
@@ -906,6 +950,55 @@ optimalBoundingBox([useTriangulation = True, useShapeTolerance = False]) -> boun
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="clearCache" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>Clear internal sub-shape cache</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="findSubShape" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
findSubShape(shape) -> (type_name, index)
|
||||
|
||||
Find sub shape and return the shape type name and index. If not found,
|
||||
then return (None, 0)
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="findSubShapesWithSharedVertex" Const="true" Keyword="true">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
findSubShapesWithSharedVertex(shape, needName=False, checkGeometry=True, tol=1e-7, atol=1e-12) -> Shape
|
||||
|
||||
shape: input elementary shape, currently only support Face, Edge, or Vertex
|
||||
|
||||
needName: if True, return a list of tuple(name, shape), or else return a list
|
||||
of shapes.
|
||||
|
||||
checkGeometry: whether to compare geometry
|
||||
|
||||
tol: distance tolerance
|
||||
|
||||
atol: angular tolerance
|
||||
|
||||
Search sub shape by checking vertex coordinates and comparing the underlying
|
||||
geometries, This can find shapes that are copied. It currently only works with
|
||||
elementary shapes, Face, Edge, Vertex.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getChildShapes" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
getChildShapes(shapetype, avoidtype='') -> list(Shape)
|
||||
|
||||
Return a list of child sub-shapes of given type.
|
||||
|
||||
shapetype: the type of requesting sub shapes
|
||||
avoidtype: optional shape type to skip when exploring
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<!--
|
||||
<Attribute Name="Location" ReadOnly="false">
|
||||
<Documentation>
|
||||
|
||||
@@ -95,6 +95,7 @@
|
||||
#include "OCCError.h"
|
||||
#include "PartPyCXX.h"
|
||||
#include "ShapeMapHasher.h"
|
||||
#include "TopoShapeMapper.h"
|
||||
|
||||
|
||||
using namespace Part;
|
||||
@@ -108,20 +109,26 @@ using namespace Part;
|
||||
#endif
|
||||
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
static Py_hash_t _TopoShapeHash(PyObject *self) {
|
||||
static Py_hash_t _TopoShapeHash(PyObject* self)
|
||||
{
|
||||
if (!self) {
|
||||
PyErr_SetString(PyExc_TypeError, "descriptor 'hash' of 'Part.TopoShape' object needs an argument");
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"descriptor 'hash' of 'Part.TopoShape' object needs an argument");
|
||||
return 0;
|
||||
}
|
||||
if (!static_cast<Base::PyObjectBase*>(self)->isValid()) {
|
||||
PyErr_SetString(PyExc_ReferenceError, "This object is already deleted most likely through closing a document. This reference is no longer valid!");
|
||||
PyErr_SetString(PyExc_ReferenceError,
|
||||
"This object is already deleted most likely through closing a document. "
|
||||
"This reference is no longer valid!");
|
||||
return 0;
|
||||
}
|
||||
return static_cast<TopoShapePy*>(self)->getTopoShapePtr()->getShape().HashCode(INT_MAX);
|
||||
}
|
||||
|
||||
struct TopoShapePyInit {
|
||||
TopoShapePyInit() {
|
||||
struct TopoShapePyInit
|
||||
{
|
||||
TopoShapePyInit()
|
||||
{
|
||||
TopoShapePy::Type.tp_hash = _TopoShapeHash;
|
||||
}
|
||||
} _TopoShapePyInit;
|
||||
@@ -192,6 +199,7 @@ int TopoShapePy::PyInit(PyObject* args, PyObject* keywds)
|
||||
}
|
||||
_PY_CATCH_OCC(return (-1))
|
||||
#else
|
||||
(void) keywds;
|
||||
PyObject* pcObj = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "|O", &pcObj)) {
|
||||
return -1;
|
||||
@@ -236,6 +244,35 @@ PyObject* TopoShapePy::copy(PyObject *args)
|
||||
{
|
||||
PyObject* copyGeom = Py_True;
|
||||
PyObject* copyMesh = Py_False;
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
const char* op = nullptr;
|
||||
PyObject* pyHasher = nullptr;
|
||||
if (!PyArg_ParseTuple(args,
|
||||
"|sO!O!O!",
|
||||
&op,
|
||||
&App::StringHasherPy::Type,
|
||||
&pyHasher,
|
||||
&PyBool_Type,
|
||||
©Geom,
|
||||
&PyBool_Type,
|
||||
©Mesh)) {
|
||||
PyErr_Clear();
|
||||
if (!PyArg_ParseTuple(args, "|O!O!", &PyBool_Type, ©Geom, &PyBool_Type, ©Mesh)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (op && !op[0]) {
|
||||
op = nullptr;
|
||||
}
|
||||
App::StringHasherRef hasher;
|
||||
if (pyHasher) {
|
||||
hasher = static_cast<App::StringHasherPy*>(pyHasher)->getStringHasherPtr();
|
||||
}
|
||||
auto& self = *getTopoShapePtr();
|
||||
return Py::new_reference_to(shape2pyshape(
|
||||
TopoShape(self.Tag, hasher)
|
||||
.makeElementCopy(self, op, PyObject_IsTrue(copyGeom), PyObject_IsTrue(copyMesh))));
|
||||
#else
|
||||
if (!PyArg_ParseTuple(args, "|O!O!", &PyBool_Type, ©Geom, &PyBool_Type, ©Mesh))
|
||||
return nullptr;
|
||||
|
||||
@@ -255,12 +292,21 @@ PyObject* TopoShapePy::copy(PyObject *args)
|
||||
static_cast<TopoShapePy*>(cpy)->getTopoShapePtr()->setShape(c.Shape());
|
||||
}
|
||||
return cpy;
|
||||
#endif
|
||||
}
|
||||
|
||||
PyObject* TopoShapePy::cleaned(PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return nullptr;
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
auto& self = *getTopoShapePtr();
|
||||
TopoShape copy(self.makeElementCopy());
|
||||
if (!copy.isNull()) {
|
||||
BRepTools::Clean(copy.getShape()); // remove triangulation
|
||||
}
|
||||
return Py::new_reference_to(shape2pyshape(copy));
|
||||
#else
|
||||
|
||||
const TopoDS_Shape& shape = this->getTopoShapePtr()->getShape();
|
||||
PyTypeObject* type = this->GetType();
|
||||
@@ -280,6 +326,7 @@ PyObject* TopoShapePy::cleaned(PyObject *args)
|
||||
static_cast<TopoShapePy*>(cpy)->getTopoShapePtr()->setShape(c.Shape());
|
||||
}
|
||||
return cpy;
|
||||
#endif
|
||||
}
|
||||
|
||||
PyObject* TopoShapePy::replaceShape(PyObject *args)
|
||||
@@ -289,6 +336,18 @@ PyObject* TopoShapePy::replaceShape(PyObject *args)
|
||||
return nullptr;
|
||||
|
||||
try {
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
Py::Sequence list(l);
|
||||
std::vector<std::pair<TopoShape, TopoShape>> shapes;
|
||||
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
|
||||
Py::Tuple tuple(*it);
|
||||
Py::TopoShape sh1(tuple[0]);
|
||||
Py::TopoShape sh2(tuple[1]);
|
||||
shapes.push_back(std::make_pair(*sh1.extensionObject()->getTopoShapePtr(),
|
||||
*sh2.extensionObject()->getTopoShapePtr()));
|
||||
}
|
||||
return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->replaceElementShape(shapes)));
|
||||
#else
|
||||
Py::Sequence list(l);
|
||||
std::vector< std::pair<TopoDS_Shape, TopoDS_Shape> > shapes;
|
||||
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
|
||||
@@ -305,6 +364,7 @@ PyObject* TopoShapePy::replaceShape(PyObject *args)
|
||||
static_cast<TopoShapePy*>(inst)->getTopoShapePtr()->setShape
|
||||
(this->getTopoShapePtr()->replaceShape(shapes));
|
||||
return inst;
|
||||
#endif
|
||||
}
|
||||
catch (const Py::Exception&) {
|
||||
return nullptr;
|
||||
@@ -322,6 +382,10 @@ PyObject* TopoShapePy::removeShape(PyObject *args)
|
||||
return nullptr;
|
||||
|
||||
try {
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
return Py::new_reference_to(
|
||||
shape2pyshape(getTopoShapePtr()->removeElementShape(getPyShapes(l))));
|
||||
#else
|
||||
Py::Sequence list(l);
|
||||
std::vector<TopoDS_Shape> shapes;
|
||||
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
|
||||
@@ -333,6 +397,7 @@ PyObject* TopoShapePy::removeShape(PyObject *args)
|
||||
static_cast<TopoShapePy*>(inst)->getTopoShapePtr()->setShape
|
||||
(this->getTopoShapePtr()->removeShape(shapes));
|
||||
return inst;
|
||||
#endif
|
||||
}
|
||||
catch (...) {
|
||||
PyErr_SetString(PartExceptionOCCError, "failed to remove shape");
|
||||
@@ -681,6 +746,10 @@ PyObject* TopoShapePy::extrude(PyObject *args)
|
||||
|
||||
try {
|
||||
Base::Vector3d vec = static_cast<Base::VectorPy*>(pVec)->value();
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
return Py::new_reference_to(
|
||||
shape2pyshape(getTopoShapePtr()->makeElementPrism(gp_Vec(vec.x, vec.y, vec.z))));
|
||||
#else
|
||||
TopoDS_Shape shape = this->getTopoShapePtr()->makePrism(gp_Vec(vec.x,vec.y,vec.z));
|
||||
TopAbs_ShapeEnum type = shape.ShapeType();
|
||||
switch (type) {
|
||||
@@ -708,6 +777,7 @@ PyObject* TopoShapePy::extrude(PyObject *args)
|
||||
|
||||
PyErr_SetString(PartExceptionOCCError, "extrusion for this shape type not supported");
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
||||
@@ -721,8 +791,14 @@ PyObject* TopoShapePy::revolve(PyObject *args)
|
||||
double d=360;
|
||||
if (!PyArg_ParseTuple(args, "O!O!|d", &(Base::VectorPy::Type), &pPos, &(Base::VectorPy::Type), &pDir,&d))
|
||||
return nullptr;
|
||||
|
||||
Base::Vector3d pos = static_cast<Base::VectorPy*>(pPos)->value();
|
||||
Base::Vector3d dir = static_cast<Base::VectorPy*>(pDir)->value();
|
||||
try {
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementRevolve(
|
||||
gp_Ax1(gp_Pnt(pos.x, pos.y, pos.z), gp_Dir(dir.x, dir.y, dir.z)),
|
||||
d * (M_PI / 180))));
|
||||
#else
|
||||
const TopoDS_Shape& input = this->getTopoShapePtr()->getShape();
|
||||
if (input.IsNull()) {
|
||||
PyErr_SetString(PartExceptionOCCError, "empty shape cannot be revolved");
|
||||
@@ -741,8 +817,6 @@ PyObject* TopoShapePy::revolve(PyObject *args)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Base::Vector3d pos = static_cast<Base::VectorPy*>(pPos)->value();
|
||||
Base::Vector3d dir = static_cast<Base::VectorPy*>(pDir)->value();
|
||||
TopoDS_Shape shape = this->getTopoShapePtr()->revolve(
|
||||
gp_Ax1(gp_Pnt(pos.x,pos.y,pos.z), gp_Dir(dir.x,dir.y,dir.z)),d*(M_PI/180));
|
||||
TopAbs_ShapeEnum type = shape.ShapeType();
|
||||
@@ -772,6 +846,7 @@ PyObject* TopoShapePy::revolve(PyObject *args)
|
||||
|
||||
PyErr_SetString(PartExceptionOCCError, "revolution for this shape type not supported");
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
||||
@@ -796,8 +871,26 @@ PyObject* TopoShapePy::check(PyObject *args)
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
static PyObject *makeShape(const char *op,const TopoShape &shape, PyObject *args) {
|
||||
double tol=0;
|
||||
PyObject *pcObj;
|
||||
if (!PyArg_ParseTuple(args, "O|d", &pcObj,&tol))
|
||||
return 0;
|
||||
PY_TRY {
|
||||
std::vector<TopoShape> shapes;
|
||||
shapes.push_back(shape);
|
||||
getPyShapes(pcObj,shapes);
|
||||
return Py::new_reference_to(shape2pyshape(TopoShape().makeElementBoolean(op,shapes,0,tol)));
|
||||
} PY_CATCH_OCC
|
||||
}
|
||||
#endif
|
||||
|
||||
PyObject* TopoShapePy::fuse(PyObject *args)
|
||||
{
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
return makeShape(Part::OpCodes::Fuse, *getTopoShapePtr(), args);
|
||||
#else
|
||||
PyObject *pcObj;
|
||||
if (PyArg_ParseTuple(args, "O!", &(TopoShapePy::Type), &pcObj)) {
|
||||
TopoDS_Shape shape = static_cast<TopoShapePy*>(pcObj)->getTopoShapePtr()->getShape();
|
||||
@@ -867,10 +960,14 @@ PyObject* TopoShapePy::fuse(PyObject *args)
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "shape or sequence of shape expected");
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
PyObject* TopoShapePy::multiFuse(PyObject *args)
|
||||
{
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
return makeShape(Part::OpCodes::Fuse, *getTopoShapePtr(), args);
|
||||
#else
|
||||
double tolerance = 0.0;
|
||||
PyObject *pcObj;
|
||||
if (!PyArg_ParseTuple(args, "O|d", &pcObj, &tolerance))
|
||||
@@ -900,6 +997,7 @@ PyObject* TopoShapePy::multiFuse(PyObject *args)
|
||||
PyErr_SetString(PartExceptionOCCError, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
PyObject* TopoShapePy::oldFuse(PyObject *args)
|
||||
@@ -926,6 +1024,9 @@ PyObject* TopoShapePy::oldFuse(PyObject *args)
|
||||
|
||||
PyObject* TopoShapePy::common(PyObject *args)
|
||||
{
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
return makeShape(Part::OpCodes::Common, *getTopoShapePtr(), args);
|
||||
#else
|
||||
PyObject *pcObj;
|
||||
if (PyArg_ParseTuple(args, "O!", &(TopoShapePy::Type), &pcObj)) {
|
||||
TopoDS_Shape shape = static_cast<TopoShapePy*>(pcObj)->getTopoShapePtr()->getShape();
|
||||
@@ -993,10 +1094,14 @@ PyObject* TopoShapePy::common(PyObject *args)
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "shape or sequence of shape expected");
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
PyObject* TopoShapePy::section(PyObject *args)
|
||||
{
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
return makeShape(Part::OpCodes::Section, *getTopoShapePtr(), args);
|
||||
#else
|
||||
PyObject *pcObj;
|
||||
PyObject *approx = Py_False;
|
||||
if (PyArg_ParseTuple(args, "O!|O!", &(TopoShapePy::Type), &pcObj, &(PyBool_Type), &approx)) {
|
||||
@@ -1065,6 +1170,7 @@ PyObject* TopoShapePy::section(PyObject *args)
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "shape or sequence of shape expected");
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
PyObject* TopoShapePy::slice(PyObject *args)
|
||||
@@ -1074,8 +1180,16 @@ PyObject* TopoShapePy::slice(PyObject *args)
|
||||
if (!PyArg_ParseTuple(args, "O!d", &(Base::VectorPy::Type), &dir, &d))
|
||||
return nullptr;
|
||||
|
||||
Base::Vector3d vec = Py::Vector(dir, false).toVector();
|
||||
|
||||
try {
|
||||
Base::Vector3d vec = Py::Vector(dir, false).toVector();
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
Py::List wires;
|
||||
for (auto& w : getTopoShapePtr()->makeElementSlice(vec, d).getSubTopoShapes(TopAbs_WIRE)) {
|
||||
wires.append(shape2pyshape(w));
|
||||
}
|
||||
return Py::new_reference_to(wires);
|
||||
#else
|
||||
std::list<TopoDS_Wire> slice = this->getTopoShapePtr()->slice(vec, d);
|
||||
Py::List wire;
|
||||
for (const auto & it : slice) {
|
||||
@@ -1083,6 +1197,7 @@ PyObject* TopoShapePy::slice(PyObject *args)
|
||||
}
|
||||
|
||||
return Py::new_reference_to(wire);
|
||||
#endif
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
|
||||
@@ -1108,8 +1223,12 @@ PyObject* TopoShapePy::slices(PyObject *args)
|
||||
d.reserve(list.size());
|
||||
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it)
|
||||
d.push_back((double)Py::Float(*it));
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementSlices(vec, d)));
|
||||
#else
|
||||
TopoDS_Compound slice = this->getTopoShapePtr()->slices(vec, d);
|
||||
return new TopoShapeCompoundPy(new TopoShape(slice));
|
||||
#endif
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
||||
@@ -1123,6 +1242,9 @@ PyObject* TopoShapePy::slices(PyObject *args)
|
||||
|
||||
PyObject* TopoShapePy::cut(PyObject *args)
|
||||
{
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
return makeShape(Part::OpCodes::Cut, *getTopoShapePtr(), args);
|
||||
#else
|
||||
PyObject *pcObj;
|
||||
if (PyArg_ParseTuple(args, "O!", &(TopoShapePy::Type), &pcObj)) {
|
||||
TopoDS_Shape shape = static_cast<TopoShapePy*>(pcObj)->getTopoShapePtr()->getShape();
|
||||
@@ -1190,6 +1312,7 @@ PyObject* TopoShapePy::cut(PyObject *args)
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "shape or sequence of shape expected");
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
PyObject* TopoShapePy::generalFuse(PyObject *args)
|
||||
@@ -1199,6 +1322,29 @@ PyObject* TopoShapePy::generalFuse(PyObject *args)
|
||||
if (!PyArg_ParseTuple(args, "O|d", &pcObj, &tolerance))
|
||||
return nullptr;
|
||||
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
std::vector<std::vector<TopoShape>> modifies;
|
||||
std::vector<TopoShape> shapes;
|
||||
shapes.push_back(*getTopoShapePtr());
|
||||
try {
|
||||
getPyShapes(pcObj, shapes);
|
||||
TopoShape res;
|
||||
res.makeElementGeneralFuse(shapes, modifies, tolerance);
|
||||
Py::List mapPy;
|
||||
for (auto& mod : modifies) {
|
||||
Py::List shapesPy;
|
||||
for (auto& sh : mod) {
|
||||
shapesPy.append(shape2pyshape(sh));
|
||||
}
|
||||
mapPy.append(shapesPy);
|
||||
}
|
||||
Py::Tuple ret(2);
|
||||
ret[0] = shape2pyshape(res);
|
||||
ret[1] = mapPy;
|
||||
return Py::new_reference_to(ret);
|
||||
}
|
||||
PY_CATCH_OCC
|
||||
#else
|
||||
std::vector<TopoDS_Shape> shapeVec;
|
||||
Py::Sequence shapeSeq(pcObj);
|
||||
for (Py::Sequence::iterator it = shapeSeq.begin(); it != shapeSeq.end(); ++it) {
|
||||
@@ -1236,6 +1382,7 @@ PyObject* TopoShapePy::generalFuse(PyObject *args)
|
||||
PyErr_SetString(PartExceptionOCCError, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
PyObject* TopoShapePy::sewShape(PyObject *args)
|
||||
@@ -1261,6 +1408,24 @@ PyObject* TopoShapePy::childShapes(PyObject *args)
|
||||
if (!PyArg_ParseTuple(args, "|O!O!", &(PyBool_Type), &cumOri, &(PyBool_Type), &cumLoc))
|
||||
return nullptr;
|
||||
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
TopoShape shape = *getTopoShapePtr();
|
||||
if (!PyObject_IsTrue(cumOri)) {
|
||||
shape.setShape(shape.getShape().Oriented(TopAbs_FORWARD), false);
|
||||
}
|
||||
if (!PyObject_IsTrue(cumLoc)) {
|
||||
shape.setShape(shape.getShape().Located(TopLoc_Location()), false);
|
||||
}
|
||||
Py::List list;
|
||||
PY_TRY
|
||||
{
|
||||
for (auto& s : shape.getSubTopoShapes()) {
|
||||
list.append(shape2pyshape(s));
|
||||
}
|
||||
return Py::new_reference_to(list);
|
||||
}
|
||||
PY_CATCH_OCC
|
||||
#else
|
||||
try {
|
||||
const TopoDS_Shape& shape = getTopoShapePtr()->getShape();
|
||||
if (shape.IsNull()) {
|
||||
@@ -1316,6 +1481,7 @@ PyObject* TopoShapePy::childShapes(PyObject *args)
|
||||
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace Part {
|
||||
@@ -1423,8 +1589,12 @@ PyObject* TopoShapePy::mirror(PyObject *args)
|
||||
|
||||
try {
|
||||
gp_Ax2 ax2(gp_Pnt(base.x,base.y,base.z), gp_Dir(norm.x,norm.y,norm.z));
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementMirror(ax2)));
|
||||
#else
|
||||
TopoDS_Shape shape = this->getTopoShapePtr()->mirror(ax2);
|
||||
return new TopoShapePy(new TopoShape(shape));
|
||||
#endif
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
||||
@@ -1575,7 +1745,12 @@ PyObject* TopoShapePy::scale(PyObject *args)
|
||||
BRepBuilderAPI_Transform BRepScale(scl);
|
||||
bool bCopy = true;
|
||||
BRepScale.Perform(shape, bCopy);
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
TopoShape copy(*getTopoShapePtr());
|
||||
getTopoShapePtr()->makeElementShape(BRepScale, copy);
|
||||
#else
|
||||
getTopoShapePtr()->setShape(BRepScale.Shape());
|
||||
#endif
|
||||
}
|
||||
return IncRef();
|
||||
}
|
||||
@@ -1605,6 +1780,25 @@ PyObject* TopoShapePy::makeFillet(PyObject *args)
|
||||
// use two radii for all edges
|
||||
double radius1, radius2;
|
||||
PyObject *obj;
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
if (!PyArg_ParseTuple(args, "ddO", &radius1, &radius2, &obj)) {
|
||||
PyErr_Clear();
|
||||
if (!PyArg_ParseTuple(args, "dO", &radius1, &obj)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"This method accepts:\n"
|
||||
"-- one radius and a list of edges\n"
|
||||
"-- two radii and a list of edges");
|
||||
return 0;
|
||||
}
|
||||
radius2 = radius1;
|
||||
}
|
||||
PY_TRY
|
||||
{
|
||||
return Py::new_reference_to(shape2pyshape(
|
||||
getTopoShapePtr()->makeElementFillet(getPyShapes(obj), radius1, radius2)));
|
||||
}
|
||||
PY_CATCH_OCC
|
||||
#else
|
||||
if (PyArg_ParseTuple(args, "ddO", &radius1, &radius2, &obj)) {
|
||||
try {
|
||||
const TopoDS_Shape& shape = this->getTopoShapePtr()->getShape();
|
||||
@@ -1626,7 +1820,7 @@ PyObject* TopoShapePy::makeFillet(PyObject *args)
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
PyErr_Clear();
|
||||
// use one radius for all edges
|
||||
double radius;
|
||||
@@ -1663,6 +1857,26 @@ PyObject* TopoShapePy::makeChamfer(PyObject *args)
|
||||
// use two radii for all edges
|
||||
double radius1, radius2;
|
||||
PyObject *obj;
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
if (!PyArg_ParseTuple(args, "ddO", &radius1, &radius2, &obj)) {
|
||||
if (!PyArg_ParseTuple(args, "dO", &radius1, &obj)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"This method accepts:\n"
|
||||
"-- one radius and a list of edges\n"
|
||||
"-- two radii and a list of edges");
|
||||
return 0;
|
||||
}
|
||||
PyErr_Clear();
|
||||
radius2 = radius1;
|
||||
}
|
||||
PY_TRY
|
||||
{
|
||||
return Py::new_reference_to(shape2pyshape(
|
||||
getTopoShapePtr()->makeElementChamfer(getPyShapes(obj), radius1, radius2)));
|
||||
}
|
||||
PY_CATCH_OCC
|
||||
#else
|
||||
|
||||
if (PyArg_ParseTuple(args, "ddO", &radius1, &radius2, &obj)) {
|
||||
try {
|
||||
const TopoDS_Shape& shape = this->getTopoShapePtr()->getShape();
|
||||
@@ -1689,7 +1903,7 @@ PyObject* TopoShapePy::makeChamfer(PyObject *args)
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
PyErr_Clear();
|
||||
// use one radius for all edges
|
||||
double radius;
|
||||
@@ -1738,6 +1952,16 @@ PyObject* TopoShapePy::makeThickness(PyObject *args)
|
||||
return nullptr;
|
||||
|
||||
try {
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
return Py::new_reference_to(shape2pyshape(
|
||||
getTopoShapePtr()->makeElementThickSolid(getPyShapes(obj),
|
||||
offset,
|
||||
tolerance,
|
||||
PyObject_IsTrue(inter) ? true : false,
|
||||
PyObject_IsTrue(self_inter) ? true : false,
|
||||
offsetMode,
|
||||
static_cast<JoinType>(join))));
|
||||
#else
|
||||
TopTools_ListOfShape facesToRemove;
|
||||
Py::Sequence list(obj);
|
||||
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
|
||||
@@ -1750,6 +1974,7 @@ PyObject* TopoShapePy::makeThickness(PyObject *args)
|
||||
TopoDS_Shape shape = this->getTopoShapePtr()->makeThickSolid(facesToRemove, offset, tolerance,
|
||||
Base::asBoolean(inter), Base::asBoolean(self_inter), offsetMode, join);
|
||||
return new TopoShapeSolidPy(new TopoShape(shape));
|
||||
#endif
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
||||
@@ -1773,11 +1998,22 @@ PyObject* TopoShapePy::makeOffsetShape(PyObject *args, PyObject *keywds)
|
||||
}
|
||||
|
||||
try {
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementOffset(
|
||||
offset,
|
||||
tolerance,
|
||||
PyObject_IsTrue(inter) ? true : false,
|
||||
PyObject_IsTrue(self_inter) ? true : false,
|
||||
offsetMode,
|
||||
static_cast<JoinType>(join),
|
||||
PyObject_IsTrue(fill) ? FillType::fill : FillType::noFill)));
|
||||
#else
|
||||
TopoDS_Shape shape = this->getTopoShapePtr()->makeOffsetShape(offset, tolerance,
|
||||
Base::asBoolean(inter),
|
||||
Base::asBoolean(self_inter), offsetMode, join,
|
||||
Base::asBoolean(fill));
|
||||
return new TopoShapePy(new TopoShape(shape));
|
||||
#endif
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
||||
@@ -1800,9 +2036,18 @@ PyObject* TopoShapePy::makeOffset2D(PyObject *args, PyObject *keywds)
|
||||
}
|
||||
|
||||
try {
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementOffset2D(
|
||||
offset,
|
||||
static_cast<JoinType>(join),
|
||||
PyObject_IsTrue(fill) ? FillType::fill : FillType::noFill,
|
||||
PyObject_IsTrue(openResult) ? OpenResult::allowOpenResult : OpenResult::noOpenResult,
|
||||
PyObject_IsTrue(inter) ? true : false)));
|
||||
#else
|
||||
TopoDS_Shape resultShape = this->getTopoShapePtr()->makeOffset2D(offset, join,
|
||||
Base::asBoolean(fill), Base::asBoolean(openResult), Base::asBoolean(inter));
|
||||
return new_reference_to(shape2pyshape(resultShape));
|
||||
#endif
|
||||
}
|
||||
PY_CATCH_OCC;
|
||||
}
|
||||
@@ -2217,6 +2462,32 @@ PyObject* TopoShapePy::makeShapeFromMesh(PyObject *args)
|
||||
PY_CATCH_OCC
|
||||
}
|
||||
|
||||
PyObject* TopoShapePy::makeEvolved(PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject* Profile;
|
||||
PyObject* AxeProf = Py_True;
|
||||
PyObject* Solid = Py_False;
|
||||
PyObject* ProfOnSpine = Py_False;
|
||||
auto JoinType = JoinType::arc;
|
||||
double Tolerance = 0.0000001;
|
||||
|
||||
static char* kwds_evolve[] = {"Profile", "Join", "AxeProf", "Solid", "ProfOnSpine", "Tolerance", nullptr};
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|iO!O!O!d", kwds_evolve,
|
||||
&TopoShapePy::Type, &Profile, &JoinType,
|
||||
&PyBool_Type, &AxeProf, &PyBool_Type, &Solid,
|
||||
&PyBool_Type, &ProfOnSpine, &Tolerance))
|
||||
return nullptr;
|
||||
|
||||
try {
|
||||
return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementEvolve(
|
||||
*static_cast<TopoShapePy*>(Profile)->getTopoShapePtr(), JoinType,
|
||||
PyObject_IsTrue(AxeProf) ? CoordinateSystem::global : CoordinateSystem::relativeToSpine,
|
||||
PyObject_IsTrue(Solid) ? MakeSolid::makeSolid : MakeSolid::noSolid,
|
||||
PyObject_IsTrue(ProfOnSpine) ? Spine::on : Spine::notOn,
|
||||
Tolerance)));
|
||||
} PY_CATCH_OCC
|
||||
}
|
||||
|
||||
PyObject* TopoShapePy::makeWires(PyObject *args) {
|
||||
const char *op = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "s", &op))
|
||||
@@ -2304,9 +2575,13 @@ PyObject* TopoShapePy::removeSplitter(PyObject *args)
|
||||
return nullptr;
|
||||
|
||||
try {
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementRefine()));
|
||||
#else
|
||||
// Remove redundant splitter
|
||||
TopoDS_Shape shape = this->getTopoShapePtr()->removeSplitter();
|
||||
return new TopoShapePy(new TopoShape(shape));
|
||||
#endif
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
||||
@@ -2779,6 +3054,15 @@ PyObject* TopoShapePy::optimalBoundingBox(PyObject *args)
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* TopoShapePy::clearCache(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return 0;
|
||||
}
|
||||
getTopoShapePtr()->initCache(1);
|
||||
return IncRef();
|
||||
}
|
||||
|
||||
PyObject* TopoShapePy::defeaturing(PyObject *args)
|
||||
{
|
||||
PyObject *l;
|
||||
@@ -2806,6 +3090,88 @@ PyObject* TopoShapePy::defeaturing(PyObject *args)
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* TopoShapePy::findSubShape(PyObject* args)
|
||||
{
|
||||
PyObject* pyobj;
|
||||
if (!PyArg_ParseTuple(args, "O", &pyobj)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PY_TRY
|
||||
{
|
||||
Py::List res;
|
||||
for (auto& s : getPyShapes(pyobj)) {
|
||||
int index = getTopoShapePtr()->findShape(s.getShape());
|
||||
if (index > 0) {
|
||||
res.append(Py::TupleN(Py::String(s.shapeName()), Py::Int(index)));
|
||||
}
|
||||
else {
|
||||
res.append(Py::TupleN(Py::Object(), Py::Int(0)));
|
||||
}
|
||||
}
|
||||
if (PySequence_Check(pyobj)) {
|
||||
return Py::new_reference_to(res);
|
||||
}
|
||||
return Py::new_reference_to(Py::Object(res[0].ptr()));
|
||||
}
|
||||
PY_CATCH_OCC
|
||||
}
|
||||
|
||||
PyObject* TopoShapePy::findSubShapesWithSharedVertex(PyObject* args, PyObject* keywds)
|
||||
{
|
||||
static char* kwlist[] = {"shape", "needName", "checkGeometry", "tol", "atol", nullptr};
|
||||
PyObject* pyobj;
|
||||
PyObject* needName = Py_False;
|
||||
PyObject* checkGeometry = Py_True;
|
||||
double tol = 1e-7;
|
||||
double atol = 1e-12;
|
||||
if (!PyArg_ParseTupleAndKeywords(args,
|
||||
keywds,
|
||||
"O!|OOdd",
|
||||
kwlist,
|
||||
&Type,
|
||||
&pyobj,
|
||||
&needName,
|
||||
&checkGeometry,
|
||||
&tol,
|
||||
&atol)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PY_TRY
|
||||
{
|
||||
Py::List res;
|
||||
const TopoShape& shape = *static_cast<TopoShapePy*>(pyobj)->getTopoShapePtr();
|
||||
if (PyObject_IsTrue(needName)) {
|
||||
std::vector<std::string> names;
|
||||
auto shapes = getTopoShapePtr()->findSubShapesWithSharedVertex(
|
||||
shape,
|
||||
&names,
|
||||
PyObject_IsTrue(checkGeometry) ? CheckGeometry::checkGeometry
|
||||
: CheckGeometry::ignoreGeometry,
|
||||
tol,
|
||||
atol);
|
||||
for (std::size_t i = 0; i < shapes.size(); ++i) {
|
||||
res.append(Py::TupleN(Py::String(names[i]), shape2pyshape(shapes[i])));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (auto& s : getTopoShapePtr()->findSubShapesWithSharedVertex(
|
||||
shape,
|
||||
nullptr,
|
||||
PyObject_IsTrue(checkGeometry) ? CheckGeometry::checkGeometry
|
||||
: CheckGeometry::ignoreGeometry,
|
||||
tol,
|
||||
atol)) {
|
||||
res.append(shape2pyshape(s));
|
||||
}
|
||||
}
|
||||
return Py::new_reference_to(res);
|
||||
}
|
||||
PY_CATCH_OCC
|
||||
}
|
||||
|
||||
// End of Methods, Start of Attributes
|
||||
|
||||
Py::String TopoShapePy::getShapeType() const
|
||||
{
|
||||
@@ -2912,23 +3278,23 @@ getElements(const TopoShape& sh, TopAbs_ShapeEnum type, TopAbs_ShapeEnum avoid =
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Todo: Toponaming Project March, 2024: This code is defined, appears to be correct, but
|
||||
// is not clearly in use, thus commented out:
|
||||
//
|
||||
//PyObject *TopoShapePy::getChildShapes(PyObject *args)
|
||||
//{
|
||||
// const char *type;
|
||||
// const char *avoid = nullptr;
|
||||
// if (!PyArg_ParseTuple(args, "s|s", &type, &avoid))
|
||||
// return nullptr;
|
||||
//
|
||||
// PY_TRY {
|
||||
// return Py::new_reference_to(
|
||||
// getElements(*getTopoShapePtr(),
|
||||
// TopoShape::shapeType(type),
|
||||
// avoid && avoid[0] ? TopoShape::shapeType(avoid) : TopAbs_SHAPE));
|
||||
// }PY_CATCH_OCC;
|
||||
//}
|
||||
PyObject* TopoShapePy::getChildShapes(PyObject* args)
|
||||
{
|
||||
const char* type;
|
||||
const char* avoid = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "s|s", &type, &avoid)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PY_TRY
|
||||
{
|
||||
return Py::new_reference_to(
|
||||
getElements(*getTopoShapePtr(),
|
||||
TopoShape::shapeType(type),
|
||||
avoid && avoid[0] ? TopoShape::shapeType(avoid) : TopAbs_SHAPE));
|
||||
}
|
||||
PY_CATCH_OCC;
|
||||
}
|
||||
|
||||
Py::List TopoShapePy::getSubShapes() const
|
||||
{
|
||||
@@ -3005,14 +3371,121 @@ Py::Float TopoShapePy::getVolume() const
|
||||
return Py::Float(props.Mass());
|
||||
}
|
||||
|
||||
PyObject *TopoShapePy::getCustomAttributes(const char* attr) const
|
||||
PyObject* TopoShapePy::getElementHistory(PyObject* args)
|
||||
{
|
||||
if (!attr)
|
||||
const char* pyname;
|
||||
if (!PyArg_ParseTuple(args, "s", &pyname)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Data::MappedName name(pyname);
|
||||
PY_TRY
|
||||
{
|
||||
Data::MappedName original;
|
||||
std::vector<Data::MappedName> history;
|
||||
long tag = getTopoShapePtr()->getElementHistory(name, &original, &history);
|
||||
if (!tag) {
|
||||
Py_Return;
|
||||
}
|
||||
Py::Tuple ret(3);
|
||||
ret.setItem(0, Py::Int(tag));
|
||||
std::string tmp;
|
||||
ret.setItem(1, Py::String(original.appendToBuffer(tmp)));
|
||||
Py::List pyHistory;
|
||||
for (auto& h : history) {
|
||||
tmp.clear();
|
||||
pyHistory.append(Py::String(h.appendToBuffer(tmp)));
|
||||
}
|
||||
ret.setItem(2, pyHistory);
|
||||
return Py::new_reference_to(ret);
|
||||
}
|
||||
PY_CATCH_OCC
|
||||
}
|
||||
|
||||
struct PyShapeMapper: Part::ShapeMapper
|
||||
{
|
||||
bool populate(MappingStatus status, PyObject* pyobj)
|
||||
{
|
||||
if (!pyobj || pyobj == Py_None) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
Py::Sequence seq(pyobj);
|
||||
for (size_t i = 0, count = seq.size(); i < count; ++i) {
|
||||
Py::Sequence item(seq[i].ptr());
|
||||
if (item.size() != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Part::ShapeMapper::populate(status,
|
||||
getPyShapes(item[0].ptr()),
|
||||
getPyShapes(item[1].ptr()));
|
||||
}
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
PyErr_Clear();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void init(PyObject* g, PyObject* m)
|
||||
{
|
||||
const char* msg =
|
||||
"Expect input mapping to be a list of tuple(srcShape|shapeList, dstShape|shapeList)";
|
||||
if (!populate(MappingStatus::Generated, g) || !populate(MappingStatus::Modified, m)) {
|
||||
throw Py::TypeError(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
PyObject* TopoShapePy::mapShapes(PyObject* args)
|
||||
{
|
||||
PyObject* generated;
|
||||
PyObject* modified;
|
||||
const char* op = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "OO|s", &generated, &modified, &op)) {
|
||||
return 0;
|
||||
}
|
||||
PY_TRY
|
||||
{
|
||||
PyShapeMapper mapper;
|
||||
mapper.init(generated, modified);
|
||||
TopoShape& self = *getTopoShapePtr();
|
||||
TopoShape s(self.Tag, self.Hasher);
|
||||
s.makeShapeWithElementMap(self.getShape(), mapper, mapper.shapes, op);
|
||||
self = s;
|
||||
return IncRef();
|
||||
}
|
||||
PY_CATCH_OCC
|
||||
}
|
||||
|
||||
PyObject* TopoShapePy::mapSubElement(PyObject* args)
|
||||
{
|
||||
const char* op = nullptr;
|
||||
PyObject* sh;
|
||||
if (!PyArg_ParseTuple(args, "O|s", &sh, &op)) {
|
||||
return 0;
|
||||
}
|
||||
PY_TRY
|
||||
{
|
||||
getTopoShapePtr()->mapSubElement(getPyShapes(sh), op);
|
||||
return IncRef();
|
||||
}
|
||||
PY_CATCH_OCC
|
||||
}
|
||||
|
||||
PyObject* TopoShapePy::getCustomAttributes(const char* attr) const
|
||||
{
|
||||
if (!attr) {
|
||||
return nullptr;
|
||||
PY_TRY {
|
||||
TopoDS_Shape res = getTopoShapePtr()->getSubShape(attr,true);
|
||||
if (!res.IsNull())
|
||||
}
|
||||
PY_TRY
|
||||
{
|
||||
TopoDS_Shape res = getTopoShapePtr()->getSubShape(attr, true);
|
||||
if (!res.IsNull()) {
|
||||
return Py::new_reference_to(shape2pyshape(res));
|
||||
}
|
||||
}
|
||||
PY_CATCH_OCC
|
||||
return nullptr;
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <Base/VectorPy.h>
|
||||
|
||||
#include "OCCError.h"
|
||||
#include "PartPyCXX.h"
|
||||
#include "Tools.h"
|
||||
#include "TopoShapeCompoundPy.h"
|
||||
#include "TopoShapeCompoundPy.h"
|
||||
@@ -45,7 +46,7 @@
|
||||
#include "TopoShapeShellPy.h"
|
||||
#include "TopoShapeShellPy.cpp"
|
||||
#include "TopoShapeSolidPy.h"
|
||||
|
||||
#include "TopoShapeOpCode.h"
|
||||
|
||||
using namespace Part;
|
||||
|
||||
@@ -85,6 +86,12 @@ int TopoShapeShellPy::PyInit(PyObject* args, PyObject* /*kwd*/)
|
||||
if (!PyArg_ParseTuple(args, "O", &obj))
|
||||
return -1;
|
||||
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
try {
|
||||
getTopoShapePtr()->makeElementBoolean(Part::OpCodes::Shell, getPyShapes(obj));
|
||||
}
|
||||
_PY_CATCH_OCC(return (-1))
|
||||
#else
|
||||
BRep_Builder builder;
|
||||
TopoDS_Shape shape;
|
||||
TopoDS_Shell shell;
|
||||
@@ -121,6 +128,7 @@ int TopoShapeShellPy::PyInit(PyObject* args, PyObject* /*kwd*/)
|
||||
}
|
||||
|
||||
getTopoShapePtr()->setShape(shape);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -134,11 +142,14 @@ PyObject* TopoShapeShellPy::add(PyObject *args)
|
||||
TopoDS_Shape shell = getTopoShapePtr()->getShape();
|
||||
|
||||
try {
|
||||
const TopoDS_Shape& sh = static_cast<TopoShapeFacePy*>(obj)->
|
||||
getTopoShapePtr()->getShape();
|
||||
const TopoShape& shape = *static_cast<TopoShapeFacePy*>(obj)->getTopoShapePtr();
|
||||
const auto &sh = shape.getShape();
|
||||
if (!sh.IsNull()) {
|
||||
builder.Add(shell, sh);
|
||||
BRepCheck_Analyzer check(shell);
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
getTopoShapePtr()->mapSubElement(shape);
|
||||
#endif
|
||||
if (!check.IsValid()) {
|
||||
ShapeUpgrade_ShellSewing sewShell;
|
||||
getTopoShapePtr()->setShape(sewShell.ApplySewing(shell));
|
||||
@@ -167,7 +178,14 @@ PyObject* TopoShapeShellPy::getFreeEdges(PyObject *args)
|
||||
as.CheckOrientedShells(getTopoShapePtr()->getShape(), Standard_True, Standard_True);
|
||||
|
||||
TopoDS_Compound comp = as.FreeEdges();
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
TopoShape res;
|
||||
res.setShape(comp);
|
||||
res.mapSubElement(*getTopoShapePtr());
|
||||
return Py::new_reference_to(shape2pyshape(res));
|
||||
#else
|
||||
return new TopoShapeCompoundPy(new TopoShape(comp));
|
||||
#endif
|
||||
}
|
||||
|
||||
PyObject* TopoShapeShellPy::getBadEdges(PyObject *args)
|
||||
@@ -179,7 +197,14 @@ PyObject* TopoShapeShellPy::getBadEdges(PyObject *args)
|
||||
as.CheckOrientedShells(getTopoShapePtr()->getShape(), Standard_True, Standard_True);
|
||||
|
||||
TopoDS_Compound comp = as.BadEdges();
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
TopoShape res;
|
||||
res.setShape(comp);
|
||||
res.mapSubElement(*getTopoShapePtr());
|
||||
return Py::new_reference_to(shape2pyshape(res));
|
||||
#else
|
||||
return new TopoShapeCompoundPy(new TopoShape(comp));
|
||||
#endif
|
||||
}
|
||||
|
||||
PyObject* TopoShapeShellPy::makeHalfSpace(PyObject *args)
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include <Base/VectorPy.h>
|
||||
|
||||
#include "OCCError.h"
|
||||
#include "PartPyCXX.h"
|
||||
#include "Tools.h"
|
||||
|
||||
// inclusion of the generated files (generated out of TopoShapeSolidPy.xml)
|
||||
@@ -87,6 +88,9 @@ int TopoShapeSolidPy::PyInit(PyObject* args, PyObject* /*kwd*/)
|
||||
return -1;
|
||||
|
||||
try {
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
getTopoShapePtr()->makeElementSolid(*static_cast<TopoShapePy*>(obj)->getTopoShapePtr());
|
||||
#else
|
||||
const TopoDS_Shape& shape = static_cast<TopoShapePy*>(obj)
|
||||
->getTopoShapePtr()->getShape();
|
||||
//first, if we were given a compsolid, try making a solid out of it
|
||||
@@ -122,7 +126,7 @@ int TopoShapeSolidPy::PyInit(PyObject* args, PyObject* /*kwd*/)
|
||||
} else /*if (count > 1)*/ {
|
||||
Standard_Failure::Raise("Only one compsolid can be accepted. Provided shape has more than one compsolid.");
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
catch (Standard_Failure& err) {
|
||||
std::stringstream errmsg;
|
||||
@@ -216,7 +220,14 @@ Py::Object TopoShapeSolidPy::getOuterShell() const
|
||||
const TopoDS_Shape& shape = getTopoShapePtr()->getShape();
|
||||
if (!shape.IsNull() && shape.ShapeType() == TopAbs_SOLID)
|
||||
shell = BRepClass3d::OuterShell(TopoDS::Solid(shape));
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
TopoShape res;
|
||||
res.setShape(shell);
|
||||
res.mapSubElement(*getTopoShapePtr());
|
||||
return shape2pyshape(res);
|
||||
#else
|
||||
return Py::Object(new TopoShapeShellPy(new TopoShape(shell)),true);
|
||||
#endif
|
||||
}
|
||||
|
||||
PyObject* TopoShapeSolidPy::getMomentOfInertia(PyObject *args)
|
||||
@@ -316,7 +327,13 @@ PyObject* TopoShapeSolidPy::offsetFaces(PyObject *args)
|
||||
try {
|
||||
builder.MakeOffsetShape();
|
||||
const TopoDS_Shape& offsetshape = builder.Shape();
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
TopoShape res;
|
||||
res.setShape(offsetshape);
|
||||
return Py::new_reference_to(shape2pyshape(res));
|
||||
#else
|
||||
return new TopoShapeSolidPy(new TopoShape(offsetshape));
|
||||
#endif
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import Part
|
||||
|
||||
import unittest
|
||||
|
||||
|
||||
class TopoShapeAssertions:
|
||||
|
||||
def assertAttrEqual(self, toposhape, attr_value_list, msg=None):
|
||||
@@ -42,6 +43,19 @@ class TopoShapeAssertions:
|
||||
if msg == None:
|
||||
msg = f"Key {key} not found in map: {map}"
|
||||
raise AssertionError(msg)
|
||||
|
||||
def assertBounds(self, shape, bounds, msg=None, precision=App.Base.Precision.confusion() * 100):
|
||||
shape_bounds = shape.BoundBox
|
||||
shape_bounds_max = App.BoundBox(shape_bounds)
|
||||
shape_bounds_max.enlarge(precision)
|
||||
bounds_max = App.BoundBox(bounds)
|
||||
bounds_max.enlarge(precision)
|
||||
if not (shape_bounds_max.isInside(bounds) and bounds_max.isInside(shape_bounds)):
|
||||
if msg == None:
|
||||
msg = f"Bounds {shape_bounds} doesn't match {bounds}"
|
||||
raise AssertionError(msg)
|
||||
|
||||
|
||||
class TopoShapeTest(unittest.TestCase, TopoShapeAssertions):
|
||||
def setUp(self):
|
||||
"""Create a document and some TopoShapes of various types"""
|
||||
@@ -161,290 +175,583 @@ class TopoShapeTest(unittest.TestCase, TopoShapeAssertions):
|
||||
]
|
||||
self.doc.recompute()
|
||||
compound2 = self.doc.Compound.Shape
|
||||
# Assert
|
||||
# This is a flag value to indicate that ElementMaps are supported under the current C++ build:
|
||||
# Assert elementMap
|
||||
# This flag indicates that ElementMaps are supported under the current C++ build:
|
||||
if compound1.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
# 52 is 2 cubes of 26 each: 6 Faces, 12 Edges, 8 Vertexes
|
||||
# Todo: This should contain something as soon as the Python interface for Part.Compound TNP exists
|
||||
# self.assertEqual(len(compound1.ElementMap), 52, "ElementMap is Incorrect: {0}".format(compound1.ElementMap))
|
||||
# Todo: This should contain something as soon as the Python interface
|
||||
# for Part.Compound TNP exists
|
||||
# self.assertEqual(len(compound1.ElementMap), 52,
|
||||
# "ElementMap is Incorrect: {0}".format(compound1.ElementMap))
|
||||
self.assertEqual(
|
||||
compound2.ElementMapSize,
|
||||
52,
|
||||
"ElementMap is Incorrect: {0}".format(compound2.ElementMap),
|
||||
)
|
||||
# Assert Shape
|
||||
self.assertBounds(compound2, App.BoundBox(0, 0, 0, 2, 2, 2))
|
||||
|
||||
def testPartCommon(self):
|
||||
# Arrange
|
||||
self.doc.addObject("Part::MultiCommon", "Common")
|
||||
self.doc.Common.Shapes = [self.doc.Box1, self.doc.Box2]
|
||||
# Act
|
||||
self.doc.recompute()
|
||||
if self.doc.Common.Shape.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertKeysInMap(self.doc.Common.Shape.ElementReverseMap,
|
||||
[
|
||||
"Edge1",
|
||||
"Edge2",
|
||||
"Edge3",
|
||||
"Edge4",
|
||||
"Edge5",
|
||||
"Edge6",
|
||||
"Edge7",
|
||||
"Edge8",
|
||||
"Edge9",
|
||||
"Edge10",
|
||||
"Edge11",
|
||||
"Edge12",
|
||||
"Face1",
|
||||
"Face2",
|
||||
"Face3",
|
||||
"Face4",
|
||||
"Face5",
|
||||
"Face6",
|
||||
"Vertex1",
|
||||
"Vertex2",
|
||||
"Vertex3",
|
||||
"Vertex4",
|
||||
"Vertex5",
|
||||
"Vertex6",
|
||||
"Vertex7",
|
||||
"Vertex8",
|
||||
],
|
||||
)
|
||||
common1 = self.doc.Common.Shape
|
||||
# Assert elementMap
|
||||
if common1.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertKeysInMap(common1.ElementReverseMap,
|
||||
[
|
||||
"Edge1",
|
||||
"Edge2",
|
||||
"Edge3",
|
||||
"Edge4",
|
||||
"Edge5",
|
||||
"Edge6",
|
||||
"Edge7",
|
||||
"Edge8",
|
||||
"Edge9",
|
||||
"Edge10",
|
||||
"Edge11",
|
||||
"Edge12",
|
||||
"Face1",
|
||||
"Face2",
|
||||
"Face3",
|
||||
"Face4",
|
||||
"Face5",
|
||||
"Face6",
|
||||
"Vertex1",
|
||||
"Vertex2",
|
||||
"Vertex3",
|
||||
"Vertex4",
|
||||
"Vertex5",
|
||||
"Vertex6",
|
||||
"Vertex7",
|
||||
"Vertex8",
|
||||
],
|
||||
)
|
||||
# Assert Shape
|
||||
self.assertBounds(common1, App.BoundBox(0, 0, 0, 1, 1, 2))
|
||||
|
||||
def testPartCut(self):
|
||||
# Arrange
|
||||
self.doc.addObject("Part::Cut", "Cut")
|
||||
self.doc.Cut.Base = self.doc.Box1
|
||||
self.doc.Cut.Tool = self.doc.Box2
|
||||
# Act
|
||||
self.doc.recompute()
|
||||
if self.doc.Cut.Shape.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertKeysInMap(self.doc.Cut.Shape.ElementReverseMap,
|
||||
[
|
||||
"Edge1",
|
||||
"Edge2",
|
||||
"Edge3",
|
||||
"Edge4",
|
||||
"Edge5",
|
||||
"Edge6",
|
||||
"Edge7",
|
||||
"Edge8",
|
||||
"Edge9",
|
||||
"Edge10",
|
||||
"Edge11",
|
||||
"Edge12",
|
||||
"Face1",
|
||||
"Face2",
|
||||
"Face3",
|
||||
"Face4",
|
||||
"Face5",
|
||||
"Face6",
|
||||
"Vertex1",
|
||||
"Vertex2",
|
||||
"Vertex3",
|
||||
"Vertex4",
|
||||
"Vertex5",
|
||||
"Vertex6",
|
||||
"Vertex7",
|
||||
"Vertex8",
|
||||
],
|
||||
)
|
||||
cut1 = self.doc.Cut.Shape
|
||||
# Assert elementMap
|
||||
if cut1.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertKeysInMap(cut1.ElementReverseMap,
|
||||
[
|
||||
"Edge1",
|
||||
"Edge2",
|
||||
"Edge3",
|
||||
"Edge4",
|
||||
"Edge5",
|
||||
"Edge6",
|
||||
"Edge7",
|
||||
"Edge8",
|
||||
"Edge9",
|
||||
"Edge10",
|
||||
"Edge11",
|
||||
"Edge12",
|
||||
"Face1",
|
||||
"Face2",
|
||||
"Face3",
|
||||
"Face4",
|
||||
"Face5",
|
||||
"Face6",
|
||||
"Vertex1",
|
||||
"Vertex2",
|
||||
"Vertex3",
|
||||
"Vertex4",
|
||||
"Vertex5",
|
||||
"Vertex6",
|
||||
"Vertex7",
|
||||
"Vertex8",
|
||||
],
|
||||
)
|
||||
# Assert Shape
|
||||
self.assertBounds(cut1, App.BoundBox(0, 1, 0, 1, 2, 2))
|
||||
|
||||
def testPartFuse(self):
|
||||
# Arrange
|
||||
self.doc.addObject("Part::Fuse", "Fuse")
|
||||
self.doc.Fuse.Base = self.doc.Box1
|
||||
self.doc.Fuse.Tool = self.doc.Box2
|
||||
# Act
|
||||
self.doc.recompute()
|
||||
if self.doc.Fuse.Shape.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(self.doc.Fuse.Shape.ElementMapSize, 58)
|
||||
fuse1 = self.doc.Fuse.Shape
|
||||
# Assert elementMap
|
||||
if fuse1.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(fuse1.ElementMapSize, 58)
|
||||
self.doc.Fuse.Refine = True
|
||||
self.doc.recompute()
|
||||
self.assertEqual(self.doc.Fuse.Shape.ElementMapSize, 38)
|
||||
self.assertEqual(fuse1.ElementMapSize, 58)
|
||||
# Shape is an extruded L, with 8 Faces, 12 Vertexes, 18 Edges
|
||||
# Assert Shape
|
||||
self.assertBounds(fuse1, App.BoundBox(0, 0, 0, 2, 2, 2))
|
||||
|
||||
def testAppPartmakeCompound(self):
|
||||
def testAppPartMakeCompound(self):
|
||||
# This doesn't do element maps.
|
||||
# compound1 = Part.Compound([self.doc.Box1.Shape, self.doc.Box2.Shape])
|
||||
# Act
|
||||
compound1 = Part.makeCompound([self.doc.Box1.Shape, self.doc.Box2.Shape])
|
||||
# Assert elementMap
|
||||
if compound1.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(compound1.ElementMapSize, 52)
|
||||
# Assert Shape
|
||||
self.assertBounds(compound1, App.BoundBox(0, 0, 0, 2, 2, 2))
|
||||
|
||||
def testAppPartmakeShell(self):
|
||||
def testAppPartMakeShell(self):
|
||||
# Act
|
||||
shell1 = Part.makeShell(self.doc.Box1.Shape.Faces)
|
||||
# Assert elementMap
|
||||
if shell1.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(shell1.ElementMapSize, 26)
|
||||
# Assert Shape
|
||||
self.assertBounds(shell1, App.BoundBox(0, 0, 0, 1, 2, 2))
|
||||
|
||||
def testAppPartmakeFace(self):
|
||||
face1 = Part.makeFace(self.doc.Box1.Shape.Faces[0],"Part::FaceMakerCheese")
|
||||
def testAppPartMakeFace(self):
|
||||
# Act
|
||||
face1 = Part.makeFace(self.doc.Box1.Shape.Faces[0], "Part::FaceMakerCheese")
|
||||
# Assert elementMap
|
||||
if face1.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(face1.ElementMapSize, 10)
|
||||
# Assert Shape
|
||||
self.assertBounds(face1, App.BoundBox(0, 0, 0, 0, 2, 2))
|
||||
|
||||
def testAppPartmakeFilledFace(self):
|
||||
face1 = Part.makeFilledFace(self.doc.Box1.Shape.Faces[3].Edges)
|
||||
# Assert elementMap
|
||||
if face1.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(face1.ElementMapSize, 9)
|
||||
# Assert Shape
|
||||
self.assertBounds(face1, App.BoundBox(-0.05, 2, -0.1, 1.05, 2, 2.1))
|
||||
|
||||
def testAppPartmakeSolid(self):
|
||||
def testAppPartMakeSolid(self):
|
||||
# Act
|
||||
solid1 = Part.makeSolid(self.doc.Box1.Shape.Shells[0])
|
||||
# Assert elementMap
|
||||
if solid1.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(solid1.ElementMapSize, 26)
|
||||
# Assert Shape
|
||||
self.assertBounds(solid1, App.BoundBox(0, 0, 0, 1, 2, 2))
|
||||
|
||||
def testAppPartmakeRuled(self):
|
||||
def testAppPartMakeRuled(self):
|
||||
# Act
|
||||
surface1 = Part.makeRuledSurface(*self.doc.Box1.Shape.Edges[3:5])
|
||||
# Assert elementMap
|
||||
if surface1.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(surface1.ElementMapSize, 9)
|
||||
# Assert Shape
|
||||
self.assertBounds(surface1, App.BoundBox(0, 0, 0, 1, 2, 2))
|
||||
|
||||
def testAppPartmakeShellFromWires(self):
|
||||
wire1 = self.doc.Box1.Shape.Wires[0] #.copy() Todo: prints double generated/modified warning because
|
||||
wire2 = self.doc.Box1.Shape.Wires[1] #.copy() Todo: copy() isn't TNP ready yet. Fix when it is.
|
||||
shell1 = Part.makeShellFromWires([wire1,wire2])
|
||||
def testAppPartMakeShellFromWires(self):
|
||||
# Arrange
|
||||
wire1 = self.doc.Box1.Shape.Wires[0] # .copy() Todo: prints 2 gen/mod warn because
|
||||
wire2 = self.doc.Box1.Shape.Wires[1] # Todo: copy() isn't TNP yet. Fix when it is.
|
||||
# Act
|
||||
shell1 = Part.makeShellFromWires([wire1, wire2])
|
||||
# Assert elementMap
|
||||
if shell1.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(shell1.ElementMapSize, 24)
|
||||
# Assert Shape
|
||||
self.assertBounds(shell1, App.BoundBox(0, 0, 0, 1, 2, 2))
|
||||
|
||||
def testAppPartmakeSweepSurface(self):
|
||||
pass # Todo: This is already fixed in a future commit
|
||||
# surface1 = Part.makeSweepSurface(*self.doc.Box1.Shape.Faces[3].Edges[0:2],1)
|
||||
# if surface1.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
# self.assertEqual(surface1.ElementMapSize, 7)
|
||||
def testAppPartMakeSweepSurface(self):
|
||||
# Arrange
|
||||
circle = Part.makeCircle(5, App.Vector(0, 0, 0))
|
||||
path = Part.makeLine(App.Vector(), App.Vector(0, 0, 10))
|
||||
Part.show(circle, "Circle") # Trigger the elementMapping
|
||||
Part.show(path, "Path") # Trigger the elementMapping
|
||||
# Act
|
||||
surface1 = Part.makeSweepSurface(self.doc.Path.Shape, self.doc.Circle.Shape, 0.001, 0)
|
||||
Part.show(surface1, "Sweep")
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
if surface1.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(surface1.ElementMapSize, 6)
|
||||
self.assertBounds(surface1, App.BoundBox(-5, -5, 0, 5, 5, 10))
|
||||
else:
|
||||
# Todo: WHY is the actual sweep different? That's BAD. However, the "New" approach
|
||||
# above, which uses BRepOffsetAPI_MakePipe appears to be correct over the older
|
||||
# code which uses Geom_Curve. This is done ostensibly because Geom_Curve is so
|
||||
# old that it doesn't even support history, which toponaming needs, but also,
|
||||
# the result is just wrong: If you look at the resulting shape after Sweeping
|
||||
# a circle along a line, you do not get a circular pipe: you get a circular
|
||||
# pipe with About a third of it removed. More specifically, an angle of
|
||||
# math.radians(math.degrees(360)%180) * 2 appears to have been applied, which
|
||||
# looks suspiciously like a substantial bug in OCCT.
|
||||
# Assert Shape
|
||||
self.assertBounds(surface1, App.BoundBox(-5, -2.72011, 0, 5, 5, 6.28319), precision=3)
|
||||
|
||||
def testAppPartmakeLoft(self):
|
||||
solid2 = Part.makeLoft(self.doc.Box1.Shape.Wires[0:2])
|
||||
if solid2.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(solid2.ElementMapSize, 24)
|
||||
def testAppPartMakeLoft(self):
|
||||
# Act
|
||||
solid1 = Part.makeLoft(self.doc.Box1.Shape.Wires[0:2])
|
||||
# Assert elementMap
|
||||
if solid1.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(solid1.ElementMapSize, 24)
|
||||
# Assert Shape
|
||||
self.assertBounds(solid1, App.BoundBox(0, 0, 0, 1, 2, 2))
|
||||
|
||||
def testAppPartmakeSplitShape(self):
|
||||
# Todo: Refine this test after all TNP code in place to elimate warnings.
|
||||
edge1 = self.doc.Box1.Shape.Faces[0].Edges[0].translated(App.Vector(0,0.5,0))
|
||||
def testAppPartMakeSplitShape(self):
|
||||
# Todo: Refine this test after all TNP code in place to eliminate warnings.
|
||||
# Arrange
|
||||
edge1 = self.doc.Box1.Shape.Faces[0].Edges[0].translated(App.Vector(0, 0.5, 0))
|
||||
face1 = self.doc.Box1.Shape.Faces[0]
|
||||
solids1 = Part.makeSplitShape(face1,[(edge1,face1)])
|
||||
# Act
|
||||
solids1 = Part.makeSplitShape(face1, [(edge1, face1)])
|
||||
# Assert elementMap
|
||||
self.assertEqual(len(solids1), 2)
|
||||
self.assertEqual(len(solids1[0]), 1)
|
||||
if solids1[0][0].ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(solids1[0][0].ElementMapSize, 9)
|
||||
self.assertEqual(solids1[1][0].ElementMapSize, 9)
|
||||
# Assert Shape
|
||||
self.assertBounds(solids1[0][0], App.BoundBox(0, 0.5, 0, 0, 2, 2))
|
||||
self.assertBounds(solids1[1][0], App.BoundBox(0, 0.5, 0, 0, 2, 2))
|
||||
|
||||
def testTopoShapePyInit(self):
|
||||
# Arrange
|
||||
self.doc.addObject("Part::Compound", "Compound")
|
||||
self.doc.Compound.Links = [
|
||||
App.activeDocument().Box1,
|
||||
App.activeDocument().Box2,
|
||||
]
|
||||
self.doc.recompute()
|
||||
compound = self.doc.Compound.Shape
|
||||
# Act
|
||||
new_toposhape = Part.Shape(compound)
|
||||
new_empty_toposhape = Part.Shape()
|
||||
# Assert elementMap
|
||||
if compound.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(compound.ElementMapSize, 52)
|
||||
self.assertEqual(new_toposhape.ElementMapSize, 52)
|
||||
|
||||
def testTopoShapeCopy(self):
|
||||
# Arrange
|
||||
self.doc.addObject("Part::Compound", "Compound")
|
||||
self.doc.Compound.Links = [
|
||||
App.activeDocument().Box1,
|
||||
App.activeDocument().Box2,
|
||||
]
|
||||
self.doc.recompute()
|
||||
compound = self.doc.Compound.Shape
|
||||
# Act
|
||||
compound_copy = compound.copy()
|
||||
# Assert elementMap
|
||||
if compound.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(compound.ElementMapSize, 52)
|
||||
self.assertEqual(compound_copy.ElementMapSize, 52)
|
||||
|
||||
def testTopoShapeCleaned(self):
|
||||
# Arrange
|
||||
self.doc.addObject("Part::Compound", "Compound")
|
||||
self.doc.Compound.Links = [
|
||||
App.activeDocument().Box1,
|
||||
App.activeDocument().Box2,
|
||||
]
|
||||
self.doc.recompute()
|
||||
compound = self.doc.Compound.Shape
|
||||
# Act
|
||||
compound_cleaned = compound.cleaned()
|
||||
# Assert elementMap
|
||||
if compound.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(compound.ElementMapSize, 52)
|
||||
self.assertEqual(compound_cleaned.ElementMapSize, 52)
|
||||
|
||||
def testTopoShapeReplaceShape(self):
|
||||
# Arrange
|
||||
self.doc.addObject("Part::Compound", "Compound")
|
||||
self.doc.Compound.Links = [
|
||||
App.activeDocument().Box1,
|
||||
App.activeDocument().Box2,
|
||||
]
|
||||
self.doc.recompute()
|
||||
compound = self.doc.Compound.Shape
|
||||
# Act
|
||||
compound_replaced = compound.replaceShape([(App.activeDocument().Box2.Shape,
|
||||
App.activeDocument().Box1.Shape)])
|
||||
# Assert elementMap
|
||||
if compound.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(compound.ElementMapSize, 52)
|
||||
self.assertEqual(compound_replaced.ElementMapSize, 52)
|
||||
|
||||
def testTopoShapeRemoveShape(self):
|
||||
# Arrange
|
||||
self.doc.addObject("Part::Compound", "Compound")
|
||||
self.doc.Compound.Links = [
|
||||
App.activeDocument().Box1,
|
||||
App.activeDocument().Box2,
|
||||
]
|
||||
self.doc.recompute()
|
||||
compound = self.doc.Compound.Shape
|
||||
# Act
|
||||
compound_removed = compound.removeShape([App.ActiveDocument.Box2.Shape])
|
||||
# Assert elementMap
|
||||
if compound.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(compound.ElementMapSize, 52)
|
||||
self.assertEqual(compound_removed.ElementMapSize, 52)
|
||||
|
||||
def testTopoShapeExtrude(self):
|
||||
# Arrange
|
||||
face = self.doc.Box1.Shape.Faces[0]
|
||||
# Act
|
||||
extrude = face.extrude(App.Vector(2, 0, 0))
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
if extrude.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(extrude.ElementMapSize, 26)
|
||||
|
||||
def testTopoShapeRevolve(self):
|
||||
# Arrange
|
||||
face = self.doc.Box1.Shape.Faces[0]
|
||||
# Act
|
||||
face.revolve(App.Vector(), App.Vector(1, 0, 0), 45)
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
if face.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(face.ElementMapSize, 9)
|
||||
|
||||
def testTopoShapeFuse(self):
|
||||
# Act
|
||||
fused = self.doc.Box1.Shape.fuse(self.doc.Box2.Shape)
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
if fused.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(fused.ElementMapSize, 58)
|
||||
|
||||
def testTopoShapeMultiFuse(self):
|
||||
# Act
|
||||
fused = self.doc.Box1.Shape.multiFuse([self.doc.Box2.Shape])
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
if fused.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(fused.ElementMapSize, 58)
|
||||
|
||||
def testTopoShapeCommon(self):
|
||||
# Act
|
||||
common = self.doc.Box1.Shape.common(self.doc.Box2.Shape)
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
if common.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(common.ElementMapSize, 26)
|
||||
|
||||
def testTopoShapeSection(self):
|
||||
# Act
|
||||
section = self.doc.Box1.Shape.Faces[0].section(self.doc.Box2.Shape.Faces[3])
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
if section.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(section.ElementMapSize, 3)
|
||||
|
||||
def testTopoShapeSlice(self):
|
||||
# Act
|
||||
slice = self.doc.Box1.Shape.slice(App.Vector(10, 10, 0), 1)
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
self.assertEqual(len(slice), 1)
|
||||
if slice[0].ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(slice[0].ElementMapSize, 8)
|
||||
|
||||
def testTopoShapeSlices(self):
|
||||
# Act
|
||||
slices = self.doc.Box1.Shape.Faces[0].slices(App.Vector(10, 10, 0), [1, 2])
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
if slices.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(slices.ElementMapSize, 6)
|
||||
|
||||
def testTopoShapeCut(self):
|
||||
# Act
|
||||
cut = self.doc.Box1.Shape.cut(self.doc.Box2.Shape)
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
if cut.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(cut.ElementMapSize, 26)
|
||||
|
||||
def testTopoShapeGeneralFuse(self):
|
||||
# Act
|
||||
fuse = self.doc.Box1.Shape.generalFuse([self.doc.Box2.Shape])
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
self.assertEqual(len(fuse), 2)
|
||||
if fuse[0].ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(fuse[0].ElementMapSize, 60)
|
||||
|
||||
def testTopoShapeChildShapes(self):
|
||||
# Act
|
||||
childShapes = self.doc.Box1.Shape.childShapes()
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
self.assertEqual(len(childShapes), 1)
|
||||
if childShapes[0].ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(childShapes[0].ElementMapSize, 26)
|
||||
|
||||
def testTopoShapeMirror(self):
|
||||
# Act
|
||||
mirror = self.doc.Box1.Shape.mirror(App.Vector(), App.Vector(1, 0, 0))
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
if mirror.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(mirror.ElementMapSize, 26)
|
||||
|
||||
def testTopoShapeScale(self):
|
||||
# Act
|
||||
scale = self.doc.Box1.Shape.scaled(2)
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
if scale.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(scale.ElementMapSize, 26)
|
||||
|
||||
def testTopoShapeMakeFillet(self):
|
||||
# Act
|
||||
fillet = self.doc.Box1.Shape.makeFillet(0.1, self.doc.Box1.Shape.Faces[0].Edges)
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
if fillet.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(fillet.ElementMapSize, 42)
|
||||
|
||||
def testTopoShapeMakeChamfer(self):
|
||||
# Act
|
||||
chamfer = self.doc.Box1.Shape.makeChamfer(0.1, self.doc.Box1.Shape.Faces[0].Edges)
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
if chamfer.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(chamfer.ElementMapSize, 42)
|
||||
|
||||
def testTopoShapeMakeThickness(self):
|
||||
# Act
|
||||
thickness = self.doc.Box1.Shape.makeThickness(self.doc.Box1.Shape.Faces[0:2], 0.1, 0.0001)
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
if thickness.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(thickness.ElementMapSize, 74)
|
||||
|
||||
def testTopoShapeMakeOffsetShape(self):
|
||||
# Act
|
||||
offset = self.doc.Box1.Shape.Faces[0].makeOffset(1)
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
if offset.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(offset.ElementMapSize, 17)
|
||||
|
||||
def testTopoShapeOffset2D(self):
|
||||
# Act
|
||||
offset = self.doc.Box1.Shape.Faces[0].makeOffset2D(1)
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
if offset.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(offset.ElementMapSize, 17)
|
||||
|
||||
def testTopoShapeRemoveSplitter(self):
|
||||
# Act
|
||||
fused = self.doc.Box1.Shape.fuse(self.doc.Box2.Shape)
|
||||
removed = fused.removeSplitter()
|
||||
self.doc.recompute()
|
||||
# Assert elementMap
|
||||
if removed.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(removed.ElementMapSize, 38)
|
||||
|
||||
def testTopoShapeCompSolid(self):
|
||||
# Act
|
||||
compSolid = Part.CompSolid([self.doc.Box1.Shape, self.doc.Box2.Shape]) # list of subobjects
|
||||
box1ts = self.doc.Box1.Shape
|
||||
compSolid.add(box1ts.Solids[0])
|
||||
# Assert elementMap
|
||||
if compSolid.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(compSolid.ElementMapSize, 78)
|
||||
|
||||
def testTopoShapeFaceOffset(self):
|
||||
# Arrange
|
||||
box_toposhape = self.doc.Box1.Shape
|
||||
# Act
|
||||
offset = box_toposhape.Faces[0].makeOffset(2.0)
|
||||
# Assert elementMap
|
||||
if box_toposhape.Faces[0].ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(box_toposhape.Faces[0].ElementMapSize, 9) # 1 Face, 4 Edges, 4 Vertexes
|
||||
self.assertEqual(offset.ElementMapSize, 17) # 1 Face, 8 Edges, 8 Vertexes
|
||||
|
||||
# Todo: makeEvolved doesn't work right, probably due to missing c++ code.
|
||||
# def testTopoShapeFaceEvolve(self):
|
||||
# # Arrange
|
||||
# box_toposhape = self.doc.Box1.Shape
|
||||
# # Act
|
||||
# evolved = box_toposhape.Faces[0].makeEvolved(self.doc.Box1.Shape.Wires[1]) # 2,3,4,5 bad
|
||||
# # Assert elementMap
|
||||
# if box_toposhape.Faces[0].ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
# self.assertEqual(box_toposhape.Faces[0].ElementMapSize, 9) # 1 Face, 4 Edges, 4 Vertexes
|
||||
# self.assertEqual(evolved.ElementMapSize, 0) # Todo: This can't be correct.
|
||||
|
||||
def testTopoShapePart(self):
|
||||
# Arrange
|
||||
box1ts = self.doc.Box1.Shape
|
||||
face1 = box1ts.Faces[0]
|
||||
box1ts2 = box1ts.copy()
|
||||
# Act
|
||||
face2 = box1ts.getElement("Face2")
|
||||
indexed_name = box1ts.findSubShape(face1)
|
||||
faces1 = box1ts.findSubShapesWithSharedVertex(face2)
|
||||
subshapes1 = box1ts.getChildShapes("Solid1")
|
||||
# box1ts.clearCache() # Todo: no apparent way to see a result at this level
|
||||
# Assert
|
||||
self.assertTrue(face2.isSame(box1ts.Faces[1]))
|
||||
self.assertEqual(indexed_name[0], "Face")
|
||||
self.assertEqual(indexed_name[1], 1)
|
||||
self.assertEqual(len(faces1), 1)
|
||||
self.assertTrue(faces1[0].isSame(box1ts.Faces[1]))
|
||||
self.assertEqual(len(subshapes1), 1)
|
||||
self.assertTrue(subshapes1[0].isSame(box1ts.Solids[0]))
|
||||
|
||||
def testTopoShapeMapSubElement(self):
|
||||
# Arrange
|
||||
box = Part.makeBox(1,2,3)
|
||||
# face = box.Faces[0] # Do not do this. Need the subelement call each usage.
|
||||
# Assert everything empty
|
||||
self.assertEqual(box.ElementMapSize,0)
|
||||
self.assertEqual(box.Faces[0].ElementMapSize,0)
|
||||
# Act
|
||||
box.mapSubElement(box.Faces[0])
|
||||
# Assert elementMaps created
|
||||
if box.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
self.assertEqual(box.ElementMapSize,9) # 1 Face, 4 Edges, 4 Vertexes
|
||||
self.assertEqual(box.Faces[0].ElementMapSize,9)
|
||||
|
||||
def testTopoShapeGetElementHistory(self):
|
||||
self.doc.addObject("Part::Fuse", "Fuse")
|
||||
self.doc.Fuse.Base = self.doc.Box1
|
||||
self.doc.Fuse.Tool = self.doc.Box2
|
||||
# Act
|
||||
self.doc.recompute()
|
||||
fuse1 = self.doc.Fuse.Shape
|
||||
if fuse1.ElementMapVersion != "": # Should be '4' as of Mar 2023.
|
||||
history1 = fuse1.getElementHistory(fuse1.ElementReverseMap["Vertex1"])
|
||||
# Assert
|
||||
self.assertEqual(len(history1),3) # Just the Fuse operation
|
||||
|
||||
# Todo: Still broken, still can't find parms that consistently work to test this.
|
||||
# However, the results with an empty elementMap are consistent with making the
|
||||
# same calls on LS3. So what this method is supposed to do remains a mystery;
|
||||
# So far, it just wipes out the elementMap and returns the Toposhape.
|
||||
# def testTopoShapeMapShapes(self):
|
||||
# self.doc.addObject("Part::Fuse", "Fuse")
|
||||
# self.doc.Fuse.Base = self.doc.Box1
|
||||
# self.doc.Fuse.Tool = self.doc.Box2
|
||||
# # Act
|
||||
# self.doc.recompute()
|
||||
# fuse1 = self.doc.Fuse.Shape
|
||||
# res = fuse1.copy() # Make it mutable
|
||||
# self.assertEqual(res.ElementMapSize,58)
|
||||
# result = res.mapShapes([(fuse1, fuse1.Faces[0])], []) #[(res, res.Vertexes[0])])
|
||||
# self.assertEqual(res.ElementMapSize,9)
|
||||
# # result2 = fuse1.copy().mapShapes([],[(fuse1, fuse1.Edges[0]),(fuse1, fuse1.Edges[1])])
|
||||
# self.assertEqual(fuse1.ElementMapSize,58) #
|
||||
# self.assertEqual(fuse1.Faces[0].ElementMapSize,9)
|
||||
# self.assertEqual(result.ElementMapSize,9)
|
||||
# self.assertEqual(result.Faces[0].ElementMapSize,0)
|
||||
# self.assertEqual(result2.ElementMapSize,9)
|
||||
# self.assertEqual(result2.Faces[0].ElementMapSize,0)
|
||||
|
||||
# TODO: Consider the following possible test objects:
|
||||
# Part::AttachExtension ::init();
|
||||
# Part::AttachExtensionPython ::init();
|
||||
# Part::PrismExtension ::init();
|
||||
# Part::Feature ::init();
|
||||
# Part::FeatureExt ::init();
|
||||
# Part::BodyBase ::init();
|
||||
# Part::FeaturePython ::init();
|
||||
# Part::FeatureGeometrySet ::init();
|
||||
# Part::CustomFeature ::init();
|
||||
# Part::CustomFeaturePython ::init();
|
||||
# Part::Boolean ::init();
|
||||
# Part::Common ::init();
|
||||
# Part::MultiCommon ::init();
|
||||
# Part::Cut ::init();
|
||||
# Part::Fuse ::init();
|
||||
# Part::MultiFuse ::init();
|
||||
# Part::Section ::init();
|
||||
# Part::FilletBase ::init();
|
||||
# Part::Fillet ::init();
|
||||
# Part::Chamfer ::init();
|
||||
# Part::Compound ::init();
|
||||
# Part::Compound2 ::init();
|
||||
# Part::Extrusion ::init();
|
||||
# Part::Scale ::init();
|
||||
# Part::Revolution ::init();
|
||||
# Part::Mirroring ::init();
|
||||
# TopoShape calls to be consider testing
|
||||
# 'add',
|
||||
# 'ancestorsOfType',
|
||||
# 'applyRotation',
|
||||
# 'applyTranslation',
|
||||
# 'check',
|
||||
# 'childShapes',
|
||||
# 'cleaned',
|
||||
# 'common',
|
||||
# 'complement',
|
||||
# 'connectEdgesToWires',
|
||||
# 'copy',
|
||||
# 'countElement',
|
||||
# 'countSubElements',
|
||||
# 'cut',
|
||||
# 'defeaturing',
|
||||
# 'distToShape',
|
||||
# 'dumpContent',
|
||||
# 'dumpToString',
|
||||
# 'dumps',
|
||||
# 'exportBinary',
|
||||
# 'exportBrep',
|
||||
# 'exportBrepToString',
|
||||
# 'exportIges',
|
||||
# 'exportStep',
|
||||
# 'exportStl',
|
||||
# 'extrude',
|
||||
# 'findPlane',
|
||||
# 'fix',
|
||||
# 'fixTolerance',
|
||||
# 'fuse',
|
||||
# 'generalFuse',
|
||||
# 'getAllDerivedFrom',
|
||||
# 'getElement',
|
||||
# 'getElementTypes',
|
||||
# 'getFaces',
|
||||
# 'getFacesFromSubElement',
|
||||
# 'getLines',
|
||||
# 'getLinesFromSubElement',
|
||||
# 'getPoints',
|
||||
# 'getTolerance',
|
||||
# 'globalTolerance',
|
||||
# 'hashCode',
|
||||
# 'importBinary',
|
||||
# 'importBrep',
|
||||
# 'importBrepFromString',
|
||||
# 'inTolerance',
|
||||
# 'isClosed',
|
||||
# 'isCoplanar',
|
||||
# 'isDerivedFrom',
|
||||
# 'isEqual',
|
||||
# 'isInfinite',
|
||||
# 'isInside',
|
||||
# 'isNull',
|
||||
# 'isPartner',
|
||||
# 'isSame',
|
||||
# 'isValid',
|
||||
# 'limitTolerance',
|
||||
# 'loads',
|
||||
# 'makeChamfer',
|
||||
# 'makeFillet',
|
||||
# 'makeOffset2D',
|
||||
# 'makeOffsetShape',
|
||||
# 'makeParallelProjection',
|
||||
# 'makePerspectiveProjection',
|
||||
# 'makeShapeFromMesh',
|
||||
# 'makeThickness',
|
||||
# 'makeWires',
|
||||
# 'mirror',
|
||||
# 'multiFuse',
|
||||
# 'nullify',
|
||||
# 'oldFuse',
|
||||
# 'optimalBoundingBox',
|
||||
# 'overTolerance',
|
||||
# 'project',
|
||||
# 'proximity',
|
||||
# 'read',
|
||||
# 'reflectLines',
|
||||
# 'removeInternalWires',
|
||||
# 'removeShape',
|
||||
# 'removeSplitter',
|
||||
# 'replaceShape',
|
||||
# 'restoreContent',
|
||||
# 'reverse',
|
||||
# 'reversed',
|
||||
# 'revolve',
|
||||
# 'rotate',
|
||||
# 'rotated',
|
||||
# 'scale',
|
||||
# 'scaled',
|
||||
# 'section',
|
||||
# 'setFaces',
|
||||
# 'sewShape',
|
||||
# 'slice',
|
||||
# 'slices',
|
||||
# 'tessellate',
|
||||
# 'toNurbs',
|
||||
# 'transformGeometry',
|
||||
# 'transformShape',
|
||||
# 'transformed',
|
||||
# 'translate',
|
||||
# 'translated',
|
||||
# 'writeInventor'
|
||||
|
||||
Reference in New Issue
Block a user