Testing - Cover Boolean operation with GTests (#721)

- Added systematic Boolean operation test coverage using Google Test framework
- Implemented test utilities for shape creation, transformation, and validation
- Migrated existing Draw-based Boolean tests to C++ GTests for better automation
This commit is contained in:
Pasukhin Dmitry
2025-10-08 11:50:42 +01:00
committed by GitHub
parent b295b40387
commit 76b05809d0
7 changed files with 6421 additions and 0 deletions

View File

@@ -0,0 +1,185 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include "BOPTest_Utilities.pxx"
//==================================================================================================
// Direct BOP Operations Tests (equivalent to bcut, bfuse, bcommon, btuc commands)
//==================================================================================================
class BOPAlgo_DirectOperationsTest : public BOPAlgo_TestBase
{
};
// Test direct cut operation: bcut result sphere box
TEST_F(BOPAlgo_DirectOperationsTest, DirectCut_SphereMinusBox)
{
const TopoDS_Shape aSphere = BOPTest_Utilities::CreateUnitSphere();
const TopoDS_Shape aBox = BOPTest_Utilities::CreateUnitBox();
const TopoDS_Shape aResult = PerformDirectBOP(aSphere, aBox, BOPAlgo_CUT);
EXPECT_FALSE(aResult.IsNull()) << "Result shape should not be null";
const Standard_Real aSurfaceArea = BOPTest_Utilities::GetSurfaceArea(aResult);
EXPECT_GT(aSurfaceArea, 0.0) << "Cut result should have positive surface area";
}
// Test direct fuse operation: bfuse result sphere box
TEST_F(BOPAlgo_DirectOperationsTest, DirectFuse_SpherePlusBox)
{
const TopoDS_Shape aSphere = BOPTest_Utilities::CreateUnitSphere();
const TopoDS_Shape aBox = BOPTest_Utilities::CreateUnitBox();
const TopoDS_Shape aResult = PerformDirectBOP(aSphere, aBox, BOPAlgo_FUSE);
EXPECT_FALSE(aResult.IsNull()) << "Result shape should not be null";
const Standard_Real aVolume = BOPTest_Utilities::GetVolume(aResult);
const Standard_Real aSphereVolume = BOPTest_Utilities::GetVolume(aSphere);
const Standard_Real aBoxVolume = BOPTest_Utilities::GetVolume(aBox);
EXPECT_GT(aVolume, aSphereVolume) << "Fuse result should be larger than sphere alone";
EXPECT_GT(aVolume, aBoxVolume) << "Fuse result should be larger than box alone";
}
// Test direct common operation: bcommon result box1 box2
TEST_F(BOPAlgo_DirectOperationsTest, DirectCommon_OverlappingBoxes)
{
const TopoDS_Shape aBox1 = BOPTest_Utilities::CreateBox(gp_Pnt(0, 0, 0), 2.0, 2.0, 2.0);
const TopoDS_Shape aBox2 = BOPTest_Utilities::CreateBox(gp_Pnt(1, 1, 1), 2.0, 2.0, 2.0);
const TopoDS_Shape aResult = PerformDirectBOP(aBox1, aBox2, BOPAlgo_COMMON);
ValidateResult(aResult, -1.0, 1.0); // Expected volume = 1.0
}
// Test direct tuc operation: btuc result box1 box2
TEST_F(BOPAlgo_DirectOperationsTest, DirectTUC_IdenticalBoxes)
{
const TopoDS_Shape aBox1 = BOPTest_Utilities::CreateBox(gp_Pnt(0, 0, 0), 1.0, 1.0, 1.0);
const TopoDS_Shape aBox2 = BOPTest_Utilities::CreateBox(gp_Pnt(0, 0, 0), 1.0, 1.0, 1.0);
const TopoDS_Shape aResult = PerformDirectBOP(aBox1, aBox2, BOPAlgo_CUT21);
ValidateResult(aResult, -1.0, -1.0, Standard_True); // Expected empty
}
// Test with NURBS converted shapes
TEST_F(BOPAlgo_DirectOperationsTest, DirectCut_NurbsBoxMinusBox)
{
TopoDS_Shape aBox1 = BOPTest_Utilities::CreateBox(gp_Pnt(0, 0, 0), 1.0, 1.0, 1.0);
aBox1 = BOPTest_Utilities::ConvertToNurbs(aBox1);
EXPECT_FALSE(aBox1.IsNull()) << "Failed to convert to NURBS";
const TopoDS_Shape aBox2 = BOPTest_Utilities::CreateBox(gp_Pnt(0, 1, 0), 1.0, 0.5, 1.0);
const TopoDS_Shape aResult = PerformDirectBOP(aBox1, aBox2, BOPAlgo_CUT);
const Standard_Real aSurfaceArea = BOPTest_Utilities::GetSurfaceArea(aResult);
EXPECT_GT(aSurfaceArea, 0.0) << "NURBS cut result should have positive surface area";
}
//==================================================================================================
// Two-step BOP Operations Tests (equivalent to bop + bopXXX commands)
//==================================================================================================
class BOPAlgo_TwoStepOperationsTest : public BOPAlgo_TestBase
{
};
// Test two-step cut operation: bop sphere box; bopcut result
TEST_F(BOPAlgo_TwoStepOperationsTest, TwoStepCut_SphereMinusBox)
{
const TopoDS_Shape aSphere = BOPTest_Utilities::CreateUnitSphere();
const TopoDS_Shape aBox = BOPTest_Utilities::CreateUnitBox();
const TopoDS_Shape aResult = PerformTwoStepBOP(aSphere, aBox, BOPAlgo_CUT);
const Standard_Real aSurfaceArea = BOPTest_Utilities::GetSurfaceArea(aResult);
EXPECT_GT(aSurfaceArea, 0.0) << "Two-step cut result should have positive surface area";
}
// Test two-step fuse operation: bop sphere box; bopfuse result
TEST_F(BOPAlgo_TwoStepOperationsTest, TwoStepFuse_SpherePlusBox)
{
const TopoDS_Shape aSphere = BOPTest_Utilities::CreateUnitSphere();
const TopoDS_Shape aBox = BOPTest_Utilities::CreateUnitBox();
const TopoDS_Shape aResult = PerformTwoStepBOP(aSphere, aBox, BOPAlgo_FUSE);
EXPECT_FALSE(aResult.IsNull()) << "Result shape should not be null";
const Standard_Real aVolume = BOPTest_Utilities::GetVolume(aResult);
const Standard_Real aSphereVolume = BOPTest_Utilities::GetVolume(aSphere);
const Standard_Real aBoxVolume = BOPTest_Utilities::GetVolume(aBox);
EXPECT_GT(aVolume, aSphereVolume) << "Two-step fuse result should be larger than sphere alone";
EXPECT_GT(aVolume, aBoxVolume) << "Two-step fuse result should be larger than box alone";
}
// Test two-step common operation: bop box1 box2; bopcommon result
TEST_F(BOPAlgo_TwoStepOperationsTest, TwoStepCommon_OverlappingBoxes)
{
const TopoDS_Shape aBox1 = BOPTest_Utilities::CreateBox(gp_Pnt(0, 0, 0), 2.0, 2.0, 2.0);
const TopoDS_Shape aBox2 = BOPTest_Utilities::CreateBox(gp_Pnt(1, 1, 1), 2.0, 2.0, 2.0);
const TopoDS_Shape aResult = PerformTwoStepBOP(aBox1, aBox2, BOPAlgo_COMMON);
ValidateResult(aResult, -1.0, 1.0); // Expected volume = 1.0
}
// Test two-step tuc operation: bop box1 box2; boptuc result
TEST_F(BOPAlgo_TwoStepOperationsTest, TwoStepTUC_IdenticalBoxes)
{
const TopoDS_Shape aBox1 = BOPTest_Utilities::CreateBox(gp_Pnt(0, 0, 0), 1.0, 1.0, 1.0);
const TopoDS_Shape aBox2 = BOPTest_Utilities::CreateBox(gp_Pnt(0, 0, 0), 1.0, 1.0, 1.0);
const TopoDS_Shape aResult = PerformTwoStepBOP(aBox1, aBox2, BOPAlgo_CUT21);
ValidateResult(aResult, -1.0, -1.0, Standard_True); // Expected empty
}
//==================================================================================================
// Complex Operations Tests
//==================================================================================================
class BOPAlgo_ComplexOperationsTest : public BOPAlgo_TestBase
{
};
// Test multiple intersecting primitives
TEST_F(BOPAlgo_ComplexOperationsTest, MultipleIntersectingPrimitives)
{
const TopoDS_Shape aSphere = BOPTest_Utilities::CreateSphere(gp_Pnt(0, 0, 0), 1.5);
const TopoDS_Shape aCylinder = BOPTest_Utilities::CreateCylinder(0.8, 3.0);
const TopoDS_Shape aBox = BOPTest_Utilities::CreateBox(gp_Pnt(-0.5, -0.5, -0.5), 1.0, 1.0, 1.0);
// First intersect sphere with cylinder
const TopoDS_Shape aIntermediate = PerformDirectBOP(aSphere, aCylinder, BOPAlgo_COMMON);
EXPECT_FALSE(aIntermediate.IsNull()) << "Intermediate result should not be null";
// Then fuse with box
const TopoDS_Shape aFinalResult = PerformDirectBOP(aIntermediate, aBox, BOPAlgo_FUSE);
const Standard_Real aVolume = BOPTest_Utilities::GetVolume(aFinalResult);
EXPECT_GT(aVolume, 0.0) << "Complex operation result should have positive volume";
}
// Test comparison between direct and two-step operations
TEST_F(BOPAlgo_ComplexOperationsTest, DirectVsTwoStepComparison)
{
const TopoDS_Shape aSphere = BOPTest_Utilities::CreateUnitSphere();
const TopoDS_Shape aBox = BOPTest_Utilities::CreateUnitBox();
// Perform direct operation
const TopoDS_Shape aDirectResult = PerformDirectBOP(aSphere, aBox, BOPAlgo_FUSE);
// Perform two-step operation
const TopoDS_Shape aTwoStepResult = PerformTwoStepBOP(aSphere, aBox, BOPAlgo_FUSE);
// Results should be equivalent
const Standard_Real aDirectVolume = BOPTest_Utilities::GetVolume(aDirectResult);
const Standard_Real aTwoStepVolume = BOPTest_Utilities::GetVolume(aTwoStepResult);
EXPECT_NEAR(aDirectVolume, aTwoStepVolume, myTolerance)
<< "Direct and two-step operations should produce equivalent results";
}

View File

@@ -0,0 +1,994 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _BOPTest_Utilities_HeaderFile
#define _BOPTest_Utilities_HeaderFile
#include <gtest/gtest.h>
#include <BOPAlgo_BOP.hxx>
#include <BOPAlgo_PaveFiller.hxx>
#include <BOPAlgo_Operation.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <BRepPrimAPI_MakeCylinder.hxx>
#include <BRepPrimAPI_MakeCone.hxx>
#include <BRepBuilderAPI_MakePolygon.hxx>
#include <BRepPrimAPI_MakePrism.hxx>
#include <BRepPrimAPI_MakeRevol.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS_Face.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepBuilderAPI_NurbsConvert.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <BRepFilletAPI_MakeFillet.hxx>
#include <gp_Trsf.hxx>
#include <gp_Ax1.hxx>
#include <gp_Vec.hxx>
#include <gp_Pnt.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS.hxx>
#include <ElSLib.hxx>
#include <gp_Vec2d.hxx>
#include <gp_Pnt2d.hxx>
#include <gp_Circ.hxx>
#include <gp_Ax2.hxx>
#include <Precision.hxx>
#include <BRepAlgoAPI_Cut.hxx>
#include <BRepAlgoAPI_Fuse.hxx>
#include <BRepAlgoAPI_Common.hxx>
#include <BRepTools.hxx>
#include <GProp_GProps.hxx>
#include <BRepGProp.hxx>
#include <TopoDS_Shape.hxx>
#include <TopTools_ListOfShape.hxx>
#include <Standard_Real.hxx>
#include <NCollection_BaseAllocator.hxx>
#include <gp_Pnt.hxx>
#include <gp_Ax2.hxx>
#include <gp_Dir.hxx>
#include <cmath>
#include <memory>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
//==================================================================================================
//! Base utility class for BOP testing with common helper functions
//==================================================================================================
class BOPTest_Utilities
{
public:
//! Profile command types (equivalent to TCL profile commands)
enum class ProfileCmd
{
O, // Set origin (O X Y Z)
P, // Set plane (P nx ny nz dx dy dz)
F, // Set first point
X, // Translate along X
Y, // Translate along Y
L, // Translate along direction
XX, // Set X coordinate
YY, // Set Y coordinate
T, // Translate by vector
TT, // Set point
R, // Rotate direction
RR, // Set direction angle
D, // Set direction vector
C, // Arc (circle)
W, // Make closed wire
WW // Make open wire
};
//! Profile command structure
struct ProfileOperation
{
ProfileCmd cmd;
std::vector<Standard_Real> params;
ProfileOperation(ProfileCmd c)
: cmd(c)
{
}
ProfileOperation(ProfileCmd c, Standard_Real p1)
: cmd(c),
params({p1})
{
}
ProfileOperation(ProfileCmd c, Standard_Real p1, Standard_Real p2)
: cmd(c),
params({p1, p2})
{
}
ProfileOperation(ProfileCmd c, Standard_Real p1, Standard_Real p2, Standard_Real p3)
: cmd(c),
params({p1, p2, p3})
{
}
ProfileOperation(ProfileCmd c,
Standard_Real p1,
Standard_Real p2,
Standard_Real p3,
Standard_Real p4,
Standard_Real p5,
Standard_Real p6)
: cmd(c),
params({p1, p2, p3, p4, p5, p6})
{
}
ProfileOperation(ProfileCmd c, const std::vector<Standard_Real>& p)
: cmd(c),
params(p)
{
}
};
//! Default tolerance values
static constexpr Standard_Real DefaultTolerance() { return 1.0e-6; }
static constexpr Standard_Real DefaultFuzzyValue() { return 1.0e-8; }
//! Calculate surface area of a shape
static Standard_Real GetSurfaceArea(const TopoDS_Shape& theShape)
{
if (theShape.IsNull())
{
return 0.0;
}
GProp_GProps aProps;
BRepGProp::SurfaceProperties(theShape, aProps);
return aProps.Mass();
}
//! Calculate volume of a shape
static Standard_Real GetVolume(const TopoDS_Shape& theShape)
{
if (theShape.IsNull())
{
return 0.0;
}
GProp_GProps aProps;
BRepGProp::VolumeProperties(theShape, aProps);
return aProps.Mass();
}
//! Check if shape is effectively empty (very small surface area)
static Standard_Boolean IsEmpty(const TopoDS_Shape& theShape,
const Standard_Real theTolerance = DefaultTolerance())
{
return GetSurfaceArea(theShape) <= theTolerance;
}
//! Create unit box at origin (1x1x1)
static TopoDS_Shape CreateUnitBox()
{
BRepPrimAPI_MakeBox aBoxMaker(1.0, 1.0, 1.0);
return aBoxMaker.Shape();
}
//! Create box at specific location
static TopoDS_Shape CreateBox(const gp_Pnt& theCorner,
Standard_Real theX,
Standard_Real theY,
Standard_Real theZ)
{
BRepPrimAPI_MakeBox aBoxMaker(theCorner, theX, theY, theZ);
return aBoxMaker.Shape();
}
//! Create unit sphere (radius = 1.0)
static TopoDS_Shape CreateUnitSphere()
{
BRepPrimAPI_MakeSphere aSphereMaker(1.0);
return aSphereMaker.Shape();
}
//! Create sphere at location with radius
static TopoDS_Shape CreateSphere(const gp_Pnt& theCenter, Standard_Real theRadius)
{
BRepPrimAPI_MakeSphere aSphereMaker(theCenter, theRadius);
return aSphereMaker.Shape();
}
//! Create cylinder
static TopoDS_Shape CreateCylinder(Standard_Real theRadius, Standard_Real theHeight)
{
BRepPrimAPI_MakeCylinder aCylinderMaker(theRadius, theHeight);
return aCylinderMaker.Shape();
}
//! Create cone
static TopoDS_Shape CreateCone(Standard_Real theR1, Standard_Real theR2, Standard_Real theHeight)
{
BRepPrimAPI_MakeCone aConeMaker(theR1, theR2, theHeight);
return aConeMaker.Shape();
}
//! Convert shape to NURBS
static TopoDS_Shape ConvertToNurbs(const TopoDS_Shape& theShape)
{
BRepBuilderAPI_NurbsConvert aNurbsConverter(theShape);
if (!aNurbsConverter.IsDone())
{
return TopoDS_Shape(); // Return null shape on failure
}
return aNurbsConverter.Shape();
}
//! Create rectangular polygon face
static TopoDS_Shape CreatePolygonFace(const gp_Pnt& theP1,
const gp_Pnt& theP2,
const gp_Pnt& theP3,
const gp_Pnt& theP4)
{
BRepBuilderAPI_MakePolygon aPolygonMaker;
aPolygonMaker.Add(theP1);
aPolygonMaker.Add(theP2);
aPolygonMaker.Add(theP3);
aPolygonMaker.Add(theP4);
aPolygonMaker.Close();
if (!aPolygonMaker.IsDone())
{
return TopoDS_Shape();
}
BRepBuilderAPI_MakeFace aFaceMaker(aPolygonMaker.Wire());
return aFaceMaker.Shape();
}
//! Rotate shape around axis
static TopoDS_Shape RotateShape(const TopoDS_Shape& theShape,
const gp_Ax1& theAxis,
Standard_Real theAngle)
{
gp_Trsf aTrsf;
aTrsf.SetRotation(theAxis, theAngle);
BRepBuilderAPI_Transform aTransformer(theShape, aTrsf);
return aTransformer.Shape();
}
//! Translate shape by vector
static TopoDS_Shape TranslateShape(const TopoDS_Shape& theShape, const gp_Vec& theVector)
{
gp_Trsf aTrsf;
aTrsf.SetTranslation(theVector);
BRepBuilderAPI_Transform aTransformer(theShape, aTrsf);
return aTransformer.Shape();
}
//! Create vertex from point
static TopoDS_Vertex CreateVertex(const gp_Pnt& thePoint)
{
BRepBuilderAPI_MakeVertex aVertexMaker(thePoint);
return aVertexMaker.Vertex();
}
//! Create edge between two points
static TopoDS_Edge CreateEdge(const gp_Pnt& theP1, const gp_Pnt& theP2)
{
BRepBuilderAPI_MakeEdge anEdgeMaker(theP1, theP2);
return anEdgeMaker.Edge();
}
//! Create wire from list of points (closed polygon)
static TopoDS_Wire CreatePolygonWire(const std::vector<gp_Pnt>& thePoints,
Standard_Boolean theClose = Standard_True)
{
BRepBuilderAPI_MakePolygon aPolygonMaker;
for (const gp_Pnt& aPt : thePoints)
{
aPolygonMaker.Add(aPt);
}
if (theClose)
{
aPolygonMaker.Close();
}
return aPolygonMaker.Wire();
}
//! Create complex profile using simplified approach (similar to TCL profile command)
//! Simulates "profile rev S face F x y [commands...]" by creating a rectangular wire
static TopoDS_Wire CreateProfileWire(const gp_Pln& thePlane,
const gp_Pnt2d& theStartPt,
const std::vector<std::string>& theCommands)
{
// Simplified profile creation - create a rectangular wire based on commands
// This approximates the TCL profile behavior for basic geometric operations
std::vector<gp_Pnt2d> aPoints;
aPoints.push_back(theStartPt);
gp_Pnt2d aCurrentPt = theStartPt;
gp_Vec2d aCurrentDir(1.0, 0.0); // Default direction
// Process simplified command set
for (size_t i = 0; i < theCommands.size(); ++i)
{
const std::string& aCmd = theCommands[i];
if (aCmd == "Y" && i + 1 < theCommands.size())
{
// Y command: translate along Y
double aDY = std::stod(theCommands[i + 1]);
aCurrentPt.SetY(aCurrentPt.Y() + aDY);
aPoints.push_back(aCurrentPt);
i++; // Skip next parameter
}
else if (aCmd == "C" && i + 2 < theCommands.size())
{
// C command: arc (simplified as straight line for now)
double aRadius = std::stod(theCommands[i + 1]);
// double aAngle = std::stod(theCommands[i + 2]); // Unused for now
// Simplified: just move in current direction
gp_Vec2d aMoveVec = aCurrentDir * aRadius;
aCurrentPt.Translate(aMoveVec);
aPoints.push_back(aCurrentPt);
i += 2; // Skip next two parameters
}
}
// Convert 2D points to 3D points on the plane
std::vector<gp_Pnt> a3DPoints;
for (const gp_Pnt2d& aPt2d : aPoints)
{
gp_Pnt aPt3d = ElSLib::Value(aPt2d.X(), aPt2d.Y(), thePlane);
a3DPoints.push_back(aPt3d);
}
return CreatePolygonWire(a3DPoints, Standard_True);
}
//! Create profile using typed commands (equivalent to TCL profile)
//! plane: The reference plane/face (equivalent to "S face" in TCL)
//! operations: List of profile operations
static TopoDS_Shape CreateProfile(const gp_Pln& thePlane,
const std::vector<ProfileOperation>& theOperations)
{
BRepBuilderAPI_MakeWire aMakeWire;
gp_Pnt2d aCurrentPt(0, 0); // Current point in 2D
gp_Vec2d aCurrentDir(1, 0); // Current direction in 2D
Standard_Boolean aFirstSet = Standard_False;
gp_Pnt2d aFirstPt(0, 0);
gp_Pln aWorkingPlane = thePlane; // Working plane that can be modified by P command
for (const auto& op : theOperations)
{
switch (op.cmd)
{
case ProfileCmd::O: // Set origin (affects the plane, not the starting point)
if (op.params.size() >= 3)
{
// O command sets the origin of the plane coordinate system
gp_Pnt aNewOrigin(op.params[0], op.params[1], op.params[2]);
gp_Ax3 aNewAx3(aNewOrigin,
aWorkingPlane.Axis().Direction(),
aWorkingPlane.XAxis().Direction());
aWorkingPlane = gp_Pln(aNewAx3);
// Profile still starts at (0,0) in the new plane coordinate system
if (!aFirstSet)
{
aCurrentPt.SetCoord(0.0, 0.0); // TCL default: start at (0,0)
aFirstPt = aCurrentPt;
aFirstSet = Standard_True;
}
}
break;
case ProfileCmd::P: // Set plane (P nx ny nz dx dy dz)
if (op.params.size() >= 6)
{
// P command sets plane normal and X direction vectors
gp_Vec aNormal(op.params[0], op.params[1], op.params[2]);
gp_Vec aXDir(op.params[3], op.params[4], op.params[5]);
// Create new coordinate system
gp_Dir aNormalDir(aNormal);
gp_Dir aXDirection(aXDir);
// Note: Y direction computed as cross product: Y = Z x X (for right-handed system)
// But DRAW uses standard X/Y axes based on normal direction
// Use the current plane's origin but new orientation
gp_Ax3 aNewAx3(aWorkingPlane.Location(), aNormalDir, aXDirection);
aWorkingPlane = gp_Pln(aNewAx3);
}
break;
case ProfileCmd::F: // Set first point
if (op.params.size() >= 2)
{
aCurrentPt.SetCoord(op.params[0], op.params[1]);
aFirstPt = aCurrentPt;
aFirstSet = Standard_True;
}
break;
case ProfileCmd::X: // Translate along X
if (op.params.size() >= 1)
{
// If first point not set, implicitly start at (0,0)
if (!aFirstSet)
{
aCurrentPt.SetCoord(0.0, 0.0);
aFirstPt = aCurrentPt;
aFirstSet = Standard_True;
}
gp_Pnt2d aNewPt(aCurrentPt.X() + op.params[0], aCurrentPt.Y());
// Add line segment
gp_Pnt aPt1 = ElSLib::Value(aCurrentPt.X(), aCurrentPt.Y(), aWorkingPlane);
gp_Pnt aPt2 = ElSLib::Value(aNewPt.X(), aNewPt.Y(), aWorkingPlane);
aMakeWire.Add(BRepBuilderAPI_MakeEdge(aPt1, aPt2));
aCurrentPt = aNewPt;
aCurrentDir = gp_Vec2d(op.params[0] > 0 ? 1 : -1, 0);
}
break;
case ProfileCmd::Y: // Translate along Y
if (op.params.size() >= 1)
{
// If first point not set, implicitly start at (0,0)
if (!aFirstSet)
{
aCurrentPt.SetCoord(0.0, 0.0);
aFirstPt = aCurrentPt;
aFirstSet = Standard_True;
}
gp_Pnt2d aNewPt(aCurrentPt.X(), aCurrentPt.Y() + op.params[0]);
// Add line segment
gp_Pnt aPt1 = ElSLib::Value(aCurrentPt.X(), aCurrentPt.Y(), aWorkingPlane);
gp_Pnt aPt2 = ElSLib::Value(aNewPt.X(), aNewPt.Y(), aWorkingPlane);
aMakeWire.Add(BRepBuilderAPI_MakeEdge(aPt1, aPt2));
aCurrentPt = aNewPt;
aCurrentDir = gp_Vec2d(0, op.params[0] > 0 ? 1 : -1);
}
break;
case ProfileCmd::C: // Arc
if (op.params.size() >= 2)
{
Standard_Real aRadius = Abs(op.params[0]);
Standard_Real aAngleDeg = op.params[1];
Standard_Real aAngleRad = aAngleDeg * M_PI / 180.0;
// Handle full circle case (360 degrees)
if (Abs(aAngleDeg) >= 360.0)
{
// Create a full circle centered at current point (0,0 if not set)
gp_Pnt2d aCenter2D = aFirstSet ? aCurrentPt : gp_Pnt2d(0, 0);
gp_Pnt aCenter3D = ElSLib::Value(aCenter2D.X(), aCenter2D.Y(), aWorkingPlane);
// Create full circle
gp_Circ aCirc(gp_Ax2(aCenter3D, aWorkingPlane.Axis().Direction()), aRadius);
aMakeWire.Add(BRepBuilderAPI_MakeEdge(aCirc));
// Set current point to a point on the circle
aCurrentPt = gp_Pnt2d(aCenter2D.X() + aRadius, aCenter2D.Y());
aCurrentDir = gp_Vec2d(0, 1); // Tangent direction
aFirstSet = Standard_True;
}
else
{
// If first point not set, start at origin with default direction
if (!aFirstSet)
{
aCurrentPt.SetCoord(0.0, 0.0);
aCurrentDir = gp_Vec2d(1, 0); // Default direction: positive X
aFirstPt = aCurrentPt;
aFirstSet = Standard_True;
}
// Create arc from current point
gp_Vec2d aNormal(-aCurrentDir.Y(), aCurrentDir.X());
gp_Pnt2d aCenter = aCurrentPt.Translated(aNormal * aRadius);
// Calculate end point
Standard_Real aStartAngle =
atan2(aCurrentPt.Y() - aCenter.Y(), aCurrentPt.X() - aCenter.X());
Standard_Real aEndAngle = aStartAngle + aAngleRad;
gp_Pnt2d aEndPt(aCenter.X() + aRadius * cos(aEndAngle),
aCenter.Y() + aRadius * sin(aEndAngle));
// Create 3D arc
gp_Pnt aPt1 = ElSLib::Value(aCurrentPt.X(), aCurrentPt.Y(), aWorkingPlane);
gp_Pnt aPt2 = ElSLib::Value(aEndPt.X(), aEndPt.Y(), aWorkingPlane);
gp_Pnt aCenter3D = ElSLib::Value(aCenter.X(), aCenter.Y(), aWorkingPlane);
gp_Circ aCirc(gp_Ax2(aCenter3D, aWorkingPlane.Axis().Direction()), aRadius);
aMakeWire.Add(BRepBuilderAPI_MakeEdge(aCirc, aPt1, aPt2));
aCurrentPt = aEndPt;
aCurrentDir = gp_Vec2d(cos(aEndAngle + M_PI / 2), sin(aEndAngle + M_PI / 2));
}
}
break;
case ProfileCmd::D: // Set direction vector
if (op.params.size() >= 2)
{
aCurrentDir = gp_Vec2d(op.params[0], op.params[1]);
aCurrentDir.Normalize();
}
break;
case ProfileCmd::W: // Make closed wire
// W command closes the current wire - handled at end of function
break;
default:
// Other commands can be added as needed
break;
}
}
// Close the wire if needed (TCL profiles are typically closed by default)
if (aFirstSet && !aCurrentPt.IsEqual(aFirstPt, Precision::Confusion()))
{
// Add closing edge back to start
gp_Pnt aPt1 = ElSLib::Value(aCurrentPt.X(), aCurrentPt.Y(), aWorkingPlane);
gp_Pnt aPt2 = ElSLib::Value(aFirstPt.X(), aFirstPt.Y(), aWorkingPlane);
aMakeWire.Add(BRepBuilderAPI_MakeEdge(aPt1, aPt2));
}
EXPECT_TRUE(aMakeWire.IsDone()) << "Profile wire creation failed";
TopoDS_Wire aWire = aMakeWire.Wire();
// Create face from wire
BRepBuilderAPI_MakeFace aFaceMaker(aWire);
EXPECT_TRUE(aFaceMaker.IsDone()) << "Profile face creation failed";
return aFaceMaker.Face();
}
//! Create profile from operations list (simplified version)
static TopoDS_Shape CreateProfileFromOperations(
const std::vector<ProfileOperation>& theOperations)
{
// Use default plane (XY plane)
const gp_Pln aPlane(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1));
return CreateProfile(aPlane, theOperations);
}
//! Create rectangular profile from corner and dimensions
static TopoDS_Wire CreateRectangularProfile(const gp_Pnt& theCorner,
Standard_Real theX,
Standard_Real theY)
{
std::vector<gp_Pnt> aPoints;
aPoints.push_back(theCorner);
aPoints.push_back(gp_Pnt(theCorner.X() + theX, theCorner.Y(), theCorner.Z()));
aPoints.push_back(gp_Pnt(theCorner.X() + theX, theCorner.Y() + theY, theCorner.Z()));
aPoints.push_back(gp_Pnt(theCorner.X(), theCorner.Y() + theY, theCorner.Z()));
return CreatePolygonWire(aPoints, Standard_True);
}
//! Create face from wire
static TopoDS_Shape CreateFaceFromWire(const TopoDS_Wire& theWire)
{
BRepBuilderAPI_MakeFace aFaceMaker(theWire);
if (!aFaceMaker.IsDone())
{
return TopoDS_Shape();
}
return aFaceMaker.Shape();
}
//! Create prism by extruding shape along vector
static TopoDS_Shape CreatePrism(const TopoDS_Shape& theProfile, const gp_Vec& theDirection)
{
BRepPrimAPI_MakePrism aPrismMaker(theProfile, theDirection);
if (!aPrismMaker.IsDone())
{
return TopoDS_Shape();
}
return aPrismMaker.Shape();
}
//! Create simple rectangular prism (like TCL profile operations)
static TopoDS_Shape CreateRectangularPrism(const gp_Pnt& theCorner,
Standard_Real theX,
Standard_Real theY,
Standard_Real theZ)
{
TopoDS_Wire aWire = CreateRectangularProfile(theCorner, theX, theY);
TopoDS_Shape aFace = CreateFaceFromWire(aWire);
return CreatePrism(aFace, gp_Vec(0, 0, theZ));
}
//! Create revolution of a profile around an axis
static TopoDS_Shape CreateRevolution(const TopoDS_Shape& theProfile,
const gp_Ax1& theAxis,
Standard_Real theAngle)
{
BRepPrimAPI_MakeRevol aRevolMaker(theProfile, theAxis, theAngle);
EXPECT_TRUE(aRevolMaker.IsDone()) << "Revolution operation failed";
return aRevolMaker.Shape();
}
//! Get a face from a shape by index (for nexplode simulation)
static TopoDS_Face GetFaceByIndex(const TopoDS_Shape& theShape, Standard_Integer theIndex)
{
TopExp_Explorer anExp(theShape, TopAbs_FACE);
Standard_Integer aCurrentIndex = 1;
while (anExp.More())
{
if (aCurrentIndex == theIndex)
{
return TopoDS::Face(anExp.Current());
}
aCurrentIndex++;
anExp.Next();
}
return TopoDS_Face(); // Return empty face if not found
}
//! Apply rotation around Z-axis (equivalent to "trotate shape 0 0 0 0 0 1 angle")
static TopoDS_Shape RotateZ(const TopoDS_Shape& theShape, Standard_Real theAngleDeg)
{
gp_Trsf aRotation;
aRotation.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), theAngleDeg * M_PI / 180.0);
BRepBuilderAPI_Transform aTransform(theShape, aRotation);
return aTransform.Shape();
}
//! Apply rotation around Y-axis (equivalent to "trotate shape 0 0 0 0 1 0 angle")
static TopoDS_Shape RotateY(const TopoDS_Shape& theShape, Standard_Real theAngleDeg)
{
gp_Trsf aRotation;
aRotation.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 1, 0)), theAngleDeg * M_PI / 180.0);
BRepBuilderAPI_Transform aTransform(theShape, aRotation);
return aTransform.Shape();
}
//! Apply rotation around X-axis (equivalent to "trotate shape 0 0 0 1 0 0 angle")
static TopoDS_Shape RotateX(const TopoDS_Shape& theShape, Standard_Real theAngleDeg)
{
gp_Trsf aRotation;
aRotation.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(1, 0, 0)), theAngleDeg * M_PI / 180.0);
BRepBuilderAPI_Transform aTransform(theShape, aRotation);
return aTransform.Shape();
}
//! Apply common test rotation: Z(-90deg) then Y(-45deg) - used in many TCL tests
static TopoDS_Shape RotateStandard(const TopoDS_Shape& theShape)
{
TopoDS_Shape aResult = RotateZ(theShape, -90.0);
return RotateY(aResult, -45.0);
}
//! Apply translation (equivalent to "ttranslate shape dx dy dz")
static TopoDS_Shape Translate(const TopoDS_Shape& theShape,
Standard_Real theDx,
Standard_Real theDy,
Standard_Real theDz)
{
gp_Trsf aTranslation;
aTranslation.SetTranslation(gp_Vec(theDx, theDy, theDz));
BRepBuilderAPI_Transform aTransform(theShape, aTranslation);
return aTransform.Shape();
}
//! Apply Y-axis 90-degree rotation (common pattern: "trotate shape 0 0 1 0 1 0 90")
static TopoDS_Shape RotateY90(const TopoDS_Shape& theShape)
{
gp_Trsf aRotation;
aRotation.SetRotation(gp_Ax1(gp_Pnt(0, 0, 1), gp_Dir(0, 1, 0)), 90.0 * M_PI / 180.0);
BRepBuilderAPI_Transform aTransform(theShape, aRotation);
return aTransform.Shape();
}
//! Create unit sphere and box pair (most common test setup)
static void CreateSphereAndBox(TopoDS_Shape& theSphere, TopoDS_Shape& theBox)
{
theSphere = CreateUnitSphere();
theBox = CreateUnitBox();
}
//! Create two identical unit boxes at origin (common BOP test setup)
static void CreateIdenticalBoxes(TopoDS_Shape& theBox1, TopoDS_Shape& theBox2)
{
theBox1 = CreateBox(gp_Pnt(0, 0, 0), 1.0, 1.0, 1.0);
theBox2 = CreateBox(gp_Pnt(0, 0, 0), 1.0, 1.0, 1.0);
}
//! Create NURBS box and regular box pair (common B-series test pattern)
static void CreateNurbsAndRegularBox(TopoDS_Shape& theNurbsBox,
TopoDS_Shape& theRegularBox,
const gp_Pnt& theNurbsCorner = gp_Pnt(0, 0, 0),
const gp_Pnt& theRegularCorner = gp_Pnt(0, 1, 0),
Standard_Real theNurbsX = 1.0,
Standard_Real theNurbsY = 1.0,
Standard_Real theNurbsZ = 1.0,
Standard_Real theRegularX = 1.0,
Standard_Real theRegularY = 0.5,
Standard_Real theRegularZ = 1.0)
{
theNurbsBox = CreateBox(theNurbsCorner, theNurbsX, theNurbsY, theNurbsZ);
theNurbsBox = ConvertToNurbs(theNurbsBox);
theRegularBox = CreateBox(theRegularCorner, theRegularX, theRegularY, theRegularZ);
}
//! Create a blend (fillet) on specified edge of a shape
static TopoDS_Shape CreateBlend(const TopoDS_Shape& theShape,
Standard_Integer theEdgeIndex,
Standard_Real theRadius)
{
// Get the edge by index (like explode command)
TopExp_Explorer anExp(theShape, TopAbs_EDGE);
Standard_Integer aCurrentIndex = 1;
TopoDS_Edge aTargetEdge;
while (anExp.More())
{
if (aCurrentIndex == theEdgeIndex)
{
aTargetEdge = TopoDS::Edge(anExp.Current());
break;
}
aCurrentIndex++;
anExp.Next();
}
if (aTargetEdge.IsNull())
{
return theShape; // Return original shape if edge not found
}
// Create fillet maker (matching DRAW blend command)
// DRAW uses ChFi3d_Rational by default
BRepFilletAPI_MakeFillet aFilletMaker(theShape, ChFi3d_Rational);
// Set parameters exactly like DRAW command does
// SetParams(ta, tesp, t2d, t3d, t2d, fl) - exact DRAW defaults
aFilletMaker.SetParams(1e-2, 1.0e-4, 1.e-5, 1.e-4, 1.e-5, 1.e-3);
// SetContinuity(blend_cont, tapp_angle) - exact DRAW defaults
aFilletMaker.SetContinuity(GeomAbs_C1, 1.e-2);
aFilletMaker.Add(theRadius, aTargetEdge);
aFilletMaker.Build();
if (!aFilletMaker.IsDone())
{
return TopoDS_Shape(); // Return null shape if fillet failed, like DRAW command
}
return aFilletMaker.Shape();
}
//! Create a cylinder on a specified plane (like TCL pcylinder command)
static TopoDS_Shape CreateCylinderOnPlane(const gp_Pln& thePlane,
Standard_Real theRadius,
Standard_Real theHeight)
{
// Use DRAW pcylinder approach exactly:
// S = BRepPrimAPI_MakeCylinder(P->Pln().Position().Ax2(), radius, height);
const gp_Ax2 anAx2 = thePlane.Position().Ax2();
// Use DRAW pcylinder approach exactly:
// S = BRepPrimAPI_MakeCylinder(P->Pln().Position().Ax2(), radius, height);
BRepPrimAPI_MakeCylinder aCylinderMaker(anAx2, theRadius, theHeight);
aCylinderMaker.Build();
if (!aCylinderMaker.IsDone())
{
return TopoDS_Shape();
}
return aCylinderMaker.Shape();
}
};
//==================================================================================================
//! Base test class for BRepAlgoAPI operations
//==================================================================================================
class BRepAlgoAPI_TestBase : public ::testing::Test
{
protected:
void SetUp() override { myTolerance = BOPTest_Utilities::DefaultTolerance(); }
//! Perform BRepAlgoAPI Cut operation
TopoDS_Shape PerformCut(const TopoDS_Shape& theObject, const TopoDS_Shape& theTool)
{
BRepAlgoAPI_Cut aCutter(theObject, theTool);
EXPECT_TRUE(aCutter.IsDone()) << "BRepAlgoAPI_Cut operation failed";
return aCutter.Shape();
}
//! Perform BRepAlgoAPI Fuse operation
TopoDS_Shape PerformFuse(const TopoDS_Shape& theShape1, const TopoDS_Shape& theShape2)
{
BRepAlgoAPI_Fuse aFuser(theShape1, theShape2);
EXPECT_TRUE(aFuser.IsDone()) << "BRepAlgoAPI_Fuse operation failed";
return aFuser.Shape();
}
//! Perform BRepAlgoAPI Common operation
TopoDS_Shape PerformCommon(const TopoDS_Shape& theShape1, const TopoDS_Shape& theShape2)
{
BRepAlgoAPI_Common aCommoner(theShape1, theShape2);
EXPECT_TRUE(aCommoner.IsDone()) << "BRepAlgoAPI_Common operation failed";
return aCommoner.Shape();
}
//! Validate result properties against expected values
void ValidateResult(const TopoDS_Shape& theResult,
Standard_Real theExpectedSurfaceArea = -1.0,
Standard_Real theExpectedVolume = -1.0,
Standard_Boolean theExpectedEmpty = Standard_False)
{
if (theExpectedEmpty)
{
EXPECT_TRUE(BOPTest_Utilities::IsEmpty(theResult, myTolerance)) << "Result should be empty";
return;
}
EXPECT_FALSE(theResult.IsNull()) << "Result shape should not be null";
if (theExpectedSurfaceArea >= 0.0)
{
const Standard_Real aSurfaceArea = BOPTest_Utilities::GetSurfaceArea(theResult);
EXPECT_NEAR(aSurfaceArea, theExpectedSurfaceArea, 5000.0) << "Surface area mismatch";
}
if (theExpectedVolume >= 0.0)
{
const Standard_Real aVolume = BOPTest_Utilities::GetVolume(theResult);
EXPECT_NEAR(aVolume, theExpectedVolume, myTolerance) << "Volume mismatch";
}
}
protected:
Standard_Real myTolerance;
};
//==================================================================================================
//! Base test class for BOPAlgo_BOP operations (direct and two-step)
//==================================================================================================
class BOPAlgo_TestBase : public ::testing::Test
{
protected:
void SetUp() override
{
myTolerance = BOPTest_Utilities::DefaultTolerance();
myFuzzyValue = BOPTest_Utilities::DefaultFuzzyValue();
myPaveFiller.reset();
}
void TearDown() override { myPaveFiller.reset(); }
//! Direct BOP operation (equivalent to bcut/bfuse/bcommon/btuc commands)
TopoDS_Shape PerformDirectBOP(const TopoDS_Shape& theShape1,
const TopoDS_Shape& theShape2,
BOPAlgo_Operation theOp)
{
Handle(NCollection_BaseAllocator) aAL = NCollection_BaseAllocator::CommonBaseAllocator();
BOPAlgo_BOP aBOP(aAL);
aBOP.AddArgument(theShape1);
aBOP.AddTool(theShape2);
aBOP.SetOperation(theOp);
aBOP.SetFuzzyValue(myFuzzyValue);
aBOP.SetRunParallel(Standard_False);
aBOP.SetNonDestructive(Standard_False);
aBOP.Perform();
EXPECT_FALSE(aBOP.HasErrors()) << "Direct BOP operation failed";
return aBOP.Shape();
}
//! Two-step BOP operation (equivalent to bop + bopXXX commands)
TopoDS_Shape PerformTwoStepBOP(const TopoDS_Shape& theShape1,
const TopoDS_Shape& theShape2,
BOPAlgo_Operation theOp)
{
// Step 1: Prepare PaveFiller (equivalent to "bop s1 s2")
PreparePaveFiller(theShape1, theShape2);
// Step 2: Perform BOP operation (equivalent to "bopXXX result")
return PerformBOPWithPaveFiller(theOp);
}
//! Prepare PaveFiller for two-step operations
void PreparePaveFiller(const TopoDS_Shape& theShape1, const TopoDS_Shape& theShape2)
{
TopTools_ListOfShape aLC;
aLC.Append(theShape1);
aLC.Append(theShape2);
Handle(NCollection_BaseAllocator) aAL = NCollection_BaseAllocator::CommonBaseAllocator();
myPaveFiller = std::make_unique<BOPAlgo_PaveFiller>(aAL);
myPaveFiller->SetArguments(aLC);
myPaveFiller->SetFuzzyValue(myFuzzyValue);
myPaveFiller->SetRunParallel(Standard_False);
myPaveFiller->SetNonDestructive(Standard_False);
myPaveFiller->Perform();
EXPECT_FALSE(myPaveFiller->HasErrors()) << "PaveFiller preparation failed";
}
//! Perform BOP operation using prepared PaveFiller
TopoDS_Shape PerformBOPWithPaveFiller(BOPAlgo_Operation theOp)
{
EXPECT_TRUE(myPaveFiller != nullptr) << "PaveFiller must be prepared first";
BOPAlgo_BOP aBOP;
const TopTools_ListOfShape& aArguments = myPaveFiller->Arguments();
EXPECT_EQ(aArguments.Extent(), 2) << "Wrong number of arguments";
const TopoDS_Shape& aS1 = aArguments.First();
const TopoDS_Shape& aS2 = aArguments.Last();
aBOP.AddArgument(aS1);
aBOP.AddTool(aS2);
aBOP.SetOperation(theOp);
aBOP.SetRunParallel(Standard_False);
aBOP.PerformWithFiller(*myPaveFiller);
EXPECT_FALSE(aBOP.HasErrors()) << "BOP operation with PaveFiller failed";
return aBOP.Shape();
}
//! Validate result properties against expected values
void ValidateResult(const TopoDS_Shape& theResult,
Standard_Real theExpectedSurfaceArea = -1.0,
Standard_Real theExpectedVolume = -1.0,
Standard_Boolean theExpectedEmpty = Standard_False)
{
if (theExpectedEmpty)
{
EXPECT_TRUE(BOPTest_Utilities::IsEmpty(theResult, myTolerance)) << "Result should be empty";
return;
}
EXPECT_FALSE(theResult.IsNull()) << "Result shape should not be null";
if (theExpectedSurfaceArea >= 0.0)
{
const Standard_Real aSurfaceArea = BOPTest_Utilities::GetSurfaceArea(theResult);
EXPECT_NEAR(aSurfaceArea, theExpectedSurfaceArea, 5000.0) << "Surface area mismatch";
}
if (theExpectedVolume >= 0.0)
{
const Standard_Real aVolume = BOPTest_Utilities::GetVolume(theResult);
EXPECT_NEAR(aVolume, theExpectedVolume, myTolerance) << "Volume mismatch";
}
}
protected:
Standard_Real myTolerance;
Standard_Real myFuzzyValue;
std::unique_ptr<BOPAlgo_PaveFiller> myPaveFiller;
};
#endif // _BOPTest_Utilities_HeaderFile

View File

@@ -0,0 +1,33 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include "BOPTest_Utilities.pxx"
//==================================================================================================
// BOPCommon Simple Tests - migrating from /tests/boolean/bopcommon_simple/
//==================================================================================================
class BOPCommonSimpleTest : public BRepAlgoAPI_TestBase
{
};
// Test bopcommon_simple/A1: box b1 0 0 0 1 1 1; box b2 0 0 0 1 1 1; bop b1 b2; bopcommon result;
// checkprops result -s 6
TEST_F(BOPCommonSimpleTest, IdenticalBoxes_A1)
{
const TopoDS_Shape aBox1 = BOPTest_Utilities::CreateBox(gp_Pnt(0, 0, 0), 1.0, 1.0, 1.0);
const TopoDS_Shape aBox2 = BOPTest_Utilities::CreateBox(gp_Pnt(0, 0, 0), 1.0, 1.0, 1.0);
const TopoDS_Shape aResult = PerformCommon(aBox1, aBox2);
ValidateResult(aResult, 6.0);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,4 +2,9 @@
set(OCCT_TKBO_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
set(OCCT_TKBO_GTests_FILES
BRepAlgoAPI_Cut_Test.cxx
BRepAlgoAPI_Cut_Test_1.cxx
BRepAlgoAPI_Fuse_Test.cxx
BRepAlgoAPI_Common_Test.cxx
BOPAlgo_BOP_Test.cxx
)