From ae4393978f88da2db5c7b7cc5929695c8db9ddca Mon Sep 17 00:00:00 2001 From: bgbsww Date: Tue, 13 Feb 2024 10:14:39 -0500 Subject: [PATCH] Toponaming/Part: clean, doc, and test getSubTopoShape --- src/Mod/Part/App/TopoShape.cpp | 1 + src/Mod/Part/App/TopoShape.h | 31 ++++++++- src/Mod/Part/App/TopoShapeExpansion.cpp | 2 + tests/src/Mod/Part/App/TopoShapeExpansion.cpp | 68 +++++++++++++++++++ 4 files changed, 101 insertions(+), 1 deletion(-) diff --git a/src/Mod/Part/App/TopoShape.cpp b/src/Mod/Part/App/TopoShape.cpp index 86664beb21..072e4ebc97 100644 --- a/src/Mod/Part/App/TopoShape.cpp +++ b/src/Mod/Part/App/TopoShape.cpp @@ -346,6 +346,7 @@ TopoDS_Shape TopoShape::getSubShape(TopAbs_ShapeEnum type, int index, bool silen if(index <= 0) { if(silent) return {}; + // TODO: Is this message clear? Should we complain about the negative index instead Standard_Failure::Raise("Unsupported sub-shape type"); } diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h index 1d51ae7df5..9c526cf32b 100644 --- a/src/Mod/Part/App/TopoShape.h +++ b/src/Mod/Part/App/TopoShape.h @@ -224,10 +224,39 @@ public: std::vector& PointNormals, std::vector& faces) const override; //@} - /// get the Topo"sub"Shape with the given name + /** + * Locate the TopoDS_Shape associated with a Topo"sub"Shape of the given name + * @param Type The complete name of the subshape - for example "Face2" + * @param silent True to suppress the exception throw if the shape isn't found + * @return The shape or a null TopoDS_Shape + */ TopoDS_Shape getSubShape(const char* Type, bool silent = false) const; + /** + * Locate a subshape's TopoDS_Shape by type enum and index. See doc above. + * @param type Shape type enum value + * @param idx Index number of the subshape within the shape + * @param silent True to suppress the exception throw + * @return The shape, or a null TopoShape. + */ TopoDS_Shape getSubShape(TopAbs_ShapeEnum type, int idx, bool silent = false) const; + /** + * Locate a subshape by name within this shape. If null or empty Type specified, try my own + * shapeType; if I'm not a COMPOUND OR COMPSOLID, return myself; otherwise, look to see if I + * have any singular SOLID, SHELL, FACE, WIRE, EDGE or VERTEX and return that. + * If a Type is specified, then treat it as the complete name of the subshape - for example + * "Face3" and try to find and return that shape. + * @param Type The Shape name + * @param silent True to suppress the exception throw if the shape isn't found. + * @return The shape or a null TopoShape. + */ TopoShape getSubTopoShape(const char* Type, bool silent = false) const; + /** + * Locate a subshape by type enum and index. See doc above. + * @param type Shape type enum value + * @param idx Index number of the subshape within the shape + * @param silent True to suppress the exception throw + * @return The shape, or a null TopoShape. + */ TopoShape getSubTopoShape(TopAbs_ShapeEnum type, int idx, bool silent = false) const; std::vector getSubTopoShapes(TopAbs_ShapeEnum type = TopAbs_SHAPE) const; std::vector getSubShapes(TopAbs_ShapeEnum type = TopAbs_SHAPE) const; diff --git a/src/Mod/Part/App/TopoShapeExpansion.cpp b/src/Mod/Part/App/TopoShapeExpansion.cpp index c079726ef6..e4870be3a2 100644 --- a/src/Mod/Part/App/TopoShapeExpansion.cpp +++ b/src/Mod/Part/App/TopoShapeExpansion.cpp @@ -1291,6 +1291,7 @@ void addShapesToBuilder(const std::vector& shapes, } } // namespace +// TODO: Can this be consolidated with getSubShape()? Empty Parm Logic is a little different. TopoShape TopoShape::getSubTopoShape(const char* Type, bool silent) const { if (!Type || !Type[0]) { @@ -1340,6 +1341,7 @@ TopoShape TopoShape::getSubTopoShape(const char* Type, bool silent) const return getSubTopoShape(res.first, res.second, silent); } +// TODO: Can this be consolidated with getSubShape()? We use ancestry; other uses current shape. TopoShape TopoShape::getSubTopoShape(TopAbs_ShapeEnum type, int idx, bool silent) const { if (isNull()) { diff --git a/tests/src/Mod/Part/App/TopoShapeExpansion.cpp b/tests/src/Mod/Part/App/TopoShapeExpansion.cpp index f92da3d9c0..c2fda968c4 100644 --- a/tests/src/Mod/Part/App/TopoShapeExpansion.cpp +++ b/tests/src/Mod/Part/App/TopoShapeExpansion.cpp @@ -532,6 +532,74 @@ TEST_F(TopoShapeExpansionTest, splitWires) // splitWires with all four reorientation values NoReorient, ReOrient, ReorientForward, // ReorientReversed +TEST_F(TopoShapeExpansionTest, getSubTopoShapeByEnum) +{ + // Arrange + auto [cube1, cube2] = CreateTwoCubes(); + TopoShape cube1TS {cube1}; + cube1TS.Tag = 1L; + + // Act + auto subShape = cube1TS.getSubTopoShape(TopAbs_FACE, 1); + auto subShape2 = cube1TS.getSubTopoShape(TopAbs_FACE, 2); + auto subShape3 = cube1TS.getSubTopoShape(TopAbs_FACE, 6); + auto noshape1 = cube1TS.getSubTopoShape(TopAbs_FACE, 7, true); + // Assert + EXPECT_EQ(subShape.getShape().ShapeType(), TopAbs_FACE); + EXPECT_EQ(subShape2.getShape().ShapeType(), TopAbs_FACE); + EXPECT_EQ(subShape2.getShape().ShapeType(), TopAbs_FACE); + EXPECT_TRUE(noshape1.isNull()); + EXPECT_THROW(cube1TS.getSubTopoShape(TopAbs_FACE, 7), Base::IndexError); // Out of range +} + +TEST_F(TopoShapeExpansionTest, getSubTopoShapeByStringDefaults) +{ + // Arrange + auto [cube1, cube2] = CreateTwoCubes(); + Part::TopoShape cube1TS {cube1}; + cube1TS.Tag = 1L; + const float Len = 3; + const float Wid = 2; + auto [face1, wire1, edge1, edge2, edge3, edge4] = CreateRectFace(Len, Wid); + TopoDS_Compound compound1; + TopoDS_Builder builder {}; + builder.MakeCompound(compound1); + builder.Add(compound1, face1); + TopoShape topoShape {compound1, 2L}; + // Act + auto subShape = cube1TS.getSubTopoShape(nullptr); + auto subShape1 = cube1TS.getSubTopoShape(""); + auto subShape2 = topoShape.getSubTopoShape(nullptr); + // Assert + EXPECT_TRUE(subShape.getShape().IsEqual(cube1TS.getShape())); + EXPECT_EQ(subShape.getShape().ShapeType(), TopAbs_SOLID); + EXPECT_TRUE(subShape1.getShape().IsEqual(cube1TS.getShape())); + EXPECT_EQ(subShape1.getShape().ShapeType(), TopAbs_SOLID); + EXPECT_TRUE(subShape2.getShape().IsEqual(face1)); + EXPECT_EQ(subShape2.getShape().ShapeType(), TopAbs_FACE); +} + +TEST_F(TopoShapeExpansionTest, getSubTopoShapeByStringNames) +{ + // Arrange + auto [cube1, cube2] = CreateTwoCubes(); + TopoShape cube1TS {cube1}; + cube1TS.Tag = 1; + + // Act + auto subShape = cube1TS.getSubTopoShape("Face1"); + auto subShape2 = cube1TS.getSubTopoShape("Face2"); + auto subShape3 = cube1TS.getSubTopoShape("Face3"); + auto noshape1 = cube1TS.getSubTopoShape("Face7", true); // Out of range + // Assert + EXPECT_EQ(subShape.getShape().ShapeType(), TopAbs_FACE); + EXPECT_EQ(subShape2.getShape().ShapeType(), TopAbs_FACE); + EXPECT_EQ(subShape3.getShape().ShapeType(), TopAbs_FACE); + EXPECT_TRUE(noshape1.isNull()); + EXPECT_THROW(cube1TS.getSubTopoShape("Face7"), Base::IndexError); // Out of range + EXPECT_THROW(cube1TS.getSubTopoShape("WOOHOO", false), Base::ValueError); // Invalid +} + TEST_F(TopoShapeExpansionTest, mapSubElementInvalidParm) { // Arrange