Merge branch 'main' into bgbsww-toponamingMakeElementShape

This commit is contained in:
bgbsww
2024-01-28 11:19:11 -05:00
committed by GitHub
42 changed files with 2257 additions and 285 deletions

View File

@@ -15,6 +15,7 @@ target_sources(
${CMAKE_CURRENT_SOURCE_DIR}/TopoShape.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TopoShapeCache.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TopoShapeExpansion.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TopoShapeMakeShapeWithElementMap.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TopoShapeMapper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TopoShapeMakeShape.cpp
)

View File

@@ -1,5 +1,7 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
#include <BRepPrimAPI_MakeBox.hxx>
#include "PartTestHelpers.h"
// NOLINTBEGIN(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers)
@@ -89,6 +91,30 @@ void rectangle(double height, double width, char* name)
ExecutePython(rectstring);
}
std::tuple<TopoDS_Face, TopoDS_Wire, TopoDS_Edge, TopoDS_Edge, TopoDS_Edge, TopoDS_Edge>
CreateRectFace(float len, float wid)
{
auto edge1 = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(len, 0.0, 0.0)).Edge();
auto edge2 = BRepBuilderAPI_MakeEdge(gp_Pnt(len, 0.0, 0.0), gp_Pnt(len, wid, 0.0)).Edge();
auto edge3 = BRepBuilderAPI_MakeEdge(gp_Pnt(len, wid, 0.0), gp_Pnt(0.0, wid, 0.0)).Edge();
auto edge4 = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, wid, 0.0), gp_Pnt(0.0, 0.0, 0.0)).Edge();
auto wire1 = BRepBuilderAPI_MakeWire({edge1, edge2, edge3, edge4}).Wire();
auto face1 = BRepBuilderAPI_MakeFace(wire1).Face();
return {face1, wire1, edge1, edge2, edge3, edge4};
}
std::tuple<TopoDS_Face, TopoDS_Wire, TopoDS_Wire>
CreateFaceWithRoundHole(float len, float wid, float radius)
{
auto [face1, wire1, edge1, edge2, edge3, edge4] = CreateRectFace(len, wid);
auto circ1 =
GC_MakeCircle(gp_Pnt(len / 2.0, wid / 2.0, 0), gp_Dir(0.0, 0.0, 1.0), radius).Value();
auto edge5 = BRepBuilderAPI_MakeEdge(circ1).Edge();
auto wire2 = BRepBuilderAPI_MakeWire(edge5).Wire();
auto face2 = BRepBuilderAPI_MakeFace(face1, wire2).Face();
return {face2, wire1, wire2};
}
testing::AssertionResult
boxesMatch(const Base::BoundBox3d& b1, const Base::BoundBox3d& b2, double prec)
{
@@ -103,6 +129,32 @@ boxesMatch(const Base::BoundBox3d& b1, const Base::BoundBox3d& b2, double prec)
<< b2.MinY << "," << b2.MinZ << " ; " << b2.MaxX << "," << b2.MaxY << "," << b2.MaxZ << ")";
}
std::map<IndexedName, MappedName> elementMap(const TopoShape& shape)
{
std::map<IndexedName, MappedName> result {};
auto elements = shape.getElementMap();
for (auto const& entry : elements) {
result[entry.index] = entry.name;
}
return result;
}
std::pair<TopoDS_Shape, TopoDS_Shape> CreateTwoCubes()
{
auto boxMaker1 = BRepPrimAPI_MakeBox(1.0, 1.0, 1.0);
boxMaker1.Build();
auto box1 = boxMaker1.Shape();
auto boxMaker2 = BRepPrimAPI_MakeBox(1.0, 1.0, 1.0);
boxMaker2.Build();
auto box2 = boxMaker2.Shape();
auto transform = gp_Trsf();
transform.SetTranslation(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0));
box2.Location(TopLoc_Location(transform));
return {box1, box2};
}
} // namespace PartTestHelpers
// NOLINTEND(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers)

View File

@@ -10,10 +10,18 @@
#include "Mod/Part/App/FeaturePartFuse.h"
#include "Mod/Part/App/FeatureFillet.h"
#include <BRepGProp.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <GC_MakeCircle.hxx>
#include <TopoDS.hxx>
namespace PartTestHelpers
{
using namespace Data;
using namespace Part;
double getVolume(const TopoDS_Shape& shape);
double getArea(const TopoDS_Shape& shape);
@@ -38,6 +46,17 @@ void executePython(const std::vector<std::string>& python);
void rectangle(double height, double width, char* name);
std::tuple<TopoDS_Face, TopoDS_Wire, TopoDS_Edge, TopoDS_Edge, TopoDS_Edge, TopoDS_Edge>
CreateRectFace(float len = 2.0, float wid = 3.0);
std::tuple<TopoDS_Face, TopoDS_Wire, TopoDS_Wire>
CreateFaceWithRoundHole(float len = 2.0, float wid = 3.0, float radius = 1.0);
testing::AssertionResult
boxesMatch(const Base::BoundBox3d& b1, const Base::BoundBox3d& b2, double prec = 1e-05); // NOLINT
std::map<IndexedName, MappedName> elementMap(const TopoShape& shape);
std::pair<TopoDS_Shape, TopoDS_Shape> CreateTwoCubes();
} // namespace PartTestHelpers

View File

@@ -8,16 +8,15 @@
#include "PartTestHelpers.h"
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <GC_MakeCircle.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
// NOLINTBEGIN(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers)
using namespace PartTestHelpers;
class TopoShapeExpansionTest: public ::testing::Test
{
@@ -31,7 +30,6 @@ protected:
{
_docName = App::GetApplication().getUniqueDocumentName("test");
App::GetApplication().newDocument(_docName.c_str(), "testUser");
_sids = &_sid;
_hasher = Base::Reference<App::StringHasher>(new App::StringHasher);
ASSERT_EQ(_hasher.getRefCount(), 1);
}
@@ -45,7 +43,6 @@ protected:
private:
std::string _docName;
Data::ElementIDRefs _sid;
QVector<App::StringIDRef>* _sids = nullptr;
App::StringHasherRef _hasher;
};
@@ -125,26 +122,6 @@ TEST_F(TopoShapeExpansionTest, makeElementCompoundTwoShapesGeneratesMap)
EXPECT_EQ(4, topoShape.getMappedChildElements().size()); // two vertices and two edges
}
namespace
{
std::pair<TopoDS_Shape, TopoDS_Shape> CreateTwoCubes()
{
auto boxMaker1 = BRepPrimAPI_MakeBox(1.0, 1.0, 1.0);
boxMaker1.Build();
auto box1 = boxMaker1.Shape();
auto boxMaker2 = BRepPrimAPI_MakeBox(1.0, 1.0, 1.0);
boxMaker2.Build();
auto box2 = boxMaker2.Shape();
auto transform = gp_Trsf();
transform.SetTranslation(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0));
box2.Location(TopLoc_Location(transform));
return {box1, box2};
}
} // namespace
TEST_F(TopoShapeExpansionTest, makeElementCompoundTwoCubes)
{
// Arrange
@@ -169,42 +146,20 @@ TEST_F(TopoShapeExpansionTest, makeElementCompoundTwoCubes)
// 26 subshapes each
}
std::tuple<TopoDS_Face, TopoDS_Wire, TopoDS_Edge, TopoDS_Edge, TopoDS_Edge, TopoDS_Edge>
CreateRectFace(float len = 2.0, float wid = 3.0)
{
auto edge1 = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(len, 0.0, 0.0)).Edge();
auto edge2 = BRepBuilderAPI_MakeEdge(gp_Pnt(len, 0.0, 0.0), gp_Pnt(len, wid, 0.0)).Edge();
auto edge3 = BRepBuilderAPI_MakeEdge(gp_Pnt(len, wid, 0.0), gp_Pnt(0.0, wid, 0.0)).Edge();
auto edge4 = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, wid, 0.0), gp_Pnt(0.0, 0.0, 0.0)).Edge();
auto wire1 = BRepBuilderAPI_MakeWire({edge1, edge2, edge3, edge4}).Wire();
auto face1 = BRepBuilderAPI_MakeFace(wire1).Face();
return {face1, wire1, edge1, edge2, edge3, edge4};
}
std::tuple<TopoDS_Face, TopoDS_Wire, TopoDS_Wire>
CreateFaceWithRoundHole(float len = 2.0, float wid = 3.0, float radius = 1.0)
{
auto [face1, wire1, edge1, edge2, edge3, edge4] = CreateRectFace(len, wid);
auto circ1 =
GC_MakeCircle(gp_Pnt(len / 2.0, wid / 2.0, 0), gp_Dir(0.0, 0.0, 1.0), radius).Value();
auto edge5 = BRepBuilderAPI_MakeEdge(circ1).Edge();
auto wire2 = BRepBuilderAPI_MakeWire(edge5).Wire();
auto face2 = BRepBuilderAPI_MakeFace(face1, wire2).Face();
return {face2, wire1, wire2};
}
TEST_F(TopoShapeExpansionTest, makeElementFaceNull)
{
// Arrange
const double Len = 3, Wid = 2, Rad = 1;
const float Len = 3;
const float Wid = 2;
const float Rad = 1;
auto [face1, wire1, wire2] = CreateFaceWithRoundHole(Len, Wid, Rad);
Part::TopoShape topoShape {face1};
double area = PartTestHelpers::getArea(face1);
double area1 = PartTestHelpers::getArea(topoShape.getShape());
double area = getArea(face1);
double area1 = getArea(topoShape.getShape());
// Act
Part::TopoShape newFace = topoShape.makeElementFace(nullptr);
double area2 = PartTestHelpers::getArea(newFace.getShape());
double area3 = PartTestHelpers::getArea(topoShape.getShape());
double area2 = getArea(newFace.getShape());
double area3 = getArea(topoShape.getShape());
// Assert
EXPECT_FALSE(face1.IsEqual(newFace.getShape()));
EXPECT_FLOAT_EQ(area, Len * Wid + M_PI * Rad * Rad);
@@ -217,15 +172,17 @@ TEST_F(TopoShapeExpansionTest, makeElementFaceNull)
TEST_F(TopoShapeExpansionTest, makeElementFaceSimple)
{
// Arrange
const double Len = 3, Wid = 2, Rad = 1;
const float Len = 3;
const float Wid = 2;
const float Rad = 1;
auto [face1, wire1, wire2] = CreateFaceWithRoundHole(Len, Wid, Rad);
Part::TopoShape topoShape {face1};
double area = PartTestHelpers::getArea(face1);
double area1 = PartTestHelpers::getArea(topoShape.getShape());
double area = getArea(face1);
double area1 = getArea(topoShape.getShape());
// Act
Part::TopoShape newFace = topoShape.makeElementFace(wire1);
double area2 = PartTestHelpers::getArea(newFace.getShape());
double area3 = PartTestHelpers::getArea(topoShape.getShape());
double area2 = getArea(newFace.getShape());
double area3 = getArea(topoShape.getShape());
// Assert
EXPECT_TRUE(newFace.getShape().IsEqual(topoShape.getShape())); // topoShape was altered
EXPECT_FALSE(face1.IsEqual(newFace.getShape()));
@@ -239,16 +196,18 @@ TEST_F(TopoShapeExpansionTest, makeElementFaceSimple)
TEST_F(TopoShapeExpansionTest, makeElementFaceParams)
{
// Arrange
const double Len = 3, Wid = 2, Rad = 1;
const float Len = 3;
const float Wid = 2;
const float Rad = 1;
auto [face1, wire1, wire2] = CreateFaceWithRoundHole(Len, Wid, Rad);
Part::TopoShape topoShape {face1, 1L};
double area = PartTestHelpers::getArea(face1);
double area1 = PartTestHelpers::getArea(topoShape.getShape());
double area = getArea(face1);
double area1 = getArea(topoShape.getShape());
// Act
Part::TopoShape newFace =
topoShape.makeElementFace(wire1, "Cut", "Part::FaceMakerBullseye", nullptr);
double area2 = PartTestHelpers::getArea(newFace.getShape());
double area3 = PartTestHelpers::getArea(topoShape.getShape());
double area2 = getArea(newFace.getShape());
double area3 = getArea(topoShape.getShape());
// Assert
EXPECT_TRUE(newFace.getShape().IsEqual(topoShape.getShape())); // topoShape was altered
EXPECT_FALSE(face1.IsEqual(newFace.getShape()));
@@ -262,16 +221,18 @@ TEST_F(TopoShapeExpansionTest, makeElementFaceParams)
TEST_F(TopoShapeExpansionTest, makeElementFaceFromFace)
{
// Arrange
const double Len = 3, Wid = 2, Rad = 1;
const float Len = 3;
const float Wid = 2;
const float Rad = 1;
auto [face1, wire1, wire2] = CreateFaceWithRoundHole(Len, Wid, Rad);
Part::TopoShape topoShape {face1, 1L};
double area = PartTestHelpers::getArea(face1);
double area1 = PartTestHelpers::getArea(topoShape.getShape());
double area = getArea(face1);
double area1 = getArea(topoShape.getShape());
// Act
Part::TopoShape newFace =
topoShape.makeElementFace(face1, "Cut", "Part::FaceMakerBullseye", nullptr);
double area2 = PartTestHelpers::getArea(newFace.getShape());
double area3 = PartTestHelpers::getArea(topoShape.getShape());
double area2 = getArea(newFace.getShape());
double area3 = getArea(topoShape.getShape());
// Assert
EXPECT_TRUE(newFace.getShape().IsEqual(topoShape.getShape())); // topoShape was altered
EXPECT_FALSE(face1.IsEqual(newFace.getShape()));
@@ -286,15 +247,17 @@ TEST_F(TopoShapeExpansionTest, makeElementFaceFromFace)
TEST_F(TopoShapeExpansionTest, makeElementFaceOpenWire)
{
// Arrange
const double Len = 3, Wid = 2, Rad = 1;
const float Len = 3;
const float Wid = 2;
const float Rad = 1;
auto [face1, wire1, wire2] = CreateFaceWithRoundHole(Len, Wid, Rad);
Part::TopoShape topoShape {wire1, 1L};
double area = PartTestHelpers::getArea(face1);
double area1 = PartTestHelpers::getArea(topoShape.getShape());
double area = getArea(face1);
double area1 = getArea(topoShape.getShape());
// Act
Part::TopoShape newFace = topoShape.makeElementFace(wire1, "Cut", nullptr, nullptr);
double area2 = PartTestHelpers::getArea(newFace.getShape());
double area3 = PartTestHelpers::getArea(topoShape.getShape());
double area2 = getArea(newFace.getShape());
double area3 = getArea(topoShape.getShape());
// Assert
EXPECT_TRUE(newFace.getShape().IsEqual(topoShape.getShape())); // topoShape was altered
EXPECT_FALSE(face1.IsEqual(newFace.getShape()));
@@ -309,16 +272,18 @@ TEST_F(TopoShapeExpansionTest, makeElementFaceOpenWire)
TEST_F(TopoShapeExpansionTest, makeElementFaceClosedWire)
{
// Arrange
const double Len = 3, Wid = 2, Rad = 1;
const float Len = 3;
const float Wid = 2;
const float Rad = 1;
auto [face1, wire1, wire2] = CreateFaceWithRoundHole(Len, Wid, Rad);
Part::TopoShape topoShape {wire2, 1L};
double area = PartTestHelpers::getArea(face1);
double area1 = PartTestHelpers::getArea(topoShape.getShape());
double area = getArea(face1);
double area1 = getArea(topoShape.getShape());
// Act
Part::TopoShape newFace =
topoShape.makeElementFace(wire2, "Cut", "Part::FaceMakerBullseye", nullptr);
double area2 = PartTestHelpers::getArea(newFace.getShape());
double area3 = PartTestHelpers::getArea(topoShape.getShape());
double area2 = getArea(newFace.getShape());
double area3 = getArea(topoShape.getShape());
// Assert
EXPECT_TRUE(newFace.getShape().IsEqual(topoShape.getShape())); // topoShape was altered
EXPECT_FALSE(face1.IsEqual(newFace.getShape()));
@@ -414,7 +379,9 @@ TEST_F(TopoShapeExpansionTest, setElementComboNameCompound)
TEST_F(TopoShapeExpansionTest, splitWires)
{
// Arrange
const double Len = 3, Wid = 2, Rad = 1;
const float Len = 3;
const float Wid = 2;
const float Rad = 1;
auto [face1, wire1, wire2] = CreateFaceWithRoundHole(Len, Wid, Rad);
Part::TopoShape topoShape {face1, 1L};
std::vector<Part::TopoShape> inner;
@@ -424,8 +391,8 @@ TEST_F(TopoShapeExpansionTest, splitWires)
topoShape.splitWires(&inner, Part::TopoShape::SplitWireReorient::ReorientReversed);
// Assert
EXPECT_EQ(inner.size(), 1);
EXPECT_FLOAT_EQ(PartTestHelpers::getLength(wire.getShape()), 2 + 2 + 3 + 3);
EXPECT_FLOAT_EQ(PartTestHelpers::getLength(inner.front().getShape()), M_PI * Rad * 2);
EXPECT_FLOAT_EQ(getLength(wire.getShape()), 2 + 2 + 3 + 3);
EXPECT_FLOAT_EQ(getLength(inner.front().getShape()), M_PI * Rad * 2);
EXPECT_EQ(wire.getShape().Orientation(), TopAbs_REVERSED);
for (Part::TopoShape& shape : inner) {
EXPECT_EQ(shape.getShape().Orientation(), TopAbs_FORWARD);
@@ -434,8 +401,8 @@ TEST_F(TopoShapeExpansionTest, splitWires)
// Possible future tests:
// splitWires without inner Wires
// splitWires with allfour reorientation values NoReorient, ReOrient, ReorientForward,
// ReorientRevesed
// splitWires with all four reorientation values NoReorient, ReOrient, ReorientForward,
// ReorientReversed
TEST_F(TopoShapeExpansionTest, mapSubElementInvalidParm)
{
@@ -461,7 +428,8 @@ TEST_F(TopoShapeExpansionTest, mapSubElementFindShapeByNames)
Part::TopoShape cube2TS {cube2};
cube1TS.Tag = 1;
cube2TS.Tag = 2;
Part::TopoShape topoShape, topoShape1;
Part::TopoShape topoShape;
Part::TopoShape topoShape1;
// Act
int fs1 = topoShape1.findShape(cube1);
@@ -546,8 +514,13 @@ TEST_F(TopoShapeExpansionTest, mapSubElementFindAncestors)
cube2TS.Tag = 2;
cube3TS.Tag = 3;
cube4TS.Tag = 4;
Part::TopoShape topoShape, topoShape1, topoShape2;
Part::TopoShape topoShape3, topoShape4, topoShape5, topoShape6;
Part::TopoShape topoShape;
Part::TopoShape topoShape1;
Part::TopoShape topoShape2;
Part::TopoShape topoShape3;
Part::TopoShape topoShape4;
Part::TopoShape topoShape5;
Part::TopoShape topoShape6;
topoShape.makeElementCompound({cube1TS, cube2TS});
topoShape1.makeElementCompound({cube3TS, cube4TS});
topoShape2.makeElementCompound({cube1TS, cube3TS});
@@ -584,4 +557,111 @@ TEST_F(TopoShapeExpansionTest, mapSubElementFindAncestors)
EXPECT_TRUE(ancestorShapeList.back().IsEqual(topoShape6.getShape()));
}
TEST_F(TopoShapeExpansionTest, makeElementShellInvalid)
{
// Arrange
Part::TopoShape topoShape {1L};
// Act / Assert
EXPECT_THROW(topoShape.makeElementShell(false, nullptr), Base::CADKernelError);
}
TEST_F(TopoShapeExpansionTest, makeElementShellSingle)
{
// Arrange
const float Len = 3;
const float Wid = 2;
auto [face1, wire1, edge1, edge2, edge3, _] = CreateRectFace(Len, Wid);
Part::TopoShape topoShape {face1, 1L};
// Act
Part::TopoShape result = topoShape.makeElementShell(false, nullptr);
// Assert
#if OCC_VERSION_HEX >= 0x070400
EXPECT_EQ(result.getShape().NbChildren(), 1);
#endif
EXPECT_EQ(result.countSubElements("Vertex"), 4);
EXPECT_EQ(result.countSubElements("Edge"), 4);
EXPECT_EQ(result.countSubElements("Face"), 1);
EXPECT_STREQ(result.shapeName().c_str(), "Shell");
}
TEST_F(TopoShapeExpansionTest, makeElementShellOpen)
{
// Arrange
const float Len = 3;
const float Wid = 2;
auto [face1, wire1, edge1, edge2, edge3, edge4] = CreateRectFace(Len, Wid);
auto transform {gp_Trsf()};
transform.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(1, 0, 0)), M_PI / 2);
auto face2 = face1; // Shallow copy
face2.Move(TopLoc_Location(transform));
TopoDS_Compound compound1;
TopoDS_Builder builder {};
builder.MakeCompound(compound1);
builder.Add(compound1, face1);
builder.Add(compound1, face2);
Part::TopoShape topoShape {compound1, 1L};
// Act
Part::TopoShape result = topoShape.makeElementShell(true, nullptr);
// Assert
#if OCC_VERSION_HEX >= 0x070400
EXPECT_EQ(result.getShape().NbChildren(), 2);
#endif
EXPECT_EQ(result.countSubElements("Vertex"), 6);
EXPECT_EQ(result.countSubElements("Edge"), 7);
EXPECT_EQ(result.countSubElements("Face"), 2);
EXPECT_STREQ(result.shapeName().c_str(), "Shell");
}
TEST_F(TopoShapeExpansionTest, makeElementShellClosed)
{
// Arrange
auto [cube1, cube2] = CreateTwoCubes();
Part::TopoShape topoShape {cube1};
std::vector<Part::TopoShape> shapes;
for (const auto& face : topoShape.getSubShapes(TopAbs_FACE)) {
shapes.emplace_back(face);
}
// Act
Part::TopoShape topoShape1 {1L};
topoShape1.makeElementCompound(shapes, "D");
// Assert
Part::TopoShape result = topoShape1.makeElementShell(false, "SH1");
#if OCC_VERSION_HEX >= 0x070400
EXPECT_EQ(result.getShape().NbChildren(), 6);
#endif
EXPECT_EQ(result.countSubElements("Vertex"), 8);
EXPECT_EQ(result.countSubElements("Edge"), 12);
EXPECT_EQ(result.countSubElements("Face"), 6);
EXPECT_STREQ(result.shapeName().c_str(), "Shell");
}
TEST_F(TopoShapeExpansionTest, makeElementShellIntersecting)
{
// Arrange
auto [cube1, cube2] = CreateTwoCubes();
auto transform {gp_Trsf()};
transform.SetTranslation(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(0.5, 0.5, 0.0));
cube2.Move(TopLoc_Location(transform));
// Arrange
Part::TopoShape topoShape {cube1};
std::vector<Part::TopoShape> shapes;
for (const auto& face : topoShape.getSubShapes(TopAbs_FACE)) {
shapes.emplace_back(face);
}
topoShape.setShape(cube2);
for (const auto& face : topoShape.getSubShapes(TopAbs_FACE)) {
shapes.emplace_back(face);
}
// Act
Part::TopoShape topoShape1 {1L};
topoShape1.makeElementCompound(shapes, "D");
// Act / Assert
EXPECT_THROW(topoShape1.makeElementShell(false, nullptr), Base::CADKernelError);
}
// TEST_F(TopoShapeExpansionTest, makeElementShellFromWires)
// {
// // Arrange
// }
// NOLINTEND(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers)

View File

@@ -0,0 +1,342 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
// Tests for the makeShapeWithElementMap method, extracted from the main set of tests for TopoShape
// due to length and complexity.
#include "gtest/gtest.h"
#include "src/App/InitApplication.h"
#include "PartTestHelpers.h"
#include <Mod/Part/App/TopoShape.h>
#include <Mod/Part/App/TopoShapeOpCode.h>
// #include <MappedName.h>
#include <TopoDS_Vertex.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Shell.hxx>
#include <TopoDS_Solid.hxx>
#include <TopoDS_CompSolid.hxx>
#include <TopoDS_Compound.hxx>
using namespace Part;
using namespace Data;
class TopoShapeMakeShapeWithElementMapTests: public ::testing::Test
{
protected:
static void SetUpTestSuite()
{
tests::initApplication();
}
void SetUp() override
{
_docName = App::GetApplication().getUniqueDocumentName("test");
App::GetApplication().newDocument(_docName.c_str(), "testUser");
}
void TearDown() override
{
App::GetApplication().closeDocument(_docName.c_str());
}
Part::TopoShape* Shape()
{
return &_shape;
}
Part::TopoShape::Mapper* Mapper()
{
return &_mapper;
}
void testFindSourceSubShapesInElementMapForSource(const std::vector<TopoShape>& sources,
const TopoShape& source);
private:
std::string _docName;
Data::ElementIDRefs _sid;
Part::TopoShape _shape;
Part::TopoShape::Mapper _mapper;
};
TEST_F(TopoShapeMakeShapeWithElementMapTests, nullShapeThrows)
{
// Arrange
auto [cube1, cube2] = PartTestHelpers::CreateTwoCubes();
std::vector<Part::TopoShape> sources {cube1, cube2};
TopoDS_Vertex nullVertex;
TopoDS_Edge nullEdge;
TopoDS_Wire nullWire;
TopoDS_Face nullFace;
TopoDS_Shell nullShell;
TopoDS_Solid nullSolid;
TopoDS_CompSolid nullCompSolid;
TopoDS_Compound nullCompound;
// Act and assert
EXPECT_THROW(Shape()->makeShapeWithElementMap(nullVertex, *Mapper(), sources),
Part::NullShapeException);
EXPECT_THROW(Shape()->makeShapeWithElementMap(nullEdge, *Mapper(), sources),
Part::NullShapeException);
EXPECT_THROW(Shape()->makeShapeWithElementMap(nullWire, *Mapper(), sources),
Part::NullShapeException);
EXPECT_THROW(Shape()->makeShapeWithElementMap(nullFace, *Mapper(), sources),
Part::NullShapeException);
EXPECT_THROW(Shape()->makeShapeWithElementMap(nullShell, *Mapper(), sources),
Part::NullShapeException);
EXPECT_THROW(Shape()->makeShapeWithElementMap(nullSolid, *Mapper(), sources),
Part::NullShapeException);
EXPECT_THROW(Shape()->makeShapeWithElementMap(nullCompSolid, *Mapper(), sources),
Part::NullShapeException);
EXPECT_THROW(Shape()->makeShapeWithElementMap(nullCompound, *Mapper(), sources),
Part::NullShapeException);
}
using Data::IndexedName, Data::MappedName;
using Part::TopoShape;
std::map<IndexedName, MappedName> elementMap(const TopoShape& shape)
{
std::map<IndexedName, MappedName> result {};
auto elements = shape.getElementMap();
for (auto const& entry : elements) {
result[entry.index] = entry.name;
}
return result;
}
// TEST_F(TopoShapeMakeShapeWithElementMapTests, mapVertex)
// TEST_F(TopoShapeMakeShapeWithElementMapTests, mapEdge)
// TEST_F(TopoShapeMakeShapeWithElementMapTests, mapWire)
// TEST_F(TopoShapeMakeShapeWithElementMapTests, mapFace)
// TEST_F(TopoShapeMakeShapeWithElementMapTests, mapShell)
// TEST_F(TopoShapeMakeShapeWithElementMapTests, mapSolid)
TEST_F(TopoShapeMakeShapeWithElementMapTests, mapCompoundCount)
{
// Arrange
auto [cube1, cube2] = PartTestHelpers::CreateTwoCubes();
std::vector<TopoShape> sources {cube1, cube2};
sources[0].Tag = 1;
sources[1].Tag = 2;
TopoShape compound = TopoShape();
compound.makeElementCompound(sources);
auto preElements = elementMap(compound); // Map before mapping.
// Act
compound.makeShapeWithElementMap(compound.getShape(), *Mapper(), sources);
auto postElements = elementMap(compound); // Map after mapping
// Assert
EXPECT_EQ(preElements.size(), 52); // Check the before map.
EXPECT_EQ(postElements.size(), 52); // 12 Edges, 8 Vertexes, 6 Faces per each Cube
EXPECT_EQ(postElements.count(IndexedName("Edge", 24)), 1);
EXPECT_EQ(postElements.count(IndexedName("Edge", 25)), 0);
EXPECT_EQ(postElements.count(IndexedName("Vertex", 16)), 1);
EXPECT_EQ(postElements.count(IndexedName("Vertex", 17)), 0);
EXPECT_EQ(postElements.count(IndexedName("Face", 12)), 1);
EXPECT_EQ(postElements.count(IndexedName("Face", 13)), 0);
EXPECT_STREQ(sources[0].shapeName().c_str(), "Solid");
EXPECT_STREQ(sources[1].shapeName().c_str(), "Solid");
EXPECT_STREQ(compound.shapeName().c_str(), "Compound");
}
TEST_F(TopoShapeMakeShapeWithElementMapTests, mapCompoundMap)
{
// Arrange
auto [cube1, cube2] = PartTestHelpers::CreateTwoCubes();
std::vector<TopoShape> sources {cube1, cube2};
sources[0].Tag = 1;
sources[1].Tag = 2;
// Map only one of the two sources to test different names.
sources[0].makeShapeWithElementMap(sources[0].getShape(), *Mapper(), {sources[0]});
TopoShape compound = TopoShape();
compound.makeElementCompound(sources);
auto preElements = elementMap(compound); // Map before mapping.
// Act
compound.makeShapeWithElementMap(compound.getShape(), *Mapper(), sources);
auto postElements = elementMap(compound); // Map after mapping
// Assert
EXPECT_EQ(preElements[IndexedName("Edge", 1)], MappedName("Edge1;MAK;:H:4,E;:H1:b,E"));
EXPECT_EQ(preElements[IndexedName("Edge", 13)], MappedName("Edge1;:H2,E"));
EXPECT_EQ(postElements[IndexedName("Edge", 1)], MappedName("Edge1;MAK;:H:4,E;MAK;:H1:f,E"));
EXPECT_EQ(postElements[IndexedName("Edge", 13)], MappedName("Edge1;MAK;:H2:4,E"));
}
TEST_F(TopoShapeMakeShapeWithElementMapTests, emptySourceShapes)
{
// Arrange
auto [cube1, cube2] = PartTestHelpers::CreateTwoCubes();
std::vector<Part::TopoShape> emptySources;
std::vector<Part::TopoShape> nonEmptySources {cube1, cube2};
// Act and assert
for (auto& source : nonEmptySources) {
Part::TopoShape& modifiedShape = source;
Part::TopoShape& originalShape = source;
EXPECT_EQ(
&originalShape,
&modifiedShape.makeShapeWithElementMap(source.getShape(), *Mapper(), emptySources));
}
}
TEST_F(TopoShapeMakeShapeWithElementMapTests, nonMappableSources)
{
// Arrange
auto [cube1, cube2] = PartTestHelpers::CreateTwoCubes();
std::vector<Part::TopoShape> sources {cube1, cube2};
// Act and assert
for (auto& source : sources) {
size_t canMap = 0;
for (const auto& mappableSource : sources) {
if (source.canMapElement(mappableSource)) {
++canMap;
}
}
if (canMap == 0U) {
EXPECT_EQ(&source,
&source.makeShapeWithElementMap(source.getShape(), *Mapper(), sources));
}
}
}
void testFindSourceShapesInSingleShape(const Part::TopoShape& cmpdShape,
const Part::TopoShape& source,
const std::vector<Part::TopoShape>& sources,
const TopoShape::Mapper& mapper)
{
std::vector<Part::TopoShape> tmpSources {source};
for (const auto& subSource : sources) {
Part::TopoShape tmpShape {source.getShape()};
tmpShape.makeShapeWithElementMap(source.getShape(), mapper, tmpSources);
if (&source == &subSource) {
EXPECT_NE(tmpShape.findShape(subSource.getShape()),
0); // if tmpShape uses, for example, cube1 and we search for cube1 than
// we should find it
}
else {
EXPECT_EQ(tmpShape.findShape(subSource.getShape()),
0); // if tmpShape uses, for example, cube1 and we search for cube2 than
// we shouldn't find it
}
}
EXPECT_NE(cmpdShape.findShape(source.getShape()),
0); // as cmpdShape is made with cube1 and cube2 we should find both of them
}
TEST_F(TopoShapeMakeShapeWithElementMapTests, findSourceShapesInShape)
{
// Arrange
auto [cube1, cube2] = PartTestHelpers::CreateTwoCubes();
std::vector<Part::TopoShape> sources {cube1, cube2};
sources[0].Tag = 1; // setting Tag explicitly otherwise it is likely that this test will be
// more or less the same of nonMappableSources
sources[1].Tag = 2; // setting Tag explicitly otherwise it is likely that this test will be
// more or less the same of nonMappableSources
Part::TopoShape cmpdShape;
cmpdShape.makeElementCompound(sources);
// Act and assert
for (const auto& source : sources) {
testFindSourceShapesInSingleShape(cmpdShape, source, sources, *Mapper());
}
}
void testFindSubShapesForSourceWithTypeAndIndex(const std::string& shapeTypeStr,
std::map<IndexedName, MappedName>& elementStdMap,
unsigned long shapeIndex)
{
std::string shapeIndexStr = std::to_string(shapeIndex);
std::string shapeName {shapeTypeStr + shapeIndexStr};
IndexedName indexedName {shapeTypeStr.c_str(), (int)shapeIndex};
MappedName mappedName {elementStdMap[indexedName]};
const char shapeTypePrefix {indexedName.toString()[0]};
EXPECT_NO_THROW(elementStdMap.at(indexedName)); // We check that the IndexedName
// is one of the keys...
EXPECT_NE(mappedName.find(shapeName.c_str()),
-1); // ... that the element name is in the MappedName...
EXPECT_EQ(mappedName.toString().back(), shapeTypePrefix);
}
void testFindSubShapesForSourceWithType(const TopoShape& source,
const char* shapeType,
std::map<IndexedName, MappedName>& elementStdMap)
{
std::string shapeTypeStr {shapeType};
// ... and all the elements of the various types in the source TopoShape ...
for (unsigned long shapeIndex = 1U; shapeIndex <= source.countSubElements(shapeType);
shapeIndex++) {
testFindSubShapesForSourceWithTypeAndIndex(shapeTypeStr, elementStdMap, shapeIndex);
}
// ... we also check that we don't find shapes that don't exist and therefore don't
// have either an IndexedName or a MappedName
IndexedName fakeIndexedName {shapeTypeStr.c_str(), (int)source.countSubElements(shapeType) + 1};
EXPECT_THROW(elementStdMap.at(fakeIndexedName), std::out_of_range);
}
void TopoShapeMakeShapeWithElementMapTests::testFindSourceSubShapesInElementMapForSource(
const std::vector<TopoShape>& sources,
const TopoShape& source)
{
TopoShape tmpShape {source.getShape()};
tmpShape.makeShapeWithElementMap(source.getShape(), *Mapper(), sources);
// First we create a map with the IndexedNames and MappedNames
std::map<IndexedName, MappedName> elementStdMap;
for (const auto& mappedElement : tmpShape.getElementMap()) {
elementStdMap.emplace(mappedElement.index, mappedElement.name);
}
// Then for all the elements types (Vertex, Edge, Face) ...
for (const auto& shapeType : source.getElementTypes()) {
testFindSubShapesForSourceWithType(source, shapeType, elementStdMap);
}
}
TEST_F(TopoShapeMakeShapeWithElementMapTests, findSourceSubShapesInElementMap)
{
// Arrange
auto [cube1, cube2] = PartTestHelpers::CreateTwoCubes();
std::vector<TopoShape> sources {cube1, cube2};
sources[0].Tag = 1; // setting Tag explicitly otherwise it is likely that this test will be
// more or less the same of nonMappableSources
sources[1].Tag = 2; // setting Tag explicitly otherwise it is likely that this test will be
// more or less the same of nonMappableSources
// Act and assert
// Testing with all the source TopoShapes
for (const auto& source : sources) {
testFindSourceSubShapesInElementMapForSource(sources, source);
}
}
TEST_F(TopoShapeMakeShapeWithElementMapTests, findMakerOpInElementMap)
{
// Arrange
auto [cube1, cube2] = PartTestHelpers::CreateTwoCubes();
std::vector<TopoShape> sources {cube1, cube2};
sources[0].Tag = 1; // setting Tag explicitly otherwise it is likely that this test will be
// more or less the same of nonMappableSources
sources[1].Tag = 2; // setting Tag explicitly otherwise it is likely that this test will be
// more or less the same of nonMappableSources
// Act and assert
// Testing with all the source TopoShapes
for (const auto& source : sources) {
TopoShape tmpShape {source.getShape()};
tmpShape.makeShapeWithElementMap(source.getShape(), *Mapper(), sources);
// For all the mappedElements ...
for (const auto& mappedElement : tmpShape.getElementMap()) {
EXPECT_NE(mappedElement.name.find(OpCodes::Maker),
-1); // ... we check that there's the "MAK" OpCode
}
}
}