diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index eb09dac82c..92bd1030bb 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -122,26 +122,35 @@ extern const char* BRepBuilderAPI_FaceErrorText(BRepBuilderAPI_FaceError fe); namespace Part { -PartExport void getPyShapes(PyObject *obj, std::vector &shapes) { - if(!obj) +PartExport void getPyShapes(PyObject* obj, std::vector& shapes) +{ + if (!obj) { return; - if(PyObject_TypeCheck(obj,&Part::TopoShapePy::Type)) + } + if (PyObject_TypeCheck(obj, &Part::TopoShapePy::Type)) { shapes.push_back(*static_cast(obj)->getTopoShapePtr()); - else if (PyObject_TypeCheck(obj, &GeometryPy::Type)) + } + else if (PyObject_TypeCheck(obj, &GeometryPy::Type)) { shapes.emplace_back(static_cast(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((*it).ptr())->getTopoShapePtr()); - else if (PyObject_TypeCheck((*it).ptr(), &GeometryPy::Type)) - shapes.emplace_back(static_cast( - (*it).ptr())->getGeometryPtr()->toShape()); - else + } + else if (PyObject_TypeCheck((*it).ptr(), &GeometryPy::Type)) { + shapes.emplace_back( + static_cast((*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 getPyShapes(PyObject *obj) { diff --git a/src/Mod/Part/App/TopoShapePy.xml b/src/Mod/Part/App/TopoShapePy.xml index ac9485ba69..1cb893963f 100644 --- a/src/Mod/Part/App/TopoShapePy.xml +++ b/src/Mod/Part/App/TopoShapePy.xml @@ -965,10 +965,10 @@ optimalBoundingBox([useTriangulation = True, useShapeTolerance = False]) -> boun - + - searchSubShape(shape, needName=False, checkGeometry=True, tol=1e-7, atol=1e-12) -> Shape + findSubShapesWithSharedVertex(shape, needName=False, checkGeometry=True, tol=1e-7, atol=1e-12) -> Shape shape: input elementary shape, currently only support Face, Edge, or Vertex diff --git a/src/Mod/Part/App/TopoShapePyImp.cpp b/src/Mod/Part/App/TopoShapePyImp.cpp index 33055c4fdf..d5b74af4da 100644 --- a/src/Mod/Part/App/TopoShapePyImp.cpp +++ b/src/Mod/Part/App/TopoShapePyImp.cpp @@ -109,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(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(self)->getTopoShapePtr()->getShape().HashCode(INT_MAX); } -struct TopoShapePyInit { - TopoShapePyInit() { +struct TopoShapePyInit +{ + TopoShapePyInit() + { TopoShapePy::Type.tp_hash = _TopoShapeHash; } } _TopoShapePyInit; @@ -193,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; @@ -238,22 +245,33 @@ 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)) { + 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)) + if (!PyArg_ParseTuple(args, "|O!O!", &PyBool_Type, ©Geom, &PyBool_Type, ©Mesh)) { return 0; + } + } + if (op && !op[0]) { + op = nullptr; } - if(op && !op[0]) op = nullptr; App::StringHasherRef hasher; - if(pyHasher) + if (pyHasher) { hasher = static_cast(pyHasher)->getStringHasherPtr(); - auto &self = *getTopoShapePtr(); + } + auto& self = *getTopoShapePtr(); return Py::new_reference_to(shape2pyshape( - TopoShape(self.Tag,hasher).makeElementCopy( - self,op,PyObject_IsTrue(copyGeom),PyObject_IsTrue(copyMesh)))); + 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; @@ -282,10 +300,11 @@ PyObject* TopoShapePy::cleaned(PyObject *args) if (!PyArg_ParseTuple(args, "")) return nullptr; #ifdef FC_USE_TNP_FIX - auto &self = *getTopoShapePtr(); + auto& self = *getTopoShapePtr(); TopoShape copy(self.makeElementCopy()); - if (!copy.isNull()) - BRepTools::Clean(copy.getShape()); // remove triangulation + if (!copy.isNull()) { + BRepTools::Clean(copy.getShape()); // remove triangulation + } return Py::new_reference_to(shape2pyshape(copy)); #else @@ -319,15 +338,13 @@ PyObject* TopoShapePy::replaceShape(PyObject *args) try { #ifdef FC_USE_TNP_FIX Py::Sequence list(l); - std::vector< std::pair > shapes; + std::vector> 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()) - ); + shapes.push_back(std::make_pair(*sh1.extensionObject()->getTopoShapePtr(), + *sh2.extensionObject()->getTopoShapePtr())); } return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->replaceElementShape(shapes))); #else @@ -366,7 +383,8 @@ PyObject* TopoShapePy::removeShape(PyObject *args) try { #ifdef FC_USE_TNP_FIX - return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->removeElementShape(getPyShapes(l)))); + return Py::new_reference_to( + shape2pyshape(getTopoShapePtr()->removeElementShape(getPyShapes(l)))); #else Py::Sequence list(l); std::vector shapes; @@ -729,7 +747,8 @@ PyObject* TopoShapePy::extrude(PyObject *args) try { Base::Vector3d vec = static_cast(pVec)->value(); #ifdef FC_USE_TNP_FIX - return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementPrism(gp_Vec(vec.x,vec.y,vec.z)))); + 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(); @@ -777,7 +796,8 @@ PyObject* TopoShapePy::revolve(PyObject *args) 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)))); + 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()) { @@ -851,6 +871,7 @@ 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; @@ -863,11 +884,12 @@ static PyObject *makeShape(const char *op,const TopoShape &shape, PyObject *args 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); + return makeShape(Part::OpCodes::Fuse, *getTopoShapePtr(), args); #else PyObject *pcObj; if (PyArg_ParseTuple(args, "O!", &(TopoShapePy::Type), &pcObj)) { @@ -944,7 +966,7 @@ PyObject* TopoShapePy::fuse(PyObject *args) PyObject* TopoShapePy::multiFuse(PyObject *args) { #ifdef FC_USE_TNP_FIX - return makeShape(Part::OpCodes::Fuse,*getTopoShapePtr(),args); + return makeShape(Part::OpCodes::Fuse, *getTopoShapePtr(), args); #else double tolerance = 0.0; PyObject *pcObj; @@ -1003,7 +1025,7 @@ PyObject* TopoShapePy::oldFuse(PyObject *args) PyObject* TopoShapePy::common(PyObject *args) { #ifdef FC_USE_TNP_FIX - return makeShape(Part::OpCodes::Common,*getTopoShapePtr(),args); + return makeShape(Part::OpCodes::Common, *getTopoShapePtr(), args); #else PyObject *pcObj; if (PyArg_ParseTuple(args, "O!", &(TopoShapePy::Type), &pcObj)) { @@ -1078,7 +1100,7 @@ PyObject* TopoShapePy::common(PyObject *args) PyObject* TopoShapePy::section(PyObject *args) { #ifdef FC_USE_TNP_FIX - return makeShape(Part::OpCodes::Section,*getTopoShapePtr(),args); + return makeShape(Part::OpCodes::Section, *getTopoShapePtr(), args); #else PyObject *pcObj; PyObject *approx = Py_False; @@ -1163,8 +1185,9 @@ PyObject* TopoShapePy::slice(PyObject *args) try { #ifdef FC_USE_TNP_FIX Py::List wires; - for(auto &w : getTopoShapePtr()->makeElementSlice(vec,d).getSubTopoShapes(TopAbs_WIRE)) + for (auto& w : getTopoShapePtr()->makeElementSlice(vec, d).getSubTopoShapes(TopAbs_WIRE)) { wires.append(shape2pyshape(w)); + } return Py::new_reference_to(wires); #else std::list slice = this->getTopoShapePtr()->slice(vec, d); @@ -1200,8 +1223,8 @@ 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)); -#if !defined(FC_NO_ELEMENT_MAP) - return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementSlices(vec,d))); +#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)); @@ -1220,7 +1243,7 @@ PyObject* TopoShapePy::slices(PyObject *args) PyObject* TopoShapePy::cut(PyObject *args) { #ifdef FC_USE_TNP_FIX - return makeShape(Part::OpCodes::Cut,*getTopoShapePtr(),args); + return makeShape(Part::OpCodes::Cut, *getTopoShapePtr(), args); #else PyObject *pcObj; if (PyArg_ParseTuple(args, "O!", &(TopoShapePy::Type), &pcObj)) { @@ -1300,25 +1323,27 @@ PyObject* TopoShapePy::generalFuse(PyObject *args) return nullptr; #ifdef FC_USE_TNP_FIX - std::vector > modifies; + std::vector> modifies; std::vector shapes; shapes.push_back(*getTopoShapePtr()); try { - getPyShapes(pcObj,shapes); + getPyShapes(pcObj, shapes); TopoShape res; - res.makeElementGeneralFuse(shapes,modifies,tolerance); + res.makeElementGeneralFuse(shapes, modifies, tolerance); Py::List mapPy; - for(auto &mod : modifies){ + for (auto& mod : modifies) { Py::List shapesPy; - for(auto &sh : mod) + 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 + } + PY_CATCH_OCC #else std::vector shapeVec; Py::Sequence shapeSeq(pcObj); @@ -1385,16 +1410,21 @@ PyObject* TopoShapePy::childShapes(PyObject *args) #ifdef FC_USE_TNP_FIX TopoShape shape = *getTopoShapePtr(); - if(!PyObject_IsTrue(cumOri)) + if (!PyObject_IsTrue(cumOri)) { shape.setShape(shape.getShape().Oriented(TopAbs_FORWARD), false); - if (!PyObject_IsTrue(cumLoc)) + } + if (!PyObject_IsTrue(cumLoc)) { shape.setShape(shape.getShape().Located(TopLoc_Location()), false); + } Py::List list; - PY_TRY { - for(auto &s : shape.getSubTopoShapes()) + PY_TRY + { + for (auto& s : shape.getSubTopoShapes()) { list.append(shape2pyshape(s)); + } return Py::new_reference_to(list); - } PY_CATCH_OCC + } + PY_CATCH_OCC #else try { const TopoDS_Shape& shape = getTopoShapePtr()->getShape(); @@ -1717,7 +1747,7 @@ PyObject* TopoShapePy::scale(PyObject *args) BRepScale.Perform(shape, bCopy); #ifdef FC_USE_TNP_FIX TopoShape copy(*getTopoShapePtr()); - getTopoShapePtr()->makeElementShape(BRepScale,copy); + getTopoShapePtr()->makeElementShape(BRepScale, copy); #else getTopoShapePtr()->setShape(BRepScale.Shape()); #endif @@ -1754,17 +1784,20 @@ PyObject* TopoShapePy::makeFillet(PyObject *args) 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"); + 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 + 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 { @@ -1827,18 +1860,21 @@ PyObject* TopoShapePy::makeChamfer(PyObject *args) #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"); + 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 + 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)) { @@ -1916,10 +1952,15 @@ PyObject* TopoShapePy::makeThickness(PyObject *args) return nullptr; try { -#ifndef FC_NO_ELEMENT_MAP - 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(join)))); +#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(join)))); #else TopTools_ListOfShape facesToRemove; Py::Sequence list(obj); @@ -1959,8 +2000,12 @@ 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(join), + offset, + tolerance, + PyObject_IsTrue(inter) ? true : false, + PyObject_IsTrue(self_inter) ? true : false, + offsetMode, + static_cast(join), PyObject_IsTrue(fill) ? FillType::fill : FillType::noFill))); #else TopoDS_Shape shape = this->getTopoShapePtr()->makeOffsetShape(offset, tolerance, @@ -1993,7 +2038,9 @@ PyObject* TopoShapePy::makeOffset2D(PyObject *args, PyObject *keywds) try { #ifdef FC_USE_TNP_FIX return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makeElementOffset2D( - offset, static_cast(join), PyObject_IsTrue(fill) ? FillType::fill : FillType::noFill, + offset, + static_cast(join), + PyObject_IsTrue(fill) ? FillType::fill : FillType::noFill, PyObject_IsTrue(openResult) ? OpenResult::allowOpenResult : OpenResult::noOpenResult, PyObject_IsTrue(inter) ? true : false))); #else @@ -3065,7 +3112,7 @@ PyObject* TopoShapePy::findSubShape(PyObject* args) PY_CATCH_OCC } -PyObject* TopoShapePy::searchSubShape(PyObject* args, PyObject* keywds) +PyObject* TopoShapePy::findSubShapesWithSharedVertex(PyObject* args, PyObject* keywds) { static char* kwlist[] = {"shape", "needName", "checkGeometry", "tol", "atol", nullptr}; PyObject* pyobj; diff --git a/src/Mod/Part/App/TopoShapeShellPyImp.cpp b/src/Mod/Part/App/TopoShapeShellPyImp.cpp index b15f27048e..7e7e9a6e6d 100644 --- a/src/Mod/Part/App/TopoShapeShellPyImp.cpp +++ b/src/Mod/Part/App/TopoShapeShellPyImp.cpp @@ -88,8 +88,9 @@ int TopoShapeShellPy::PyInit(PyObject* args, PyObject* /*kwd*/) #ifdef FC_USE_TNP_FIX try { - getTopoShapePtr()->makeElementBoolean(Part::OpCodes::Shell,getPyShapes(obj)); - } _PY_CATCH_OCC(return(-1)) + getTopoShapePtr()->makeElementBoolean(Part::OpCodes::Shell, getPyShapes(obj)); + } + _PY_CATCH_OCC(return (-1)) #else BRep_Builder builder; TopoDS_Shape shape; diff --git a/src/Mod/Part/App/TopoShapeSolidPyImp.cpp b/src/Mod/Part/App/TopoShapeSolidPyImp.cpp index f81efe8f2b..160316945c 100644 --- a/src/Mod/Part/App/TopoShapeSolidPyImp.cpp +++ b/src/Mod/Part/App/TopoShapeSolidPyImp.cpp @@ -327,7 +327,7 @@ PyObject* TopoShapeSolidPy::offsetFaces(PyObject *args) try { builder.MakeOffsetShape(); const TopoDS_Shape& offsetshape = builder.Shape(); -#ifndef FC_USE_TNP_FIX +#ifdef FC_USE_TNP_FIX TopoShape res; res.setShape(offsetshape); return Py::new_reference_to(shape2pyshape(res)); diff --git a/src/Mod/Part/parttests/TopoShapeTest.py b/src/Mod/Part/parttests/TopoShapeTest.py index 596373cd55..8fc2150ea0 100644 --- a/src/Mod/Part/parttests/TopoShapeTest.py +++ b/src/Mod/Part/parttests/TopoShapeTest.py @@ -3,6 +3,7 @@ import Part import unittest + class TopoShapeAssertions: def assertAttrEqual(self, toposhape, attr_value_list, msg=None): @@ -43,17 +44,18 @@ class TopoShapeAssertions: 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): + 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); + 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""" @@ -174,18 +176,20 @@ class TopoShapeTest(unittest.TestCase, TopoShapeAssertions): self.doc.recompute() compound2 = self.doc.Compound.Shape # Assert elementMap - # This is a flag value to indicate that ElementMaps are supported under the current C++ build: + # 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) ) + self.assertBounds(compound2, App.BoundBox(0, 0, 0, 2, 2, 2)) def testPartCommon(self): # Arrange @@ -197,37 +201,37 @@ class TopoShapeTest(unittest.TestCase, TopoShapeAssertions): # 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", - ], - ) + [ + "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) ) + self.assertBounds(common1, App.BoundBox(0, 0, 0, 1, 1, 2)) def testPartCut(self): # Arrange @@ -240,37 +244,37 @@ class TopoShapeTest(unittest.TestCase, TopoShapeAssertions): # 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", - ], - ) + [ + "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) ) + self.assertBounds(cut1, App.BoundBox(0, 1, 0, 1, 2, 2)) def testPartFuse(self): # Arrange @@ -288,7 +292,7 @@ class TopoShapeTest(unittest.TestCase, TopoShapeAssertions): 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) ) + self.assertBounds(fuse1, App.BoundBox(0, 0, 0, 2, 2, 2)) def testAppPartMakeCompound(self): # This doesn't do element maps. @@ -299,7 +303,7 @@ class TopoShapeTest(unittest.TestCase, TopoShapeAssertions): 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) ) + self.assertBounds(compound1, App.BoundBox(0, 0, 0, 2, 2, 2)) def testAppPartMakeShell(self): # Act @@ -308,16 +312,16 @@ class TopoShapeTest(unittest.TestCase, TopoShapeAssertions): 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) ) + self.assertBounds(shell1, App.BoundBox(0, 0, 0, 1, 2, 2)) def testAppPartMakeFace(self): # Act - face1 = Part.makeFace(self.doc.Box1.Shape.Faces[0],"Part::FaceMakerCheese") + 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) ) + self.assertBounds(face1, App.BoundBox(0, 0, 0, 0, 2, 2)) def testAppPartmakeFilledFace(self): face1 = Part.makeFilledFace(self.doc.Box1.Shape.Faces[3].Edges) @@ -325,7 +329,7 @@ class TopoShapeTest(unittest.TestCase, TopoShapeAssertions): 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) ) + self.assertBounds(face1, App.BoundBox(-0.05, 2, -0.1, 1.05, 2, 2.1)) def testAppPartMakeSolid(self): # Act @@ -334,7 +338,7 @@ class TopoShapeTest(unittest.TestCase, TopoShapeAssertions): 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) ) + self.assertBounds(solid1, App.BoundBox(0, 0, 0, 1, 2, 2)) def testAppPartMakeRuled(self): # Act @@ -343,44 +347,46 @@ class TopoShapeTest(unittest.TestCase, TopoShapeAssertions): 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) ) + self.assertBounds(surface1, App.BoundBox(0, 0, 0, 1, 2, 2)) def testAppPartMakeShellFromWires(self): # Arrange - 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. + 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]) + 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) ) + self.assertBounds(shell1, App.BoundBox(0, 0, 0, 1, 2, 2)) 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 + 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") + 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) ) + 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. + # 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) ) + self.assertBounds(surface1, App.BoundBox(-5, -2.72011, 0, 5, 5, 6.28319), precision=3) def testAppPartMakeLoft(self): # Act @@ -389,15 +395,15 @@ class TopoShapeTest(unittest.TestCase, TopoShapeAssertions): 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) ) + 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 eliminate warnings. # Arrange - edge1 = self.doc.Box1.Shape.Faces[0].Edges[0].translated(App.Vector(0,0.5,0)) + edge1 = self.doc.Box1.Shape.Faces[0].Edges[0].translated(App.Vector(0, 0.5, 0)) face1 = self.doc.Box1.Shape.Faces[0] # Act - solids1 = Part.makeSplitShape(face1,[(edge1,face1)]) + solids1 = Part.makeSplitShape(face1, [(edge1, face1)]) # Assert elementMap self.assertEqual(len(solids1), 2) self.assertEqual(len(solids1[0]), 1) @@ -405,10 +411,11 @@ class TopoShapeTest(unittest.TestCase, TopoShapeAssertions): 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) ) + 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, @@ -416,12 +423,16 @@ class TopoShapeTest(unittest.TestCase, TopoShapeAssertions): ] 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, @@ -429,12 +440,15 @@ class TopoShapeTest(unittest.TestCase, TopoShapeAssertions): ] 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, @@ -442,12 +456,15 @@ class TopoShapeTest(unittest.TestCase, TopoShapeAssertions): ] 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, @@ -455,12 +472,16 @@ class TopoShapeTest(unittest.TestCase, TopoShapeAssertions): ] self.doc.recompute() compound = self.doc.Compound.Shape - compound_replaced = compound.replaceShape([(App.activeDocument().Box2.Shape,App.activeDocument().Box1.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, @@ -468,145 +489,269 @@ class TopoShapeTest(unittest.TestCase, TopoShapeAssertions): ] 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): - extrude = self.doc.Box1.Shape.Faces[0].extrude(App.Vector(2,0,0)) + # 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): - face2 = self.doc.Box1.Shape.Faces[0] - face2.revolve(App.Vector(),App.Vector(1,0,0),45) + # Arrange + face = self.doc.Box1.Shape.Faces[0] + # Act + face.revolve(App.Vector(), App.Vector(1, 0, 0), 45) self.doc.recompute() - - if face2.ElementMapVersion != "": # Should be '4' as of Mar 2023. - self.assertEqual(face2.ElementMapSize, 9) + # 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): - slice = self.doc.Box1.Shape.slice(App.Vector(10,10,0),1) + # 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): - slices = self.doc.Box1.Shape.Faces[0].slices(App.Vector(10,10,0),[1,2]) + # 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): - mirror = self.doc.Box1.Shape.mirror(App.Vector(),App.Vector(1,0,0)) + # 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): - thickness = self.doc.Box1.Shape.makeThickness(self.doc.Box1.Shape.Faces[0:2],0.1,0.0001) + # 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): + 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, 0) # Todo: Wrong, or deprecated? + 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) +