Merge pull request #12366 from bgbsww/bgbsww-toponamingGetSubTopoShape

Toponaming/Part:  Move getSubTopoShape
This commit is contained in:
Chris Hennes
2024-02-13 14:09:24 -06:00
committed by GitHub
4 changed files with 187 additions and 1 deletions

View File

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

View File

@@ -224,9 +224,40 @@ public:
std::vector<Base::Vector3d>& PointNormals,
std::vector<Facet>& 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<TopoShape> getSubTopoShapes(TopAbs_ShapeEnum type = TopAbs_SHAPE) const;
std::vector<TopoDS_Shape> getSubShapes(TopAbs_ShapeEnum type = TopAbs_SHAPE) const;
unsigned long countSubShapes(const char* Type) const;
@@ -697,6 +728,7 @@ public:
void mapSubElementsTo(std::vector<TopoShape>& shapes, const char* op = nullptr) const;
bool hasPendingElementMap() const;
/** Helper class to return the generated and modified shape given an input shape
*
* Shape history information is extracted using OCCT APIs

View File

@@ -1318,6 +1318,91 @@ void addShapesToBuilder(const std::vector<TopoShape>& 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]) {
switch (shapeType(true)) {
case TopAbs_COMPOUND:
case TopAbs_COMPSOLID:
if (countSubShapes(TopAbs_SOLID) == 1) {
return getSubTopoShape(TopAbs_SOLID, 1);
}
if (countSubShapes(TopAbs_SHELL) == 1) {
return getSubTopoShape(TopAbs_SHELL, 1);
}
if (countSubShapes(TopAbs_FACE) == 1) {
return getSubTopoShape(TopAbs_FACE, 1);
}
if (countSubShapes(TopAbs_WIRE) == 1) {
return getSubTopoShape(TopAbs_WIRE, 1);
}
if (countSubShapes(TopAbs_EDGE) == 1) {
return getSubTopoShape(TopAbs_EDGE, 1);
}
if (countSubShapes(TopAbs_VERTEX) == 1) {
return getSubTopoShape(TopAbs_VERTEX, 1);
}
break;
default:
break;
}
return *this;
}
Data::MappedElement mapped = getElementName(Type);
if (!mapped.index && boost::starts_with(Type, elementMapPrefix())) {
if (!silent) {
FC_THROWM(Base::CADKernelError, "Mapped element not found: " << Type);
}
return TopoShape();
}
auto res = shapeTypeAndIndex(Type);
if (res.second <= 0) {
if (!silent) {
FC_THROWM(Base::ValueError, "Invalid shape name " << (Type ? Type : ""));
}
return TopoShape();
}
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()) {
if (!silent) {
FC_THROWM(NullShapeException, "null shape");
}
return TopoShape();
}
if (idx <= 0) {
if (!silent) {
FC_THROWM(Base::ValueError, "Invalid shape index " << idx);
}
return TopoShape();
}
if (type < 0 || type > TopAbs_SHAPE) {
if (!silent) {
FC_THROWM(Base::ValueError, "Invalid shape type " << type);
}
return TopoShape();
}
initCache();
auto& shapeMap = _cache->getAncestry(type);
if (idx > shapeMap.count()) {
if (!silent) {
FC_THROWM(Base::IndexError,
"Shape index " << idx << " out of bound " << shapeMap.count());
}
return TopoShape();
}
return shapeMap.getTopoShape(*this, idx);
}
TopoShape& TopoShape::makeElementCompound(const std::vector<TopoShape>& shapes,
const char* op,
SingleShapeCompoundCreationPolicy policy)

View File

@@ -525,6 +525,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