Merge branch 'main' of https://github.com/FreeCAD/FreeCAD.git into toponamingTopoShapeWire

# Conflicts:
#	src/Mod/Part/App/TopoShape.h
#	src/Mod/Part/App/TopoShapeExpansion.cpp
This commit is contained in:
CalligaroV
2024-02-07 23:51:49 +01:00
142 changed files with 7035 additions and 3003 deletions

View File

@@ -444,7 +444,7 @@ TEST_F(ComplexGeoDataTest, saveDocFileWithNoElementMap)
{
// Arrange
Base::StringWriter writer;
cgd().resetElementMap(nullptr, true); // Force undefined map
cgd().resetElementMap(nullptr, Data::AllowNoMap); // Force undefined map
// Act
cgd().SaveDocFile(writer);

View File

@@ -145,4 +145,10 @@ TEST(BaseToolsSuite, TestJoinList)
{
EXPECT_EQ(Base::Tools::joinList({"AB", "CD"}), "AB, CD, ");
}
TEST(BaseToolsSuite, TestEscapeQuotesFromString)
{
EXPECT_EQ(Base::Tools::escapeQuotesFromString("\'"), "\\\'");
EXPECT_EQ(Base::Tools::escapeQuotesFromString("\""), "\\\"");
EXPECT_EQ(Base::Tools::escapeQuotesFromString("\\"), "\\");
}
// NOLINTEND(cppcoreguidelines-*,readability-*)

View File

@@ -1,5 +1,15 @@
add_subdirectory(Material)
add_subdirectory(Mesh)
add_subdirectory(Part)
add_subdirectory(Points)
add_subdirectory(Sketcher)
if(BUILD_MATERIAL)
add_subdirectory(Material)
endif(BUILD_MATERIAL)
if(BUILD_MESH)
add_subdirectory(Mesh)
endif(BUILD_MESH)
if(BUILD_PART)
add_subdirectory(Part)
endif(BUILD_PART)
if(BUILD_POINTS)
add_subdirectory(Points)
endif(BUILD_POINTS)
if(BUILD_SKETCHER)
add_subdirectory(Sketcher)
endif(BUILD_SKETCHER)

View File

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

View File

@@ -770,7 +770,6 @@ TEST_F(TopoShapeExpansionTest, makeElementShellIntersecting)
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)) {
@@ -783,7 +782,7 @@ TEST_F(TopoShapeExpansionTest, makeElementShellIntersecting)
// Act
Part::TopoShape topoShape1 {1L};
topoShape1.makeElementCompound(shapes, "D");
// Act / Assert
// Assert
EXPECT_THROW(topoShape1.makeElementShell(false, nullptr), Base::CADKernelError);
}

View File

@@ -0,0 +1,53 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
#include "gtest/gtest.h"
#include <src/App/InitApplication.h>
#include "PartTestHelpers.h"
class FeaturePartMakeElementRefineTest: public ::testing::Test,
public PartTestHelpers::PartTestHelperClass
{
protected:
static void SetUpTestSuite()
{
tests::initApplication();
}
void SetUp() override
{
createTestDoc();
}
void TearDown() override
{}
};
TEST_F(FeaturePartMakeElementRefineTest, makeElementRefineBoxes)
{
// Arrange
auto _doc = App::GetApplication().getActiveDocument();
auto _fuse = dynamic_cast<Part::Fuse*>(_doc->addObject("Part::Fuse"));
_fuse->Base.setValue(_boxes[0]);
_fuse->Tool.setValue(_boxes[3]);
// Act
_fuse->execute();
Part::TopoShape ts = _fuse->Shape.getValue();
Part::TopoShape refined = ts.makeElementRefine();
double volume = PartTestHelpers::getVolume(ts.getShape());
double refinedVolume = PartTestHelpers::getVolume(refined.getShape());
Base::BoundBox3d bb = ts.getBoundBox();
// Assert
EXPECT_TRUE(bb.IsValid());
EXPECT_DOUBLE_EQ(volume, 12.0);
EXPECT_DOUBLE_EQ(refinedVolume, 12.0); // Refine shouldn't change the volume
EXPECT_EQ(ts.countSubElements("Face"), 10); // Two boxes touching each loose one face
EXPECT_EQ(ts.countSubElements("Edge"), 20); // Two boxes touching loose 4 edges
EXPECT_EQ(refined.countSubElements("Face"), 6); // After refining it is one box
EXPECT_EQ(refined.countSubElements("Edge"), 12); // 12 edges in a box
// TODO: Make sure we have an elementMap for the refine.
// Refine doesn't work on compounds, so we're going to need a binary operation or the
// like, and those don't exist yet. Once they do, this test can be expanded
}

View File

@@ -0,0 +1,129 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
// Tests for the makeShape methods, 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 <BRepBuilderAPI_MakeVertex.hxx>
using namespace Data;
using namespace Part;
using namespace PartTestHelpers;
class TopoShapeMakeShapeTests: public ::testing::Test
{
protected:
static void SetUpTestSuite()
{
tests::initApplication();
}
void SetUp() override
{
_docName = App::GetApplication().getUniqueDocumentName("test");
App::GetApplication().newDocument(_docName.c_str(), "testUser");
_sids = &_sid;
}
void TearDown() override
{
App::GetApplication().closeDocument(_docName.c_str());
}
Part::TopoShape* Shape()
{
return &_shape;
}
Part::TopoShape::Mapper* Mapper()
{
return &_mapper;
}
private:
std::string _docName;
Data::ElementIDRefs _sid;
QVector<App::StringIDRef>* _sids = nullptr;
Part::TopoShape _shape;
Part::TopoShape::Mapper _mapper;
};
TEST_F(TopoShapeMakeShapeTests, nullShapeThrows)
{
// Arrange
auto [cube1, cube2] = CreateTwoCubes();
std::vector<Part::TopoShape> sources {cube1, cube2};
TopoDS_Vertex nullShape;
// Act and assert
EXPECT_THROW(Shape()->makeShapeWithElementMap(nullShape, *Mapper(), sources),
Part::NullShapeException);
}
TEST_F(TopoShapeMakeShapeTests, shapeVertex)
{
// Arrange
BRepBuilderAPI_MakeVertex vertexMaker = BRepBuilderAPI_MakeVertex(gp_Pnt(10, 10, 10));
TopoShape topoShape(vertexMaker.Vertex(), 1L);
// Act
TopoShape& result = topoShape.makeElementShape(vertexMaker, topoShape);
auto elements = elementMap(result);
// Assert
EXPECT_EQ(elements.size(), 1);
EXPECT_EQ(elements.count(IndexedName("Vertex", 1)), 1);
EXPECT_EQ(elements[IndexedName("Vertex", 1)], MappedName("Vertex1;MAK;:H:4,V"));
EXPECT_EQ(getArea(result.getShape()), 0);
}
TEST_F(TopoShapeMakeShapeTests, thruSections)
{
// Arrange
auto [face1, wire1, edge1, edge2, edge3, edge4] = CreateRectFace();
TopoDS_Wire wire2 = wire1;
auto transform {gp_Trsf()};
transform.SetTranslation(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(0.0, 0.5, 1.0));
wire2.Move(TopLoc_Location(transform));
TopoShape wire1ts {wire1, 1L};
TopoShape wire2ts {wire2, 2L};
BRepOffsetAPI_ThruSections thruMaker;
thruMaker.AddWire(wire1);
thruMaker.AddWire(wire2);
TopoShape topoShape {};
// Act
TopoShape& result = topoShape.makeElementShape(thruMaker, {wire1ts, wire2ts});
auto elements = elementMap(result);
// Assert
EXPECT_EQ(elements.size(), 24);
EXPECT_EQ(elements.count(IndexedName("Vertex", 1)), 1);
EXPECT_EQ(elements[IndexedName("Vertex", 1)], MappedName("Vertex1;TRU;:H1:4,V"));
EXPECT_EQ(getVolume(result.getShape()), 4);
}
TEST_F(TopoShapeMakeShapeTests, sewing)
{
// Arrange
auto [face1, wire1, edge1, edge2, edge3, edge4] = CreateRectFace();
auto face2 = face1;
auto transform {gp_Trsf()};
transform.SetTranslation(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(0.5, 0.5, 0.0));
face2.Move(TopLoc_Location(transform));
BRepBuilderAPI_Sewing sewer;
sewer.Add(face1);
sewer.Add(face2);
sewer.Perform();
std::vector<TopoShape> sources {{face1, 1L}, {face2, 2L}};
TopoShape topoShape {};
// Act
TopoShape& result = topoShape.makeElementShape(sewer, sources);
auto elements = elementMap(result);
// Assert
EXPECT_EQ(&result, &topoShape);
EXPECT_EQ(elements.size(), 18); // Now a single cube
EXPECT_EQ(elements.count(IndexedName("Vertex", 1)), 1);
EXPECT_EQ(elements[IndexedName("Vertex", 1)], MappedName("Vertex1;SEW;:H1:4,V"));
EXPECT_EQ(getArea(result.getShape()), 12);
}

View File

@@ -340,3 +340,48 @@ TEST_F(TopoShapeMakeShapeWithElementMapTests, findMakerOpInElementMap)
}
}
}
std::string composeTagInfo(const MappedElement& element, const TopoShape& shape)
{
std::string elementNameStr {element.name.constPostfix()};
std::string tagInfo = POSTFIX_TAG + std::to_string(shape.Tag);
tagInfo +=
":" + std::to_string(elementNameStr.substr(0, elementNameStr.find(tagInfo)).length());
return tagInfo;
}
TEST_F(TopoShapeMakeShapeWithElementMapTests, findTagInfoInMappedName)
{
// 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
// Act and assert
// Testing with all the source TopoShapes
for (const auto& source : sources) {
Part::TopoShape tmpShape {source.getShape()};
tmpShape.makeShapeWithElementMap(source.getShape(), *Mapper(), sources);
// Make sure that there's at least 1 mapped element
ASSERT_GE(tmpShape.getElementMap().size(), 1);
// For all the mappedElements ...
for (const auto& mappedElement : tmpShape.getElementMap()) {
std::string tagInfo = composeTagInfo(mappedElement, source);
EXPECT_NE(mappedElement.name.find(tagInfo),
-1); // ... we check that in the name postfix there's the source tag
// preceded by the POSTFIX_TAG, followed by a semicolon and the
// number of characters, in Hex, from the beginning of the name
// postfix to the beginning of the POSTFIX_TAG of the given
// source's tag. VALID ONLY FOR SINGLE SHAPES!!! For complex
// shapes the number of characters is calculated differently
}
}
}