From 3aeb4668f516cfd8577acfa40a173089ed7ec26d Mon Sep 17 00:00:00 2001 From: Pasukhin Dmitry Date: Fri, 23 Jan 2026 21:08:39 +0000 Subject: [PATCH] Foundation Classes - Refactor TShape hierarchy for performance and memory efficiency (#1027) - Made ShapeType() non-virtual by embedding the shape type in a compact uint16_t state field alongside flags - Replaced int myFlags with uint16_t myState using a BitLayout enum for compact storage - Moved Compose/Reverse/Complement operations from TopAbs.cxx to inline implementations in TopAbs.hxx - Updated all TShape derived class constructors to pass their type to the base class - Refactored TopoDS_Iterator to use index-based iteration with updateCurrentShape() helper --- src/ModelingData/TKBRep/GTests/FILES.cmake | 2 + .../TKBRep/GTests/TopoDS_Builder_Test.cxx | 547 ++++++++++++++++++ .../TKBRep/GTests/TopoDS_Iterator_Test.cxx | 440 +++++++++++++- .../TKBRep/GTests/TopoDS_TShape_Test.cxx | 313 ++++++++++ .../TKBRep/TopoDS/TopoDS_Builder.cxx | 61 +- .../TKBRep/TopoDS/TopoDS_Builder.lxx | 16 +- .../TKBRep/TopoDS/TopoDS_Iterator.cxx | 36 +- .../TKBRep/TopoDS/TopoDS_Iterator.hxx | 18 +- .../TKBRep/TopoDS/TopoDS_TCompSolid.cxx | 7 - .../TKBRep/TopoDS/TopoDS_TCompSolid.hxx | 9 +- .../TKBRep/TopoDS/TopoDS_TCompound.cxx | 7 - .../TKBRep/TopoDS/TopoDS_TCompound.hxx | 10 +- .../TKBRep/TopoDS/TopoDS_TEdge.cxx | 4 +- .../TKBRep/TopoDS/TopoDS_TEdge.hxx | 11 +- .../TKBRep/TopoDS/TopoDS_TFace.cxx | 7 - .../TKBRep/TopoDS/TopoDS_TFace.hxx | 12 +- .../TKBRep/TopoDS/TopoDS_TShape.cxx | 4 +- .../TKBRep/TopoDS/TopoDS_TShape.hxx | 124 ++-- .../TKBRep/TopoDS/TopoDS_TShell.cxx | 7 - .../TKBRep/TopoDS/TopoDS_TShell.hxx | 9 +- .../TKBRep/TopoDS/TopoDS_TSolid.cxx | 7 - .../TKBRep/TopoDS/TopoDS_TSolid.hxx | 10 +- .../TKBRep/TopoDS/TopoDS_TVertex.cxx | 7 - .../TKBRep/TopoDS/TopoDS_TVertex.hxx | 7 +- .../TKBRep/TopoDS/TopoDS_TWire.cxx | 7 - .../TKBRep/TopoDS/TopoDS_TWire.hxx | 9 +- src/ModelingData/TKG3d/TopAbs/TopAbs.cxx | 43 -- src/ModelingData/TKG3d/TopAbs/TopAbs.hxx | 32 +- 28 files changed, 1494 insertions(+), 272 deletions(-) create mode 100644 src/ModelingData/TKBRep/GTests/TopoDS_Builder_Test.cxx create mode 100644 src/ModelingData/TKBRep/GTests/TopoDS_TShape_Test.cxx diff --git a/src/ModelingData/TKBRep/GTests/FILES.cmake b/src/ModelingData/TKBRep/GTests/FILES.cmake index 1d0ccde0cd..23e163c70d 100644 --- a/src/ModelingData/TKBRep/GTests/FILES.cmake +++ b/src/ModelingData/TKBRep/GTests/FILES.cmake @@ -3,6 +3,8 @@ set(OCCT_TKBRep_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}") set(OCCT_TKBRep_GTests_FILES BRepAdaptor_CompCurve_Test.cxx + TopoDS_Builder_Test.cxx TopoDS_Edge_Test.cxx TopoDS_Iterator_Test.cxx + TopoDS_TShape_Test.cxx ) diff --git a/src/ModelingData/TKBRep/GTests/TopoDS_Builder_Test.cxx b/src/ModelingData/TKBRep/GTests/TopoDS_Builder_Test.cxx new file mode 100644 index 0000000000..377f123a71 --- /dev/null +++ b/src/ModelingData/TKBRep/GTests/TopoDS_Builder_Test.cxx @@ -0,0 +1,547 @@ +// Copyright (c) 2026 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//================================================================================================== +// Test TopoDS_Builder::MakeWire +//================================================================================================== + +TEST(TopoDS_Builder_Test, MakeWire) +{ + TopoDS_Builder aBuilder; + TopoDS_Wire aWire; + + aBuilder.MakeWire(aWire); + + EXPECT_FALSE(aWire.IsNull()) << "Wire should not be null after MakeWire"; + EXPECT_EQ(aWire.ShapeType(), TopAbs_WIRE) << "Shape type should be WIRE"; + EXPECT_TRUE(aWire.Free()) << "Newly created wire should be free"; +} + +//================================================================================================== +// Test TopoDS_Builder::MakeShell +//================================================================================================== + +TEST(TopoDS_Builder_Test, MakeShell) +{ + TopoDS_Builder aBuilder; + TopoDS_Shell aShell; + + aBuilder.MakeShell(aShell); + + EXPECT_FALSE(aShell.IsNull()) << "Shell should not be null"; + EXPECT_EQ(aShell.ShapeType(), TopAbs_SHELL); +} + +//================================================================================================== +// Test TopoDS_Builder::MakeSolid +//================================================================================================== + +TEST(TopoDS_Builder_Test, MakeSolid) +{ + TopoDS_Builder aBuilder; + TopoDS_Solid aSolid; + + aBuilder.MakeSolid(aSolid); + + EXPECT_FALSE(aSolid.IsNull()) << "Solid should not be null"; + EXPECT_EQ(aSolid.ShapeType(), TopAbs_SOLID); +} + +//================================================================================================== +// Test TopoDS_Builder::MakeCompSolid +//================================================================================================== + +TEST(TopoDS_Builder_Test, MakeCompSolid) +{ + TopoDS_Builder aBuilder; + TopoDS_CompSolid aCompSolid; + + aBuilder.MakeCompSolid(aCompSolid); + + EXPECT_FALSE(aCompSolid.IsNull()) << "CompSolid should not be null"; + EXPECT_EQ(aCompSolid.ShapeType(), TopAbs_COMPSOLID); +} + +//================================================================================================== +// Test TopoDS_Builder::MakeCompound +//================================================================================================== + +TEST(TopoDS_Builder_Test, MakeCompound) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + + aBuilder.MakeCompound(aCompound); + + EXPECT_FALSE(aCompound.IsNull()) << "Compound should not be null"; + EXPECT_EQ(aCompound.ShapeType(), TopAbs_COMPOUND); +} + +//================================================================================================== +// Test TopoDS_Builder::Add - add vertices to compound +//================================================================================================== + +TEST(TopoDS_Builder_Test, Add_VerticesToCompound) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + + // Create and add vertices + TopoDS_Vertex aV1 = BRepBuilderAPI_MakeVertex(gp_Pnt(0, 0, 0)); + TopoDS_Vertex aV2 = BRepBuilderAPI_MakeVertex(gp_Pnt(1, 0, 0)); + TopoDS_Vertex aV3 = BRepBuilderAPI_MakeVertex(gp_Pnt(0, 1, 0)); + + aBuilder.Add(aCompound, aV1); + aBuilder.Add(aCompound, aV2); + aBuilder.Add(aCompound, aV3); + + // Count children using iterator + int aCount = 0; + for (TopoDS_Iterator anIt(aCompound); anIt.More(); anIt.Next()) + { + ++aCount; + } + + EXPECT_EQ(aCount, 3) << "Compound should have 3 vertices"; +} + +//================================================================================================== +// Test TopoDS_Builder::Add - add edges to wire +//================================================================================================== + +TEST(TopoDS_Builder_Test, Add_EdgesToWire) +{ + TopoDS_Builder aBuilder; + TopoDS_Wire aWire; + aBuilder.MakeWire(aWire); + + // Create edges forming a triangle + TopoDS_Edge aE1 = BRepBuilderAPI_MakeEdge(gp_Pnt(0, 0, 0), gp_Pnt(1, 0, 0)); + TopoDS_Edge aE2 = BRepBuilderAPI_MakeEdge(gp_Pnt(1, 0, 0), gp_Pnt(0.5, 1, 0)); + TopoDS_Edge aE3 = BRepBuilderAPI_MakeEdge(gp_Pnt(0.5, 1, 0), gp_Pnt(0, 0, 0)); + + aBuilder.Add(aWire, aE1); + aBuilder.Add(aWire, aE2); + aBuilder.Add(aWire, aE3); + + // Count children + int aCount = 0; + for (TopoDS_Iterator anIt(aWire); anIt.More(); anIt.Next()) + { + EXPECT_EQ(anIt.Value().ShapeType(), TopAbs_EDGE); + ++aCount; + } + + EXPECT_EQ(aCount, 3) << "Wire should have 3 edges"; +} + +//================================================================================================== +// Test TopoDS_Builder::Remove +//================================================================================================== + +TEST(TopoDS_Builder_Test, Remove_FromCompound) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + + // Add vertices + TopoDS_Vertex aV1 = BRepBuilderAPI_MakeVertex(gp_Pnt(0, 0, 0)); + TopoDS_Vertex aV2 = BRepBuilderAPI_MakeVertex(gp_Pnt(1, 0, 0)); + TopoDS_Vertex aV3 = BRepBuilderAPI_MakeVertex(gp_Pnt(0, 1, 0)); + + aBuilder.Add(aCompound, aV1); + aBuilder.Add(aCompound, aV2); + aBuilder.Add(aCompound, aV3); + + // Remove middle vertex + aBuilder.Remove(aCompound, aV2); + + // Count remaining children + int aCount = 0; + for (TopoDS_Iterator anIt(aCompound); anIt.More(); anIt.Next()) + { + ++aCount; + } + + EXPECT_EQ(aCount, 2) << "Compound should have 2 vertices after removal"; +} + +//================================================================================================== +// Test adding many shapes to compound +//================================================================================================== + +TEST(TopoDS_Builder_Test, Add_ManyShapes) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + + aBuilder.MakeCompound(aCompound); + + // Add 500 vertices + for (int i = 0; i < 500; ++i) + { + TopoDS_Vertex aV = BRepBuilderAPI_MakeVertex(gp_Pnt(i, 0, 0)); + aBuilder.Add(aCompound, aV); + } + + // Verify count + int aCount = 0; + for (TopoDS_Iterator anIt(aCompound); anIt.More(); anIt.Next()) + { + ++aCount; + } + + EXPECT_EQ(aCount, 500) << "Compound should have 500 vertices"; +} + +//================================================================================================== +// Test TShape flags through shape interface +//================================================================================================== + +TEST(TopoDS_Builder_Test, TShapeFlags) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + + // Test initial flags + EXPECT_TRUE(aCompound.Free()) << "New shape should be free"; + EXPECT_TRUE(aCompound.Modified()) << "New shape should be modified"; + + // Test setting flags + aCompound.Checked(true); + EXPECT_TRUE(aCompound.Checked()); + + aCompound.Closed(true); + EXPECT_TRUE(aCompound.Closed()); + + aCompound.Infinite(true); + EXPECT_TRUE(aCompound.Infinite()); + + aCompound.Convex(true); + EXPECT_TRUE(aCompound.Convex()); +} + +//================================================================================================== +// Test TopoDS_Builder::Remove first child +//================================================================================================== + +TEST(TopoDS_Builder_Test, Remove_FirstChild) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + + TopoDS_Vertex aV1 = BRepBuilderAPI_MakeVertex(gp_Pnt(1, 0, 0)); + TopoDS_Vertex aV2 = BRepBuilderAPI_MakeVertex(gp_Pnt(2, 0, 0)); + TopoDS_Vertex aV3 = BRepBuilderAPI_MakeVertex(gp_Pnt(3, 0, 0)); + + aBuilder.Add(aCompound, aV1); + aBuilder.Add(aCompound, aV2); + aBuilder.Add(aCompound, aV3); + + // Remove first vertex + aBuilder.Remove(aCompound, aV1); + + // Should have 2 remaining + int aCount = 0; + for (TopoDS_Iterator anIt(aCompound); anIt.More(); anIt.Next()) + { + ++aCount; + } + EXPECT_EQ(aCount, 2); +} + +//================================================================================================== +// Test TopoDS_Builder::Remove last child +//================================================================================================== + +TEST(TopoDS_Builder_Test, Remove_LastChild) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + + TopoDS_Vertex aV1 = BRepBuilderAPI_MakeVertex(gp_Pnt(1, 0, 0)); + TopoDS_Vertex aV2 = BRepBuilderAPI_MakeVertex(gp_Pnt(2, 0, 0)); + TopoDS_Vertex aV3 = BRepBuilderAPI_MakeVertex(gp_Pnt(3, 0, 0)); + + aBuilder.Add(aCompound, aV1); + aBuilder.Add(aCompound, aV2); + aBuilder.Add(aCompound, aV3); + + // Remove last vertex + aBuilder.Remove(aCompound, aV3); + + // Should have 2 remaining + int aCount = 0; + for (TopoDS_Iterator anIt(aCompound); anIt.More(); anIt.Next()) + { + ++aCount; + } + EXPECT_EQ(aCount, 2); +} + +//================================================================================================== +// Test TopoDS_Builder::Remove all children one by one +//================================================================================================== + +TEST(TopoDS_Builder_Test, Remove_AllChildren) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + + TopoDS_Vertex aV1 = BRepBuilderAPI_MakeVertex(gp_Pnt(1, 0, 0)); + TopoDS_Vertex aV2 = BRepBuilderAPI_MakeVertex(gp_Pnt(2, 0, 0)); + TopoDS_Vertex aV3 = BRepBuilderAPI_MakeVertex(gp_Pnt(3, 0, 0)); + + aBuilder.Add(aCompound, aV1); + aBuilder.Add(aCompound, aV2); + aBuilder.Add(aCompound, aV3); + + // Remove all + aBuilder.Remove(aCompound, aV1); + aBuilder.Remove(aCompound, aV2); + aBuilder.Remove(aCompound, aV3); + + // Should be empty + TopoDS_Iterator anIt(aCompound); + EXPECT_FALSE(anIt.More()) << "Compound should be empty after removing all children"; +} + +//================================================================================================== +// Test TopoDS_Builder::Remove from wire +//================================================================================================== + +TEST(TopoDS_Builder_Test, Remove_FromWire) +{ + TopoDS_Builder aBuilder; + TopoDS_Wire aWire; + aBuilder.MakeWire(aWire); + + TopoDS_Edge aE1 = BRepBuilderAPI_MakeEdge(gp_Pnt(0, 0, 0), gp_Pnt(1, 0, 0)); + TopoDS_Edge aE2 = BRepBuilderAPI_MakeEdge(gp_Pnt(1, 0, 0), gp_Pnt(1, 1, 0)); + TopoDS_Edge aE3 = BRepBuilderAPI_MakeEdge(gp_Pnt(1, 1, 0), gp_Pnt(0, 0, 0)); + + aBuilder.Add(aWire, aE1); + aBuilder.Add(aWire, aE2); + aBuilder.Add(aWire, aE3); + + // Remove middle edge + aBuilder.Remove(aWire, aE2); + + // Should have 2 edges + int aCount = 0; + for (TopoDS_Iterator anIt(aWire); anIt.More(); anIt.Next()) + { + ++aCount; + } + EXPECT_EQ(aCount, 2); +} + +//================================================================================================== +// Test TopoDS_Builder with nested compounds +//================================================================================================== + +TEST(TopoDS_Builder_Test, NestedCompounds) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aOuter, aInner; + aBuilder.MakeCompound(aOuter); + aBuilder.MakeCompound(aInner); + + // Add vertices to inner + aBuilder.Add(aInner, BRepBuilderAPI_MakeVertex(gp_Pnt(0, 0, 0))); + aBuilder.Add(aInner, BRepBuilderAPI_MakeVertex(gp_Pnt(1, 0, 0))); + + // Add inner to outer + aBuilder.Add(aOuter, aInner); + + // Outer should have 1 child (the inner compound) + int aOuterCount = 0; + for (TopoDS_Iterator anIt(aOuter); anIt.More(); anIt.Next()) + { + EXPECT_EQ(anIt.Value().ShapeType(), TopAbs_COMPOUND); + ++aOuterCount; + } + EXPECT_EQ(aOuterCount, 1); + + // Inner should still have 2 vertices + EXPECT_EQ(aInner.TShape()->NbChildren(), 2); +} + +//================================================================================================== +// Test TopoDS_Builder::Add sets Modified flag +//================================================================================================== + +TEST(TopoDS_Builder_Test, Add_SetsModifiedFlag) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + + // Clear modified flag + aCompound.TShape()->Modified(false); + EXPECT_FALSE(aCompound.Modified()); + + // Add should set modified + aBuilder.Add(aCompound, BRepBuilderAPI_MakeVertex(gp_Pnt(0, 0, 0))); + EXPECT_TRUE(aCompound.Modified()) << "Add should set Modified flag"; +} + +//================================================================================================== +// Test TopoDS_Builder::Remove sets Modified flag +//================================================================================================== + +TEST(TopoDS_Builder_Test, Remove_SetsModifiedFlag) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + + TopoDS_Vertex aV = BRepBuilderAPI_MakeVertex(gp_Pnt(0, 0, 0)); + aBuilder.Add(aCompound, aV); + + // Clear modified flag + aCompound.TShape()->Modified(false); + EXPECT_FALSE(aCompound.Modified()); + + // Remove should set modified + aBuilder.Remove(aCompound, aV); + EXPECT_TRUE(aCompound.Modified()) << "Remove should set Modified flag"; +} + +//================================================================================================== +// Test all shape types +//================================================================================================== + +TEST(TopoDS_Builder_Test, AllTypes) +{ + TopoDS_Builder aBuilder; + + // Wire + TopoDS_Wire aWire; + aBuilder.MakeWire(aWire); + EXPECT_FALSE(aWire.IsNull()); + EXPECT_EQ(aWire.ShapeType(), TopAbs_WIRE); + EXPECT_TRUE(aWire.Free()); + + // Shell + TopoDS_Shell aShell; + aBuilder.MakeShell(aShell); + EXPECT_FALSE(aShell.IsNull()); + EXPECT_EQ(aShell.ShapeType(), TopAbs_SHELL); + EXPECT_TRUE(aShell.Free()); + + // Solid + TopoDS_Solid aSolid; + aBuilder.MakeSolid(aSolid); + EXPECT_FALSE(aSolid.IsNull()); + EXPECT_EQ(aSolid.ShapeType(), TopAbs_SOLID); + EXPECT_TRUE(aSolid.Free()); + + // CompSolid + TopoDS_CompSolid aCompSolid; + aBuilder.MakeCompSolid(aCompSolid); + EXPECT_FALSE(aCompSolid.IsNull()); + EXPECT_EQ(aCompSolid.ShapeType(), TopAbs_COMPSOLID); + EXPECT_TRUE(aCompSolid.Free()); + + // Compound + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + EXPECT_FALSE(aCompound.IsNull()); + EXPECT_EQ(aCompound.ShapeType(), TopAbs_COMPOUND); + EXPECT_TRUE(aCompound.Free()); +} + +//================================================================================================== +// Test mixed shapes in compound +//================================================================================================== + +TEST(TopoDS_Builder_Test, MixedShapesInCompound) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + + // Add different shape types + aBuilder.Add(aCompound, BRepBuilderAPI_MakeVertex(gp_Pnt(0, 0, 0))); + aBuilder.Add(aCompound, BRepBuilderAPI_MakeEdge(gp_Pnt(0, 0, 0), gp_Pnt(1, 0, 0))); + + TopoDS_Wire aWire; + aBuilder.MakeWire(aWire); + aBuilder.Add(aCompound, aWire); + + TopoDS_Shell aShell; + aBuilder.MakeShell(aShell); + aBuilder.Add(aCompound, aShell); + + TopoDS_Compound aInner; + aBuilder.MakeCompound(aInner); + aBuilder.Add(aCompound, aInner); + + EXPECT_EQ(aCompound.TShape()->NbChildren(), 5); + + // Verify types via iteration + int aVertexCount = 0, aEdgeCount = 0, aWireCount = 0, aShellCount = 0, aCompoundCount = 0; + for (TopoDS_Iterator anIt(aCompound); anIt.More(); anIt.Next()) + { + switch (anIt.Value().ShapeType()) + { + case TopAbs_VERTEX: + ++aVertexCount; + break; + case TopAbs_EDGE: + ++aEdgeCount; + break; + case TopAbs_WIRE: + ++aWireCount; + break; + case TopAbs_SHELL: + ++aShellCount; + break; + case TopAbs_COMPOUND: + ++aCompoundCount; + break; + default: + break; + } + } + + EXPECT_EQ(aVertexCount, 1); + EXPECT_EQ(aEdgeCount, 1); + EXPECT_EQ(aWireCount, 1); + EXPECT_EQ(aShellCount, 1); + EXPECT_EQ(aCompoundCount, 1); +} diff --git a/src/ModelingData/TKBRep/GTests/TopoDS_Iterator_Test.cxx b/src/ModelingData/TKBRep/GTests/TopoDS_Iterator_Test.cxx index e6ba5ca991..f3a18b56d4 100644 --- a/src/ModelingData/TKBRep/GTests/TopoDS_Iterator_Test.cxx +++ b/src/ModelingData/TKBRep/GTests/TopoDS_Iterator_Test.cxx @@ -11,10 +11,33 @@ // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include +#include +#include +#include +#include -#include +//================================================================================================= +// Test OCC30708_1: Initialize with null shape +//================================================================================================= TEST(TopoDS_Iterator_Test, OCC30708_1_InitializeWithNullShape) { @@ -27,3 +50,418 @@ TEST(TopoDS_Iterator_Test, OCC30708_1_InitializeWithNullShape) // More() should return false on null shape EXPECT_FALSE(it.More()); } + +//================================================================================================= +// Test iterator on empty compound +//================================================================================================= + +TEST(TopoDS_Iterator_Test, EmptyCompound) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + + TopoDS_Iterator anIt(aCompound); + EXPECT_FALSE(anIt.More()) << "Empty compound should have no children"; +} + +//================================================================================================= +// Test iterator on compound with vertices +//================================================================================================= + +TEST(TopoDS_Iterator_Test, CompoundWithVertices) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + + // Add 5 vertices + for (int i = 0; i < 5; ++i) + { + TopoDS_Vertex aV = BRepBuilderAPI_MakeVertex(gp_Pnt(i, 0, 0)); + aBuilder.Add(aCompound, aV); + } + + // Iterate and count + int aCount = 0; + for (TopoDS_Iterator anIt(aCompound); anIt.More(); anIt.Next()) + { + EXPECT_EQ(anIt.Value().ShapeType(), TopAbs_VERTEX); + ++aCount; + } + + EXPECT_EQ(aCount, 5) << "Should iterate over 5 vertices"; +} + +//================================================================================================= +// Test iterator on wire with edges +//================================================================================================= + +TEST(TopoDS_Iterator_Test, WireWithEdges) +{ + TopoDS_Builder aBuilder; + TopoDS_Wire aWire; + aBuilder.MakeWire(aWire); + + // Create a rectangular wire (4 edges) + TopoDS_Edge aE1 = BRepBuilderAPI_MakeEdge(gp_Pnt(0, 0, 0), gp_Pnt(1, 0, 0)); + TopoDS_Edge aE2 = BRepBuilderAPI_MakeEdge(gp_Pnt(1, 0, 0), gp_Pnt(1, 1, 0)); + TopoDS_Edge aE3 = BRepBuilderAPI_MakeEdge(gp_Pnt(1, 1, 0), gp_Pnt(0, 1, 0)); + TopoDS_Edge aE4 = BRepBuilderAPI_MakeEdge(gp_Pnt(0, 1, 0), gp_Pnt(0, 0, 0)); + + aBuilder.Add(aWire, aE1); + aBuilder.Add(aWire, aE2); + aBuilder.Add(aWire, aE3); + aBuilder.Add(aWire, aE4); + + // Iterate and verify + int aCount = 0; + for (TopoDS_Iterator anIt(aWire); anIt.More(); anIt.Next()) + { + EXPECT_EQ(anIt.Value().ShapeType(), TopAbs_EDGE); + ++aCount; + } + + EXPECT_EQ(aCount, 4) << "Wire should have 4 edges"; +} + +//================================================================================================= +// Test iterator on edge with vertices +//================================================================================================= + +TEST(TopoDS_Iterator_Test, EdgeWithVertices) +{ + TopoDS_Edge anEdge = BRepBuilderAPI_MakeEdge(gp_Pnt(0, 0, 0), gp_Pnt(1, 1, 1)); + + int aCount = 0; + for (TopoDS_Iterator anIt(anEdge); anIt.More(); anIt.Next()) + { + EXPECT_EQ(anIt.Value().ShapeType(), TopAbs_VERTEX); + ++aCount; + } + + EXPECT_EQ(aCount, 2) << "Edge should have 2 vertices"; +} + +//================================================================================================= +// Test iterator on vertex (no children) +//================================================================================================= + +TEST(TopoDS_Iterator_Test, VertexNoChildren) +{ + TopoDS_Vertex aVertex = BRepBuilderAPI_MakeVertex(gp_Pnt(0, 0, 0)); + + TopoDS_Iterator anIt(aVertex); + EXPECT_FALSE(anIt.More()) << "Vertex should have no children"; +} + +//================================================================================================= +// Test iterator cumulative orientation +//================================================================================================= + +TEST(TopoDS_Iterator_Test, CumulativeOrientation) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + + TopoDS_Vertex aV = BRepBuilderAPI_MakeVertex(gp_Pnt(0, 0, 0)); + aBuilder.Add(aCompound, aV); + + // Reverse the compound + aCompound.Reverse(); + + // With cumOri=true (default), child orientation should be composed + TopoDS_Iterator anIt1(aCompound, true, true); + EXPECT_TRUE(anIt1.More()); + TopAbs_Orientation anOri1 = anIt1.Value().Orientation(); + + // With cumOri=false, child orientation should be original + TopoDS_Iterator anIt2(aCompound, false, true); + EXPECT_TRUE(anIt2.More()); + TopAbs_Orientation anOri2 = anIt2.Value().Orientation(); + + // Orientations should differ when compound is reversed + EXPECT_NE(anOri1, anOri2) << "Cumulative orientation should affect result"; +} + +//================================================================================================= +// Test iterator re-initialization +//================================================================================================= + +TEST(TopoDS_Iterator_Test, ReInitialization) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound1, aCompound2; + aBuilder.MakeCompound(aCompound1); + aBuilder.MakeCompound(aCompound2); + + // Add different number of vertices + for (int i = 0; i < 3; ++i) + { + aBuilder.Add(aCompound1, BRepBuilderAPI_MakeVertex(gp_Pnt(i, 0, 0))); + } + for (int i = 0; i < 5; ++i) + { + aBuilder.Add(aCompound2, BRepBuilderAPI_MakeVertex(gp_Pnt(i, 1, 0))); + } + + TopoDS_Iterator anIt(aCompound1); + + // Count first compound + int aCount1 = 0; + for (; anIt.More(); anIt.Next()) + ++aCount1; + EXPECT_EQ(aCount1, 3); + + // Re-initialize with second compound + anIt.Initialize(aCompound2); + + // Count second compound + int aCount2 = 0; + for (; anIt.More(); anIt.Next()) + ++aCount2; + EXPECT_EQ(aCount2, 5); +} + +//================================================================================================= +// Test iterator on box solid (shell -> faces) +//================================================================================================= + +TEST(TopoDS_Iterator_Test, BoxSolidIteration) +{ + // Create a box + TopoDS_Shape aBox = BRepPrimAPI_MakeBox(1.0, 2.0, 3.0).Shape(); + + // Iterate over solid's children (should be 1 shell) + int aShellCount = 0; + for (TopoDS_Iterator anIt(aBox); anIt.More(); anIt.Next()) + { + EXPECT_EQ(anIt.Value().ShapeType(), TopAbs_SHELL); + ++aShellCount; + + // Iterate over shell's children (should be 6 faces) + int aFaceCount = 0; + for (TopoDS_Iterator anIt2(anIt.Value()); anIt2.More(); anIt2.Next()) + { + EXPECT_EQ(anIt2.Value().ShapeType(), TopAbs_FACE); + ++aFaceCount; + } + EXPECT_EQ(aFaceCount, 6) << "Box shell should have 6 faces"; + } + + EXPECT_EQ(aShellCount, 1) << "Box solid should have 1 shell"; +} + +//================================================================================================= +// Test iterator with many children (performance/stress test) +//================================================================================================= + +TEST(TopoDS_Iterator_Test, ManyChildren) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + + const int aNbVertices = 1000; + + // Add many vertices + for (int i = 0; i < aNbVertices; ++i) + { + aBuilder.Add(aCompound, BRepBuilderAPI_MakeVertex(gp_Pnt(i, 0, 0))); + } + + // Iterate and count + int aCount = 0; + for (TopoDS_Iterator anIt(aCompound); anIt.More(); anIt.Next()) + { + ++aCount; + } + + EXPECT_EQ(aCount, aNbVertices) << "Should iterate over all vertices"; +} + +//================================================================================================= +// Test default constructor followed by Initialize +//================================================================================================= + +TEST(TopoDS_Iterator_Test, DefaultConstructorThenInitialize) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + aBuilder.Add(aCompound, BRepBuilderAPI_MakeVertex(gp_Pnt(0, 0, 0))); + + // Default construct, then initialize + TopoDS_Iterator anIt; + EXPECT_FALSE(anIt.More()) << "Default constructed iterator should have More()=false"; + + anIt.Initialize(aCompound); + EXPECT_TRUE(anIt.More()) << "After Initialize, More() should be true"; + + EXPECT_EQ(anIt.Value().ShapeType(), TopAbs_VERTEX); +} + +//================================================================================================= +// Test Value() throws when not More() (only in debug builds with exceptions enabled) +//================================================================================================= + +#ifndef No_Exception +TEST(TopoDS_Iterator_Test, ValueThrowsWhenNotMore) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + + TopoDS_Iterator anIt(aCompound); + EXPECT_FALSE(anIt.More()); + + // Value() should throw Standard_NoSuchObject when !More() + EXPECT_THROW(anIt.Value(), Standard_NoSuchObject); +} +#endif + +//================================================================================================= +// Test iterator with cumulative location +//================================================================================================= + +TEST(TopoDS_Iterator_Test, CumulativeLocation) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + + TopoDS_Vertex aV = BRepBuilderAPI_MakeVertex(gp_Pnt(0, 0, 0)); + aBuilder.Add(aCompound, aV); + + // Apply a translation to the compound + gp_Trsf aTrsf; + aTrsf.SetTranslation(gp_Vec(10, 20, 30)); + TopLoc_Location aLoc(aTrsf); + aCompound.Location(aLoc); + + // With cumLoc=true (default), child should have composed location + TopoDS_Iterator anIt1(aCompound, true, true); + EXPECT_TRUE(anIt1.More()); + TopLoc_Location aChildLoc1 = anIt1.Value().Location(); + + // With cumLoc=false, child should have original location + TopoDS_Iterator anIt2(aCompound, true, false); + EXPECT_TRUE(anIt2.More()); + TopLoc_Location aChildLoc2 = anIt2.Value().Location(); + + // Locations should differ + EXPECT_NE(aChildLoc1.IsIdentity(), aChildLoc2.IsIdentity()) + << "Cumulative location should affect child location"; +} + +//================================================================================================= +// Test iterator on nested compounds +//================================================================================================= + +TEST(TopoDS_Iterator_Test, NestedCompounds) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aOuter, aInner1, aInner2; + aBuilder.MakeCompound(aOuter); + aBuilder.MakeCompound(aInner1); + aBuilder.MakeCompound(aInner2); + + // Add vertices to inner compounds + aBuilder.Add(aInner1, BRepBuilderAPI_MakeVertex(gp_Pnt(0, 0, 0))); + aBuilder.Add(aInner1, BRepBuilderAPI_MakeVertex(gp_Pnt(1, 0, 0))); + aBuilder.Add(aInner2, BRepBuilderAPI_MakeVertex(gp_Pnt(2, 0, 0))); + + // Add inner compounds to outer + aBuilder.Add(aOuter, aInner1); + aBuilder.Add(aOuter, aInner2); + + // Outer should have 2 children (both compounds) + int aOuterCount = 0; + for (TopoDS_Iterator anIt(aOuter); anIt.More(); anIt.Next()) + { + EXPECT_EQ(anIt.Value().ShapeType(), TopAbs_COMPOUND); + ++aOuterCount; + } + EXPECT_EQ(aOuterCount, 2); + + // First inner should have 2 children + TopoDS_Iterator anIt(aOuter); + int aInner1Count = 0; + for (TopoDS_Iterator anIt2(anIt.Value()); anIt2.More(); anIt2.Next()) + { + ++aInner1Count; + } + EXPECT_EQ(aInner1Count, 2); +} + +//================================================================================================= +// Test iterator on face with wires (from box) +//================================================================================================= + +TEST(TopoDS_Iterator_Test, FaceWithWires) +{ + TopoDS_Shape aBox = BRepPrimAPI_MakeBox(1.0, 1.0, 1.0).Shape(); + + // Get first face + TopExp_Explorer anExp(aBox, TopAbs_FACE); + ASSERT_TRUE(anExp.More()); + const TopoDS_Face& aFace = TopoDS::Face(anExp.Current()); + + // Iterate over face's children (should be wires) + int aWireCount = 0; + for (TopoDS_Iterator anIt(aFace); anIt.More(); anIt.Next()) + { + EXPECT_EQ(anIt.Value().ShapeType(), TopAbs_WIRE); + ++aWireCount; + } + + EXPECT_GE(aWireCount, 1) << "Face should have at least 1 wire"; +} + +//================================================================================================= +// Test iterator preserves shape identity +//================================================================================================= + +TEST(TopoDS_Iterator_Test, ShapeIdentity) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + + TopoDS_Vertex aV1 = BRepBuilderAPI_MakeVertex(gp_Pnt(1, 0, 0)); + TopoDS_Vertex aV2 = BRepBuilderAPI_MakeVertex(gp_Pnt(2, 0, 0)); + + aBuilder.Add(aCompound, aV1); + aBuilder.Add(aCompound, aV2); + + // Iterate and check that TShape pointers match + TopoDS_Iterator anIt(aCompound); + EXPECT_TRUE(anIt.Value().TShape() == aV1.TShape() || anIt.Value().TShape() == aV2.TShape()); + anIt.Next(); + EXPECT_TRUE(anIt.Value().TShape() == aV1.TShape() || anIt.Value().TShape() == aV2.TShape()); +} + +//================================================================================================= +// Test iterator on shell with faces +//================================================================================================= + +TEST(TopoDS_Iterator_Test, ShellWithFaces) +{ + TopoDS_Shape aBox = BRepPrimAPI_MakeBox(1.0, 1.0, 1.0).Shape(); + + // Get shell from box + TopExp_Explorer anExp(aBox, TopAbs_SHELL); + ASSERT_TRUE(anExp.More()); + const TopoDS_Shell& aShell = TopoDS::Shell(anExp.Current()); + + // Iterate over shell's faces + int aFaceCount = 0; + for (TopoDS_Iterator anIt(aShell); anIt.More(); anIt.Next()) + { + EXPECT_EQ(anIt.Value().ShapeType(), TopAbs_FACE); + ++aFaceCount; + } + + EXPECT_EQ(aFaceCount, 6) << "Box shell should have 6 faces"; +} diff --git a/src/ModelingData/TKBRep/GTests/TopoDS_TShape_Test.cxx b/src/ModelingData/TKBRep/GTests/TopoDS_TShape_Test.cxx new file mode 100644 index 0000000000..e430cc89b8 --- /dev/null +++ b/src/ModelingData/TKBRep/GTests/TopoDS_TShape_Test.cxx @@ -0,0 +1,313 @@ +// Copyright (c) 2026 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//================================================================================================== +// Test TShape ShapeType() returns correct type for each shape kind +//================================================================================================== + +TEST(TopoDS_TShape_Test, ShapeType_AllTypes) +{ + TopoDS_Builder aBuilder; + + // Create various shapes and verify ShapeType + TopoDS_Vertex aVertex = BRepBuilderAPI_MakeVertex(gp_Pnt(0, 0, 0)); + EXPECT_EQ(aVertex.TShape()->ShapeType(), TopAbs_VERTEX); + + TopoDS_Edge anEdge = BRepBuilderAPI_MakeEdge(gp_Pnt(0, 0, 0), gp_Pnt(1, 0, 0)); + EXPECT_EQ(anEdge.TShape()->ShapeType(), TopAbs_EDGE); + + TopoDS_Wire aWire; + aBuilder.MakeWire(aWire); + EXPECT_EQ(aWire.TShape()->ShapeType(), TopAbs_WIRE); + + TopoDS_Shell aShell; + aBuilder.MakeShell(aShell); + EXPECT_EQ(aShell.TShape()->ShapeType(), TopAbs_SHELL); + + TopoDS_Solid aSolid; + aBuilder.MakeSolid(aSolid); + EXPECT_EQ(aSolid.TShape()->ShapeType(), TopAbs_SOLID); + + TopoDS_CompSolid aCompSolid; + aBuilder.MakeCompSolid(aCompSolid); + EXPECT_EQ(aCompSolid.TShape()->ShapeType(), TopAbs_COMPSOLID); + + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + EXPECT_EQ(aCompound.TShape()->ShapeType(), TopAbs_COMPOUND); +} + +//================================================================================================== +// Test TShape flag setters and getters +//================================================================================================== + +TEST(TopoDS_TShape_Test, FlagSettersGetters) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + + TopoDS_TShape* aTShape = aCompound.TShape().get(); + + // Test Free flag + EXPECT_TRUE(aTShape->Free()); + aTShape->Free(false); + EXPECT_FALSE(aTShape->Free()); + aTShape->Free(true); + EXPECT_TRUE(aTShape->Free()); + + // Test Modified flag + EXPECT_TRUE(aTShape->Modified()); + aTShape->Modified(false); + EXPECT_FALSE(aTShape->Modified()); + + // Test Checked flag + EXPECT_FALSE(aTShape->Checked()); + aTShape->Checked(true); + EXPECT_TRUE(aTShape->Checked()); + + // Test that setting Modified(true) clears Checked + aTShape->Modified(true); + EXPECT_FALSE(aTShape->Checked()) << "Modified(true) should clear Checked flag"; + + // Test Orientable flag + EXPECT_FALSE(aTShape->Orientable()) << "Compound should not be orientable"; + + // Test Closed flag + EXPECT_FALSE(aTShape->Closed()); + aTShape->Closed(true); + EXPECT_TRUE(aTShape->Closed()); + + // Test Infinite flag + EXPECT_FALSE(aTShape->Infinite()); + aTShape->Infinite(true); + EXPECT_TRUE(aTShape->Infinite()); + + // Test Convex flag + EXPECT_FALSE(aTShape->Convex()); + aTShape->Convex(true); + EXPECT_TRUE(aTShape->Convex()); + + // Test Locked flag + EXPECT_FALSE(aTShape->Locked()); + aTShape->Locked(true); + EXPECT_TRUE(aTShape->Locked()); +} + +//================================================================================================== +// Test TShape NbChildren() for various shapes +//================================================================================================== + +TEST(TopoDS_TShape_Test, NbChildren) +{ + TopoDS_Builder aBuilder; + + // Vertex has 0 children + TopoDS_Vertex aVertex = BRepBuilderAPI_MakeVertex(gp_Pnt(0, 0, 0)); + EXPECT_EQ(aVertex.TShape()->NbChildren(), 0); + + // Edge has 2 children (vertices) + TopoDS_Edge anEdge = BRepBuilderAPI_MakeEdge(gp_Pnt(0, 0, 0), gp_Pnt(1, 0, 0)); + EXPECT_EQ(anEdge.TShape()->NbChildren(), 2); + + // Empty wire has 0 children + TopoDS_Wire aWire; + aBuilder.MakeWire(aWire); + EXPECT_EQ(aWire.TShape()->NbChildren(), 0); + + // Wire with edges + aBuilder.Add(aWire, anEdge); + EXPECT_EQ(aWire.TShape()->NbChildren(), 1); + + // Compound with multiple children + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + for (int i = 0; i < 10; ++i) + { + aBuilder.Add(aCompound, BRepBuilderAPI_MakeVertex(gp_Pnt(i, 0, 0))); + } + EXPECT_EQ(aCompound.TShape()->NbChildren(), 10); +} + +//================================================================================================== +// Test TShape EmptyCopy creates same type with no children +//================================================================================================== + +TEST(TopoDS_TShape_Test, EmptyCopy) +{ + TopoDS_Builder aBuilder; + + // Create compound with children + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + aBuilder.Add(aCompound, BRepBuilderAPI_MakeVertex(gp_Pnt(0, 0, 0))); + aBuilder.Add(aCompound, BRepBuilderAPI_MakeVertex(gp_Pnt(1, 0, 0))); + + EXPECT_EQ(aCompound.TShape()->NbChildren(), 2); + + // EmptyCopy should create same type with no children + occ::handle aCopy = aCompound.TShape()->EmptyCopy(); + + EXPECT_EQ(aCopy->ShapeType(), TopAbs_COMPOUND); + EXPECT_EQ(aCopy->NbChildren(), 0) << "EmptyCopy should have no children"; +} + +//================================================================================================== +// Test TShape EmptyCopy for all shape types +//================================================================================================== + +TEST(TopoDS_TShape_Test, EmptyCopy_AllTypes) +{ + TopoDS_Builder aBuilder; + + // Test Edge EmptyCopy + { + TopoDS_Edge anEdge = BRepBuilderAPI_MakeEdge(gp_Pnt(0, 0, 0), gp_Pnt(1, 0, 0)); + occ::handle aCopy = anEdge.TShape()->EmptyCopy(); + EXPECT_EQ(aCopy->ShapeType(), TopAbs_EDGE); + EXPECT_EQ(aCopy->NbChildren(), 0); + } + + // Test Wire EmptyCopy + { + TopoDS_Wire aWire; + aBuilder.MakeWire(aWire); + occ::handle aCopy = aWire.TShape()->EmptyCopy(); + EXPECT_EQ(aCopy->ShapeType(), TopAbs_WIRE); + } + + // Test Shell EmptyCopy + { + TopoDS_Shell aShell; + aBuilder.MakeShell(aShell); + occ::handle aCopy = aShell.TShape()->EmptyCopy(); + EXPECT_EQ(aCopy->ShapeType(), TopAbs_SHELL); + } + + // Test Solid EmptyCopy + { + TopoDS_Solid aSolid; + aBuilder.MakeSolid(aSolid); + occ::handle aCopy = aSolid.TShape()->EmptyCopy(); + EXPECT_EQ(aCopy->ShapeType(), TopAbs_SOLID); + } + + // Test CompSolid EmptyCopy + { + TopoDS_CompSolid aCompSolid; + aBuilder.MakeCompSolid(aCompSolid); + occ::handle aCopy = aCompSolid.TShape()->EmptyCopy(); + EXPECT_EQ(aCopy->ShapeType(), TopAbs_COMPSOLID); + } +} + +//================================================================================================== +// Test TShape Orientable flag for different shape types +//================================================================================================== + +TEST(TopoDS_TShape_Test, Orientable_DifferentTypes) +{ + TopoDS_Builder aBuilder; + + // Edge should be orientable + TopoDS_Edge anEdge = BRepBuilderAPI_MakeEdge(gp_Pnt(0, 0, 0), gp_Pnt(1, 0, 0)); + EXPECT_TRUE(anEdge.TShape()->Orientable()) << "Edge should be orientable"; + + // Compound should not be orientable + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + EXPECT_FALSE(aCompound.TShape()->Orientable()) << "Compound should not be orientable"; + + // Wire should be orientable + TopoDS_Wire aWire; + aBuilder.MakeWire(aWire); + EXPECT_TRUE(aWire.TShape()->Orientable()) << "Wire should be orientable"; +} + +//================================================================================================== +// Test TShape flags are independent +//================================================================================================== + +TEST(TopoDS_TShape_Test, FlagsIndependent) +{ + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + + TopoDS_TShape* aTShape = aCompound.TShape().get(); + + // Set all flags + aTShape->Closed(true); + aTShape->Infinite(true); + aTShape->Convex(true); + aTShape->Locked(true); + + // Verify all are set + EXPECT_TRUE(aTShape->Closed()); + EXPECT_TRUE(aTShape->Infinite()); + EXPECT_TRUE(aTShape->Convex()); + EXPECT_TRUE(aTShape->Locked()); + + // Clear one flag, others should remain + aTShape->Closed(false); + EXPECT_FALSE(aTShape->Closed()); + EXPECT_TRUE(aTShape->Infinite()) << "Clearing Closed should not affect Infinite"; + EXPECT_TRUE(aTShape->Convex()) << "Clearing Closed should not affect Convex"; + EXPECT_TRUE(aTShape->Locked()) << "Clearing Closed should not affect Locked"; +} + +//================================================================================================== +// Test NbChildren consistency with iterator +//================================================================================================== + +TEST(TopoDS_TShape_Test, NbChildren_ConsistencyWithIterator) +{ + TopoDS_Builder aBuilder; + + // Create wire with edge + TopoDS_Wire aWire; + aBuilder.MakeWire(aWire); + TopoDS_Edge anEdge = BRepBuilderAPI_MakeEdge(gp_Pnt(0, 0, 0), gp_Pnt(1, 0, 0)); + aBuilder.Add(aWire, anEdge); + + // Get NbChildren via TShape + int aNbViaTShape = aWire.TShape()->NbChildren(); + + // Count via iterator + int aNbViaIterator = 0; + for (TopoDS_Iterator anIt(aWire); anIt.More(); anIt.Next()) + { + ++aNbViaIterator; + } + + EXPECT_EQ(aNbViaTShape, aNbViaIterator) << "NbChildren should match iterator count"; + EXPECT_EQ(aNbViaTShape, 1); +} diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_Builder.cxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_Builder.cxx index d4db393966..95831adb65 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_Builder.cxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_Builder.cxx @@ -22,12 +22,9 @@ #include #include #include -class TopoDS_Shape; -//======================================================================= -// function : MakeShape -// purpose : Make a Shape from a TShape -//======================================================================= +//================================================================================================== + void TopoDS_Builder::MakeShape(TopoDS_Shape& S, const occ::handle& T) const { S.TShape(T); @@ -35,10 +32,7 @@ void TopoDS_Builder::MakeShape(TopoDS_Shape& S, const occ::handle S.Orientation(TopAbs_FORWARD); } -//======================================================================= -// function : Add -// purpose : insert aComponent in aShape -//======================================================================= +//================================================================================================== void TopoDS_Builder::Add(TopoDS_Shape& aShape, const TopoDS_Shape& aComponent) const { @@ -71,27 +65,27 @@ void TopoDS_Builder::Add(TopoDS_Shape& aShape, const TopoDS_Shape& aComponent) c | (1 << ((unsigned int)TopAbs_FACE)) | (1 << ((unsigned int)TopAbs_EDGE)), // SHAPE to: 0}; - // + const unsigned int iC = (unsigned int)aComponent.ShapeType(); const unsigned int iS = (unsigned int)aShape.ShapeType(); - // + if ((aTb[iC] & (1 << iS)) != 0) { - NCollection_List& L = aShape.TShape()->myShapes; - L.Append(aComponent); - TopoDS_Shape& S = L.Last(); - // + TopoDS_Shape aChild = aComponent; + // compute the relative Orientation if (aShape.Orientation() == TopAbs_REVERSED) - S.Reverse(); - // + aChild.Reverse(); + // and the Relative Location const TopLoc_Location& aLoc = aShape.Location(); if (!aLoc.IsIdentity()) - S.Move(aLoc.Inverted(), false); - // - // Set the TShape as modified. - aShape.TShape()->Modified(true); + aChild.Move(aLoc.Inverted(), false); + + // Add to the subshapes list + TopoDS_TShape* aTShape = aShape.TShape().get(); + aTShape->myShapes.Append(aChild); + aTShape->Modified(true); } else { @@ -104,14 +98,11 @@ void TopoDS_Builder::Add(TopoDS_Shape& aShape, const TopoDS_Shape& aComponent) c } } -//======================================================================= -// function : Remove -// purpose : Remove a Shape from an other one -//======================================================================= +//================================================================================================== void TopoDS_Builder::Remove(TopoDS_Shape& aShape, const TopoDS_Shape& aComponent) const { - // check if aShape is not Frozen + // check if aShape is not Frozen TopoDS_FrozenShape_Raise_if(!aShape.Free(), "TopoDS_Builder::Remove"); // compute the relative Orientation and Location of aComponent @@ -120,16 +111,18 @@ void TopoDS_Builder::Remove(TopoDS_Shape& aShape, const TopoDS_Shape& aComponent S.Reverse(); S.Location(S.Location().Predivided(aShape.Location()), false); - NCollection_List& L = aShape.TShape()->myShapes; - NCollection_List::Iterator It(L); - while (It.More()) + TopoDS_TShape* aTShape = aShape.TShape().get(); + NCollection_List& aList = aTShape->myShapes; + NCollection_List::Iterator anIter(aList); + + while (anIter.More()) { - if (It.Value() == S) + if (anIter.Value() == S) { - L.Remove(It); - aShape.TShape()->Modified(true); - break; + aList.Remove(anIter); + aTShape->Modified(true); + return; } - It.Next(); + anIter.Next(); } } diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_Builder.lxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_Builder.lxx index 754ea14352..7c75377cce 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_Builder.lxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_Builder.lxx @@ -25,7 +25,7 @@ #include #include -//================================================================================================= +//================================================================================================== inline void TopoDS_Builder::MakeWire(TopoDS_Wire& W) const { @@ -33,7 +33,7 @@ inline void TopoDS_Builder::MakeWire(TopoDS_Wire& W) const MakeShape(W, TW); } -//================================================================================================= +//================================================================================================== inline void TopoDS_Builder::MakeShell(TopoDS_Shell& S) const { @@ -41,7 +41,7 @@ inline void TopoDS_Builder::MakeShell(TopoDS_Shell& S) const MakeShape(S, TS); } -//================================================================================================= +//================================================================================================== inline void TopoDS_Builder::MakeSolid(TopoDS_Solid& S) const { @@ -49,10 +49,7 @@ inline void TopoDS_Builder::MakeSolid(TopoDS_Solid& S) const MakeShape(S, TS); } -//======================================================================= -// function : MakeCompSolid -// purpose : Make an empty CompSolid -//======================================================================= +//================================================================================================== inline void TopoDS_Builder::MakeCompSolid(TopoDS_CompSolid& C) const { @@ -60,10 +57,7 @@ inline void TopoDS_Builder::MakeCompSolid(TopoDS_CompSolid& C) const MakeShape(C, TC); } -//======================================================================= -// function : MakeCompound -// purpose : Make an empty Compound -//======================================================================= +//================================================================================================== inline void TopoDS_Builder::MakeCompound(TopoDS_Compound& C) const { diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_Iterator.cxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_Iterator.cxx index a7b775793a..7eadde4b25 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_Iterator.cxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_Iterator.cxx @@ -17,8 +17,9 @@ #define No_Standard_NoSuchObject #include +#include -//================================================================================================= +//================================================================================================== void TopoDS_Iterator::Initialize(const TopoDS_Shape& S, const bool cumOri, const bool cumLoc) { @@ -26,35 +27,44 @@ void TopoDS_Iterator::Initialize(const TopoDS_Shape& S, const bool cumOri, const myLocation = S.Location(); else myLocation.Identity(); + if (cumOri) myOrientation = S.Orientation(); else myOrientation = TopAbs_FORWARD; if (S.IsNull()) - myShapes = NCollection_List::Iterator(); + { + myIterator = NCollection_List::Iterator(); + } else - myShapes.Initialize(S.TShape()->myShapes); + { + myIterator.Init(S.TShape()->myShapes); + } if (More()) { - myShape = myShapes.Value(); - myShape.Orientation(TopAbs::Compose(myOrientation, myShape.Orientation())); - if (!myLocation.IsIdentity()) - myShape.Move(myLocation, false); + updateCurrentShape(); } } -//================================================================================================= +//================================================================================================== void TopoDS_Iterator::Next() { - myShapes.Next(); + myIterator.Next(); if (More()) { - myShape = myShapes.Value(); - myShape.Orientation(TopAbs::Compose(myOrientation, myShape.Orientation())); - if (!myLocation.IsIdentity()) - myShape.Move(myLocation, false); + updateCurrentShape(); } } + +//================================================================================================== + +void TopoDS_Iterator::updateCurrentShape() +{ + myShape = myIterator.Value(); + myShape.Orientation(TopAbs::Compose(myOrientation, myShape.Orientation())); + if (!myLocation.IsIdentity()) + myShape.Move(myLocation, false); +} diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_Iterator.hxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_Iterator.hxx index 719f1c501e..ac832f988f 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_Iterator.hxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_Iterator.hxx @@ -18,11 +18,10 @@ #define _TopoDS_Iterator_HeaderFile #include -#include #include +#include #include #include -class TopoDS_Shape; //! Iterates on the underlying shape underlying a given //! TopoDS_Shape object, providing access to its @@ -48,6 +47,7 @@ public: //! sub-shapes by the location of S, i.e. it applies to //! each sub-shape the transformation that is associated with S. TopoDS_Iterator(const TopoDS_Shape& S, const bool cumOri = true, const bool cumLoc = true) + : myOrientation(TopAbs_FORWARD) { Initialize(S, cumOri, cumLoc); } @@ -65,7 +65,7 @@ public: //! Returns true if there is another sub-shape in the //! shape which this iterator is scanning. - bool More() const { return myShapes.More(); } + bool More() const { return myIterator.More(); } //! Moves on to the next sub-shape in the shape which //! this iterator is scanning. @@ -84,10 +84,14 @@ public: } private: - TopoDS_Shape myShape; - NCollection_List::Iterator myShapes; - TopAbs_Orientation myOrientation; - TopLoc_Location myLocation; + //! Updates myShape from the current iterator position. + void updateCurrentShape(); + +private: + TopoDS_Shape myShape; //!< Current composed sub-shape + NCollection_List::Iterator myIterator; //!< Iterator over child shapes list + TopAbs_Orientation myOrientation; //!< Cumulative orientation + TopLoc_Location myLocation; //!< Cumulative location }; #endif // _TopoDS_Iterator_HeaderFile diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_TCompSolid.cxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_TCompSolid.cxx index 0da554111b..1f1b12e815 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_TCompSolid.cxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_TCompSolid.cxx @@ -22,13 +22,6 @@ IMPLEMENT_STANDARD_RTTIEXT(TopoDS_TCompSolid, TopoDS_TShape) //================================================================================================= -TopAbs_ShapeEnum TopoDS_TCompSolid::ShapeType() const -{ - return TopAbs_COMPSOLID; -} - -//================================================================================================= - occ::handle TopoDS_TCompSolid::EmptyCopy() const { return occ::handle(new TopoDS_TCompSolid()); diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_TCompSolid.hxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_TCompSolid.hxx index bc5d7146c4..bc8233e607 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_TCompSolid.hxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_TCompSolid.hxx @@ -19,7 +19,6 @@ #include #include -#include #include //! A set of solids connected by their faces. @@ -28,11 +27,9 @@ class TopoDS_TCompSolid : public TopoDS_TShape public: //! Creates an empty TCompSolid. TopoDS_TCompSolid() - - = default; - - //! returns COMPSOLID - Standard_EXPORT TopAbs_ShapeEnum ShapeType() const override; + : TopoDS_TShape(TopAbs_COMPSOLID) + { + } //! Returns an empty TCompSolid. Standard_EXPORT occ::handle EmptyCopy() const override; diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_TCompound.cxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_TCompound.cxx index 607a090bf2..c9c1531652 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_TCompound.cxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_TCompound.cxx @@ -22,13 +22,6 @@ IMPLEMENT_STANDARD_RTTIEXT(TopoDS_TCompound, TopoDS_TShape) //================================================================================================= -TopAbs_ShapeEnum TopoDS_TCompound::ShapeType() const -{ - return TopAbs_COMPOUND; -} - -//================================================================================================= - occ::handle TopoDS_TCompound::EmptyCopy() const { return occ::handle(new TopoDS_TCompound()); diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_TCompound.hxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_TCompound.hxx index 5cb1ffd2c9..bf2620c393 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_TCompound.hxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_TCompound.hxx @@ -19,7 +19,6 @@ #include #include -#include #include //! A TCompound is an all-purpose set of Shapes. @@ -27,10 +26,11 @@ class TopoDS_TCompound : public TopoDS_TShape { public: //! Creates an empty TCompound. - TopoDS_TCompound() { Orientable(false); } - - //! Returns COMPOUND. - Standard_EXPORT TopAbs_ShapeEnum ShapeType() const override; + TopoDS_TCompound() + : TopoDS_TShape(TopAbs_COMPOUND) + { + Orientable(false); + } //! Returns an empty TCompound. Standard_EXPORT occ::handle EmptyCopy() const override; diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_TEdge.cxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_TEdge.cxx index f35471d86a..10c1b12479 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_TEdge.cxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_TEdge.cxx @@ -21,7 +21,7 @@ IMPLEMENT_STANDARD_RTTIEXT(TopoDS_TEdge, TopoDS_TShape) //================================================================================================= -TopAbs_ShapeEnum TopoDS_TEdge::ShapeType() const +occ::handle TopoDS_TEdge::EmptyCopy() const { - return TopAbs_EDGE; + return occ::handle(new TopoDS_TEdge()); } diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_TEdge.hxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_TEdge.hxx index f2ea188a0c..cb7b8d6b58 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_TEdge.hxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_TEdge.hxx @@ -18,8 +18,6 @@ #define _TopoDS_TEdge_HeaderFile #include - -#include #include //! A topological part of a curve in 2D or 3D, the @@ -27,14 +25,17 @@ class TopoDS_TEdge : public TopoDS_TShape { public: - //! Returns EDGE. - Standard_EXPORT TopAbs_ShapeEnum ShapeType() const override; + //! Returns an empty TEdge. + Standard_EXPORT occ::handle EmptyCopy() const override; DEFINE_STANDARD_RTTIEXT(TopoDS_TEdge, TopoDS_TShape) protected: //! Construct an edge. - TopoDS_TEdge() {} + TopoDS_TEdge() + : TopoDS_TShape(TopAbs_EDGE) + { + } }; #endif // _TopoDS_TEdge_HeaderFile diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_TFace.cxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_TFace.cxx index a1462875f0..01f828092c 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_TFace.cxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_TFace.cxx @@ -22,13 +22,6 @@ IMPLEMENT_STANDARD_RTTIEXT(TopoDS_TFace, TopoDS_TShape) //================================================================================================= -TopAbs_ShapeEnum TopoDS_TFace::ShapeType() const -{ - return TopAbs_FACE; -} - -//================================================================================================= - occ::handle TopoDS_TFace::EmptyCopy() const { return occ::handle(new TopoDS_TFace()); diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_TFace.hxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_TFace.hxx index f9df071d29..3fdedca79c 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_TFace.hxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_TFace.hxx @@ -19,22 +19,18 @@ #include #include -#include #include //! A topological part of a surface or of the 2D -//! space. The boundary is a set of wires and -//! vertices. +//! space. The boundary is a set of wires and vertices. class TopoDS_TFace : public TopoDS_TShape { public: //! Creates an empty TFace. TopoDS_TFace() - - = default; - - //! returns FACE. - Standard_EXPORT TopAbs_ShapeEnum ShapeType() const override; + : TopoDS_TShape(TopAbs_FACE) + { + } //! Returns an empty TFace. Standard_EXPORT occ::handle EmptyCopy() const override; diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_TShape.cxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_TShape.cxx index bd243e74b2..a3f5126def 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_TShape.cxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_TShape.cxx @@ -32,9 +32,7 @@ void TopoDS_TShape::DumpJson(Standard_OStream& theOStream, int) const OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, ShapeType()) OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, NbChildren()) - OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, myFlags) - - OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, Free()) + OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, myState) OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, Free()) OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, Locked()) diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_TShape.hxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_TShape.hxx index 2faed7a7b9..0c67faac18 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_TShape.hxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_TShape.hxx @@ -17,9 +17,15 @@ #ifndef _TopoDS_TShape_HeaderFile #define _TopoDS_TShape_HeaderFile +#include +#include +#include +#include + +#include #include #include -#include + class TopoDS_Shape; // resolve name collisions with X11 headers @@ -37,7 +43,7 @@ class TopoDS_Shape; //! TShapes are defined by their optional domain //! (geometry) and their components (other TShapes //! with Locations and Orientations). The components -//! are stored in a List of Shapes. +//! are stored in a list in the base class. //! //! A TShape contains the following boolean flags: //! @@ -48,77 +54,97 @@ class TopoDS_Shape; //! - Closed : Is closed (note that only Wires and Shells may be closed). //! - Infinite : Is infinite. //! - Convex : Is convex. +//! - Locked : Is locked against modifications. //! //! Users have no direct access to the classes derived //! from TShape. They handle them with the classes //! derived from Shape. class TopoDS_TShape : public Standard_Transient { +public: + //! Bit layout for compact state storage. + //! Bits 0-3 store the TopAbs_ShapeEnum value (0-8). + //! Bits 4-11 store boolean flags. + //! Bits 12-15 are reserved for future use. + enum BitLayout : uint16_t + { + Bits_ShapeType_Mask = 0x000F, //!< bits 0-3: shape type mask + Bits_ShapeType_Shift = 0, //!< shift for shape type + Bit_Free = 0x0010, //!< bit 4: free flag + Bit_Modified = 0x0020, //!< bit 5: modified flag + Bit_Checked = 0x0040, //!< bit 6: checked flag + Bit_Orientable = 0x0080, //!< bit 7: orientable flag + Bit_Closed = 0x0100, //!< bit 8: closed flag + Bit_Infinite = 0x0200, //!< bit 9: infinite flag + Bit_Convex = 0x0400, //!< bit 10: convex flag + Bit_Locked = 0x0800, //!< bit 11: locked flag + Bits_Reserved = 0xF000 //!< bits 12-15: reserved + }; public: //! Returns the free flag. - bool Free() const { return ((myFlags & TopoDS_TShape_Flags_Free) != 0); } + bool Free() const { return (myState & Bit_Free) != 0; } //! Sets the free flag. - void Free(bool theIsFree) { setFlag(TopoDS_TShape_Flags_Free, theIsFree); } + void Free(bool theIsFree) { setBit(Bit_Free, theIsFree); } //! Returns the locked flag. - bool Locked() const { return ((myFlags & TopoDS_TShape_Flags_Locked) != 0); } + bool Locked() const { return (myState & Bit_Locked) != 0; } //! Sets the locked flag. - void Locked(bool theIsLocked) { setFlag(TopoDS_TShape_Flags_Locked, theIsLocked); } + void Locked(bool theIsLocked) { setBit(Bit_Locked, theIsLocked); } //! Returns the modification flag. - bool Modified() const { return ((myFlags & TopoDS_TShape_Flags_Modified) != 0); } + bool Modified() const { return (myState & Bit_Modified) != 0; } //! Sets the modification flag. void Modified(bool theIsModified) { - setFlag(TopoDS_TShape_Flags_Modified, theIsModified); + setBit(Bit_Modified, theIsModified); if (theIsModified) { - // clang-format off - setFlag (TopoDS_TShape_Flags_Checked, false); // when a TShape is modified it is also unchecked - // clang-format on + // when a TShape is modified it is also unchecked + setBit(Bit_Checked, false); } } //! Returns the checked flag. - bool Checked() const { return ((myFlags & TopoDS_TShape_Flags_Checked) != 0); } + bool Checked() const { return (myState & Bit_Checked) != 0; } //! Sets the checked flag. - void Checked(bool theIsChecked) { setFlag(TopoDS_TShape_Flags_Checked, theIsChecked); } + void Checked(bool theIsChecked) { setBit(Bit_Checked, theIsChecked); } //! Returns the orientability flag. - bool Orientable() const { return ((myFlags & TopoDS_TShape_Flags_Orientable) != 0); } + bool Orientable() const { return (myState & Bit_Orientable) != 0; } //! Sets the orientability flag. - void Orientable(bool theIsOrientable) - { - setFlag(TopoDS_TShape_Flags_Orientable, theIsOrientable); - } + void Orientable(bool theIsOrientable) { setBit(Bit_Orientable, theIsOrientable); } //! Returns the closedness flag. - bool Closed() const { return ((myFlags & TopoDS_TShape_Flags_Closed) != 0); } + bool Closed() const { return (myState & Bit_Closed) != 0; } //! Sets the closedness flag. - void Closed(bool theIsClosed) { setFlag(TopoDS_TShape_Flags_Closed, theIsClosed); } + void Closed(bool theIsClosed) { setBit(Bit_Closed, theIsClosed); } //! Returns the infinity flag. - bool Infinite() const { return ((myFlags & TopoDS_TShape_Flags_Infinite) != 0); } + bool Infinite() const { return (myState & Bit_Infinite) != 0; } //! Sets the infinity flag. - void Infinite(bool theIsInfinite) { setFlag(TopoDS_TShape_Flags_Infinite, theIsInfinite); } + void Infinite(bool theIsInfinite) { setBit(Bit_Infinite, theIsInfinite); } //! Returns the convexness flag. - bool Convex() const { return ((myFlags & TopoDS_TShape_Flags_Convex) != 0); } + bool Convex() const { return (myState & Bit_Convex) != 0; } //! Sets the convexness flag. - void Convex(bool theIsConvex) { setFlag(TopoDS_TShape_Flags_Convex, theIsConvex); } + void Convex(bool theIsConvex) { setBit(Bit_Convex, theIsConvex); } - //! Returns the type as a term of the ShapeEnum enum : - //! VERTEX, EDGE, WIRE, FACE, .... - Standard_EXPORT virtual TopAbs_ShapeEnum ShapeType() const = 0; + //! Returns the type as a term of the ShapeEnum enum: + //! VERTEX, EDGE, WIRE, FACE, SHELL, SOLID, COMPSOLID, COMPOUND. + //! The type is embedded in the lower 4 bits of the state. + TopAbs_ShapeEnum ShapeType() const + { + return static_cast(myState & Bits_ShapeType_Mask); + } //! Returns a copy of the TShape with no sub-shapes. Standard_EXPORT virtual occ::handle EmptyCopy() const = 0; @@ -136,46 +162,28 @@ public: DEFINE_STANDARD_RTTIEXT(TopoDS_TShape, Standard_Transient) protected: - //! Constructs an empty TShape. - //! Free : True - //! Modified : True - //! Checked : False - //! Orientable : True - //! Closed : False - //! Infinite : False - //! Convex : False - TopoDS_TShape() - : myFlags(TopoDS_TShape_Flags_Free | TopoDS_TShape_Flags_Modified - | TopoDS_TShape_Flags_Orientable) + //! Constructs a TShape with the given shape type. + //! Default flags: Free = true, Modified = true, Orientable = true. + //! @param theType the shape type to embed in the state + TopoDS_TShape(TopAbs_ShapeEnum theType) + : myState(static_cast(theType) | Bit_Free | Bit_Modified | Bit_Orientable) { } -private: - // Defined mask values - enum TopoDS_TShape_Flags - { - TopoDS_TShape_Flags_Free = 0x001, - TopoDS_TShape_Flags_Modified = 0x002, - TopoDS_TShape_Flags_Checked = 0x004, - TopoDS_TShape_Flags_Orientable = 0x008, - TopoDS_TShape_Flags_Closed = 0x010, - TopoDS_TShape_Flags_Infinite = 0x020, - TopoDS_TShape_Flags_Convex = 0x040, - TopoDS_TShape_Flags_Locked = 0x080 - }; - - //! Set bit flag. - void setFlag(TopoDS_TShape_Flags theFlag, bool theIsOn) + //! Set a bit flag. + //! @param theBit the bit to set + //! @param theIsOn true to set, false to clear + void setBit(uint16_t theBit, bool theIsOn) { if (theIsOn) - myFlags |= (int)theFlag; + myState |= theBit; else - myFlags &= ~(int)theFlag; + myState &= ~theBit; } private: - NCollection_List myShapes; - int myFlags; + NCollection_List myShapes; //!< Child shapes stored in a list + uint16_t myState; //!< Compact state: shape type(bits 0-3)+flags(bits 4-11)+reserved(bits 12-15) }; #endif // _TopoDS_TShape_HeaderFile diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_TShell.cxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_TShell.cxx index 5243d73a83..574e982118 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_TShell.cxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_TShell.cxx @@ -22,13 +22,6 @@ IMPLEMENT_STANDARD_RTTIEXT(TopoDS_TShell, TopoDS_TShape) //================================================================================================= -TopAbs_ShapeEnum TopoDS_TShell::ShapeType() const -{ - return TopAbs_SHELL; -} - -//================================================================================================= - occ::handle TopoDS_TShell::EmptyCopy() const { return occ::handle(new TopoDS_TShell()); diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_TShell.hxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_TShell.hxx index 9c918df6ed..0d745aee1a 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_TShell.hxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_TShell.hxx @@ -19,7 +19,6 @@ #include #include -#include #include //! A set of faces connected by their edges. @@ -28,11 +27,9 @@ class TopoDS_TShell : public TopoDS_TShape public: //! Creates an empty TShell. TopoDS_TShell() - - = default; - - //! Returns SHELL. - Standard_EXPORT TopAbs_ShapeEnum ShapeType() const override; + : TopoDS_TShape(TopAbs_SHELL) + { + } //! Returns an empty TShell. Standard_EXPORT occ::handle EmptyCopy() const override; diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_TSolid.cxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_TSolid.cxx index 8b7a6ea850..aba90d75a9 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_TSolid.cxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_TSolid.cxx @@ -22,13 +22,6 @@ IMPLEMENT_STANDARD_RTTIEXT(TopoDS_TSolid, TopoDS_TShape) //================================================================================================= -TopAbs_ShapeEnum TopoDS_TSolid::ShapeType() const -{ - return TopAbs_SOLID; -} - -//================================================================================================= - occ::handle TopoDS_TSolid::EmptyCopy() const { return occ::handle(new TopoDS_TSolid()); diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_TSolid.hxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_TSolid.hxx index 2bb12e3b90..8b308fb18c 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_TSolid.hxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_TSolid.hxx @@ -19,7 +19,6 @@ #include #include -#include #include //! A Topological part of 3D space, bounded by shells, @@ -28,10 +27,11 @@ class TopoDS_TSolid : public TopoDS_TShape { public: //! Creates an empty TSolid. - TopoDS_TSolid() { Orientable(false); } - - //! returns SOLID. - Standard_EXPORT TopAbs_ShapeEnum ShapeType() const override; + TopoDS_TSolid() + : TopoDS_TShape(TopAbs_SOLID) + { + Orientable(false); + } //! Returns an empty TSolid. Standard_EXPORT occ::handle EmptyCopy() const override; diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_TVertex.cxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_TVertex.cxx index e38a6a6702..7a3a0c0e1e 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_TVertex.cxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_TVertex.cxx @@ -18,10 +18,3 @@ #include IMPLEMENT_STANDARD_RTTIEXT(TopoDS_TVertex, TopoDS_TShape) - -//================================================================================================= - -TopAbs_ShapeEnum TopoDS_TVertex::ShapeType() const -{ - return TopAbs_VERTEX; -} diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_TVertex.hxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_TVertex.hxx index e9465f2033..142ba2e9df 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_TVertex.hxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_TVertex.hxx @@ -18,7 +18,6 @@ #define _TopoDS_TVertex_HeaderFile #include -#include #include // resolve name collisions with X11 headers @@ -27,18 +26,16 @@ #endif //! A Vertex is a topological point in two or three dimensions. +//! TVertex has no children (sub-shapes). class TopoDS_TVertex : public TopoDS_TShape { public: - //! Returns VERTEX. - Standard_EXPORT TopAbs_ShapeEnum ShapeType() const override; - DEFINE_STANDARD_RTTIEXT(TopoDS_TVertex, TopoDS_TShape) protected: //! Construct a vertex. TopoDS_TVertex() - + : TopoDS_TShape(TopAbs_VERTEX) { Closed(true); Convex(true); diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_TWire.cxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_TWire.cxx index 4c9f34c2ab..5763753557 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_TWire.cxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_TWire.cxx @@ -22,13 +22,6 @@ IMPLEMENT_STANDARD_RTTIEXT(TopoDS_TWire, TopoDS_TShape) //================================================================================================= -TopAbs_ShapeEnum TopoDS_TWire::ShapeType() const -{ - return TopAbs_WIRE; -} - -//================================================================================================= - occ::handle TopoDS_TWire::EmptyCopy() const { return occ::handle(new TopoDS_TWire()); diff --git a/src/ModelingData/TKBRep/TopoDS/TopoDS_TWire.hxx b/src/ModelingData/TKBRep/TopoDS/TopoDS_TWire.hxx index 968b8b7627..a398afe031 100644 --- a/src/ModelingData/TKBRep/TopoDS/TopoDS_TWire.hxx +++ b/src/ModelingData/TKBRep/TopoDS/TopoDS_TWire.hxx @@ -19,7 +19,6 @@ #include #include -#include #include //! A set of edges connected by their vertices. @@ -28,11 +27,9 @@ class TopoDS_TWire : public TopoDS_TShape public: //! Creates an empty TWire. TopoDS_TWire() - - = default; - - //! Returns WIRE. - Standard_EXPORT TopAbs_ShapeEnum ShapeType() const override; + : TopoDS_TShape(TopAbs_WIRE) + { + } //! Returns an empty TWire. Standard_EXPORT occ::handle EmptyCopy() const override; diff --git a/src/ModelingData/TKG3d/TopAbs/TopAbs.cxx b/src/ModelingData/TKG3d/TopAbs/TopAbs.cxx index 9a1d820038..a9e5ba038b 100644 --- a/src/ModelingData/TKG3d/TopAbs/TopAbs.cxx +++ b/src/ModelingData/TKG3d/TopAbs/TopAbs.cxx @@ -80,49 +80,6 @@ bool TopAbs::ShapeOrientationFromString(const char* const theOrientationString return false; } -//======================================================================= -// function : TopAbs_Compose -// purpose : Compose two orientations -//======================================================================= -TopAbs_Orientation TopAbs::Compose(const TopAbs_Orientation O1, const TopAbs_Orientation O2) -{ - // see the composition table in the file TopAbs.cdl - static const TopAbs_Orientation TopAbs_Table_Compose[4][4] = { - {TopAbs_FORWARD, TopAbs_REVERSED, TopAbs_INTERNAL, TopAbs_EXTERNAL}, - {TopAbs_REVERSED, TopAbs_FORWARD, TopAbs_INTERNAL, TopAbs_EXTERNAL}, - {TopAbs_INTERNAL, TopAbs_INTERNAL, TopAbs_INTERNAL, TopAbs_INTERNAL}, - {TopAbs_EXTERNAL, TopAbs_EXTERNAL, TopAbs_EXTERNAL, TopAbs_EXTERNAL}}; - return TopAbs_Table_Compose[(int)O2][(int)O1]; -} - -//======================================================================= -// function : TopAbs::Reverse -// purpose : reverse an Orientation -//======================================================================= - -TopAbs_Orientation TopAbs::Reverse(const TopAbs_Orientation Ori) -{ - static const TopAbs_Orientation TopAbs_Table_Reverse[4] = {TopAbs_REVERSED, - TopAbs_FORWARD, - TopAbs_INTERNAL, - TopAbs_EXTERNAL}; - return TopAbs_Table_Reverse[(int)Ori]; -} - -//======================================================================= -// function : TopAbs::Complement -// purpose : complement an Orientation -//======================================================================= - -TopAbs_Orientation TopAbs::Complement(const TopAbs_Orientation Ori) -{ - static const TopAbs_Orientation TopAbs_Table_Complement[4] = {TopAbs_REVERSED, - TopAbs_FORWARD, - TopAbs_EXTERNAL, - TopAbs_INTERNAL}; - return TopAbs_Table_Complement[(int)Ori]; -} - //======================================================================= // function : TopAbs_Print // purpose : print the name of a State on a stream. diff --git a/src/ModelingData/TKG3d/TopAbs/TopAbs.hxx b/src/ModelingData/TKG3d/TopAbs/TopAbs.hxx index f181286415..a12f63638f 100644 --- a/src/ModelingData/TKG3d/TopAbs/TopAbs.hxx +++ b/src/ModelingData/TKG3d/TopAbs/TopAbs.hxx @@ -66,10 +66,18 @@ public: //! EXTERNAL | EXTERNAL EXTERNAL EXTERNAL EXTERNAL //! Note: The top corner in the table is the most important //! for the purposes of Open CASCADE topology and shape sharing. - Standard_EXPORT static TopAbs_Orientation Compose(const TopAbs_Orientation Or1, - const TopAbs_Orientation Or2); + static TopAbs_Orientation Compose(const TopAbs_Orientation Or1, + const TopAbs_Orientation Or2) noexcept + { + static constexpr TopAbs_Orientation aTable[4][4] = { + {TopAbs_FORWARD, TopAbs_REVERSED, TopAbs_INTERNAL, TopAbs_EXTERNAL}, + {TopAbs_REVERSED, TopAbs_FORWARD, TopAbs_INTERNAL, TopAbs_EXTERNAL}, + {TopAbs_INTERNAL, TopAbs_INTERNAL, TopAbs_INTERNAL, TopAbs_INTERNAL}, + {TopAbs_EXTERNAL, TopAbs_EXTERNAL, TopAbs_EXTERNAL, TopAbs_EXTERNAL}}; + return aTable[static_cast(Or2)][static_cast(Or1)]; + } - //! xchanges the interior/exterior status of the two + //! Exchanges the interior/exterior status of the two //! sides. This is what happens when the sense of //! direction is reversed. The following rules apply: //! @@ -79,7 +87,14 @@ public: //! EXTERNAL EXTERNAL //! //! Reverse exchange the material sides. - Standard_EXPORT static TopAbs_Orientation Reverse(const TopAbs_Orientation Or); + static TopAbs_Orientation Reverse(const TopAbs_Orientation Or) noexcept + { + static constexpr TopAbs_Orientation aTable[4] = {TopAbs_REVERSED, + TopAbs_FORWARD, + TopAbs_INTERNAL, + TopAbs_EXTERNAL}; + return aTable[static_cast(Or)]; + } //! Reverses the interior/exterior status of each side of //! the object. So, to take the complement of an object @@ -94,7 +109,14 @@ public: //! //! Complement complements the material side. //! Inside becomes outside. - Standard_EXPORT static TopAbs_Orientation Complement(const TopAbs_Orientation Or); + static TopAbs_Orientation Complement(const TopAbs_Orientation Or) noexcept + { + static constexpr TopAbs_Orientation aTable[4] = {TopAbs_REVERSED, + TopAbs_FORWARD, + TopAbs_EXTERNAL, + TopAbs_INTERNAL}; + return aTable[static_cast(Or)]; + } //! Prints the name of Shape type as a String on the Stream. static Standard_OStream& Print(const TopAbs_ShapeEnum theShapeType, Standard_OStream& theStream)