Adding additional TNP tests (#11829)
* Initial tests for Chamfer, Fillet, Compound * Lint cleanup, new tests * Outline of Extrusion and Revolution * Use python to define a 2d object to extrude and test * Refactor; start filling in revolution tests * Example of parameterized tests in Extrusion, cleanups * Use gtest framework for parameterised tests * Rearrange for clarity * WIP with TEST_P use for posterity * Switch from parameters to individual tests * Guess at test failures on other platforms * Cleanups and Revolution Tests * Remove temp code * Switch Revolutions to boundbox test; add Compound subshape count test * Calculate test volume correctly; lint fixes Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Chris Hennes <chennes@pioneerlibrarysystem.org>
This commit is contained in:
@@ -3,6 +3,16 @@ target_sources(
|
||||
Part_tests_run
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TopoShape.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/FeatureChamfer.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/FeatureCompound.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/FeatureExtrusion.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/FeatureFillet.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/FeaturePartBoolean.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/FeaturePartCommon.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/FeaturePartCut.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/FeaturePartFuse.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/FeatureRevolution.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/PartTestHelpers.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TopoShapeCache.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/FeaturePartCommon.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/FeaturePartCut.cpp
|
||||
|
||||
136
tests/src/Mod/Part/App/FeatureChamfer.cpp
Normal file
136
tests/src/Mod/Part/App/FeatureChamfer.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <src/App/InitApplication.h>
|
||||
|
||||
#include "PartTestHelpers.h"
|
||||
#include "Mod/Part/App/FeatureChamfer.h"
|
||||
|
||||
class FeatureChamferTest: public ::testing::Test, public PartTestHelpers::PartTestHelperClass
|
||||
{
|
||||
protected:
|
||||
static void SetUpTestSuite()
|
||||
{
|
||||
tests::initApplication();
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
createTestDoc();
|
||||
_boxes[0]->Length.setValue(length);
|
||||
_boxes[0]->Width.setValue(width);
|
||||
_boxes[0]->Height.setValue(height);
|
||||
_boxes[0]->Placement.setValue(
|
||||
Base::Placement(Base::Vector3d(), Base::Rotation(), Base::Vector3d()));
|
||||
_boxes[1]->Placement.setValue(
|
||||
Base::Placement(Base::Vector3d(0, 1, height), Base::Rotation(), Base::Vector3d()));
|
||||
_boxes[1]->Length.setValue(1);
|
||||
_boxes[1]->Width.setValue(2);
|
||||
_boxes[1]->Height.setValue(3);
|
||||
_fused = dynamic_cast<Part::Fuse*>(_doc->addObject("Part::Fuse"));
|
||||
_fused->Base.setValue(_boxes[0]);
|
||||
_fused->Tool.setValue(_boxes[1]);
|
||||
_fused->execute();
|
||||
_chamfer = dynamic_cast<Part::Chamfer*>(_doc->addObject("Part::Chamfer"));
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{}
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-non-private-member-variables-in-classes)
|
||||
const double length = 4.0;
|
||||
const double width = 5.0;
|
||||
const double height = 6.0;
|
||||
const double chamfer = 0.5;
|
||||
Part::Fuse* _fused = nullptr;
|
||||
Part::Chamfer* _chamfer = nullptr;
|
||||
// NOLINTEND(cppcoreguidelines-non-private-member-variables-in-classes)
|
||||
};
|
||||
|
||||
// Unfortunately for these next two tests, there are upstream errors in OCCT
|
||||
// at least until 7.5.2 that cause some chamfers that intersect each other to
|
||||
// fail. Until that's fixed, test subsets of the complete chamfer list.
|
||||
|
||||
TEST_F(FeatureChamferTest, testOther)
|
||||
{
|
||||
const double baseVolume =
|
||||
_boxes[0]->Length.getValue() * _boxes[0]->Width.getValue() * _boxes[0]->Height.getValue()
|
||||
+ _boxes[1]->Length.getValue() * _boxes[1]->Width.getValue() * _boxes[1]->Height.getValue();
|
||||
// Arrange
|
||||
_chamfer->Base.setValue(_fused);
|
||||
Part::TopoShape ts = _fused->Shape.getValue();
|
||||
unsigned long sec = ts.countSubElements("Edge");
|
||||
// Assert
|
||||
EXPECT_EQ(sec, 25);
|
||||
// Act
|
||||
_fused->Refine.setValue(true);
|
||||
_fused->execute();
|
||||
ts = _fused->Shape.getValue();
|
||||
sec = ts.countSubElements("Edge");
|
||||
// Assert
|
||||
EXPECT_EQ(sec, 24);
|
||||
// Act
|
||||
// _chamfer->Edges.setValues(PartTestHelpers::_getFilletEdges({1, 2}, chamfer, chamfer));
|
||||
_chamfer->Edges.setValues(PartTestHelpers::_getFilletEdges({1, 2}, chamfer, chamfer));
|
||||
double fusedVolume = PartTestHelpers::getVolume(_fused->Shape.getValue());
|
||||
double chamferVolume = PartTestHelpers::getVolume(_chamfer->Shape.getValue());
|
||||
// Assert
|
||||
EXPECT_DOUBLE_EQ(fusedVolume, baseVolume);
|
||||
EXPECT_DOUBLE_EQ(chamferVolume, 0.0);
|
||||
// Act
|
||||
_chamfer->execute();
|
||||
chamferVolume = PartTestHelpers::getVolume(_chamfer->Shape.getValue());
|
||||
double cv = (_boxes[0]->Length.getValue()) * chamfer * chamfer / 2
|
||||
+ (_boxes[0]->Height.getValue()) * chamfer * chamfer / 2 - chamfer * chamfer * chamfer / 3;
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(chamferVolume, baseVolume - cv);
|
||||
}
|
||||
|
||||
TEST_F(FeatureChamferTest, testMost)
|
||||
{
|
||||
// Arrange
|
||||
_fused->Refine.setValue(true);
|
||||
_fused->execute();
|
||||
_chamfer->Base.setValue(_fused);
|
||||
_chamfer->Edges.setValues(PartTestHelpers::_getFilletEdges(
|
||||
{3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // NOLINT magic number
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24}, // NOLINT magic number
|
||||
0.4, // NOLINT magic number
|
||||
0.4)); // NOLINT magic number
|
||||
// Act
|
||||
_chamfer->execute();
|
||||
double chamferVolume = PartTestHelpers::getVolume(_chamfer->Shape.getValue());
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(chamferVolume, 121.46667); // This is calculable, but painful.
|
||||
}
|
||||
|
||||
// Worth noting that FeaturePartCommon with insufficient parameters says MustExecute false,
|
||||
// but FeatureChamfer says MustExecute true. Not a condition that should ever really be hit.
|
||||
|
||||
TEST_F(FeatureChamferTest, testMustExecute)
|
||||
{
|
||||
// Assert
|
||||
EXPECT_TRUE(_chamfer->mustExecute());
|
||||
// Act
|
||||
_chamfer->Base.setValue(_boxes[0]);
|
||||
// Assert
|
||||
EXPECT_TRUE(_chamfer->mustExecute());
|
||||
// Act
|
||||
_chamfer->Edges.setValues(PartTestHelpers::_getFilletEdges({1}, chamfer, chamfer));
|
||||
// Assert
|
||||
EXPECT_TRUE(_chamfer->mustExecute());
|
||||
// Act
|
||||
_doc->recompute();
|
||||
// Assert
|
||||
EXPECT_FALSE(_chamfer->mustExecute());
|
||||
}
|
||||
|
||||
TEST_F(FeatureChamferTest, testGetProviderName)
|
||||
{
|
||||
// Act
|
||||
_chamfer->execute();
|
||||
const char* name = _chamfer->getViewProviderName();
|
||||
// Assert
|
||||
EXPECT_STREQ(name, "PartGui::ViewProviderChamfer");
|
||||
}
|
||||
59
tests/src/Mod/Part/App/FeatureCompound.cpp
Normal file
59
tests/src/Mod/Part/App/FeatureCompound.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "Mod/Part/App/FeatureCompound.h"
|
||||
#include <src/App/InitApplication.h>
|
||||
|
||||
#include "PartTestHelpers.h"
|
||||
|
||||
class FeatureCompoundTest: public ::testing::Test, public PartTestHelpers::PartTestHelperClass
|
||||
{
|
||||
protected:
|
||||
static void SetUpTestSuite()
|
||||
{
|
||||
tests::initApplication();
|
||||
}
|
||||
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
createTestDoc();
|
||||
_compound = dynamic_cast<Part::Compound*>(_doc->addObject("Part::Compound"));
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{}
|
||||
|
||||
Part::Compound* _compound = nullptr; // NOLINT Can't be private in a test framework
|
||||
};
|
||||
|
||||
TEST_F(FeatureCompoundTest, testIntersecting)
|
||||
{
|
||||
// Arrange
|
||||
_compound->Links.setValues({_boxes[0], _boxes[1]});
|
||||
// Act
|
||||
_compound->execute();
|
||||
Part::TopoShape ts = _compound->Shape.getValue();
|
||||
double volume = PartTestHelpers::getVolume(ts.getShape());
|
||||
Base::BoundBox3d bb = ts.getBoundBox();
|
||||
// Assert
|
||||
EXPECT_DOUBLE_EQ(volume, 12.0);
|
||||
EXPECT_TRUE(PartTestHelpers::boxesMatch(bb, Base::BoundBox3d(0.0, 0.0, 0.0, 1.0, 3.0, 3.0)));
|
||||
EXPECT_EQ(ts.countSubShapes(TopAbs_SHAPE), 2);
|
||||
}
|
||||
|
||||
TEST_F(FeatureCompoundTest, testNonIntersecting)
|
||||
{
|
||||
// Arrange
|
||||
_compound->Links.setValues({_boxes[0], _boxes[2]});
|
||||
// Act
|
||||
_compound->execute();
|
||||
Part::TopoShape ts = _compound->Shape.getValue();
|
||||
double volume = PartTestHelpers::getVolume(ts.getShape());
|
||||
Base::BoundBox3d bb = ts.getBoundBox();
|
||||
// Assert
|
||||
EXPECT_DOUBLE_EQ(volume, 12.0);
|
||||
EXPECT_TRUE(PartTestHelpers::boxesMatch(bb, Base::BoundBox3d(0.0, 0.0, 0.0, 1.0, 5.0, 3.0)));
|
||||
EXPECT_EQ(ts.countSubShapes(TopAbs_SHAPE), 2);
|
||||
}
|
||||
300
tests/src/Mod/Part/App/FeatureExtrusion.cpp
Normal file
300
tests/src/Mod/Part/App/FeatureExtrusion.cpp
Normal file
@@ -0,0 +1,300 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#include <cmath>
|
||||
#include "Mod/Part/App/FeatureExtrusion.h"
|
||||
#include <src/App/InitApplication.h>
|
||||
|
||||
#include "BRepBuilderAPI_MakeEdge.hxx"
|
||||
|
||||
#include "PartTestHelpers.h"
|
||||
|
||||
class FeatureExtrusionTest: public ::testing::Test, public PartTestHelpers::PartTestHelperClass
|
||||
{
|
||||
protected:
|
||||
static void SetUpTestSuite()
|
||||
{
|
||||
tests::initApplication();
|
||||
}
|
||||
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
createTestDoc();
|
||||
_extrusion = dynamic_cast<Part::Extrusion*>(_doc->addObject("Part::Extrusion"));
|
||||
PartTestHelpers::rectangle(len, wid, "Rect1");
|
||||
_extrusion->Base.setValue(_doc->getObjects().back());
|
||||
_extrusion->LengthFwd.setValue(ext1);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{}
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-non-private-member-variables-in-classes)
|
||||
Part::Extrusion* _extrusion = nullptr;
|
||||
// Arbtitrary constants for testing. Named here for clarity.
|
||||
const double len = 3.0;
|
||||
const double wid = 4.0;
|
||||
const double ext1 = 10.0;
|
||||
// NOLINTEND(cppcoreguidelines-non-private-member-variables-in-classes)
|
||||
};
|
||||
|
||||
TEST_F(FeatureExtrusionTest, testMustExecute)
|
||||
{
|
||||
// Assert
|
||||
EXPECT_TRUE(_extrusion->mustExecute());
|
||||
// Act
|
||||
_doc->recompute();
|
||||
// Assert
|
||||
EXPECT_FALSE(_extrusion->mustExecute());
|
||||
// Act
|
||||
_extrusion->Base.setValue(_extrusion->Base.getValue());
|
||||
// Assert
|
||||
EXPECT_TRUE(_extrusion->mustExecute());
|
||||
// Act
|
||||
_doc->recompute();
|
||||
// Assert
|
||||
EXPECT_FALSE(_extrusion->mustExecute());
|
||||
// Act
|
||||
_extrusion->Solid.setValue(Standard_True);
|
||||
// Assert
|
||||
EXPECT_TRUE(_extrusion->mustExecute());
|
||||
// Act
|
||||
_doc->recompute();
|
||||
// Assert
|
||||
EXPECT_FALSE(_extrusion->mustExecute());
|
||||
}
|
||||
|
||||
TEST_F(FeatureExtrusionTest, testGetProviderName)
|
||||
{
|
||||
// Act
|
||||
_extrusion->execute();
|
||||
const char* name = _extrusion->getViewProviderName();
|
||||
// Assert
|
||||
EXPECT_STREQ(name, "PartGui::ViewProviderExtrusion");
|
||||
}
|
||||
|
||||
// Not clear if there is test value in this one.
|
||||
|
||||
TEST_F(FeatureExtrusionTest, testFetchAxisLink)
|
||||
{
|
||||
// static bool fetchAxisLink(const App::PropertyLinkSub& axisLink,
|
||||
// Base::Vector3d& basepoint,
|
||||
// Base::Vector3d& dir);
|
||||
}
|
||||
|
||||
// Filling in these next two tests seems very redundant, since they are used in execute()
|
||||
// and thus tested by the results there. In the event that ever went funny, then maybe
|
||||
// implementation here would make sense.
|
||||
|
||||
TEST_F(FeatureExtrusionTest, testExtrudeShape)
|
||||
{
|
||||
// static TopoShape extrudeShape(const TopoShape& source, const ExtrusionParameters& params);
|
||||
}
|
||||
|
||||
TEST_F(FeatureExtrusionTest, testComputeFinalParameters)
|
||||
{
|
||||
// ExtrusionParameters computeFinalParameters();
|
||||
}
|
||||
|
||||
TEST_F(FeatureExtrusionTest, testExecuteSimple)
|
||||
{
|
||||
// Arrange
|
||||
// Act
|
||||
_extrusion->execute();
|
||||
Part::TopoShape ts = _extrusion->Shape.getValue();
|
||||
double volume = PartTestHelpers::getVolume(ts.getShape());
|
||||
Base::BoundBox3d bb = ts.getBoundBox();
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(volume, len * wid * ext1);
|
||||
EXPECT_TRUE(PartTestHelpers::boxesMatch(bb, Base::BoundBox3d(0, 0, 0, len, wid, ext1)));
|
||||
}
|
||||
|
||||
TEST_F(FeatureExtrusionTest, testExecuteSimpleRev)
|
||||
{
|
||||
const double ext2 = 9;
|
||||
// Arrange
|
||||
_extrusion->LengthFwd.setValue(0);
|
||||
_extrusion->LengthRev.setValue(ext2);
|
||||
// Act
|
||||
_extrusion->execute();
|
||||
Part::TopoShape ts = _extrusion->Shape.getValue();
|
||||
double volume = PartTestHelpers::getVolume(ts.getShape());
|
||||
Base::BoundBox3d bb = ts.getBoundBox();
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(volume, len * wid * ext2);
|
||||
EXPECT_TRUE(PartTestHelpers::boxesMatch(bb, Base::BoundBox3d(0, 0, -ext2, len, wid, 0)));
|
||||
}
|
||||
|
||||
TEST_F(FeatureExtrusionTest, testExecuteSolid)
|
||||
{
|
||||
// Arrange
|
||||
_extrusion->Solid.setValue(true);
|
||||
// Act
|
||||
_extrusion->execute();
|
||||
Part::TopoShape ts = _extrusion->Shape.getValue();
|
||||
double volume = PartTestHelpers::getVolume(ts.getShape());
|
||||
Base::BoundBox3d bb = ts.getBoundBox();
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(volume, len * wid * ext1);
|
||||
EXPECT_TRUE(PartTestHelpers::boxesMatch(bb, Base::BoundBox3d(0, 0, 0, len, wid, ext1)));
|
||||
}
|
||||
|
||||
TEST_F(FeatureExtrusionTest, testExecuteReverse)
|
||||
{
|
||||
// Arrange
|
||||
_extrusion->Reversed.setValue(true);
|
||||
// Act
|
||||
_extrusion->execute();
|
||||
Part::TopoShape ts = _extrusion->Shape.getValue();
|
||||
double volume = PartTestHelpers::getVolume(ts.getShape());
|
||||
Base::BoundBox3d bb = ts.getBoundBox();
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(volume, len * wid * ext1);
|
||||
EXPECT_TRUE(PartTestHelpers::boxesMatch(bb, Base::BoundBox3d(0, 0, -ext1, len, wid, 0)));
|
||||
}
|
||||
|
||||
TEST_F(FeatureExtrusionTest, testExecuteSymmetric)
|
||||
{
|
||||
// Arrange
|
||||
_extrusion->Symmetric.setValue(true);
|
||||
// Act
|
||||
_extrusion->execute();
|
||||
Part::TopoShape ts = _extrusion->Shape.getValue();
|
||||
double volume = PartTestHelpers::getVolume(ts.getShape());
|
||||
Base::BoundBox3d bb = ts.getBoundBox();
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(volume, len * wid * ext1);
|
||||
EXPECT_TRUE(
|
||||
PartTestHelpers::boxesMatch(bb, Base::BoundBox3d(0, 0, -ext1 / 2, len, wid, ext1 / 2)));
|
||||
}
|
||||
|
||||
TEST_F(FeatureExtrusionTest, testExecuteAngled)
|
||||
{
|
||||
// Arrange
|
||||
const double ang = 30;
|
||||
const double tangent = tan(ang / 180.0 * M_PI);
|
||||
|
||||
// The shape is a truncated pyramid elongated by a truncated triangular prism in the middle.
|
||||
// Calc the volume of full size pyramid and prism, and subtract top volumes to truncate.
|
||||
const double shorterSide = len > wid ? wid : len;
|
||||
const double longerSide = len < wid ? wid : len;
|
||||
const double centerWidth = longerSide - shorterSide; // Width of the triang prism.
|
||||
const double topHeight = shorterSide / tangent / 2; // Height of the truncation
|
||||
const double fullHeight = ext1 + topHeight;
|
||||
const double fullPrismVol =
|
||||
fullHeight * (shorterSide + ext1 * tangent * 2.0) / 2.0 * centerWidth;
|
||||
const double fullPyrVol = pow(shorterSide + ext1 * tangent * 2.0, 2.0) / 3.0 * fullHeight;
|
||||
const double topPrismVol = topHeight * shorterSide / 2.0 * centerWidth;
|
||||
const double topPyrVol = pow(shorterSide, 2.0) / 3.0 * topHeight;
|
||||
const double targetVol = (fullPyrVol + fullPrismVol) - (topPyrVol + topPrismVol);
|
||||
_extrusion->Solid.setValue(true);
|
||||
_extrusion->TaperAngle.setValue(ang);
|
||||
// Act
|
||||
_extrusion->execute();
|
||||
Part::TopoShape ts = _extrusion->Shape.getValue();
|
||||
double volume = PartTestHelpers::getVolume(ts.getShape());
|
||||
Base::BoundBox3d bb = ts.getBoundBox();
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(volume, targetVol);
|
||||
EXPECT_TRUE(PartTestHelpers::boxesMatch(bb,
|
||||
Base::BoundBox3d(-ext1 * tangent,
|
||||
-ext1 * tangent,
|
||||
0,
|
||||
len + ext1 * tangent,
|
||||
wid + ext1 * tangent,
|
||||
ext1)));
|
||||
}
|
||||
|
||||
TEST_F(FeatureExtrusionTest, testExecuteAngledRev)
|
||||
{
|
||||
// Arrange
|
||||
const double ang = 30;
|
||||
const double tangent = tan(ang / 180.0 * M_PI);
|
||||
// The shape is a truncated pyramid elongated by a truncated triangular prism in the middle,
|
||||
// plus a rectangular prism.
|
||||
// Calc the volume of full size pyramid and prism, and subtract top volumes to truncate.
|
||||
const double shorterSide = len > wid ? wid : len;
|
||||
const double longerSide = len < wid ? wid : len;
|
||||
const double centerWidth = longerSide - shorterSide; // Width of the triang prism.
|
||||
const double topHeight = shorterSide / tangent / 2; // Height of the truncation
|
||||
const double fullHeight = ext1 / 2 + topHeight;
|
||||
const double fullPrismVol =
|
||||
fullHeight * (shorterSide + ext1 / 2 * tangent * 2.0) / 2.0 * centerWidth;
|
||||
const double fullPyrVol = pow(shorterSide + ext1 / 2 * tangent * 2.0, 2.0) / 3.0 * fullHeight;
|
||||
const double topPrismVol = topHeight * shorterSide / 2.0 * centerWidth;
|
||||
const double topPyrVol = pow(shorterSide, 2.0) / 3.0 * topHeight;
|
||||
const double targetVol =
|
||||
(fullPyrVol + fullPrismVol) - (topPyrVol + topPrismVol) + len * wid * ext1 / 2;
|
||||
|
||||
_extrusion->Solid.setValue(true);
|
||||
_extrusion->Symmetric.setValue(true);
|
||||
_extrusion->TaperAngleRev.setValue(ang);
|
||||
// Act
|
||||
_extrusion->execute();
|
||||
Part::TopoShape ts = _extrusion->Shape.getValue();
|
||||
double volume = PartTestHelpers::getVolume(ts.getShape());
|
||||
Base::BoundBox3d bb = ts.getBoundBox();
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(volume, targetVol);
|
||||
EXPECT_TRUE(PartTestHelpers::boxesMatch(bb,
|
||||
Base::BoundBox3d(-ext1 * tangent / 2,
|
||||
-ext1 * tangent / 2,
|
||||
-ext1 / 2,
|
||||
len + ext1 * tangent / 2,
|
||||
wid + ext1 * tangent / 2,
|
||||
ext1 / 2)));
|
||||
}
|
||||
|
||||
TEST_F(FeatureExtrusionTest, testExecuteEdge)
|
||||
{
|
||||
// Arrange
|
||||
const double ang = 30;
|
||||
const double tangent = tan(ang / 180.0 * M_PI);
|
||||
BRepBuilderAPI_MakeEdge e1(gp_Pnt(0, 0, 0), gp_Pnt(ext1, ext1, ext1));
|
||||
auto edge = dynamic_cast<Part::Feature*>(_doc->addObject("Part::Feature", "Edge"));
|
||||
edge->Shape.setValue(e1);
|
||||
_extrusion->DirLink.setValue(edge);
|
||||
_extrusion->DirMode.setValue(1);
|
||||
// Act
|
||||
_extrusion->execute();
|
||||
Part::TopoShape ts = _extrusion->Shape.getValue();
|
||||
double volume = PartTestHelpers::getVolume(ts.getShape());
|
||||
Base::BoundBox3d bb = ts.getBoundBox();
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(volume, len * wid * ext1 * tangent);
|
||||
EXPECT_TRUE(PartTestHelpers::boxesMatch(
|
||||
bb,
|
||||
Base::BoundBox3d(0, 0, 0, len + ext1 * tangent, wid + ext1 * tangent, ext1 * tangent)));
|
||||
}
|
||||
|
||||
TEST_F(FeatureExtrusionTest, testExecuteDir)
|
||||
{
|
||||
// Arrange
|
||||
const double sin45 = sin(45 / 180.0 * M_PI);
|
||||
_extrusion->Dir.setValue(Base::Vector3d(0, 1, 1));
|
||||
_extrusion->DirMode.setValue((long)0);
|
||||
// Act
|
||||
_extrusion->execute();
|
||||
Part::TopoShape ts = _extrusion->Shape.getValue();
|
||||
double volume = PartTestHelpers::getVolume(ts.getShape());
|
||||
Base::BoundBox3d bb = ts.getBoundBox();
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(volume, len * wid * ext1 * sin45);
|
||||
EXPECT_TRUE(PartTestHelpers::boxesMatch(
|
||||
bb,
|
||||
Base::BoundBox3d(0, 0, 0, len, wid + ext1 * sin45, ext1 * sin45)));
|
||||
}
|
||||
|
||||
TEST_F(FeatureExtrusionTest, testExecuteFaceMaker)
|
||||
{
|
||||
// Arrange
|
||||
_extrusion->FaceMakerClass.setValue("Part::FaceMakerCheese");
|
||||
// Act
|
||||
_extrusion->execute();
|
||||
Part::TopoShape ts = _extrusion->Shape.getValue();
|
||||
double volume = PartTestHelpers::getVolume(ts.getShape());
|
||||
Base::BoundBox3d bb = ts.getBoundBox();
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(volume, len * wid * ext1);
|
||||
EXPECT_TRUE(PartTestHelpers::boxesMatch(bb, Base::BoundBox3d(0, 0, 0, len, wid, ext1)));
|
||||
}
|
||||
159
tests/src/Mod/Part/App/FeatureFillet.cpp
Normal file
159
tests/src/Mod/Part/App/FeatureFillet.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <src/App/InitApplication.h>
|
||||
|
||||
#include "PartTestHelpers.h"
|
||||
|
||||
// NOLINTBEGIN(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers)
|
||||
class FeatureFilletTest: public ::testing::Test, public PartTestHelpers::PartTestHelperClass
|
||||
{
|
||||
protected:
|
||||
static void SetUpTestSuite()
|
||||
{
|
||||
tests::initApplication();
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
createTestDoc();
|
||||
_boxes[0]->Length.setValue(4);
|
||||
_boxes[0]->Width.setValue(5);
|
||||
_boxes[0]->Height.setValue(6);
|
||||
_boxes[0]->Placement.setValue(
|
||||
Base::Placement(Base::Vector3d(), Base::Rotation(), Base::Vector3d()));
|
||||
_boxes[1]->Placement.setValue(
|
||||
Base::Placement(Base::Vector3d(0, 1, 6), Base::Rotation(), Base::Vector3d()));
|
||||
_boxes[1]->Length.setValue(1);
|
||||
_boxes[1]->Width.setValue(2);
|
||||
_boxes[1]->Height.setValue(3);
|
||||
_fused = dynamic_cast<Part::Fuse*>(_doc->addObject("Part::Fuse"));
|
||||
_fused->Base.setValue(_boxes[0]);
|
||||
_fused->Tool.setValue(_boxes[1]);
|
||||
_fused->execute();
|
||||
_fillet = dynamic_cast<Part::Fillet*>(_doc->addObject("Part::Fillet"));
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{}
|
||||
|
||||
Part::Fuse* _fused = nullptr; // NOLINT Can't be private in a test framework
|
||||
Part::Fillet* _fillet = nullptr; // NOLINT Can't be private in a test framework
|
||||
};
|
||||
|
||||
// Unfortunately for these next two tests, there are upstream errors in OCCT
|
||||
// at least until 7.5.2 that cause some fillets that intersect each other to
|
||||
// fail. Until that's fixed, test subsets of the complete fillet list.
|
||||
|
||||
TEST_F(FeatureFilletTest, testOtherEdges)
|
||||
{
|
||||
const double baseVolume =
|
||||
_boxes[0]->Length.getValue() * _boxes[0]->Width.getValue() * _boxes[0]->Height.getValue()
|
||||
+ _boxes[1]->Length.getValue() * _boxes[1]->Width.getValue() * _boxes[1]->Height.getValue();
|
||||
// Arrange
|
||||
_fillet->Base.setValue(_fused);
|
||||
Part::TopoShape ts = _fused->Shape.getValue();
|
||||
unsigned long sec = ts.countSubElements("Edge");
|
||||
// Assert
|
||||
EXPECT_EQ(sec, 25);
|
||||
// Act
|
||||
_fused->Refine.setValue(true);
|
||||
_fused->execute();
|
||||
ts = _fused->Shape.getValue();
|
||||
sec = ts.countSubElements("Edge");
|
||||
// Assert
|
||||
EXPECT_EQ(sec, 24);
|
||||
|
||||
// Act
|
||||
_fillet->Edges.setValues(PartTestHelpers::_getFilletEdges({15, 17}, 0.5, 0.5));
|
||||
double fusedVolume = PartTestHelpers::getVolume(_fused->Shape.getValue());
|
||||
double filletVolume = PartTestHelpers::getVolume(_fillet->Shape.getValue());
|
||||
// Assert
|
||||
EXPECT_DOUBLE_EQ(fusedVolume, baseVolume);
|
||||
EXPECT_DOUBLE_EQ(filletVolume, 0.0);
|
||||
// Act
|
||||
_fillet->execute();
|
||||
filletVolume = PartTestHelpers::getVolume(_fillet->Shape.getValue());
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(filletVolume, 125.57079);
|
||||
}
|
||||
|
||||
TEST_F(FeatureFilletTest, testMostEdges)
|
||||
{
|
||||
// Arrange
|
||||
_fused->Refine.setValue(true);
|
||||
// _fused->execute();
|
||||
_fillet->Base.setValue(_fused);
|
||||
_fillet->Edges.setValues(PartTestHelpers::_getFilletEdges(
|
||||
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 18, 19, 20, 22, 23, 24},
|
||||
0.4,
|
||||
0.4));
|
||||
// Act
|
||||
_fillet->execute();
|
||||
double filletVolume = PartTestHelpers::getVolume(_fillet->Shape.getValue());
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(filletVolume, 118.38763);
|
||||
}
|
||||
|
||||
// Worth noting that FeaturePartCommon with insufficient parameters says MustExecute false,
|
||||
// but FeatureFillet says MustExecute true. Not a condition that should ever really be hit.
|
||||
|
||||
TEST_F(FeatureFilletTest, testMustExecute)
|
||||
{
|
||||
// Assert
|
||||
EXPECT_TRUE(_fillet->mustExecute());
|
||||
// Act
|
||||
_fillet->Base.setValue(_boxes[0]);
|
||||
// Assert
|
||||
EXPECT_TRUE(_fillet->mustExecute());
|
||||
// Act
|
||||
_fillet->Edges.setValues(PartTestHelpers::_getFilletEdges({1}, 0.5, 0.5));
|
||||
// Assert
|
||||
EXPECT_TRUE(_fillet->mustExecute());
|
||||
// Act
|
||||
_doc->recompute();
|
||||
// Assert
|
||||
EXPECT_FALSE(_fillet->mustExecute());
|
||||
}
|
||||
|
||||
TEST_F(FeatureFilletTest, testGetProviderName)
|
||||
{
|
||||
// Act
|
||||
_fillet->execute();
|
||||
const char* name = _fillet->getViewProviderName();
|
||||
// Assert
|
||||
EXPECT_STREQ(name, "PartGui::ViewProviderFillet");
|
||||
}
|
||||
|
||||
// NOLINTEND(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers)
|
||||
|
||||
// void PrintTo(const TopoDS_Shape& ds, std::ostream* os)
|
||||
// {
|
||||
// *os << "TopoDS_Shape ";
|
||||
// for (TopExp_Explorer ex(ds, TopAbs_VERTEX); ex.More(); ex.Next()) {
|
||||
// gp_Pnt point = BRep_Tool::Pnt(TopoDS::Vertex(ex.Current()));
|
||||
// *os << "(" << point.X() << "," << point.Y() << "," << point.Z() << ") ";
|
||||
// }
|
||||
// *os << std::endl;
|
||||
// }
|
||||
|
||||
// void edgesAtBusyVertexes(Part::TopoShape ts)
|
||||
// {
|
||||
// const char* categories[] = { "Face", "Wire", "Edge", "Vertex" };
|
||||
|
||||
// for (auto category : categories ) {
|
||||
// int count = ts.countSubShapes(category);
|
||||
// for ( int index=1; index <= count; index++ ) {
|
||||
// std::string name = category + std::to_string(index);
|
||||
// const char * cname = name.c_str();
|
||||
// TopoDS_Shape ss = ts.getSubShape(cname);
|
||||
// os << cname << ": ";
|
||||
// for (TopExp_Explorer ex(ss, TopAbs_VERTEX); ex.More(); ex.Next()) {
|
||||
// gp_Pnt point = BRep_Tool::Pnt(TopoDS::Vertex(ex.Current()));
|
||||
// os << "(" << point.X() << "," << point.Y() << "," << point.Z() << ") ";
|
||||
// }
|
||||
// os << std::endl;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
33
tests/src/Mod/Part/App/FeaturePartBoolean.cpp
Normal file
33
tests/src/Mod/Part/App/FeaturePartBoolean.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "Mod/Part/App/FeaturePartBoolean.h"
|
||||
#include <src/App/InitApplication.h>
|
||||
|
||||
#include "PartTestHelpers.h"
|
||||
|
||||
class FeaturePartBooleanTest: public ::testing::Test, public PartTestHelpers::PartTestHelperClass
|
||||
{
|
||||
protected:
|
||||
static void SetUpTestSuite()
|
||||
{
|
||||
tests::initApplication();
|
||||
}
|
||||
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
// createTestDoc();
|
||||
// _boolean = dynamic_cast<Part::Boolean*>(_doc->addObject("Part::Boolean"));
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{}
|
||||
|
||||
Part::Boolean* _boolean; // NOLINT Can't be private in a test framework
|
||||
};
|
||||
|
||||
// This is completely tested in the FeaturePartCommon, FeaturePartCut, and FeaturePartFuse
|
||||
// subclasses. This class is unfortunately not usable unless initialized in one of those
|
||||
// forms, so no testing at this level.
|
||||
192
tests/src/Mod/Part/App/FeatureRevolution.cpp
Normal file
192
tests/src/Mod/Part/App/FeatureRevolution.cpp
Normal file
@@ -0,0 +1,192 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "Mod/Part/App/FeatureRevolution.h"
|
||||
#include <src/App/InitApplication.h>
|
||||
|
||||
#include "Base/Interpreter.h"
|
||||
|
||||
#include "BRepBuilderAPI_MakeEdge.hxx"
|
||||
|
||||
#include "TopoDS_Iterator.hxx"
|
||||
|
||||
#include "PartTestHelpers.h"
|
||||
|
||||
class FeatureRevolutionTest: public ::testing::Test, public PartTestHelpers::PartTestHelperClass
|
||||
{
|
||||
protected:
|
||||
static void SetUpTestSuite()
|
||||
{
|
||||
tests::initApplication();
|
||||
}
|
||||
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
createTestDoc();
|
||||
_revolution = dynamic_cast<Part::Revolution*>(_doc->addObject("Part::Revolution"));
|
||||
PartTestHelpers::rectangle(len, wid, "Rect1");
|
||||
_revolution->Source.setValue(_doc->getObjects().back());
|
||||
_revolution->Axis.setValue(0, 1, 0);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{}
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-non-private-member-variables-in-classes)
|
||||
Part::Revolution* _revolution = nullptr;
|
||||
// Arbtitrary constants for testing. Named here for clarity.
|
||||
const double len = 3;
|
||||
const double wid = 4;
|
||||
const double ext1 = 10;
|
||||
// NOLINTEND(cppcoreguidelines-non-private-member-variables-in-classes)
|
||||
};
|
||||
|
||||
TEST_F(FeatureRevolutionTest, testExecute)
|
||||
{
|
||||
// Arrange
|
||||
double puckVolume = len * len * M_PI * wid; // Area is PIr2; apply height
|
||||
// Act
|
||||
_revolution->execute();
|
||||
Part::TopoShape ts = _revolution->Shape.getValue();
|
||||
double volume = PartTestHelpers::getVolume(ts.getShape());
|
||||
Base::BoundBox3d bb = ts.getBoundBox();
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(volume, puckVolume);
|
||||
EXPECT_TRUE(PartTestHelpers::boxesMatch(bb, Base::BoundBox3d(-len, 0, -len, len, wid, len)));
|
||||
}
|
||||
|
||||
TEST_F(FeatureRevolutionTest, testExecuteBase)
|
||||
{
|
||||
// Arrange
|
||||
double rad = len + 1.0;
|
||||
double rad2 = 1.0;
|
||||
double outerPuckVolume = rad * rad * M_PI * wid; // Area is PIr2; apply height
|
||||
double innerPuckVolume = rad2 * rad2 * M_PI * wid; // Area is PIr2; apply height
|
||||
_revolution->Base.setValue(Base::Vector3d(len + 1, 0, 0));
|
||||
// Act
|
||||
_revolution->execute();
|
||||
Part::TopoShape ts = _revolution->Shape.getValue();
|
||||
double volume = PartTestHelpers::getVolume(ts.getShape());
|
||||
Base::BoundBox3d bb = ts.getBoundBox();
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(volume, outerPuckVolume - innerPuckVolume);
|
||||
EXPECT_TRUE(PartTestHelpers::boxesMatch(bb, Base::BoundBox3d(0, 0, -wid, wid * 2, wid, wid)));
|
||||
}
|
||||
|
||||
|
||||
TEST_F(FeatureRevolutionTest, testAxis)
|
||||
{
|
||||
// Arrange
|
||||
double puckVolume = wid * wid * M_PI * len; // Area is PIr2 times height
|
||||
_revolution->Axis.setValue(Base::Vector3d(1, 0, 0));
|
||||
// Act
|
||||
_revolution->execute();
|
||||
Part::TopoShape ts = _revolution->Shape.getValue();
|
||||
double volume = PartTestHelpers::getVolume(ts.getShape());
|
||||
Base::BoundBox3d bb = ts.getBoundBox();
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(volume, puckVolume);
|
||||
EXPECT_TRUE(PartTestHelpers::boxesMatch(bb, Base::BoundBox3d(0, -wid, -wid, len, wid, wid)));
|
||||
}
|
||||
|
||||
TEST_F(FeatureRevolutionTest, testAxisLink)
|
||||
{
|
||||
// Arrange
|
||||
BRepBuilderAPI_MakeEdge e1(gp_Pnt(0, 0, 0), gp_Pnt(0, 0, ext1));
|
||||
auto edge = dynamic_cast<Part::Feature*>(_doc->addObject("Part::Feature", "Edge"));
|
||||
edge->Shape.setValue(e1);
|
||||
_revolution->AxisLink.setValue(edge);
|
||||
// double puckVolume = wid * wid * M_PI * len; // Area is PIr2; apply height
|
||||
// Act
|
||||
_revolution->execute();
|
||||
Part::TopoShape ts = _revolution->Shape.getValue();
|
||||
double volume = PartTestHelpers::getVolume(ts.getShape());
|
||||
Base::BoundBox3d bb = ts.getBoundBox();
|
||||
// Assert
|
||||
double puckVolume = 0; // Someday make this test use a more interesting edge angle
|
||||
EXPECT_FLOAT_EQ(volume, puckVolume);
|
||||
EXPECT_TRUE(PartTestHelpers::boxesMatch(
|
||||
bb,
|
||||
Base::BoundBox3d(-ext1 / 2, -ext1 / 2, 0, ext1 / 2, ext1 / 2, 0)));
|
||||
}
|
||||
|
||||
TEST_F(FeatureRevolutionTest, testSymmetric)
|
||||
{
|
||||
// Arrange
|
||||
double puckVolume = len * len * M_PI * wid; // Area is PIr2 times height
|
||||
_revolution->Symmetric.setValue(true);
|
||||
// Act
|
||||
_revolution->execute();
|
||||
Part::TopoShape ts = _revolution->Shape.getValue();
|
||||
double volume = PartTestHelpers::getVolume(ts.getShape());
|
||||
Base::BoundBox3d bb = ts.getBoundBox();
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(volume, puckVolume);
|
||||
EXPECT_TRUE(PartTestHelpers::boxesMatch(bb, Base::BoundBox3d(-len, 0, -len, len, wid, len)));
|
||||
}
|
||||
|
||||
TEST_F(FeatureRevolutionTest, testAngle)
|
||||
{
|
||||
// Arrange
|
||||
double puckVolume = len * len * M_PI * wid; // Area is PIr2 times height
|
||||
_revolution->Angle.setValue(90); // NOLINT magic number
|
||||
// Act
|
||||
_revolution->execute();
|
||||
Part::TopoShape ts = _revolution->Shape.getValue();
|
||||
double volume = PartTestHelpers::getVolume(ts.getShape());
|
||||
Base::BoundBox3d bb = ts.getBoundBox();
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(volume, puckVolume / 4);
|
||||
EXPECT_TRUE(PartTestHelpers::boxesMatch(bb, Base::BoundBox3d(0, 0, -len, len, wid, 0)));
|
||||
}
|
||||
|
||||
TEST_F(FeatureRevolutionTest, testMustExecute)
|
||||
{
|
||||
// Assert
|
||||
EXPECT_TRUE(_revolution->mustExecute());
|
||||
// Act
|
||||
_doc->recompute();
|
||||
// Assert
|
||||
EXPECT_FALSE(_revolution->mustExecute());
|
||||
// Act
|
||||
_revolution->Base.setValue(_revolution->Base.getValue());
|
||||
// Assert
|
||||
EXPECT_TRUE(_revolution->mustExecute());
|
||||
// Act
|
||||
_doc->recompute();
|
||||
// Assert
|
||||
EXPECT_FALSE(_revolution->mustExecute());
|
||||
// Act
|
||||
_revolution->Solid.setValue(Standard_True);
|
||||
// Assert
|
||||
EXPECT_TRUE(_revolution->mustExecute());
|
||||
// Act
|
||||
_doc->recompute();
|
||||
// Assert
|
||||
EXPECT_FALSE(_revolution->mustExecute());
|
||||
}
|
||||
|
||||
// TEST_F(FeatureRevolutionTest, testOnChanged)
|
||||
// {
|
||||
// // void onChanged(const App::Property* prop) override;
|
||||
// }
|
||||
|
||||
TEST_F(FeatureRevolutionTest, testGetProviderName)
|
||||
{
|
||||
// Act
|
||||
_revolution->execute();
|
||||
const char* name = _revolution->getViewProviderName();
|
||||
// Assert
|
||||
EXPECT_STREQ(name, "PartGui::ViewProviderRevolution");
|
||||
}
|
||||
|
||||
// Tested by execute above
|
||||
// TEST_F(FeatureRevolutionTest, testFetchAxisLink)
|
||||
// {
|
||||
// // static bool fetchAxisLink(const App::PropertyLinkSub& axisLink,
|
||||
// // Base::Vector3d ¢er,
|
||||
// // Base::Vector3d &dir,
|
||||
// // double &angle);
|
||||
// }
|
||||
@@ -1,10 +1,13 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#include "PartTestHelpers.h"
|
||||
|
||||
// NOLINTBEGIN(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers)
|
||||
|
||||
namespace PartTestHelpers
|
||||
{
|
||||
|
||||
double getVolume(const TopoDS_Shape shape)
|
||||
double getVolume(const TopoDS_Shape& shape)
|
||||
{
|
||||
GProp_GProps prop;
|
||||
BRepGProp::VolumeProperties(shape, prop);
|
||||
@@ -16,7 +19,6 @@ void PartTestHelperClass::createTestDoc()
|
||||
_docName = App::GetApplication().getUniqueDocumentName("test");
|
||||
_doc = App::GetApplication().newDocument(_docName.c_str(), "testUser");
|
||||
std::array<Base::Vector3d, 6> box_origins = {
|
||||
// NOLINT magic number
|
||||
Base::Vector3d(), // First box at 0,0,0
|
||||
Base::Vector3d(0, 1, 0), // Overlap with first box
|
||||
Base::Vector3d(0, 3, 0), // Don't Overlap with first box
|
||||
@@ -25,14 +27,73 @@ void PartTestHelperClass::createTestDoc()
|
||||
// For the Just Inside Of Touching case, go enough that we exceed precision rounding
|
||||
Base::Vector3d(0, 2 - minimalDistance, 0)};
|
||||
|
||||
for (int i = 0; i < _boxes.size(); i++) {
|
||||
auto box = _boxes[i] = static_cast<Part::Box*>(_doc->addObject("Part::Box"));
|
||||
for (unsigned i = 0; i < _boxes.size(); i++) {
|
||||
auto box = _boxes[i] = dynamic_cast<Part::Box*>(_doc->addObject("Part::Box")); // NOLINT
|
||||
box->Length.setValue(1);
|
||||
box->Width.setValue(2);
|
||||
box->Height.setValue(3);
|
||||
box->Placement.setValue(
|
||||
Base::Placement(box_origins[i], Base::Rotation(), Base::Vector3d()));
|
||||
Base::Placement(box_origins[i], Base::Rotation(), Base::Vector3d())); // NOLINT
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Part::FilletElement>
|
||||
_getFilletEdges(const std::vector<int>& edges, double startRadius, double endRadius)
|
||||
{
|
||||
std::vector<Part::FilletElement> filletElements;
|
||||
for (auto edge : edges) {
|
||||
Part::FilletElement fe = {edge, startRadius, endRadius};
|
||||
filletElements.push_back(fe);
|
||||
}
|
||||
return filletElements;
|
||||
}
|
||||
|
||||
void executePython(const std::vector<std::string>& python)
|
||||
{
|
||||
Base::InterpreterSingleton is = Base::InterpreterSingleton();
|
||||
|
||||
for (auto const& line : python) {
|
||||
is.runInteractiveString(line.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void rectangle(double height, double width, char* name)
|
||||
{
|
||||
std::vector<std::string> rectstring {
|
||||
"import FreeCAD, Part",
|
||||
"V1 = FreeCAD.Vector(0, 0, 0)",
|
||||
boost::str(boost::format("V2 = FreeCAD.Vector(%d, 0, 0)") % height),
|
||||
boost::str(boost::format("V3 = FreeCAD.Vector(%d, %d, 0)") % height % width),
|
||||
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);
|
||||
}
|
||||
|
||||
testing::AssertionResult
|
||||
boxesMatch(const Base::BoundBox3d& b1, const Base::BoundBox3d& b2, double prec)
|
||||
{
|
||||
if (abs(b1.MinX - b2.MinX) < prec && abs(b1.MinY - b2.MinY) < prec
|
||||
&& abs(b1.MinZ - b2.MinZ) < prec && abs(b1.MaxX - b2.MaxX) < prec
|
||||
&& abs(b1.MaxY - b2.MaxY) < prec && abs(b1.MaxZ - b2.MaxZ) < prec) {
|
||||
return testing::AssertionSuccess();
|
||||
}
|
||||
return testing::AssertionFailure()
|
||||
<< "(" << b1.MinX << "," << b1.MinY << "," << b1.MinZ << " ; "
|
||||
<< "(" << b1.MaxX << "," << b1.MaxY << "," << b1.MaxZ << ") != (" << b2.MinX << ","
|
||||
<< b2.MinY << "," << b2.MinZ << " ; " << b2.MaxX << "," << b2.MaxY << "," << b2.MaxZ << ")";
|
||||
}
|
||||
|
||||
} // namespace PartTestHelpers
|
||||
|
||||
// NOLINTEND(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers)
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <Base/Precision.h>
|
||||
@@ -5,21 +8,32 @@
|
||||
#include "Mod/Part/App/FeaturePartFuse.h"
|
||||
#include "Mod/Part/App/FeatureFillet.h"
|
||||
#include <BRepGProp.hxx>
|
||||
#include "Base/Interpreter.h"
|
||||
#include <boost/format.hpp>
|
||||
|
||||
namespace PartTestHelpers
|
||||
{
|
||||
|
||||
double getVolume(TopoDS_Shape shape);
|
||||
double getVolume(const TopoDS_Shape& shape);
|
||||
|
||||
std::vector<Part::FilletElement>
|
||||
_getFilletEdges(const std::vector<int>& edges, double startRadius, double endRadius);
|
||||
|
||||
class PartTestHelperClass
|
||||
{
|
||||
public:
|
||||
App::Document* _doc;
|
||||
std::string _docName;
|
||||
std::array<Part::Box*, 6> _boxes;
|
||||
std::array<Part::Box*, 6> _boxes; // NOLINT magic number
|
||||
void createTestDoc();
|
||||
};
|
||||
|
||||
const double minimalDistance = Base::Precision::Confusion() * 1000;
|
||||
|
||||
void executePython(const std::vector<std::string>& python);
|
||||
|
||||
void rectangle(double height, double width, char* name);
|
||||
|
||||
testing::AssertionResult
|
||||
boxesMatch(const Base::BoundBox3d& b1, const Base::BoundBox3d& b2, double prec = 1e-05); // NOLINT
|
||||
} // namespace PartTestHelpers
|
||||
|
||||
Reference in New Issue
Block a user