Add Tests

This commit is contained in:
bgbsww
2024-03-27 16:47:15 -04:00
parent f00784f00e
commit a2f342fe54
6 changed files with 415 additions and 213 deletions

View File

@@ -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) {

View File

@@ -965,10 +965,10 @@ optimalBoundingBox([useTriangulation = True, useShapeTolerance = False]) -> boun
</UserDocu>
</Documentation>
</Methode>
<Methode Name="searchSubShape" Const="true" Keyword="true">
<Methode Name="findSubShapesWithSharedVertex" Const="true" Keyword="true">
<Documentation>
<UserDocu>
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

View File

@@ -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<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;
@@ -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,&copyGeom,&PyBool_Type,&copyMesh)) {
const char* op = nullptr;
PyObject* pyHasher = nullptr;
if (!PyArg_ParseTuple(args,
"|sO!O!O!",
&op,
&App::StringHasherPy::Type,
&pyHasher,
&PyBool_Type,
&copyGeom,
&PyBool_Type,
&copyMesh)) {
PyErr_Clear();
if (!PyArg_ParseTuple(args, "|O!O!", &PyBool_Type, &copyGeom, &PyBool_Type, &copyMesh))
if (!PyArg_ParseTuple(args, "|O!O!", &PyBool_Type, &copyGeom, &PyBool_Type, &copyMesh)) {
return 0;
}
}
if (op && !op[0]) {
op = nullptr;
}
if(op && !op[0]) op = nullptr;
App::StringHasherRef hasher;
if(pyHasher)
if (pyHasher) {
hasher = static_cast<App::StringHasherPy*>(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, &copyGeom, &PyBool_Type, &copyMesh))
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<TopoShape, TopoShape> > shapes;
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())
);
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<TopoDS_Shape> shapes;
@@ -729,7 +747,8 @@ 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))));
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<TopoDS_Wire> 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<std::vector<TopoShape> > modifies;
std::vector<std::vector<TopoShape>> modifies;
std::vector<TopoShape> 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<TopoDS_Shape> 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<JoinType>(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<JoinType>(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<JoinType>(join),
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,
@@ -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<JoinType>(join), PyObject_IsTrue(fill) ? FillType::fill : FillType::noFill,
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
@@ -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;

View File

@@ -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;

View File

@@ -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));

View File

@@ -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)