Merge branch 'main' into toponamingTopoShapeWire
# Conflicts: # src/Mod/Part/App/TopoShape.h # src/Mod/Part/App/TopoShapeExpansion.cpp # tests/src/Mod/Part/App/TopoShapeExpansion.cpp Signed-off-by: CalligaroV <vincenzo.calligaro@gmail.com>
This commit is contained in:
@@ -15,4 +15,6 @@ 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
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
@@ -14,6 +16,21 @@ double getVolume(const TopoDS_Shape& shape)
|
||||
return prop.Mass();
|
||||
}
|
||||
|
||||
double getArea(const TopoDS_Shape& shape)
|
||||
{
|
||||
GProp_GProps prop;
|
||||
BRepGProp::SurfaceProperties(shape, prop);
|
||||
return prop.Mass();
|
||||
}
|
||||
|
||||
double getLength(const TopoDS_Shape& shape)
|
||||
{
|
||||
GProp_GProps prop;
|
||||
BRepGProp::LinearProperties(shape, prop);
|
||||
return prop.Mass();
|
||||
}
|
||||
|
||||
|
||||
void PartTestHelperClass::createTestDoc()
|
||||
{
|
||||
_docName = App::GetApplication().getUniqueDocumentName("test");
|
||||
@@ -48,7 +65,8 @@ _getFilletEdges(const std::vector<int>& edges, double startRadius, double endRad
|
||||
return filletElements;
|
||||
}
|
||||
|
||||
void executePython(const std::vector<std::string>& python)
|
||||
|
||||
void ExecutePython(const std::vector<std::string>& python)
|
||||
{
|
||||
Base::InterpreterSingleton is = Base::InterpreterSingleton();
|
||||
|
||||
@@ -68,16 +86,33 @@ void rectangle(double height, double width, char* name)
|
||||
boost::str(boost::format("V4 = FreeCAD.Vector(0, %d, 0)") % width),
|
||||
"P1 = Part.makePolygon([V1, V2, V3, V4],True)",
|
||||
"F1 = Part.Face(P1)", // Make the face or the volume calc won't work right.
|
||||
// "L1 = Part.LineSegment(V1, V2)",
|
||||
// "L2 = Part.LineSegment(V2, V3)",
|
||||
// "L3 = Part.LineSegment(V3, V4)",
|
||||
// "L4 = Part.LineSegment(V4, V1)",
|
||||
// "S1 = Part.Shape([L1,L2,L3,L4])",
|
||||
// "W1 = Part.Wire(S1.Edges)",
|
||||
// "F1 = Part.Face(W1)", // Make the face or the volume calc won't work right.
|
||||
boost::str(boost::format("Part.show(F1,'%s')") % name),
|
||||
};
|
||||
executePython(rectstring);
|
||||
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
|
||||
@@ -94,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)
|
||||
|
||||
@@ -1,21 +1,33 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include <boost/format.hpp>
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include "Base/Interpreter.h"
|
||||
#include <Base/Precision.h>
|
||||
#include "Mod/Part/App/FeaturePartBox.h"
|
||||
#include "Mod/Part/App/FeaturePartFuse.h"
|
||||
#include "Mod/Part/App/FeatureFillet.h"
|
||||
#include <BRepGProp.hxx>
|
||||
#include "Base/Interpreter.h"
|
||||
#include <boost/format.hpp>
|
||||
#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);
|
||||
|
||||
double getLength(const TopoDS_Shape& shape);
|
||||
|
||||
std::vector<Part::FilletElement>
|
||||
_getFilletEdges(const std::vector<int>& edges, double startRadius, double endRadius);
|
||||
|
||||
@@ -34,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
|
||||
|
||||
@@ -3,15 +3,21 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "src/App/InitApplication.h"
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
#include <Mod/Part/App/TopoShapeOpCode.h>
|
||||
|
||||
#include "PartTestHelpers.h"
|
||||
|
||||
#include <BRepAlgoAPI_Fuse.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <BRepPrimAPI_MakeBox.hxx>
|
||||
#include <GC_MakeCircle.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
|
||||
// NOLINTBEGIN(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers)
|
||||
|
||||
using namespace PartTestHelpers;
|
||||
|
||||
class TopoShapeExpansionTest: public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
@@ -24,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);
|
||||
}
|
||||
@@ -34,10 +39,10 @@ protected:
|
||||
App::GetApplication().closeDocument(_docName.c_str());
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::string _docName;
|
||||
Data::ElementIDRefs _sid;
|
||||
QVector<App::StringIDRef>* _sids = nullptr;
|
||||
App::StringHasherRef _hasher;
|
||||
};
|
||||
|
||||
@@ -49,7 +54,10 @@ TEST_F(TopoShapeExpansionTest, makeElementCompoundOneShapeReturnsShape)
|
||||
std::vector<Part::TopoShape> shapes {topoShape};
|
||||
|
||||
// Act
|
||||
topoShape.makeElementCompound(shapes, "C", false /*Don't force the creation*/);
|
||||
topoShape.makeElementCompound(shapes,
|
||||
"C",
|
||||
Part::TopoShape::SingleShapeCompoundCreationPolicy::
|
||||
RETURN_SHAPE /*Don't force the creation*/);
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(edge.ShapeType(), topoShape.getShape().ShapeType()); // NOT a Compound
|
||||
@@ -63,7 +71,10 @@ TEST_F(TopoShapeExpansionTest, makeElementCompoundOneShapeForceReturnsCompound)
|
||||
std::vector<Part::TopoShape> shapes {topoShape};
|
||||
|
||||
// Act
|
||||
topoShape.makeElementCompound(shapes, "C", true /*Force the creation*/);
|
||||
topoShape.makeElementCompound(
|
||||
shapes,
|
||||
"C",
|
||||
Part::TopoShape::SingleShapeCompoundCreationPolicy::FORCE_COMPOUND /*Force the creation*/);
|
||||
|
||||
// Assert
|
||||
EXPECT_NE(edge.ShapeType(), topoShape.getShape().ShapeType()); // No longer the same thing
|
||||
@@ -117,26 +128,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
|
||||
@@ -177,4 +168,522 @@ TEST_F(TopoShapeExpansionTest, makeElementWiresCombinesAdjacent)
|
||||
EXPECT_EQ(6, elementMap.size());
|
||||
}
|
||||
|
||||
TEST_F(TopoShapeExpansionTest, makeElementFaceNull)
|
||||
{
|
||||
// Arrange
|
||||
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 = getArea(face1);
|
||||
double area1 = getArea(topoShape.getShape());
|
||||
// Act
|
||||
Part::TopoShape newFace = topoShape.makeElementFace(nullptr);
|
||||
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);
|
||||
EXPECT_FLOAT_EQ(area1, Len * Wid + M_PI * Rad * Rad);
|
||||
EXPECT_FLOAT_EQ(area2, Len * Wid - M_PI * Rad * Rad);
|
||||
EXPECT_FLOAT_EQ(area3, Len * Wid + M_PI * Rad * Rad);
|
||||
EXPECT_STREQ(newFace.shapeName().c_str(), "Face");
|
||||
}
|
||||
|
||||
TEST_F(TopoShapeExpansionTest, makeElementFaceSimple)
|
||||
{
|
||||
// Arrange
|
||||
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 = getArea(face1);
|
||||
double area1 = getArea(topoShape.getShape());
|
||||
// Act
|
||||
Part::TopoShape newFace = topoShape.makeElementFace(wire1);
|
||||
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()));
|
||||
EXPECT_FLOAT_EQ(area, Len * Wid + M_PI * Rad * Rad);
|
||||
EXPECT_FLOAT_EQ(area1, Len * Wid + M_PI * Rad * Rad);
|
||||
EXPECT_FLOAT_EQ(area2, Len * Wid);
|
||||
EXPECT_FLOAT_EQ(area3, Len * Wid);
|
||||
EXPECT_STREQ(newFace.shapeName().c_str(), "Face");
|
||||
}
|
||||
|
||||
TEST_F(TopoShapeExpansionTest, makeElementFaceParams)
|
||||
{
|
||||
// Arrange
|
||||
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 = getArea(face1);
|
||||
double area1 = getArea(topoShape.getShape());
|
||||
// Act
|
||||
Part::TopoShape newFace =
|
||||
topoShape.makeElementFace(wire1, "Cut", "Part::FaceMakerBullseye", nullptr);
|
||||
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()));
|
||||
EXPECT_FLOAT_EQ(area, Len * Wid + M_PI * Rad * Rad);
|
||||
EXPECT_FLOAT_EQ(area1, Len * Wid + M_PI * Rad * Rad);
|
||||
EXPECT_FLOAT_EQ(area2, Len * Wid);
|
||||
EXPECT_FLOAT_EQ(area3, Len * Wid);
|
||||
EXPECT_STREQ(newFace.shapeName().c_str(), "Face");
|
||||
}
|
||||
|
||||
TEST_F(TopoShapeExpansionTest, makeElementFaceFromFace)
|
||||
{
|
||||
// Arrange
|
||||
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 = getArea(face1);
|
||||
double area1 = getArea(topoShape.getShape());
|
||||
// Act
|
||||
Part::TopoShape newFace =
|
||||
topoShape.makeElementFace(face1, "Cut", "Part::FaceMakerBullseye", nullptr);
|
||||
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()));
|
||||
EXPECT_FLOAT_EQ(area, Len * Wid + M_PI * Rad * Rad);
|
||||
EXPECT_FLOAT_EQ(area1, Len * Wid + M_PI * Rad * Rad);
|
||||
EXPECT_FLOAT_EQ(area2, Len * Wid - M_PI * Rad * Rad);
|
||||
EXPECT_FLOAT_EQ(area3, Len * Wid - M_PI * Rad * Rad);
|
||||
EXPECT_STREQ(newFace.shapeName().c_str(), "Face");
|
||||
}
|
||||
|
||||
|
||||
TEST_F(TopoShapeExpansionTest, makeElementFaceOpenWire)
|
||||
{
|
||||
// Arrange
|
||||
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 = getArea(face1);
|
||||
double area1 = getArea(topoShape.getShape());
|
||||
// Act
|
||||
Part::TopoShape newFace = topoShape.makeElementFace(wire1, "Cut", nullptr, nullptr);
|
||||
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()));
|
||||
EXPECT_FLOAT_EQ(area, Len * Wid + M_PI * Rad * Rad);
|
||||
EXPECT_FLOAT_EQ(area1, 0); // Len * Wid - M_PI * Rad * Rad);
|
||||
EXPECT_FLOAT_EQ(area2, Len * Wid);
|
||||
EXPECT_FLOAT_EQ(area3, Len * Wid);
|
||||
EXPECT_STREQ(newFace.shapeName().c_str(), "Face");
|
||||
}
|
||||
|
||||
|
||||
TEST_F(TopoShapeExpansionTest, makeElementFaceClosedWire)
|
||||
{
|
||||
// Arrange
|
||||
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 = getArea(face1);
|
||||
double area1 = getArea(topoShape.getShape());
|
||||
// Act
|
||||
Part::TopoShape newFace =
|
||||
topoShape.makeElementFace(wire2, "Cut", "Part::FaceMakerBullseye", nullptr);
|
||||
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()));
|
||||
EXPECT_FLOAT_EQ(area, Len * Wid + M_PI * Rad * Rad);
|
||||
EXPECT_FLOAT_EQ(area1, 0); // Len * Wid - M_PI * Rad * Rad);
|
||||
EXPECT_FLOAT_EQ(area2, M_PI * Rad * Rad);
|
||||
EXPECT_FLOAT_EQ(area3, M_PI * Rad * Rad);
|
||||
EXPECT_STREQ(newFace.shapeName().c_str(), "Face");
|
||||
}
|
||||
|
||||
// Possible future makeElementFace tests:
|
||||
// Overlapping wire
|
||||
// Compound of wires
|
||||
// Compound of faces
|
||||
// Compound of other shape types
|
||||
|
||||
|
||||
TEST_F(TopoShapeExpansionTest, setElementComboNameNothing)
|
||||
{
|
||||
// Arrange
|
||||
Part::TopoShape topoShape(1L);
|
||||
// Act
|
||||
Data::MappedName result = topoShape.setElementComboName(Data::IndexedName(), {});
|
||||
// ASSERT
|
||||
EXPECT_STREQ(result.toString().c_str(), "");
|
||||
}
|
||||
|
||||
|
||||
TEST_F(TopoShapeExpansionTest, setElementComboNameSimple)
|
||||
{
|
||||
// Arrange
|
||||
auto edge1 = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0)).Edge();
|
||||
Part::TopoShape topoShape(edge1, 1L);
|
||||
topoShape.setElementMap({}); // Initialize the map to avoid a segfault.
|
||||
// Also, maybe the end of TopoShape::mapSubElementTypeForShape should enforce that elementMap()
|
||||
// isn't nullptr to eliminate the segfault.
|
||||
Data::MappedName edgeName("testname");
|
||||
// Act
|
||||
Data::MappedName result =
|
||||
topoShape.setElementComboName(Data::IndexedName::fromConst("Edge", 1), {edgeName});
|
||||
// Assert
|
||||
EXPECT_STREQ(result.toString().c_str(), "testname;");
|
||||
}
|
||||
|
||||
|
||||
TEST_F(TopoShapeExpansionTest, setElementComboName)
|
||||
{
|
||||
// Arrange
|
||||
Part::TopoShape topoShape(2L);
|
||||
topoShape.setElementMap({});
|
||||
Data::MappedName edgeName =
|
||||
topoShape.getMappedName(Data::IndexedName::fromConst("Edge", 1), true);
|
||||
Data::MappedName faceName =
|
||||
topoShape.getMappedName(Data::IndexedName::fromConst("Face", 7), true);
|
||||
Data::MappedName faceName2 =
|
||||
topoShape.getMappedName(Data::IndexedName::fromConst("Face", 8), true);
|
||||
char* op = "Copy";
|
||||
// Act
|
||||
Data::MappedName result = topoShape.setElementComboName(Data::IndexedName::fromConst("Edge", 1),
|
||||
{edgeName, faceName, faceName2},
|
||||
Part::OpCodes::Common,
|
||||
op);
|
||||
// Assert
|
||||
EXPECT_STREQ(result.toString().c_str(), "Edge1;CMN(Face7|Face8);Copy");
|
||||
// The detailed forms of names are covered in encodeElementName tests
|
||||
}
|
||||
|
||||
TEST_F(TopoShapeExpansionTest, setElementComboNameCompound)
|
||||
{
|
||||
// Arrange
|
||||
auto edge1 = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0)).Edge();
|
||||
auto wire1 = BRepBuilderAPI_MakeWire({edge1}).Wire();
|
||||
auto wire2 = BRepBuilderAPI_MakeWire({edge1}).Wire();
|
||||
Part::TopoShape topoShape(2L);
|
||||
topoShape.makeElementCompound({wire1, wire2}); // Quality of shape doesn't matter
|
||||
Data::MappedName edgeName =
|
||||
topoShape.getMappedName(Data::IndexedName::fromConst("Edge", 1), true);
|
||||
Data::MappedName faceName =
|
||||
topoShape.getMappedName(Data::IndexedName::fromConst("Face", 7), true);
|
||||
Data::MappedName faceName2 =
|
||||
topoShape.getMappedName(Data::IndexedName::fromConst("Face", 8), true);
|
||||
char* op = "Copy";
|
||||
// Act
|
||||
Data::MappedName result = topoShape.setElementComboName(Data::IndexedName::fromConst("Edge", 1),
|
||||
{edgeName, faceName, faceName2},
|
||||
Part::OpCodes::Common,
|
||||
op);
|
||||
// ASSERT
|
||||
EXPECT_STREQ(result.toString().c_str(), "Edge1;:H,E;CMN(Face7|Face8);Copy");
|
||||
// The detailed forms of names are covered in encodeElementName tests
|
||||
}
|
||||
|
||||
TEST_F(TopoShapeExpansionTest, splitWires)
|
||||
{
|
||||
// Arrange
|
||||
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;
|
||||
// Act
|
||||
EXPECT_EQ(topoShape.getShape().Orientation(), TopAbs_FORWARD);
|
||||
Part::TopoShape wire =
|
||||
topoShape.splitWires(&inner, Part::TopoShape::SplitWireReorient::ReorientReversed);
|
||||
// Assert
|
||||
EXPECT_EQ(inner.size(), 1);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Possible future tests:
|
||||
// splitWires without inner Wires
|
||||
// splitWires with all four reorientation values NoReorient, ReOrient, ReorientForward,
|
||||
// ReorientReversed
|
||||
|
||||
TEST_F(TopoShapeExpansionTest, mapSubElementInvalidParm)
|
||||
{
|
||||
// Arrange
|
||||
auto [cube1, cube2] = CreateTwoCubes();
|
||||
Part::TopoShape cube1TS {cube1};
|
||||
cube1TS.Tag = 1;
|
||||
|
||||
// Act
|
||||
std::vector<Part::TopoShape> subShapes = cube1TS.getSubTopoShapes(TopAbs_FACE);
|
||||
Part::TopoShape face1 = subShapes.front();
|
||||
face1.Tag = 2;
|
||||
|
||||
// Assert
|
||||
EXPECT_THROW(cube1TS.mapSubElement(face1), Part::NullShapeException); // No subshapes
|
||||
}
|
||||
|
||||
TEST_F(TopoShapeExpansionTest, mapSubElementFindShapeByNames)
|
||||
{
|
||||
// Arrange
|
||||
auto [cube1, cube2] = CreateTwoCubes();
|
||||
Part::TopoShape cube1TS {cube1};
|
||||
Part::TopoShape cube2TS {cube2};
|
||||
cube1TS.Tag = 1;
|
||||
cube2TS.Tag = 2;
|
||||
Part::TopoShape topoShape;
|
||||
Part::TopoShape topoShape1;
|
||||
|
||||
// Act
|
||||
int fs1 = topoShape1.findShape(cube1);
|
||||
topoShape.setShape(cube2TS);
|
||||
topoShape1.makeElementCompound({cube1TS, cube2TS});
|
||||
int fs2 = topoShape1.findShape(cube1);
|
||||
|
||||
TopoDS_Shape tds1 = topoShape.findShape("SubShape1");
|
||||
TopoDS_Shape tds2 = topoShape.findShape("SubShape2"); // Nonexistent
|
||||
TopoDS_Shape tds3 = topoShape1.findShape("SubShape1");
|
||||
TopoDS_Shape tds4 = topoShape1.findShape("SubShape2");
|
||||
TopoDS_Shape tds5 = topoShape1.findShape("NonExistentName"); // Invalid Name
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(fs1, 0);
|
||||
EXPECT_EQ(fs2, 1);
|
||||
EXPECT_FALSE(tds1.IsNull());
|
||||
EXPECT_TRUE(tds2.IsNull());
|
||||
EXPECT_FALSE(tds3.IsNull());
|
||||
EXPECT_FALSE(tds4.IsNull());
|
||||
EXPECT_TRUE(tds5.IsNull());
|
||||
}
|
||||
|
||||
TEST_F(TopoShapeExpansionTest, mapSubElementFindShapeByType)
|
||||
{
|
||||
// Arrange
|
||||
auto [cube1, cube2] = CreateTwoCubes();
|
||||
Part::TopoShape cube1TS {cube1};
|
||||
Part::TopoShape cube2TS {cube2};
|
||||
cube1TS.Tag = 1;
|
||||
cube2TS.Tag = 2;
|
||||
Part::TopoShape topoShape;
|
||||
topoShape.makeElementCompound({cube1TS, cube2TS});
|
||||
topoShape.mapSubElement(cube2TS, "Name", false);
|
||||
|
||||
// Act, Assert
|
||||
for (int i = 1; i <= 12; i++) {
|
||||
TopoDS_Shape dshape1 = topoShape.findShape(TopAbs_FACE, i);
|
||||
EXPECT_FALSE(dshape1.IsNull()) << "Face num " << i;
|
||||
}
|
||||
TopoDS_Shape dshape1 = topoShape.findShape(TopAbs_FACE, 13);
|
||||
EXPECT_TRUE(dshape1.IsNull());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(TopoShapeExpansionTest, mapSubElementFindAncestor)
|
||||
{
|
||||
// Arrange
|
||||
auto [cube1, cube2] = CreateTwoCubes();
|
||||
Part::TopoShape cube1TS {cube1};
|
||||
Part::TopoShape cube2TS {cube2};
|
||||
cube1TS.Tag = 1;
|
||||
cube2TS.Tag = 2;
|
||||
Part::TopoShape topoShape;
|
||||
topoShape.makeElementCompound({cube1TS, cube2TS});
|
||||
topoShape.mapSubElement(cube2TS, "Name", false);
|
||||
|
||||
// Act
|
||||
int fa1 = topoShape.findAncestor(cube2, TopAbs_COMPOUND);
|
||||
TopoDS_Shape tds1 = topoShape.findAncestorShape(cube1, TopAbs_COMPOUND);
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(fa1, 1);
|
||||
EXPECT_TRUE(tds1.IsEqual(topoShape.getShape()));
|
||||
}
|
||||
|
||||
|
||||
TEST_F(TopoShapeExpansionTest, mapSubElementFindAncestors)
|
||||
{
|
||||
// Arrange
|
||||
auto [cube1, cube2] = CreateTwoCubes();
|
||||
auto [cube3, cube4] = CreateTwoCubes();
|
||||
auto tr {gp_Trsf()};
|
||||
tr.SetTranslation(gp_Vec(gp_XYZ(0, 1, 0)));
|
||||
cube3.Move(TopLoc_Location(tr));
|
||||
cube4.Move(TopLoc_Location(tr));
|
||||
Part::TopoShape cube1TS {cube1};
|
||||
Part::TopoShape cube2TS {cube2};
|
||||
Part::TopoShape cube3TS {cube3};
|
||||
Part::TopoShape cube4TS {cube4};
|
||||
cube1TS.Tag = 1;
|
||||
cube2TS.Tag = 2;
|
||||
cube3TS.Tag = 3;
|
||||
cube4TS.Tag = 4;
|
||||
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});
|
||||
topoShape3.makeElementCompound({cube2TS, cube4TS});
|
||||
topoShape4.makeElementCompound({topoShape, topoShape1});
|
||||
topoShape5.makeElementCompound({topoShape2, topoShape3});
|
||||
topoShape6.makeElementCompound({topoShape4, topoShape5});
|
||||
topoShape6.mapSubElement(cube2TS, nullptr, false);
|
||||
|
||||
// Act
|
||||
auto ancestorList = topoShape6.findAncestors(cube3, TopAbs_COMPOUND);
|
||||
auto ancestorShapeList = topoShape6.findAncestorsShapes(cube3, TopAbs_COMPOUND);
|
||||
|
||||
// FIXME: It seems very strange that both of these ancestors calls return lists of two items
|
||||
// that contain the same thing twice. What I expect is that the ancestors of cube3 would be
|
||||
// topoShape6 topoShape5, topoShape3, topoShape2, and topoShape1.
|
||||
//
|
||||
// This is a very convoluted hierarchy, and the only way I could get more than one result from
|
||||
// findAncestors. I guess it's possible that it's only intended to return a single result in
|
||||
// almost all cases; that would mean that what it returns is the shape at the top of the tree.
|
||||
// But that's exactly the shape we use to call it in the first place, so we already have it.
|
||||
//
|
||||
// Note that in the RT branch, findAncestorsShapes is called by GenericShapeMapper::init,
|
||||
// TopoShape::makEChamfer and MapperPrism
|
||||
// findAncestors is used in a dozen places.
|
||||
//
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(ancestorList.size(), 2);
|
||||
EXPECT_EQ(ancestorList.front(), 1);
|
||||
EXPECT_EQ(ancestorList.back(), 1);
|
||||
EXPECT_EQ(ancestorShapeList.size(), 2);
|
||||
EXPECT_TRUE(ancestorShapeList.front().IsEqual(topoShape6.getShape()));
|
||||
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)
|
||||
|
||||
342
tests/src/Mod/Part/App/TopoShapeMakeShapeWithElementMap.cpp
Normal file
342
tests/src/Mod/Part/App/TopoShapeMakeShapeWithElementMap.cpp
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
158
tests/src/Mod/Part/App/TopoShapeMapper.cpp
Normal file
158
tests/src/Mod/Part/App/TopoShapeMapper.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "src/App/InitApplication.h"
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
#include "Mod/Part/App/TopoShapeMapper.h"
|
||||
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeShape.hxx>
|
||||
#include <BRepPrimAPI_MakeBox.hxx>
|
||||
#include <BRepTools_History.hxx>
|
||||
#include <BRepTools_ReShape.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
|
||||
// NOLINTBEGIN(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers)
|
||||
|
||||
class TopoShapeMapperTest: 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());
|
||||
}
|
||||
|
||||
private:
|
||||
std::string _docName;
|
||||
};
|
||||
|
||||
TEST_F(TopoShapeMapperTest, shapeHasherSingle)
|
||||
{
|
||||
// Arrange
|
||||
auto edge = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0)).Edge();
|
||||
Part::TopoShape topoShape {edge};
|
||||
auto edge2 = BRepBuilderAPI_MakeEdge(gp_Pnt(1.0, 0.0, 0.0), gp_Pnt(1.0, 1.0, 0.0)).Edge();
|
||||
Part::TopoShape topoShape2 {edge2};
|
||||
struct Part::ShapeHasher hasher;
|
||||
|
||||
// Act
|
||||
size_t hash1 = hasher(topoShape);
|
||||
size_t hash2 = hasher(topoShape2);
|
||||
size_t hash3 = hasher(edge);
|
||||
size_t hash4 = hasher(edge2);
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(hash1, hash3);
|
||||
EXPECT_EQ(hash2, hash4);
|
||||
EXPECT_NE(hash1, hash2);
|
||||
}
|
||||
|
||||
TEST_F(TopoShapeMapperTest, shapeHasherDual)
|
||||
{
|
||||
// Arrange
|
||||
auto edge = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0)).Edge();
|
||||
Part::TopoShape topoShape {edge};
|
||||
auto edge2 = BRepBuilderAPI_MakeEdge(gp_Pnt(1.0, 0.0, 0.0), gp_Pnt(1.0, 1.0, 0.0)).Edge();
|
||||
Part::TopoShape topoShape2 {edge2};
|
||||
struct Part::ShapeHasher hasher;
|
||||
|
||||
// Act
|
||||
size_t hash5 = hasher(topoShape, topoShape);
|
||||
size_t hash6 = hasher(topoShape, topoShape2);
|
||||
size_t hash7 = hasher(edge, edge);
|
||||
size_t hash8 = hasher(edge, edge2);
|
||||
|
||||
// Assert
|
||||
EXPECT_TRUE(hash5);
|
||||
EXPECT_FALSE(hash6);
|
||||
EXPECT_TRUE(hash7);
|
||||
EXPECT_FALSE(hash8);
|
||||
}
|
||||
|
||||
TEST_F(TopoShapeMapperTest, shapeHasherPair)
|
||||
{
|
||||
// Arrange
|
||||
auto edge = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0)).Edge();
|
||||
Part::TopoShape topoShape {edge};
|
||||
auto edge2 = BRepBuilderAPI_MakeEdge(gp_Pnt(1.0, 0.0, 0.0), gp_Pnt(1.0, 1.0, 0.0)).Edge();
|
||||
Part::TopoShape topoShape2 {edge2};
|
||||
std::pair<Part::TopoShape, Part::TopoShape> pair1(topoShape, topoShape2);
|
||||
std::pair<Part::TopoShape, Part::TopoShape> pair2(topoShape, topoShape);
|
||||
std::pair<TopoDS_Shape, TopoDS_Shape> pair3(edge, edge2);
|
||||
std::pair<TopoDS_Shape, TopoDS_Shape> pair4(edge, edge);
|
||||
struct Part::ShapeHasher hasher;
|
||||
|
||||
// Act
|
||||
size_t hash9 = hasher(pair1);
|
||||
size_t hash10 = hasher(pair2);
|
||||
size_t hash11 = hasher(pair3);
|
||||
size_t hash12 = hasher(pair4);
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(hash9, hash11);
|
||||
EXPECT_EQ(hash10, hash12);
|
||||
EXPECT_NE(hash9, hash10);
|
||||
}
|
||||
|
||||
TEST_F(TopoShapeMapperTest, shapeHasherPairs)
|
||||
{
|
||||
// Arrange
|
||||
auto edge = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0)).Edge();
|
||||
Part::TopoShape topoShape {edge};
|
||||
auto edge2 = BRepBuilderAPI_MakeEdge(gp_Pnt(1.0, 0.0, 0.0), gp_Pnt(1.0, 1.0, 0.0)).Edge();
|
||||
Part::TopoShape topoShape2 {edge2};
|
||||
std::pair<Part::TopoShape, Part::TopoShape> pair1(topoShape, topoShape2);
|
||||
std::pair<Part::TopoShape, Part::TopoShape> pair2(topoShape, topoShape);
|
||||
std::pair<TopoDS_Shape, TopoDS_Shape> pair3(edge, edge2);
|
||||
std::pair<TopoDS_Shape, TopoDS_Shape> pair4(edge, edge);
|
||||
struct Part::ShapeHasher hasher;
|
||||
|
||||
// Act
|
||||
size_t hash13 = hasher(pair1, pair1);
|
||||
size_t hash14 = hasher(pair1, pair2);
|
||||
size_t hash15 = hasher(pair3, pair3);
|
||||
size_t hash16 = hasher(pair3, pair4);
|
||||
|
||||
// Assert
|
||||
EXPECT_TRUE(hash13);
|
||||
EXPECT_FALSE(hash14);
|
||||
EXPECT_TRUE(hash15);
|
||||
EXPECT_FALSE(hash16);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(TopoShapeMapperTest, shapeMapperTests)
|
||||
{
|
||||
// Arrange
|
||||
auto mapper = Part::ShapeMapper();
|
||||
auto boxMaker1 = BRepPrimAPI_MakeBox(1.0, 1.0, 1.0);
|
||||
boxMaker1.Build();
|
||||
auto box1 = boxMaker1.Shape();
|
||||
Part::TopoShape topoShape1 {box1};
|
||||
|
||||
// Act
|
||||
auto e = topoShape1.getSubTopoShapes(TopAbs_EDGE);
|
||||
mapper.populate(Part::MappingStatus::Modified, box1, {e[0], e[1], e[2], e[3]});
|
||||
mapper.populate(Part::MappingStatus::Generated, box1, {e[4], e[5], e[6]});
|
||||
std::vector<TopoDS_Shape> vec1 = mapper.modified(box1);
|
||||
std::vector<TopoDS_Shape> vec2 = mapper.generated(box1);
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(vec1.size(), 4);
|
||||
EXPECT_EQ(vec2.size(), 3);
|
||||
}
|
||||
|
||||
|
||||
// NOLINTEND(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers)
|
||||
Reference in New Issue
Block a user