From e384f0bb93f18b05fd4baabf6b9b1109c51d3cd9 Mon Sep 17 00:00:00 2001 From: Pasukhin Dmitry Date: Fri, 20 Feb 2026 20:25:09 +0000 Subject: [PATCH] Testing - Add unit tests for geometric classes and conversions (#1099) - Introduced new tests for TopExp class to validate shape mapping and vertex retrieval. - Added tests for Geom_Circle, Geom_Line, and Geom_Plane classes to ensure correct geometric behavior and transformations. - Implemented tests for GCPnts_AbscissaPoint to verify length calculations and parameter retrieval for lines and circles. - Created conversion tests in GeomConvert to check the accuracy of converting geometric entities to B-spline representations. - Updated CMake files to include new test files for the added tests. --- .../TKMath/GTests/FILES.cmake | 10 + .../TKMath/GTests/gp_Circ_Test.cxx | 96 +++++++++ .../TKMath/GTests/gp_Dir2d_Test.cxx | 138 +++++++++++++ .../TKMath/GTests/gp_Dir_Test.cxx | 182 +++++++++++++++++ .../TKMath/GTests/gp_Lin_Test.cxx | 111 +++++++++++ .../TKMath/GTests/gp_Pln_Test.cxx | 124 ++++++++++++ .../TKMath/GTests/gp_Pnt2d_Test.cxx | 137 +++++++++++++ .../TKMath/GTests/gp_Pnt_Test.cxx | 181 +++++++++++++++++ .../TKMath/GTests/gp_Vec2d_Test.cxx | 165 ++++++++++++++++ .../TKMath/GTests/gp_Vec_Test.cxx | 187 ++++++++++++++++++ .../TKMath/GTests/gp_XYZ_Test.cxx | 160 +++++++++++++++ .../GTests/BRepFilletAPI_MakeChamfer_Test.cxx | 94 +++++++++ .../GTests/BRepFilletAPI_MakeFillet_Test.cxx | 101 ++++++++++ .../TKFillet/GTests/FILES.cmake | 2 + .../GTests/BRepBuilderAPI_Sewing_Test.cxx | 117 +++++++++++ .../BRepOffsetAPI_MakeThickSolid_Test.cxx | 149 ++++++++++++++ .../TKOffset/GTests/FILES.cmake | 2 + .../GTests/BRepPrimAPI_MakeBox_Test.cxx | 124 ++++++++++++ .../GTests/BRepPrimAPI_MakeCone_Test.cxx | 113 +++++++++++ .../GTests/BRepPrimAPI_MakeCylinder_Test.cxx | 99 ++++++++++ .../GTests/BRepPrimAPI_MakeSphere_Test.cxx | 102 ++++++++++ .../GTests/BRepPrimAPI_MakeWedge_Test.cxx | 94 +++++++++ .../TKPrim/GTests/FILES.cmake | 5 + .../TKShHealing/GTests/FILES.cmake | 2 + .../GTests/ShapeAnalysis_Edge_Test.cxx | 91 +++++++++ .../GTests/ShapeFix_Shape_Test.cxx | 94 +++++++++ .../GTests/BRepBuilderAPI_Copy_Test.cxx | 106 ++++++++++ .../GTests/BRepBuilderAPI_MakeEdge_Test.cxx | 132 +++++++++++++ .../GTests/BRepBuilderAPI_MakeFace_Test.cxx | 116 +++++++++++ .../GTests/BRepBuilderAPI_Transform_Test.cxx | 135 +++++++++++++ .../BRepClass3d_SolidClassifier_Test.cxx | 83 ++++++++ .../TKTopAlgo/GTests/BRepGProp_Test.cxx | 117 +++++++++++ .../TKTopAlgo/GTests/FILES.cmake | 6 + .../TKBRep/GTests/BRep_Tool_Test.cxx | 160 +++++++++++++++ src/ModelingData/TKBRep/GTests/FILES.cmake | 2 + .../TKBRep/GTests/TopExp_Test.cxx | 152 ++++++++++++++ src/ModelingData/TKG3d/GTests/FILES.cmake | 3 + .../TKG3d/GTests/Geom_Circle_Test.cxx | 135 +++++++++++++ .../TKG3d/GTests/Geom_Line_Test.cxx | 119 +++++++++++ .../TKG3d/GTests/Geom_Plane_Test.cxx | 111 +++++++++++ .../TKGeomBase/GTests/FILES.cmake | 2 + .../GTests/GCPnts_AbscissaPoint_Test.cxx | 80 ++++++++ .../TKGeomBase/GTests/GeomConvert_Test.cxx | 78 ++++++++ .../TKGeomBase/GTests/Hermit_Test.cxx | 52 ++--- 44 files changed, 4243 insertions(+), 26 deletions(-) create mode 100644 src/FoundationClasses/TKMath/GTests/gp_Circ_Test.cxx create mode 100644 src/FoundationClasses/TKMath/GTests/gp_Dir2d_Test.cxx create mode 100644 src/FoundationClasses/TKMath/GTests/gp_Dir_Test.cxx create mode 100644 src/FoundationClasses/TKMath/GTests/gp_Lin_Test.cxx create mode 100644 src/FoundationClasses/TKMath/GTests/gp_Pln_Test.cxx create mode 100644 src/FoundationClasses/TKMath/GTests/gp_Pnt2d_Test.cxx create mode 100644 src/FoundationClasses/TKMath/GTests/gp_Pnt_Test.cxx create mode 100644 src/FoundationClasses/TKMath/GTests/gp_Vec2d_Test.cxx create mode 100644 src/FoundationClasses/TKMath/GTests/gp_Vec_Test.cxx create mode 100644 src/FoundationClasses/TKMath/GTests/gp_XYZ_Test.cxx create mode 100644 src/ModelingAlgorithms/TKFillet/GTests/BRepFilletAPI_MakeChamfer_Test.cxx create mode 100644 src/ModelingAlgorithms/TKFillet/GTests/BRepFilletAPI_MakeFillet_Test.cxx create mode 100644 src/ModelingAlgorithms/TKOffset/GTests/BRepBuilderAPI_Sewing_Test.cxx create mode 100644 src/ModelingAlgorithms/TKOffset/GTests/BRepOffsetAPI_MakeThickSolid_Test.cxx create mode 100644 src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeBox_Test.cxx create mode 100644 src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeCone_Test.cxx create mode 100644 src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeCylinder_Test.cxx create mode 100644 src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeSphere_Test.cxx create mode 100644 src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeWedge_Test.cxx create mode 100644 src/ModelingAlgorithms/TKShHealing/GTests/ShapeAnalysis_Edge_Test.cxx create mode 100644 src/ModelingAlgorithms/TKShHealing/GTests/ShapeFix_Shape_Test.cxx create mode 100644 src/ModelingAlgorithms/TKTopAlgo/GTests/BRepBuilderAPI_Copy_Test.cxx create mode 100644 src/ModelingAlgorithms/TKTopAlgo/GTests/BRepBuilderAPI_MakeEdge_Test.cxx create mode 100644 src/ModelingAlgorithms/TKTopAlgo/GTests/BRepBuilderAPI_MakeFace_Test.cxx create mode 100644 src/ModelingAlgorithms/TKTopAlgo/GTests/BRepBuilderAPI_Transform_Test.cxx create mode 100644 src/ModelingAlgorithms/TKTopAlgo/GTests/BRepClass3d_SolidClassifier_Test.cxx create mode 100644 src/ModelingAlgorithms/TKTopAlgo/GTests/BRepGProp_Test.cxx create mode 100644 src/ModelingData/TKBRep/GTests/BRep_Tool_Test.cxx create mode 100644 src/ModelingData/TKBRep/GTests/TopExp_Test.cxx create mode 100644 src/ModelingData/TKG3d/GTests/Geom_Circle_Test.cxx create mode 100644 src/ModelingData/TKG3d/GTests/Geom_Line_Test.cxx create mode 100644 src/ModelingData/TKG3d/GTests/Geom_Plane_Test.cxx create mode 100644 src/ModelingData/TKGeomBase/GTests/GCPnts_AbscissaPoint_Test.cxx create mode 100644 src/ModelingData/TKGeomBase/GTests/GeomConvert_Test.cxx diff --git a/src/FoundationClasses/TKMath/GTests/FILES.cmake b/src/FoundationClasses/TKMath/GTests/FILES.cmake index d8d20cf2e5..e645860cb1 100644 --- a/src/FoundationClasses/TKMath/GTests/FILES.cmake +++ b/src/FoundationClasses/TKMath/GTests/FILES.cmake @@ -42,8 +42,18 @@ set(OCCT_TKMath_GTests_FILES CSLib_Test.cxx ElCLib_Test.cxx gp_Ax3_Test.cxx + gp_Circ_Test.cxx + gp_Dir_Test.cxx + gp_Dir2d_Test.cxx + gp_Lin_Test.cxx gp_Mat_Test.cxx + gp_Pln_Test.cxx + gp_Pnt_Test.cxx + gp_Pnt2d_Test.cxx gp_Trsf_Test.cxx + gp_Vec_Test.cxx + gp_Vec2d_Test.cxx + gp_XYZ_Test.cxx math_BFGS_Test.cxx math_BissecNewton_Test.cxx math_BracketMinimum_Test.cxx diff --git a/src/FoundationClasses/TKMath/GTests/gp_Circ_Test.cxx b/src/FoundationClasses/TKMath/GTests/gp_Circ_Test.cxx new file mode 100644 index 0000000000..b38f54f628 --- /dev/null +++ b/src/FoundationClasses/TKMath/GTests/gp_Circ_Test.cxx @@ -0,0 +1,96 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(gp_CircTest, Constructor) +{ + gp_Ax2 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Circ aCirc(anAxis, 5.0); + EXPECT_NEAR(aCirc.Radius(), 5.0, Precision::Confusion()); +} + +TEST(gp_CircTest, Area) +{ + gp_Ax2 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Circ aCirc(anAxis, 1.0); + EXPECT_NEAR(aCirc.Area(), M_PI, Precision::Confusion()); +} + +TEST(gp_CircTest, Length) +{ + gp_Ax2 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Circ aCirc(anAxis, 1.0); + EXPECT_NEAR(aCirc.Length(), 2.0 * M_PI, Precision::Confusion()); +} + +TEST(gp_CircTest, Center) +{ + gp_Pnt aCenter(1.0, 2.0, 3.0); + gp_Ax2 anAxis(aCenter, gp_Dir(0.0, 0.0, 1.0)); + gp_Circ aCirc(anAxis, 5.0); + EXPECT_TRUE(aCirc.Location().IsEqual(aCenter, Precision::Confusion())); +} + +TEST(gp_CircTest, Translate) +{ + gp_Ax2 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Circ aCirc(anAxis, 5.0); + gp_Vec aVec(10.0, 20.0, 30.0); + gp_Circ aTranslated = aCirc.Translated(aVec); + EXPECT_NEAR(aTranslated.Location().X(), 10.0, Precision::Confusion()); + EXPECT_NEAR(aTranslated.Location().Y(), 20.0, Precision::Confusion()); + EXPECT_NEAR(aTranslated.Location().Z(), 30.0, Precision::Confusion()); + EXPECT_NEAR(aTranslated.Radius(), 5.0, Precision::Confusion()); +} + +TEST(gp_CircTest, Rotate) +{ + gp_Ax2 anAxis(gp_Pnt(1.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Circ aCirc(anAxis, 2.0); + gp_Ax1 aRotAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Circ aRotated = aCirc.Rotated(aRotAxis, M_PI_2); + EXPECT_NEAR(aRotated.Location().X(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aRotated.Location().Y(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aRotated.Radius(), 2.0, Precision::Confusion()); +} + +TEST(gp_CircTest, Mirror) +{ + gp_Ax2 anAxis(gp_Pnt(1.0, 2.0, 3.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Circ aCirc(anAxis, 5.0); + gp_Pnt aMirrorPnt(0.0, 0.0, 0.0); + gp_Circ aMirrored = aCirc.Mirrored(aMirrorPnt); + EXPECT_NEAR(aMirrored.Location().X(), -1.0, Precision::Confusion()); + EXPECT_NEAR(aMirrored.Location().Y(), -2.0, Precision::Confusion()); + EXPECT_NEAR(aMirrored.Location().Z(), -3.0, Precision::Confusion()); +} + +TEST(gp_CircTest, Transform) +{ + gp_Ax2 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Circ aCirc(anAxis, 3.0); + gp_Trsf aTrsf; + aTrsf.SetScale(gp_Pnt(0.0, 0.0, 0.0), 2.0); + gp_Circ aTransformed = aCirc.Transformed(aTrsf); + EXPECT_NEAR(aTransformed.Radius(), 6.0, Precision::Confusion()); +} diff --git a/src/FoundationClasses/TKMath/GTests/gp_Dir2d_Test.cxx b/src/FoundationClasses/TKMath/GTests/gp_Dir2d_Test.cxx new file mode 100644 index 0000000000..e18cc8fc69 --- /dev/null +++ b/src/FoundationClasses/TKMath/GTests/gp_Dir2d_Test.cxx @@ -0,0 +1,138 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(gp_Dir2dTest, CoordinateConstructor) +{ + gp_Dir2d aDir(1.0, 0.0); + EXPECT_NEAR(aDir.X(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aDir.Y(), 0.0, Precision::Confusion()); +} + +TEST(gp_Dir2dTest, XYConstructor) +{ + gp_XY aXY(0.0, 3.0); + gp_Dir2d aDir(aXY); + EXPECT_NEAR(aDir.X(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aDir.Y(), 1.0, Precision::Confusion()); +} + +TEST(gp_Dir2dTest, Vec2dConstructor) +{ + gp_Vec2d aVec(3.0, 0.0); + gp_Dir2d aDir(aVec); + EXPECT_NEAR(aDir.X(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aDir.Y(), 0.0, Precision::Confusion()); +} + +TEST(gp_Dir2dTest, Angle) +{ + gp_Dir2d aD1(1.0, 0.0); + gp_Dir2d aD2(0.0, 1.0); + EXPECT_NEAR(aD1.Angle(aD2), M_PI_2, Precision::Angular()); +} + +TEST(gp_Dir2dTest, IsEqual) +{ + gp_Dir2d aD1(1.0, 0.0); + gp_Dir2d aD2(1.0, 0.0); + EXPECT_TRUE(aD1.IsEqual(aD2, Precision::Angular())); +} + +TEST(gp_Dir2dTest, IsNormal) +{ + gp_Dir2d aD1(1.0, 0.0); + gp_Dir2d aD2(0.0, 1.0); + EXPECT_TRUE(aD1.IsNormal(aD2, Precision::Angular())); +} + +TEST(gp_Dir2dTest, IsOpposite) +{ + gp_Dir2d aD1(1.0, 0.0); + gp_Dir2d aD2(-1.0, 0.0); + EXPECT_TRUE(aD1.IsOpposite(aD2, Precision::Angular())); +} + +TEST(gp_Dir2dTest, IsParallel) +{ + gp_Dir2d aD1(1.0, 0.0); + gp_Dir2d aD2(-1.0, 0.0); + EXPECT_TRUE(aD1.IsParallel(aD2, Precision::Angular())); +} + +TEST(gp_Dir2dTest, Dot) +{ + gp_Dir2d aD1(1.0, 0.0); + gp_Dir2d aD2(0.0, 1.0); + EXPECT_NEAR(aD1.Dot(aD2), 0.0, Precision::Confusion()); + + gp_Dir2d aD3(1.0, 0.0); + EXPECT_NEAR(aD1.Dot(aD3), 1.0, Precision::Confusion()); +} + +TEST(gp_Dir2dTest, Crossed) +{ + gp_Dir2d aD1(1.0, 0.0); + gp_Dir2d aD2(0.0, 1.0); + // D1.X*D2.Y - D1.Y*D2.X = 1*1 - 0*0 = 1 + EXPECT_NEAR(aD1.Crossed(aD2), 1.0, Precision::Confusion()); +} + +TEST(gp_Dir2dTest, Rotate) +{ + gp_Dir2d aDir(1.0, 0.0); + gp_Dir2d aRotated = aDir.Rotated(M_PI_2); + EXPECT_NEAR(aRotated.X(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aRotated.Y(), 1.0, Precision::Confusion()); +} + +TEST(gp_Dir2dTest, Mirror) +{ + gp_Dir2d aDir(1.0, 0.0); + // Mirror through the Y axis + gp_Ax2d anAxis(gp_Pnt2d(0.0, 0.0), gp_Dir2d(0.0, 1.0)); + gp_Dir2d aMirrored = aDir.Mirrored(anAxis); + // Mirroring (1,0) through axis with direction (0,1): + // d_mirror = 2*(d.axis_dir)*axis_dir - d = 2*0*(0,1) - (1,0) = (-1,0) + EXPECT_NEAR(aMirrored.X(), -1.0, Precision::Confusion()); + EXPECT_NEAR(aMirrored.Y(), 0.0, Precision::Confusion()); +} + +TEST(gp_Dir2dTest, Transform) +{ + gp_Dir2d aDir(1.0, 0.0); + gp_Trsf2d aTrsf; + aTrsf.SetRotation(gp_Pnt2d(0.0, 0.0), M_PI); + gp_Dir2d aTransformed = aDir.Transformed(aTrsf); + EXPECT_NEAR(aTransformed.X(), -1.0, Precision::Confusion()); + EXPECT_NEAR(aTransformed.Y(), 0.0, Precision::Confusion()); +} + +TEST(gp_Dir2dTest, ZeroMagnitudeThrows) +{ +#ifndef No_Exception + EXPECT_THROW(gp_Dir2d aDir(0.0, 0.0), Standard_ConstructionError); +#else + GTEST_SKIP() << "No_Exception is defined; exception behavior is disabled in this build."; +#endif +} diff --git a/src/FoundationClasses/TKMath/GTests/gp_Dir_Test.cxx b/src/FoundationClasses/TKMath/GTests/gp_Dir_Test.cxx new file mode 100644 index 0000000000..3a870f2541 --- /dev/null +++ b/src/FoundationClasses/TKMath/GTests/gp_Dir_Test.cxx @@ -0,0 +1,182 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(gp_DirTest, CoordinateConstructor) +{ + gp_Dir aDir(0.0, 0.0, 1.0); + EXPECT_NEAR(aDir.X(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aDir.Y(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aDir.Z(), 1.0, Precision::Confusion()); +} + +TEST(gp_DirTest, XYZConstructor) +{ + gp_XYZ aXYZ(0.0, 3.0, 4.0); + gp_Dir aDir(aXYZ); + EXPECT_NEAR(aDir.X(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aDir.Y(), 0.6, Precision::Confusion()); + EXPECT_NEAR(aDir.Z(), 0.8, Precision::Confusion()); +} + +TEST(gp_DirTest, VecConstructor) +{ + gp_Vec aVec(3.0, 0.0, 0.0); + gp_Dir aDir(aVec); + EXPECT_NEAR(aDir.X(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aDir.Y(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aDir.Z(), 0.0, Precision::Confusion()); +} + +TEST(gp_DirTest, PredefinedDirections) +{ + EXPECT_TRUE(gp_Dir(1.0, 0.0, 0.0).IsEqual(gp_Dir(gp_Dir::D::X), Precision::Angular())); + EXPECT_TRUE(gp_Dir(0.0, 1.0, 0.0).IsEqual(gp_Dir(gp_Dir::D::Y), Precision::Angular())); + EXPECT_TRUE(gp_Dir(0.0, 0.0, 1.0).IsEqual(gp_Dir(gp_Dir::D::Z), Precision::Angular())); +} + +TEST(gp_DirTest, Angle) +{ + gp_Dir aD1(1.0, 0.0, 0.0); + gp_Dir aD2(0.0, 1.0, 0.0); + EXPECT_NEAR(aD1.Angle(aD2), M_PI_2, Precision::Angular()); +} + +TEST(gp_DirTest, AngleWithRef) +{ + gp_Dir aD1(1.0, 0.0, 0.0); + gp_Dir aD2(0.0, 1.0, 0.0); + gp_Dir aRef(0.0, 0.0, 1.0); + double anAngle = aD1.AngleWithRef(aD2, aRef); + EXPECT_NEAR(anAngle, M_PI_2, Precision::Angular()); + + // Reverse reference direction should negate the angle + double anAngleReversed = aD1.AngleWithRef(aD2, gp_Dir(0.0, 0.0, -1.0)); + EXPECT_NEAR(anAngleReversed, -M_PI_2, Precision::Angular()); +} + +TEST(gp_DirTest, IsEqual) +{ + gp_Dir aD1(1.0, 0.0, 0.0); + gp_Dir aD2(1.0, 0.0, 0.0); + EXPECT_TRUE(aD1.IsEqual(aD2, Precision::Angular())); +} + +TEST(gp_DirTest, IsNormal) +{ + gp_Dir aD1(1.0, 0.0, 0.0); + gp_Dir aD2(0.0, 1.0, 0.0); + EXPECT_TRUE(aD1.IsNormal(aD2, Precision::Angular())); +} + +TEST(gp_DirTest, IsOpposite) +{ + gp_Dir aD1(1.0, 0.0, 0.0); + gp_Dir aD2(-1.0, 0.0, 0.0); + EXPECT_TRUE(aD1.IsOpposite(aD2, Precision::Angular())); +} + +TEST(gp_DirTest, IsParallel) +{ + gp_Dir aD1(1.0, 0.0, 0.0); + gp_Dir aD2(-1.0, 0.0, 0.0); + EXPECT_TRUE(aD1.IsParallel(aD2, Precision::Angular())); +} + +TEST(gp_DirTest, Cross) +{ + gp_Dir aD1(1.0, 0.0, 0.0); + gp_Dir aD2(0.0, 1.0, 0.0); + gp_Dir aCross = aD1.Crossed(aD2); + EXPECT_NEAR(aCross.X(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aCross.Y(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aCross.Z(), 1.0, Precision::Confusion()); +} + +TEST(gp_DirTest, CrossCross) +{ + gp_Dir aA(1.0, 0.0, 0.0); + gp_Dir aB(1.0, 1.0, 0.0); + gp_Dir aC(0.0, 0.0, 1.0); + gp_Dir aCrossCross = aA.CrossCrossed(aB, aC); + // Result should be a valid normalized direction + double aMag = std::sqrt(aCrossCross.X() * aCrossCross.X() + aCrossCross.Y() * aCrossCross.Y() + + aCrossCross.Z() * aCrossCross.Z()); + EXPECT_NEAR(aMag, 1.0, Precision::Confusion()); +} + +TEST(gp_DirTest, Dot) +{ + gp_Dir aD1(1.0, 0.0, 0.0); + gp_Dir aD2(0.0, 1.0, 0.0); + EXPECT_NEAR(aD1.Dot(aD2), 0.0, Precision::Confusion()); + + gp_Dir aD3(1.0, 0.0, 0.0); + EXPECT_NEAR(aD1.Dot(aD3), 1.0, Precision::Confusion()); +} + +TEST(gp_DirTest, Mirror_Point) +{ + gp_Dir aDir(1.0, 0.0, 0.0); + gp_Ax1 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 1.0, 0.0)); + gp_Dir aMirrored = aDir.Mirrored(anAxis); + // Mirror X direction through Y axis: result should be (-1,0,0)... + // Actually mirroring direction (1,0,0) through axis Y means reflecting about the Y axis line + // The component along Y stays, the perpendicular component reverses: result is (-1,0,0) + // But for axis mirror of a direction, it reflects in the axis: + // d_mirror = 2*(d.axis)*axis - d + // d.axis = (1,0,0).(0,1,0) = 0 + // result = 2*0*(0,1,0) - (1,0,0) = (-1,0,0) + EXPECT_NEAR(aMirrored.X(), -1.0, Precision::Confusion()); + EXPECT_NEAR(aMirrored.Y(), 0.0, Precision::Confusion()); +} + +TEST(gp_DirTest, Rotate) +{ + gp_Dir aDir(1.0, 0.0, 0.0); + gp_Ax1 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Dir aRotated = aDir.Rotated(anAxis, M_PI_2); + EXPECT_NEAR(aRotated.X(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aRotated.Y(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aRotated.Z(), 0.0, Precision::Confusion()); +} + +TEST(gp_DirTest, Transform) +{ + gp_Dir aDir(1.0, 0.0, 0.0); + gp_Trsf aTrsf; + aTrsf.SetRotation(gp_Ax1(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)), M_PI); + gp_Dir aTransformed = aDir.Transformed(aTrsf); + EXPECT_NEAR(aTransformed.X(), -1.0, Precision::Confusion()); + EXPECT_NEAR(aTransformed.Y(), 0.0, Precision::Confusion()); +} + +TEST(gp_DirTest, ZeroMagnitudeInput_ThrowsException) +{ +#ifndef No_Exception + EXPECT_THROW(gp_Dir aDir(0.0, 0.0, 0.0), Standard_ConstructionError); +#else + GTEST_SKIP() << "No_Exception is defined; exception behavior is disabled in this build."; +#endif +} diff --git a/src/FoundationClasses/TKMath/GTests/gp_Lin_Test.cxx b/src/FoundationClasses/TKMath/GTests/gp_Lin_Test.cxx new file mode 100644 index 0000000000..8ad4b0a4e4 --- /dev/null +++ b/src/FoundationClasses/TKMath/GTests/gp_Lin_Test.cxx @@ -0,0 +1,111 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(gp_LinTest, ConstructorFromAx1) +{ + gp_Ax1 anAx1(gp_Pnt(1.0, 2.0, 3.0), gp_Dir(1.0, 0.0, 0.0)); + gp_Lin aLin(anAx1); + EXPECT_TRUE(aLin.Location().IsEqual(gp_Pnt(1.0, 2.0, 3.0), Precision::Confusion())); + EXPECT_TRUE(aLin.Direction().IsEqual(gp_Dir(1.0, 0.0, 0.0), Precision::Angular())); +} + +TEST(gp_LinTest, ConstructorFromPointAndDir) +{ + gp_Lin aLin(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + EXPECT_TRUE(aLin.Location().IsEqual(gp_Pnt(0.0, 0.0, 0.0), Precision::Confusion())); + EXPECT_TRUE(aLin.Direction().IsEqual(gp_Dir(0.0, 0.0, 1.0), Precision::Angular())); +} + +TEST(gp_LinTest, DistanceToPoint) +{ + gp_Lin aLin(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + gp_Pnt aPnt(5.0, 3.0, 4.0); + // Distance from point to X axis: sqrt(3^2 + 4^2) = 5 + EXPECT_NEAR(aLin.Distance(aPnt), 5.0, Precision::Confusion()); +} + +TEST(gp_LinTest, DistanceToLine_Parallel) +{ + gp_Lin aL1(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + gp_Lin aL2(gp_Pnt(0.0, 3.0, 4.0), gp_Dir(1.0, 0.0, 0.0)); + EXPECT_NEAR(aL1.Distance(aL2), 5.0, Precision::Confusion()); +} + +TEST(gp_LinTest, DistanceToLine_Intersecting) +{ + gp_Lin aL1(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + gp_Lin aL2(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 1.0, 0.0)); + EXPECT_NEAR(aL1.Distance(aL2), 0.0, Precision::Confusion()); +} + +TEST(gp_LinTest, Contains) +{ + gp_Lin aLin(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + gp_Pnt aOnLine(5.0, 0.0, 0.0); + gp_Pnt aOffLine(5.0, 1.0, 0.0); + EXPECT_TRUE(aLin.Contains(aOnLine, Precision::Confusion())); + EXPECT_FALSE(aLin.Contains(aOffLine, Precision::Confusion())); +} + +TEST(gp_LinTest, Angle) +{ + gp_Lin aL1(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + gp_Lin aL2(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 1.0, 0.0)); + EXPECT_NEAR(aL1.Angle(aL2), M_PI_2, Precision::Angular()); +} + +TEST(gp_LinTest, Translate) +{ + gp_Lin aLin(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + gp_Vec aVec(0.0, 5.0, 0.0); + gp_Lin aTranslated = aLin.Translated(aVec); + EXPECT_NEAR(aTranslated.Location().Y(), 5.0, Precision::Confusion()); +} + +TEST(gp_LinTest, Rotate) +{ + gp_Lin aLin(gp_Pnt(1.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + gp_Ax1 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Lin aRotated = aLin.Rotated(anAxis, M_PI_2); + EXPECT_NEAR(aRotated.Location().X(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aRotated.Location().Y(), 1.0, Precision::Confusion()); + EXPECT_TRUE(aRotated.Direction().IsEqual(gp_Dir(0.0, 1.0, 0.0), Precision::Angular())); +} + +TEST(gp_LinTest, Mirror) +{ + gp_Lin aLin(gp_Pnt(1.0, 1.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + gp_Ax1 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + gp_Lin aMirrored = aLin.Mirrored(anAxis); + EXPECT_NEAR(aMirrored.Location().Y(), -1.0, Precision::Confusion()); +} + +TEST(gp_LinTest, Transform) +{ + gp_Lin aLin(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + gp_Trsf aTrsf; + aTrsf.SetTranslation(gp_Vec(0.0, 0.0, 10.0)); + gp_Lin aTransformed = aLin.Transformed(aTrsf); + EXPECT_NEAR(aTransformed.Location().Z(), 10.0, Precision::Confusion()); +} diff --git a/src/FoundationClasses/TKMath/GTests/gp_Pln_Test.cxx b/src/FoundationClasses/TKMath/GTests/gp_Pln_Test.cxx new file mode 100644 index 0000000000..2b842af0c9 --- /dev/null +++ b/src/FoundationClasses/TKMath/GTests/gp_Pln_Test.cxx @@ -0,0 +1,124 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(gp_PlnTest, ConstructorFromAx3) +{ + gp_Ax3 anAx3(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Pln aPln(anAx3); + EXPECT_TRUE(aPln.Location().IsEqual(gp_Pnt(0.0, 0.0, 0.0), Precision::Confusion())); + EXPECT_TRUE(aPln.Axis().Direction().IsEqual(gp_Dir(0.0, 0.0, 1.0), Precision::Angular())); +} + +TEST(gp_PlnTest, ConstructorFromPointAndDir) +{ + gp_Pnt aLoc(1.0, 2.0, 3.0); + gp_Dir aNorm(0.0, 0.0, 1.0); + gp_Pln aPln(aLoc, aNorm); + EXPECT_TRUE(aPln.Location().IsEqual(aLoc, Precision::Confusion())); + EXPECT_TRUE(aPln.Axis().Direction().IsEqual(aNorm, Precision::Angular())); +} + +TEST(gp_PlnTest, ConstructorFromCoefficients) +{ + // Plane Z = 5 => 0*X + 0*Y + 1*Z - 5 = 0 + gp_Pln aPln(0.0, 0.0, 1.0, -5.0); + double anA, aB, aC, aD; + aPln.Coefficients(anA, aB, aC, aD); + EXPECT_NEAR(anA, 0.0, Precision::Confusion()); + EXPECT_NEAR(aB, 0.0, Precision::Confusion()); + EXPECT_NEAR(aC, 1.0, Precision::Confusion()); + EXPECT_NEAR(aD, -5.0, Precision::Confusion()); +} + +TEST(gp_PlnTest, DistanceToPoint) +{ + gp_Pln aPln(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Pnt aPnt(3.0, 4.0, 5.0); + EXPECT_NEAR(aPln.Distance(aPnt), 5.0, Precision::Confusion()); +} + +TEST(gp_PlnTest, Contains) +{ + gp_Pln aPln(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Pnt aOnPlane(3.0, 4.0, 0.0); + gp_Pnt aOffPlane(3.0, 4.0, 1.0); + EXPECT_TRUE(aPln.Contains(aOnPlane, Precision::Confusion())); + EXPECT_FALSE(aPln.Contains(aOffPlane, Precision::Confusion())); +} + +TEST(gp_PlnTest, Coefficients) +{ + gp_Pln aPln(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + double anA, aB, aC, aD; + aPln.Coefficients(anA, aB, aC, aD); + EXPECT_NEAR(anA, 0.0, Precision::Confusion()); + EXPECT_NEAR(aB, 0.0, Precision::Confusion()); + EXPECT_NEAR(aC, 1.0, Precision::Confusion()); + EXPECT_NEAR(aD, 0.0, Precision::Confusion()); +} + +TEST(gp_PlnTest, Mirror) +{ + gp_Pln aPln(gp_Pnt(0.0, 0.0, 5.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Ax2 aMirrorPlane(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Pln aMirrored = aPln.Mirrored(aMirrorPlane); + EXPECT_NEAR(aMirrored.Location().Z(), -5.0, Precision::Confusion()); +} + +TEST(gp_PlnTest, Rotate) +{ + gp_Pln aPln(gp_Pnt(1.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Ax1 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Pln aRotated = aPln.Rotated(anAxis, M_PI_2); + EXPECT_NEAR(aRotated.Location().X(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aRotated.Location().Y(), 1.0, Precision::Confusion()); +} + +TEST(gp_PlnTest, Scale) +{ + gp_Pln aPln(gp_Pnt(1.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Pnt aCenter(0.0, 0.0, 0.0); + gp_Pln aScaled = aPln.Scaled(aCenter, 3.0); + EXPECT_NEAR(aScaled.Location().X(), 3.0, Precision::Confusion()); +} + +TEST(gp_PlnTest, Translate) +{ + gp_Pln aPln(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Vec aVec(1.0, 2.0, 3.0); + gp_Pln aTranslated = aPln.Translated(aVec); + EXPECT_NEAR(aTranslated.Location().X(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aTranslated.Location().Y(), 2.0, Precision::Confusion()); + EXPECT_NEAR(aTranslated.Location().Z(), 3.0, Precision::Confusion()); +} + +TEST(gp_PlnTest, Transform) +{ + gp_Pln aPln(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Trsf aTrsf; + aTrsf.SetTranslation(gp_Vec(0.0, 0.0, 10.0)); + gp_Pln aTransformed = aPln.Transformed(aTrsf); + EXPECT_NEAR(aTransformed.Location().Z(), 10.0, Precision::Confusion()); +} diff --git a/src/FoundationClasses/TKMath/GTests/gp_Pnt2d_Test.cxx b/src/FoundationClasses/TKMath/GTests/gp_Pnt2d_Test.cxx new file mode 100644 index 0000000000..a2a26c9093 --- /dev/null +++ b/src/FoundationClasses/TKMath/GTests/gp_Pnt2d_Test.cxx @@ -0,0 +1,137 @@ +// 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 +#include +#include +#include +#include +#include +#include + +#include + +TEST(gp_Pnt2dTest, DefaultConstructor) +{ + gp_Pnt2d aPnt; + EXPECT_DOUBLE_EQ(aPnt.X(), 0.0); + EXPECT_DOUBLE_EQ(aPnt.Y(), 0.0); +} + +TEST(gp_Pnt2dTest, CoordinateConstructor) +{ + gp_Pnt2d aPnt(1.0, 2.0); + EXPECT_DOUBLE_EQ(aPnt.X(), 1.0); + EXPECT_DOUBLE_EQ(aPnt.Y(), 2.0); +} + +TEST(gp_Pnt2dTest, XYConstructor) +{ + gp_XY aXY(3.0, 4.0); + gp_Pnt2d aPnt(aXY); + EXPECT_DOUBLE_EQ(aPnt.X(), 3.0); + EXPECT_DOUBLE_EQ(aPnt.Y(), 4.0); +} + +TEST(gp_Pnt2dTest, SetCoord) +{ + gp_Pnt2d aPnt; + aPnt.SetX(10.0); + aPnt.SetY(20.0); + EXPECT_DOUBLE_EQ(aPnt.X(), 10.0); + EXPECT_DOUBLE_EQ(aPnt.Y(), 20.0); + + aPnt.SetCoord(7.0, 8.0); + EXPECT_DOUBLE_EQ(aPnt.X(), 7.0); + EXPECT_DOUBLE_EQ(aPnt.Y(), 8.0); +} + +TEST(gp_Pnt2dTest, Distance) +{ + gp_Pnt2d aP1(0.0, 0.0); + gp_Pnt2d aP2(3.0, 4.0); + EXPECT_NEAR(aP1.Distance(aP2), 5.0, Precision::Confusion()); +} + +TEST(gp_Pnt2dTest, SquareDistance) +{ + gp_Pnt2d aP1(1.0, 2.0); + gp_Pnt2d aP2(4.0, 6.0); + // (4-1)^2 + (6-2)^2 = 9 + 16 = 25 + EXPECT_NEAR(aP1.SquareDistance(aP2), 25.0, Precision::Confusion()); +} + +TEST(gp_Pnt2dTest, IsEqual) +{ + gp_Pnt2d aP1(1.0, 2.0); + gp_Pnt2d aP2(1.0, 2.0); + gp_Pnt2d aP3(1.0, 3.0); + EXPECT_TRUE(aP1.IsEqual(aP2, Precision::Confusion())); + EXPECT_FALSE(aP1.IsEqual(aP3, Precision::Confusion())); +} + +TEST(gp_Pnt2dTest, Translate_ByVec2d) +{ + gp_Pnt2d aPnt(1.0, 2.0); + gp_Vec2d aVec(10.0, 20.0); + gp_Pnt2d aResult = aPnt.Translated(aVec); + EXPECT_NEAR(aResult.X(), 11.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Y(), 22.0, Precision::Confusion()); +} + +TEST(gp_Pnt2dTest, Scale) +{ + gp_Pnt2d aPnt(2.0, 4.0); + gp_Pnt2d aCenter(0.0, 0.0); + gp_Pnt2d aResult = aPnt.Scaled(aCenter, 2.0); + EXPECT_NEAR(aResult.X(), 4.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Y(), 8.0, Precision::Confusion()); +} + +TEST(gp_Pnt2dTest, Rotate) +{ + gp_Pnt2d aPnt(1.0, 0.0); + gp_Pnt2d aCenter(0.0, 0.0); + gp_Pnt2d aResult = aPnt.Rotated(aCenter, M_PI_2); + EXPECT_NEAR(aResult.X(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Y(), 1.0, Precision::Confusion()); +} + +TEST(gp_Pnt2dTest, Mirror_Point) +{ + gp_Pnt2d aPnt(1.0, 0.0); + gp_Pnt2d aCenter(0.0, 0.0); + gp_Pnt2d aResult = aPnt.Mirrored(aCenter); + EXPECT_NEAR(aResult.X(), -1.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Y(), 0.0, Precision::Confusion()); +} + +TEST(gp_Pnt2dTest, Mirror_Axis) +{ + gp_Pnt2d aPnt(1.0, 1.0); + // Mirror through the X axis + gp_Ax2d anAxis(gp_Pnt2d(0.0, 0.0), gp_Dir2d(1.0, 0.0)); + gp_Pnt2d aResult = aPnt.Mirrored(anAxis); + EXPECT_NEAR(aResult.X(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Y(), -1.0, Precision::Confusion()); +} + +TEST(gp_Pnt2dTest, Transformed) +{ + gp_Pnt2d aPnt(1.0, 0.0); + gp_Trsf2d aTrsf; + aTrsf.SetTranslation(gp_Vec2d(0.0, 5.0)); + gp_Pnt2d aResult = aPnt.Transformed(aTrsf); + EXPECT_NEAR(aResult.X(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Y(), 5.0, Precision::Confusion()); +} diff --git a/src/FoundationClasses/TKMath/GTests/gp_Pnt_Test.cxx b/src/FoundationClasses/TKMath/GTests/gp_Pnt_Test.cxx new file mode 100644 index 0000000000..4c39b5bc91 --- /dev/null +++ b/src/FoundationClasses/TKMath/GTests/gp_Pnt_Test.cxx @@ -0,0 +1,181 @@ +// 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 +#include +#include +#include +#include +#include +#include + +#include + +TEST(gp_PntTest, DefaultConstructor) +{ + gp_Pnt aPnt; + EXPECT_DOUBLE_EQ(aPnt.X(), 0.0); + EXPECT_DOUBLE_EQ(aPnt.Y(), 0.0); + EXPECT_DOUBLE_EQ(aPnt.Z(), 0.0); +} + +TEST(gp_PntTest, CoordinateConstructor) +{ + gp_Pnt aPnt(1.0, 2.0, 3.0); + EXPECT_DOUBLE_EQ(aPnt.X(), 1.0); + EXPECT_DOUBLE_EQ(aPnt.Y(), 2.0); + EXPECT_DOUBLE_EQ(aPnt.Z(), 3.0); +} + +TEST(gp_PntTest, XYZConstructor) +{ + gp_XYZ aXYZ(4.0, 5.0, 6.0); + gp_Pnt aPnt(aXYZ); + EXPECT_DOUBLE_EQ(aPnt.X(), 4.0); + EXPECT_DOUBLE_EQ(aPnt.Y(), 5.0); + EXPECT_DOUBLE_EQ(aPnt.Z(), 6.0); +} + +TEST(gp_PntTest, SetCoord) +{ + gp_Pnt aPnt; + aPnt.SetX(10.0); + aPnt.SetY(20.0); + aPnt.SetZ(30.0); + EXPECT_DOUBLE_EQ(aPnt.X(), 10.0); + EXPECT_DOUBLE_EQ(aPnt.Y(), 20.0); + EXPECT_DOUBLE_EQ(aPnt.Z(), 30.0); + + aPnt.SetCoord(7.0, 8.0, 9.0); + EXPECT_DOUBLE_EQ(aPnt.X(), 7.0); + EXPECT_DOUBLE_EQ(aPnt.Y(), 8.0); + EXPECT_DOUBLE_EQ(aPnt.Z(), 9.0); +} + +TEST(gp_PntTest, Distance) +{ + gp_Pnt aP1(0.0, 0.0, 0.0); + gp_Pnt aP2(3.0, 4.0, 0.0); + EXPECT_NEAR(aP1.Distance(aP2), 5.0, Precision::Confusion()); +} + +TEST(gp_PntTest, SquareDistance) +{ + gp_Pnt aP1(1.0, 2.0, 3.0); + gp_Pnt aP2(4.0, 6.0, 3.0); + // (4-1)^2 + (6-2)^2 + (3-3)^2 = 9 + 16 + 0 = 25 + EXPECT_NEAR(aP1.SquareDistance(aP2), 25.0, Precision::Confusion()); +} + +TEST(gp_PntTest, IsEqual) +{ + gp_Pnt aP1(1.0, 2.0, 3.0); + gp_Pnt aP2(1.0, 2.0, 3.0); + gp_Pnt aP3(1.0, 2.0, 4.0); + EXPECT_TRUE(aP1.IsEqual(aP2, Precision::Confusion())); + EXPECT_FALSE(aP1.IsEqual(aP3, Precision::Confusion())); +} + +TEST(gp_PntTest, BaryCenter) +{ + gp_Pnt aP1(0.0, 0.0, 0.0); + gp_Pnt aP2(10.0, 0.0, 0.0); + // BaryCenter with equal weights: midpoint + aP1.BaryCenter(1.0, aP2, 1.0); + EXPECT_NEAR(aP1.X(), 5.0, Precision::Confusion()); + EXPECT_NEAR(aP1.Y(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aP1.Z(), 0.0, Precision::Confusion()); +} + +TEST(gp_PntTest, Translate_ByVec) +{ + gp_Pnt aPnt(1.0, 2.0, 3.0); + gp_Vec aVec(10.0, 20.0, 30.0); + gp_Pnt aResult = aPnt.Translated(aVec); + EXPECT_NEAR(aResult.X(), 11.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Y(), 22.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Z(), 33.0, Precision::Confusion()); +} + +TEST(gp_PntTest, Translate_ByTwoPoints) +{ + gp_Pnt aPnt(1.0, 2.0, 3.0); + gp_Pnt aFrom(0.0, 0.0, 0.0); + gp_Pnt aTo(5.0, 5.0, 5.0); + gp_Pnt aResult = aPnt.Translated(aFrom, aTo); + EXPECT_NEAR(aResult.X(), 6.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Y(), 7.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Z(), 8.0, Precision::Confusion()); +} + +TEST(gp_PntTest, Scale) +{ + gp_Pnt aPnt(2.0, 4.0, 6.0); + gp_Pnt aCenter(0.0, 0.0, 0.0); + gp_Pnt aResult = aPnt.Scaled(aCenter, 2.0); + EXPECT_NEAR(aResult.X(), 4.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Y(), 8.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Z(), 12.0, Precision::Confusion()); +} + +TEST(gp_PntTest, Rotate) +{ + gp_Pnt aPnt(1.0, 0.0, 0.0); + gp_Ax1 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Pnt aResult = aPnt.Rotated(anAxis, M_PI_2); + EXPECT_NEAR(aResult.X(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Y(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Z(), 0.0, Precision::Confusion()); +} + +TEST(gp_PntTest, Mirror_Point) +{ + gp_Pnt aPnt(1.0, 0.0, 0.0); + gp_Pnt aCenter(0.0, 0.0, 0.0); + gp_Pnt aResult = aPnt.Mirrored(aCenter); + EXPECT_NEAR(aResult.X(), -1.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Y(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Z(), 0.0, Precision::Confusion()); +} + +TEST(gp_PntTest, Mirror_Axis) +{ + gp_Pnt aPnt(1.0, 1.0, 0.0); + gp_Ax1 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + gp_Pnt aResult = aPnt.Mirrored(anAxis); + EXPECT_NEAR(aResult.X(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Y(), -1.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Z(), 0.0, Precision::Confusion()); +} + +TEST(gp_PntTest, Mirror_Plane) +{ + gp_Pnt aPnt(1.0, 2.0, 3.0); + // Mirror through XY plane (Z=0) + gp_Ax2 anAx2(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Pnt aResult = aPnt.Mirrored(anAx2); + EXPECT_NEAR(aResult.X(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Y(), 2.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Z(), -3.0, Precision::Confusion()); +} + +TEST(gp_PntTest, Transformed) +{ + gp_Pnt aPnt(1.0, 0.0, 0.0); + gp_Trsf aTrsf; + aTrsf.SetTranslation(gp_Vec(0.0, 0.0, 5.0)); + gp_Pnt aResult = aPnt.Transformed(aTrsf); + EXPECT_NEAR(aResult.X(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Y(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Z(), 5.0, Precision::Confusion()); +} diff --git a/src/FoundationClasses/TKMath/GTests/gp_Vec2d_Test.cxx b/src/FoundationClasses/TKMath/GTests/gp_Vec2d_Test.cxx new file mode 100644 index 0000000000..aa5f23c339 --- /dev/null +++ b/src/FoundationClasses/TKMath/GTests/gp_Vec2d_Test.cxx @@ -0,0 +1,165 @@ +// 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 +#include +#include +#include +#include + +#include + +TEST(gp_Vec2dTest, DefaultConstructor) +{ + gp_Vec2d aVec; + EXPECT_DOUBLE_EQ(aVec.X(), 0.0); + EXPECT_DOUBLE_EQ(aVec.Y(), 0.0); +} + +TEST(gp_Vec2dTest, CoordinateConstructor) +{ + gp_Vec2d aVec(1.0, 2.0); + EXPECT_DOUBLE_EQ(aVec.X(), 1.0); + EXPECT_DOUBLE_EQ(aVec.Y(), 2.0); +} + +TEST(gp_Vec2dTest, TwoPointConstructor) +{ + gp_Pnt2d aP1(1.0, 2.0); + gp_Pnt2d aP2(4.0, 6.0); + gp_Vec2d aVec(aP1, aP2); + EXPECT_DOUBLE_EQ(aVec.X(), 3.0); + EXPECT_DOUBLE_EQ(aVec.Y(), 4.0); +} + +TEST(gp_Vec2dTest, Dir2dConstructor) +{ + gp_Dir2d aDir(0.0, 1.0); + gp_Vec2d aVec(aDir); + EXPECT_NEAR(aVec.Magnitude(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aVec.Y(), 1.0, Precision::Confusion()); +} + +TEST(gp_Vec2dTest, AddSubtract) +{ + gp_Vec2d aV1(1.0, 2.0); + gp_Vec2d aV2(4.0, 5.0); + + gp_Vec2d aSum = aV1 + aV2; + EXPECT_DOUBLE_EQ(aSum.X(), 5.0); + EXPECT_DOUBLE_EQ(aSum.Y(), 7.0); + + gp_Vec2d aDiff = aV2 - aV1; + EXPECT_DOUBLE_EQ(aDiff.X(), 3.0); + EXPECT_DOUBLE_EQ(aDiff.Y(), 3.0); +} + +TEST(gp_Vec2dTest, MultiplyDivide) +{ + gp_Vec2d aVec(2.0, 4.0); + + gp_Vec2d aScaled = aVec * 3.0; + EXPECT_DOUBLE_EQ(aScaled.X(), 6.0); + EXPECT_DOUBLE_EQ(aScaled.Y(), 12.0); + + gp_Vec2d aDivided = aVec / 2.0; + EXPECT_DOUBLE_EQ(aDivided.X(), 1.0); + EXPECT_DOUBLE_EQ(aDivided.Y(), 2.0); +} + +TEST(gp_Vec2dTest, Dot) +{ + gp_Vec2d aV1(1.0, 0.0); + gp_Vec2d aV2(0.0, 1.0); + EXPECT_DOUBLE_EQ(aV1.Dot(aV2), 0.0); + + gp_Vec2d aV3(1.0, 2.0); + gp_Vec2d aV4(4.0, 5.0); + // 1*4 + 2*5 = 14 + EXPECT_DOUBLE_EQ(aV3.Dot(aV4), 14.0); +} + +TEST(gp_Vec2dTest, Crossed) +{ + gp_Vec2d aV1(1.0, 0.0); + gp_Vec2d aV2(0.0, 1.0); + // V1.X*V2.Y - V1.Y*V2.X = 1*1 - 0*0 = 1 + EXPECT_NEAR(aV1.Crossed(aV2), 1.0, Precision::Confusion()); + + gp_Vec2d aV3(3.0, 4.0); + gp_Vec2d aV4(2.0, 5.0); + // 3*5 - 4*2 = 15 - 8 = 7 + EXPECT_NEAR(aV3.Crossed(aV4), 7.0, Precision::Confusion()); +} + +TEST(gp_Vec2dTest, Magnitude) +{ + gp_Vec2d aVec(3.0, 4.0); + EXPECT_NEAR(aVec.Magnitude(), 5.0, Precision::Confusion()); + EXPECT_NEAR(aVec.SquareMagnitude(), 25.0, Precision::Confusion()); +} + +TEST(gp_Vec2dTest, Normalize) +{ + gp_Vec2d aVec(3.0, 4.0); + gp_Vec2d aNormalized = aVec.Normalized(); + EXPECT_NEAR(aNormalized.Magnitude(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aNormalized.X(), 0.6, Precision::Confusion()); + EXPECT_NEAR(aNormalized.Y(), 0.8, Precision::Confusion()); +} + +TEST(gp_Vec2dTest, Angle) +{ + gp_Vec2d aV1(1.0, 0.0); + gp_Vec2d aV2(0.0, 1.0); + EXPECT_NEAR(aV1.Angle(aV2), M_PI_2, Precision::Angular()); +} + +TEST(gp_Vec2dTest, IsParallel) +{ + gp_Vec2d aV1(1.0, 0.0); + gp_Vec2d aV2(5.0, 0.0); + EXPECT_TRUE(aV1.IsParallel(aV2, Precision::Angular())); +} + +TEST(gp_Vec2dTest, IsNormal) +{ + gp_Vec2d aV1(1.0, 0.0); + gp_Vec2d aV2(0.0, 1.0); + EXPECT_TRUE(aV1.IsNormal(aV2, Precision::Angular())); +} + +TEST(gp_Vec2dTest, IsOpposite) +{ + gp_Vec2d aV1(1.0, 0.0); + gp_Vec2d aV2(-3.0, 0.0); + EXPECT_TRUE(aV1.IsOpposite(aV2, Precision::Angular())); +} + +TEST(gp_Vec2dTest, Reverse) +{ + gp_Vec2d aVec(1.0, 2.0); + gp_Vec2d aReversed = aVec.Reversed(); + EXPECT_DOUBLE_EQ(aReversed.X(), -1.0); + EXPECT_DOUBLE_EQ(aReversed.Y(), -2.0); +} + +TEST(gp_Vec2dTest, SetLinearForm) +{ + gp_Vec2d aV1(1.0, 0.0); + gp_Vec2d aV2(0.0, 1.0); + gp_Vec2d aResult; + aResult.SetLinearForm(2.0, aV1, 3.0, aV2); + EXPECT_NEAR(aResult.X(), 2.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Y(), 3.0, Precision::Confusion()); +} diff --git a/src/FoundationClasses/TKMath/GTests/gp_Vec_Test.cxx b/src/FoundationClasses/TKMath/GTests/gp_Vec_Test.cxx new file mode 100644 index 0000000000..a49e2977d5 --- /dev/null +++ b/src/FoundationClasses/TKMath/GTests/gp_Vec_Test.cxx @@ -0,0 +1,187 @@ +// 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 +#include +#include +#include +#include + +#include + +TEST(gp_VecTest, DefaultConstructor) +{ + gp_Vec aVec; + EXPECT_DOUBLE_EQ(aVec.X(), 0.0); + EXPECT_DOUBLE_EQ(aVec.Y(), 0.0); + EXPECT_DOUBLE_EQ(aVec.Z(), 0.0); +} + +TEST(gp_VecTest, CoordinateConstructor) +{ + gp_Vec aVec(1.0, 2.0, 3.0); + EXPECT_DOUBLE_EQ(aVec.X(), 1.0); + EXPECT_DOUBLE_EQ(aVec.Y(), 2.0); + EXPECT_DOUBLE_EQ(aVec.Z(), 3.0); +} + +TEST(gp_VecTest, TwoPointConstructor) +{ + gp_Pnt aP1(1.0, 2.0, 3.0); + gp_Pnt aP2(4.0, 6.0, 8.0); + gp_Vec aVec(aP1, aP2); + EXPECT_DOUBLE_EQ(aVec.X(), 3.0); + EXPECT_DOUBLE_EQ(aVec.Y(), 4.0); + EXPECT_DOUBLE_EQ(aVec.Z(), 5.0); +} + +TEST(gp_VecTest, DirConstructor) +{ + gp_Dir aDir(0.0, 0.0, 1.0); + gp_Vec aVec(aDir); + EXPECT_NEAR(aVec.Magnitude(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aVec.Z(), 1.0, Precision::Confusion()); +} + +TEST(gp_VecTest, AddSubtract) +{ + gp_Vec aV1(1.0, 2.0, 3.0); + gp_Vec aV2(4.0, 5.0, 6.0); + + gp_Vec aSum = aV1 + aV2; + EXPECT_DOUBLE_EQ(aSum.X(), 5.0); + EXPECT_DOUBLE_EQ(aSum.Y(), 7.0); + EXPECT_DOUBLE_EQ(aSum.Z(), 9.0); + + gp_Vec aDiff = aV2 - aV1; + EXPECT_DOUBLE_EQ(aDiff.X(), 3.0); + EXPECT_DOUBLE_EQ(aDiff.Y(), 3.0); + EXPECT_DOUBLE_EQ(aDiff.Z(), 3.0); +} + +TEST(gp_VecTest, MultiplyDivide) +{ + gp_Vec aVec(2.0, 4.0, 6.0); + + gp_Vec aScaled = aVec * 3.0; + EXPECT_DOUBLE_EQ(aScaled.X(), 6.0); + EXPECT_DOUBLE_EQ(aScaled.Y(), 12.0); + EXPECT_DOUBLE_EQ(aScaled.Z(), 18.0); + + gp_Vec aDivided = aVec / 2.0; + EXPECT_DOUBLE_EQ(aDivided.X(), 1.0); + EXPECT_DOUBLE_EQ(aDivided.Y(), 2.0); + EXPECT_DOUBLE_EQ(aDivided.Z(), 3.0); +} + +TEST(gp_VecTest, Dot) +{ + gp_Vec aV1(1.0, 0.0, 0.0); + gp_Vec aV2(0.0, 1.0, 0.0); + EXPECT_DOUBLE_EQ(aV1.Dot(aV2), 0.0); + + gp_Vec aV3(1.0, 2.0, 3.0); + gp_Vec aV4(4.0, 5.0, 6.0); + // 1*4 + 2*5 + 3*6 = 32 + EXPECT_DOUBLE_EQ(aV3.Dot(aV4), 32.0); +} + +TEST(gp_VecTest, Cross) +{ + gp_Vec aVx(1.0, 0.0, 0.0); + gp_Vec aVy(0.0, 1.0, 0.0); + gp_Vec aCross = aVx.Crossed(aVy); + EXPECT_NEAR(aCross.X(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aCross.Y(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aCross.Z(), 1.0, Precision::Confusion()); +} + +TEST(gp_VecTest, CrossMagnitude) +{ + gp_Vec aV1(1.0, 0.0, 0.0); + gp_Vec aV2(0.0, 1.0, 0.0); + EXPECT_NEAR(aV1.CrossMagnitude(aV2), 1.0, Precision::Confusion()); +} + +TEST(gp_VecTest, DotCross_TripleScalarProduct) +{ + gp_Vec aV1(1.0, 0.0, 0.0); + gp_Vec aV2(0.0, 1.0, 0.0); + gp_Vec aV3(0.0, 0.0, 1.0); + // Triple scalar product of orthogonal unit vectors = 1 + EXPECT_NEAR(aV1.DotCross(aV2, aV3), 1.0, Precision::Confusion()); +} + +TEST(gp_VecTest, Magnitude) +{ + gp_Vec aVec(3.0, 4.0, 0.0); + EXPECT_NEAR(aVec.Magnitude(), 5.0, Precision::Confusion()); + EXPECT_NEAR(aVec.SquareMagnitude(), 25.0, Precision::Confusion()); +} + +TEST(gp_VecTest, Normalize) +{ + gp_Vec aVec(3.0, 4.0, 0.0); + gp_Vec aNormalized = aVec.Normalized(); + EXPECT_NEAR(aNormalized.Magnitude(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aNormalized.X(), 0.6, Precision::Confusion()); + EXPECT_NEAR(aNormalized.Y(), 0.8, Precision::Confusion()); +} + +TEST(gp_VecTest, Angle) +{ + gp_Vec aV1(1.0, 0.0, 0.0); + gp_Vec aV2(0.0, 1.0, 0.0); + EXPECT_NEAR(aV1.Angle(aV2), M_PI_2, Precision::Angular()); +} + +TEST(gp_VecTest, IsParallel) +{ + gp_Vec aV1(1.0, 0.0, 0.0); + gp_Vec aV2(5.0, 0.0, 0.0); + EXPECT_TRUE(aV1.IsParallel(aV2, Precision::Angular())); +} + +TEST(gp_VecTest, IsNormal) +{ + gp_Vec aV1(1.0, 0.0, 0.0); + gp_Vec aV2(0.0, 1.0, 0.0); + EXPECT_TRUE(aV1.IsNormal(aV2, Precision::Angular())); +} + +TEST(gp_VecTest, IsOpposite) +{ + gp_Vec aV1(1.0, 0.0, 0.0); + gp_Vec aV2(-3.0, 0.0, 0.0); + EXPECT_TRUE(aV1.IsOpposite(aV2, Precision::Angular())); +} + +TEST(gp_VecTest, Reverse) +{ + gp_Vec aVec(1.0, 2.0, 3.0); + gp_Vec aReversed = aVec.Reversed(); + EXPECT_DOUBLE_EQ(aReversed.X(), -1.0); + EXPECT_DOUBLE_EQ(aReversed.Y(), -2.0); + EXPECT_DOUBLE_EQ(aReversed.Z(), -3.0); +} + +TEST(gp_VecTest, SetLinearForm) +{ + gp_Vec aV1(1.0, 0.0, 0.0); + gp_Vec aV2(0.0, 1.0, 0.0); + gp_Vec aResult; + aResult.SetLinearForm(2.0, aV1, 3.0, aV2); + EXPECT_NEAR(aResult.X(), 2.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Y(), 3.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Z(), 0.0, Precision::Confusion()); +} diff --git a/src/FoundationClasses/TKMath/GTests/gp_XYZ_Test.cxx b/src/FoundationClasses/TKMath/GTests/gp_XYZ_Test.cxx new file mode 100644 index 0000000000..3e22d295f3 --- /dev/null +++ b/src/FoundationClasses/TKMath/GTests/gp_XYZ_Test.cxx @@ -0,0 +1,160 @@ +// 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 +#include + +#include + +TEST(gp_XYZTest, DefaultConstructor) +{ + gp_XYZ aXYZ; + EXPECT_DOUBLE_EQ(aXYZ.X(), 0.0); + EXPECT_DOUBLE_EQ(aXYZ.Y(), 0.0); + EXPECT_DOUBLE_EQ(aXYZ.Z(), 0.0); +} + +TEST(gp_XYZTest, CoordinateConstructor) +{ + gp_XYZ aXYZ(1.0, 2.0, 3.0); + EXPECT_DOUBLE_EQ(aXYZ.X(), 1.0); + EXPECT_DOUBLE_EQ(aXYZ.Y(), 2.0); + EXPECT_DOUBLE_EQ(aXYZ.Z(), 3.0); +} + +TEST(gp_XYZTest, SetCoord) +{ + gp_XYZ aXYZ; + aXYZ.SetCoord(7.0, 8.0, 9.0); + EXPECT_DOUBLE_EQ(aXYZ.X(), 7.0); + EXPECT_DOUBLE_EQ(aXYZ.Y(), 8.0); + EXPECT_DOUBLE_EQ(aXYZ.Z(), 9.0); +} + +TEST(gp_XYZTest, Accessors) +{ + gp_XYZ aXYZ(1.0, 2.0, 3.0); + EXPECT_DOUBLE_EQ(aXYZ.Coord(1), 1.0); + EXPECT_DOUBLE_EQ(aXYZ.Coord(2), 2.0); + EXPECT_DOUBLE_EQ(aXYZ.Coord(3), 3.0); +} + +TEST(gp_XYZTest, Add) +{ + gp_XYZ aA(1.0, 2.0, 3.0); + gp_XYZ aB(4.0, 5.0, 6.0); + gp_XYZ aSum = aA + aB; + EXPECT_DOUBLE_EQ(aSum.X(), 5.0); + EXPECT_DOUBLE_EQ(aSum.Y(), 7.0); + EXPECT_DOUBLE_EQ(aSum.Z(), 9.0); +} + +TEST(gp_XYZTest, Subtract) +{ + gp_XYZ aA(4.0, 5.0, 6.0); + gp_XYZ aB(1.0, 2.0, 3.0); + gp_XYZ aDiff = aA - aB; + EXPECT_DOUBLE_EQ(aDiff.X(), 3.0); + EXPECT_DOUBLE_EQ(aDiff.Y(), 3.0); + EXPECT_DOUBLE_EQ(aDiff.Z(), 3.0); +} + +TEST(gp_XYZTest, Multiply) +{ + gp_XYZ aXYZ(1.0, 2.0, 3.0); + gp_XYZ aScaled = aXYZ * 2.0; + EXPECT_DOUBLE_EQ(aScaled.X(), 2.0); + EXPECT_DOUBLE_EQ(aScaled.Y(), 4.0); + EXPECT_DOUBLE_EQ(aScaled.Z(), 6.0); +} + +TEST(gp_XYZTest, Divide) +{ + gp_XYZ aXYZ(4.0, 6.0, 8.0); + gp_XYZ aDivided = aXYZ / 2.0; + EXPECT_DOUBLE_EQ(aDivided.X(), 2.0); + EXPECT_DOUBLE_EQ(aDivided.Y(), 3.0); + EXPECT_DOUBLE_EQ(aDivided.Z(), 4.0); +} + +TEST(gp_XYZTest, Cross) +{ + gp_XYZ aA(1.0, 0.0, 0.0); + gp_XYZ aB(0.0, 1.0, 0.0); + gp_XYZ aCross = aA.Crossed(aB); + EXPECT_NEAR(aCross.X(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aCross.Y(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aCross.Z(), 1.0, Precision::Confusion()); +} + +TEST(gp_XYZTest, Dot) +{ + gp_XYZ aA(1.0, 2.0, 3.0); + gp_XYZ aB(4.0, 5.0, 6.0); + // 1*4 + 2*5 + 3*6 = 32 + EXPECT_DOUBLE_EQ(aA.Dot(aB), 32.0); +} + +TEST(gp_XYZTest, CrossMagnitude) +{ + gp_XYZ aA(1.0, 0.0, 0.0); + gp_XYZ aB(0.0, 1.0, 0.0); + EXPECT_NEAR(aA.CrossMagnitude(aB), 1.0, Precision::Confusion()); +} + +TEST(gp_XYZTest, CrossSquareMagnitude) +{ + gp_XYZ aA(1.0, 0.0, 0.0); + gp_XYZ aB(0.0, 1.0, 0.0); + EXPECT_NEAR(aA.CrossSquareMagnitude(aB), 1.0, Precision::Confusion()); +} + +TEST(gp_XYZTest, DotCross) +{ + gp_XYZ aA(1.0, 0.0, 0.0); + gp_XYZ aB(0.0, 1.0, 0.0); + gp_XYZ aC(0.0, 0.0, 1.0); + EXPECT_NEAR(aA.DotCross(aB, aC), 1.0, Precision::Confusion()); +} + +TEST(gp_XYZTest, Modulus) +{ + gp_XYZ aXYZ(3.0, 4.0, 0.0); + EXPECT_NEAR(aXYZ.Modulus(), 5.0, Precision::Confusion()); +} + +TEST(gp_XYZTest, SquareModulus) +{ + gp_XYZ aXYZ(3.0, 4.0, 0.0); + EXPECT_NEAR(aXYZ.SquareModulus(), 25.0, Precision::Confusion()); +} + +TEST(gp_XYZTest, SetLinearForm) +{ + gp_XYZ aA(1.0, 0.0, 0.0); + gp_XYZ aB(0.0, 1.0, 0.0); + gp_XYZ aResult; + aResult.SetLinearForm(2.0, aA, 3.0, aB); + EXPECT_NEAR(aResult.X(), 2.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Y(), 3.0, Precision::Confusion()); + EXPECT_NEAR(aResult.Z(), 0.0, Precision::Confusion()); +} + +TEST(gp_XYZTest, IsEqual) +{ + gp_XYZ aA(1.0, 2.0, 3.0); + gp_XYZ aB(1.0, 2.0, 3.0); + gp_XYZ aC(1.0, 2.0, 4.0); + EXPECT_TRUE(aA.IsEqual(aB, Precision::Confusion())); + EXPECT_FALSE(aA.IsEqual(aC, Precision::Confusion())); +} diff --git a/src/ModelingAlgorithms/TKFillet/GTests/BRepFilletAPI_MakeChamfer_Test.cxx b/src/ModelingAlgorithms/TKFillet/GTests/BRepFilletAPI_MakeChamfer_Test.cxx new file mode 100644 index 0000000000..99689c7aef --- /dev/null +++ b/src/ModelingAlgorithms/TKFillet/GTests/BRepFilletAPI_MakeChamfer_Test.cxx @@ -0,0 +1,94 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(BRepFilletAPI_MakeChamferTest, SymmetricChamfer) +{ + BRepPrimAPI_MakeBox aBoxMaker(20.0, 20.0, 20.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + TopExp_Explorer anExp(aBox, TopAbs_EDGE); + ASSERT_TRUE(anExp.More()); + const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current()); + + BRepFilletAPI_MakeChamfer aChamfer(aBox); + aChamfer.Add(2.0, anEdge); + const TopoDS_Shape& aResult = aChamfer.Shape(); + ASSERT_TRUE(aChamfer.IsDone()); + + BRepCheck_Analyzer anAnalyzer(aResult); + EXPECT_TRUE(anAnalyzer.IsValid()); +} + +TEST(BRepFilletAPI_MakeChamferTest, AsymmetricChamfer) +{ + BRepPrimAPI_MakeBox aBoxMaker(20.0, 20.0, 20.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + NCollection_IndexedDataMap, TopTools_ShapeMapHasher> + anEdgeFaceMap; + TopExp::MapShapesAndAncestors(aBox, TopAbs_EDGE, TopAbs_FACE, anEdgeFaceMap); + + TopExp_Explorer anExp(aBox, TopAbs_EDGE); + ASSERT_TRUE(anExp.More()); + const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current()); + const TopoDS_Face& aFace = TopoDS::Face(anEdgeFaceMap.FindFromKey(anEdge).First()); + + BRepFilletAPI_MakeChamfer aChamfer(aBox); + aChamfer.Add(1.0, 3.0, anEdge, aFace); + const TopoDS_Shape& aResult = aChamfer.Shape(); + ASSERT_TRUE(aChamfer.IsDone()); + + BRepCheck_Analyzer anAnalyzer(aResult); + EXPECT_TRUE(anAnalyzer.IsValid()); +} + +TEST(BRepFilletAPI_MakeChamferTest, ChamferMoreFaces) +{ + BRepPrimAPI_MakeBox aBoxMaker(20.0, 20.0, 20.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + TopExp_Explorer anExp(aBox, TopAbs_EDGE); + ASSERT_TRUE(anExp.More()); + const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current()); + + BRepFilletAPI_MakeChamfer aChamfer(aBox); + aChamfer.Add(2.0, anEdge); + const TopoDS_Shape& aResult = aChamfer.Shape(); + ASSERT_TRUE(aChamfer.IsDone()); + + int aFaceCount = 0; + for (TopExp_Explorer aFaceExp(aResult, TopAbs_FACE); aFaceExp.More(); aFaceExp.Next()) + { + aFaceCount++; + } + EXPECT_GT(aFaceCount, 6); +} diff --git a/src/ModelingAlgorithms/TKFillet/GTests/BRepFilletAPI_MakeFillet_Test.cxx b/src/ModelingAlgorithms/TKFillet/GTests/BRepFilletAPI_MakeFillet_Test.cxx new file mode 100644 index 0000000000..fe0e77f192 --- /dev/null +++ b/src/ModelingAlgorithms/TKFillet/GTests/BRepFilletAPI_MakeFillet_Test.cxx @@ -0,0 +1,101 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(BRepFilletAPI_MakeFilletTest, FilletOneEdge) +{ + BRepPrimAPI_MakeBox aBoxMaker(20.0, 20.0, 20.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + TopExp_Explorer anExp(aBox, TopAbs_EDGE); + ASSERT_TRUE(anExp.More()); + const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current()); + + BRepFilletAPI_MakeFillet aFillet(aBox); + aFillet.Add(2.0, anEdge); + const TopoDS_Shape& aResult = aFillet.Shape(); + ASSERT_TRUE(aFillet.IsDone()); + + BRepCheck_Analyzer anAnalyzer(aResult); + EXPECT_TRUE(anAnalyzer.IsValid()); +} + +TEST(BRepFilletAPI_MakeFilletTest, FilletAllEdges) +{ + BRepPrimAPI_MakeBox aBoxMaker(20.0, 20.0, 20.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + BRepFilletAPI_MakeFillet aFillet(aBox); + for (TopExp_Explorer anExp(aBox, TopAbs_EDGE); anExp.More(); anExp.Next()) + { + aFillet.Add(1.0, TopoDS::Edge(anExp.Current())); + } + const TopoDS_Shape& aResult = aFillet.Shape(); + ASSERT_TRUE(aFillet.IsDone()); + + BRepCheck_Analyzer anAnalyzer(aResult); + EXPECT_TRUE(anAnalyzer.IsValid()); +} + +TEST(BRepFilletAPI_MakeFilletTest, FilletMoreFaces) +{ + BRepPrimAPI_MakeBox aBoxMaker(20.0, 20.0, 20.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + BRepFilletAPI_MakeFillet aFillet(aBox); + for (TopExp_Explorer anExp(aBox, TopAbs_EDGE); anExp.More(); anExp.Next()) + { + aFillet.Add(1.0, TopoDS::Edge(anExp.Current())); + } + const TopoDS_Shape& aResult = aFillet.Shape(); + ASSERT_TRUE(aFillet.IsDone()); + + int aFaceCount = 0; + for (TopExp_Explorer aFaceExp(aResult, TopAbs_FACE); aFaceExp.More(); aFaceExp.Next()) + { + aFaceCount++; + } + EXPECT_GT(aFaceCount, 6); +} + +TEST(BRepFilletAPI_MakeFilletTest, FilletVariableRadius) +{ + BRepPrimAPI_MakeBox aBoxMaker(20.0, 20.0, 20.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + TopExp_Explorer anExp(aBox, TopAbs_EDGE); + ASSERT_TRUE(anExp.More()); + const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current()); + + BRepFilletAPI_MakeFillet aFillet(aBox); + aFillet.Add(1.0, 3.0, anEdge); + const TopoDS_Shape& aResult = aFillet.Shape(); + ASSERT_TRUE(aFillet.IsDone()); + + BRepCheck_Analyzer anAnalyzer(aResult); + EXPECT_TRUE(anAnalyzer.IsValid()); +} diff --git a/src/ModelingAlgorithms/TKFillet/GTests/FILES.cmake b/src/ModelingAlgorithms/TKFillet/GTests/FILES.cmake index 6ccc5c50ad..c7dfcd2bac 100644 --- a/src/ModelingAlgorithms/TKFillet/GTests/FILES.cmake +++ b/src/ModelingAlgorithms/TKFillet/GTests/FILES.cmake @@ -2,4 +2,6 @@ set(OCCT_TKFillet_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}") set(OCCT_TKFillet_GTests_FILES + BRepFilletAPI_MakeChamfer_Test.cxx + BRepFilletAPI_MakeFillet_Test.cxx ) diff --git a/src/ModelingAlgorithms/TKOffset/GTests/BRepBuilderAPI_Sewing_Test.cxx b/src/ModelingAlgorithms/TKOffset/GTests/BRepBuilderAPI_Sewing_Test.cxx new file mode 100644 index 0000000000..9c3b459f4e --- /dev/null +++ b/src/ModelingAlgorithms/TKOffset/GTests/BRepBuilderAPI_Sewing_Test.cxx @@ -0,0 +1,117 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(BRepBuilderAPI_SewingTest, SewTwoFaces) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + TopExp_Explorer anExp(aBox, TopAbs_FACE); + ASSERT_TRUE(anExp.More()); + TopoDS_Face aFace1 = TopoDS::Face(anExp.Current()); + anExp.Next(); + ASSERT_TRUE(anExp.More()); + TopoDS_Face aFace2 = TopoDS::Face(anExp.Current()); + + BRepBuilderAPI_Sewing aSewing; + aSewing.Add(aFace1); + aSewing.Add(aFace2); + aSewing.Perform(); + + const TopoDS_Shape& aResult = aSewing.SewedShape(); + EXPECT_FALSE(aResult.IsNull()); +} + +TEST(BRepBuilderAPI_SewingTest, NbFreeEdges) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + TopExp_Explorer anExp(aBox, TopAbs_FACE); + ASSERT_TRUE(anExp.More()); + TopoDS_Face aFace1 = TopoDS::Face(anExp.Current()); + anExp.Next(); + ASSERT_TRUE(anExp.More()); + TopoDS_Face aFace2 = TopoDS::Face(anExp.Current()); + + BRepBuilderAPI_Sewing aSewing; + aSewing.Add(aFace1); + aSewing.Add(aFace2); + aSewing.Perform(); + + // Two faces from a box share one edge; the remaining edges are free. + EXPECT_GT(aSewing.NbFreeEdges(), 0); +} + +TEST(BRepBuilderAPI_SewingTest, NbDegeneratedShapes) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + TopExp_Explorer anExp(aBox, TopAbs_FACE); + ASSERT_TRUE(anExp.More()); + TopoDS_Face aFace1 = TopoDS::Face(anExp.Current()); + anExp.Next(); + ASSERT_TRUE(anExp.More()); + TopoDS_Face aFace2 = TopoDS::Face(anExp.Current()); + + BRepBuilderAPI_Sewing aSewing; + aSewing.Add(aFace1); + aSewing.Add(aFace2); + aSewing.Perform(); + + // Planar faces should have no degenerated shapes. + EXPECT_EQ(aSewing.NbDegeneratedShapes(), 0); +} + +TEST(BRepBuilderAPI_SewingTest, SetTolerance) +{ + BRepBuilderAPI_Sewing aSewing; + const double aTol = 0.01; + aSewing.SetTolerance(aTol); + EXPECT_NEAR(aSewing.Tolerance(), aTol, Precision::Confusion()); +} + +TEST(BRepBuilderAPI_SewingTest, SewAllBoxFaces) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + BRepBuilderAPI_Sewing aSewing; + for (TopExp_Explorer anExp(aBox, TopAbs_FACE); anExp.More(); anExp.Next()) + { + aSewing.Add(anExp.Current()); + } + aSewing.Perform(); + + const TopoDS_Shape& aResult = aSewing.SewedShape(); + EXPECT_FALSE(aResult.IsNull()); + + // All 6 faces of a box form a closed shell, so there should be no free edges. + EXPECT_EQ(aSewing.NbFreeEdges(), 0); +} diff --git a/src/ModelingAlgorithms/TKOffset/GTests/BRepOffsetAPI_MakeThickSolid_Test.cxx b/src/ModelingAlgorithms/TKOffset/GTests/BRepOffsetAPI_MakeThickSolid_Test.cxx new file mode 100644 index 0000000000..15488e2b5b --- /dev/null +++ b/src/ModelingAlgorithms/TKOffset/GTests/BRepOffsetAPI_MakeThickSolid_Test.cxx @@ -0,0 +1,149 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +TEST(BRepOffsetAPI_MakeThickSolidTest, HollowBox) +{ + BRepPrimAPI_MakeBox aBoxMaker(20.0, 20.0, 20.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + // Get the first face to remove. + TopExp_Explorer anExp(aBox, TopAbs_FACE); + ASSERT_TRUE(anExp.More()); + TopoDS_Face aFaceToRemove = TopoDS::Face(anExp.Current()); + + NCollection_List aFacesToRemove; + aFacesToRemove.Append(aFaceToRemove); + + BRepOffsetAPI_MakeThickSolid aMaker; + aMaker.MakeThickSolidByJoin(aBox, aFacesToRemove, -1.0, Precision::Confusion()); + aMaker.Build(); + + ASSERT_TRUE(aMaker.IsDone()); + + const TopoDS_Shape& aResult = aMaker.Shape(); + EXPECT_FALSE(aResult.IsNull()); + + BRepCheck_Analyzer aChecker(aResult); + EXPECT_TRUE(aChecker.IsValid()); +} + +TEST(BRepOffsetAPI_MakeThickSolidTest, HollowBoxVolume) +{ + BRepPrimAPI_MakeBox aBoxMaker(20.0, 20.0, 20.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + GProp_GProps aOrigProps; + BRepGProp::VolumeProperties(aBox, aOrigProps); + const double anOrigVolume = aOrigProps.Mass(); + + TopExp_Explorer anExp(aBox, TopAbs_FACE); + ASSERT_TRUE(anExp.More()); + TopoDS_Face aFaceToRemove = TopoDS::Face(anExp.Current()); + + NCollection_List aFacesToRemove; + aFacesToRemove.Append(aFaceToRemove); + + BRepOffsetAPI_MakeThickSolid aMaker; + aMaker.MakeThickSolidByJoin(aBox, aFacesToRemove, -1.0, Precision::Confusion()); + aMaker.Build(); + + ASSERT_TRUE(aMaker.IsDone()); + + const TopoDS_Shape& aResult = aMaker.Shape(); + ASSERT_FALSE(aResult.IsNull()); + + GProp_GProps aHollowProps; + BRepGProp::VolumeProperties(aResult, aHollowProps); + const double aHollowVolume = aHollowProps.Mass(); + + // Hollowed box must have less volume than the original solid. + EXPECT_LT(aHollowVolume, anOrigVolume); +} + +TEST(BRepOffsetAPI_MakeThickSolidTest, MakeThickSolidBySimple) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + // Extract a single face (non-closed shell) for MakeThickSolidBySimple. + TopExp_Explorer anExp(aBox, TopAbs_FACE); + ASSERT_TRUE(anExp.More()); + TopoDS_Face aFace = TopoDS::Face(anExp.Current()); + + BRepOffsetAPI_MakeThickSolid aMaker; + aMaker.MakeThickSolidBySimple(aFace, 2.0); + aMaker.Build(); + + ASSERT_TRUE(aMaker.IsDone()); + + const TopoDS_Shape& aResult = aMaker.Shape(); + EXPECT_FALSE(aResult.IsNull()); + + BRepCheck_Analyzer aChecker(aResult); + EXPECT_TRUE(aChecker.IsValid()); +} + +TEST(BRepOffsetAPI_MakeThickSolidTest, ThickSolidLargerVolume) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + // Extract a single face for MakeThickSolidBySimple. + TopExp_Explorer anExp(aBox, TopAbs_FACE); + ASSERT_TRUE(anExp.More()); + TopoDS_Face aFace = TopoDS::Face(anExp.Current()); + + // Compute the area of the original face to estimate expected volume. + GProp_GProps aFaceProps; + BRepGProp::SurfaceProperties(aFace, aFaceProps); + const double aFaceArea = aFaceProps.Mass(); + + const double anOffset = 2.0; + BRepOffsetAPI_MakeThickSolid aMaker; + aMaker.MakeThickSolidBySimple(aFace, anOffset); + aMaker.Build(); + + ASSERT_TRUE(aMaker.IsDone()); + + const TopoDS_Shape& aResult = aMaker.Shape(); + ASSERT_FALSE(aResult.IsNull()); + + GProp_GProps aResultProps; + BRepGProp::VolumeProperties(aResult, aResultProps); + const double aResultVolume = std::abs(aResultProps.Mass()); + + // The thickened face should produce a solid with volume > 0. + // A planar face of area A thickened by offset d produces volume approximately A*d. + EXPECT_GT(aResultVolume, aFaceArea * anOffset * 0.5); +} diff --git a/src/ModelingAlgorithms/TKOffset/GTests/FILES.cmake b/src/ModelingAlgorithms/TKOffset/GTests/FILES.cmake index 6310b4e4c5..7158b6b6a5 100644 --- a/src/ModelingAlgorithms/TKOffset/GTests/FILES.cmake +++ b/src/ModelingAlgorithms/TKOffset/GTests/FILES.cmake @@ -2,5 +2,7 @@ set(OCCT_TKOffset_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}") set(OCCT_TKOffset_GTests_FILES + BRepBuilderAPI_Sewing_Test.cxx BRepOffset_MakeOffset_Test.cxx + BRepOffsetAPI_MakeThickSolid_Test.cxx ) diff --git a/src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeBox_Test.cxx b/src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeBox_Test.cxx new file mode 100644 index 0000000000..abffe8240e --- /dev/null +++ b/src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeBox_Test.cxx @@ -0,0 +1,124 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(BRepPrimAPI_MakeBoxTest, UnitBox) +{ + BRepPrimAPI_MakeBox aBox(1.0, 1.0, 1.0); + TopoDS_Shape aShape = aBox.Shape(); + + ASSERT_TRUE(aBox.IsDone()) << "Unit box creation failed"; + ASSERT_FALSE(aShape.IsNull()) << "Resulting shape is null"; + + BRepCheck_Analyzer anAnalyzer(aShape); + EXPECT_TRUE(anAnalyzer.IsValid()) << "Unit box shape is not valid"; +} + +TEST(BRepPrimAPI_MakeBoxTest, TopologyCounts) +{ + BRepPrimAPI_MakeBox aBox(10.0, 20.0, 30.0); + TopoDS_Shape aShape = aBox.Shape(); + ASSERT_TRUE(aBox.IsDone()); + + int aFaceCount = 0; + for (TopExp_Explorer anExp(aShape, TopAbs_FACE); anExp.More(); anExp.Next()) + { + aFaceCount++; + } + EXPECT_EQ(aFaceCount, 6) << "Box should have 6 faces"; + + int anEdgeCount = 0; + for (TopExp_Explorer anExp(aShape, TopAbs_EDGE); anExp.More(); anExp.Next()) + { + anEdgeCount++; + } + EXPECT_EQ(anEdgeCount, 24) << "Box should have 24 edge occurrences (12 edges x 2 faces each)"; + + int aVertexCount = 0; + for (TopExp_Explorer anExp(aShape, TopAbs_VERTEX); anExp.More(); anExp.Next()) + { + aVertexCount++; + } + EXPECT_EQ(aVertexCount, 48) << "Box should have 48 vertex occurrences (8 vertices x 6 faces)"; +} + +TEST(BRepPrimAPI_MakeBoxTest, Volume) +{ + const double aWidth = 3.0; + const double aHeight = 4.0; + const double aDepth = 5.0; + + BRepPrimAPI_MakeBox aBox(aWidth, aHeight, aDepth); + TopoDS_Shape aShape = aBox.Shape(); + ASSERT_TRUE(aBox.IsDone()); + + GProp_GProps aProps; + BRepGProp::VolumeProperties(aShape, aProps); + EXPECT_NEAR(aProps.Mass(), aWidth * aHeight * aDepth, Precision::Confusion()); +} + +TEST(BRepPrimAPI_MakeBoxTest, SurfaceArea) +{ + const double aW = 3.0; + const double aH = 4.0; + const double aD = 5.0; + + BRepPrimAPI_MakeBox aBox(aW, aH, aD); + TopoDS_Shape aShape = aBox.Shape(); + ASSERT_TRUE(aBox.IsDone()); + + GProp_GProps aProps; + BRepGProp::SurfaceProperties(aShape, aProps); + double anExpectedArea = 2.0 * (aW * aH + aW * aD + aH * aD); + EXPECT_NEAR(aProps.Mass(), anExpectedArea, Precision::Confusion()); +} + +TEST(BRepPrimAPI_MakeBoxTest, TwoCornerPoints) +{ + gp_Pnt aP1(1.0, 2.0, 3.0); + gp_Pnt aP2(4.0, 6.0, 8.0); + + BRepPrimAPI_MakeBox aBox(aP1, aP2); + TopoDS_Shape aShape = aBox.Shape(); + + ASSERT_TRUE(aBox.IsDone()) << "Box from two corner points failed"; + ASSERT_FALSE(aShape.IsNull()); + + BRepCheck_Analyzer anAnalyzer(aShape); + EXPECT_TRUE(anAnalyzer.IsValid()) << "Box from two points is not valid"; + + // Volume = (4-1)*(6-2)*(8-3) = 3*4*5 = 60 + GProp_GProps aProps; + BRepGProp::VolumeProperties(aShape, aProps); + EXPECT_NEAR(aProps.Mass(), 60.0, Precision::Confusion()); +} + +TEST(BRepPrimAPI_MakeBoxTest, ShapeValidity) +{ + BRepPrimAPI_MakeBox aBox(100.0, 200.0, 300.0); + TopoDS_Shape aShape = aBox.Shape(); + ASSERT_TRUE(aBox.IsDone()); + + BRepCheck_Analyzer anAnalyzer(aShape); + EXPECT_TRUE(anAnalyzer.IsValid()) << "Large box shape is not valid"; +} diff --git a/src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeCone_Test.cxx b/src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeCone_Test.cxx new file mode 100644 index 0000000000..b87c27acdd --- /dev/null +++ b/src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeCone_Test.cxx @@ -0,0 +1,113 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(BRepPrimAPI_MakeConeTest, FullCone) +{ + BRepPrimAPI_MakeCone aCone(gp_Ax2(), 5.0, 0.0, 10.0); + TopoDS_Shape aShape = aCone.Shape(); + + ASSERT_TRUE(aCone.IsDone()) << "Full cone creation failed"; + ASSERT_FALSE(aShape.IsNull()) << "Resulting shape is null"; + + BRepCheck_Analyzer anAnalyzer(aShape); + EXPECT_TRUE(anAnalyzer.IsValid()) << "Full cone shape is not valid"; +} + +TEST(BRepPrimAPI_MakeConeTest, TruncatedCone) +{ + BRepPrimAPI_MakeCone aCone(gp_Ax2(), 5.0, 2.0, 10.0); + TopoDS_Shape aShape = aCone.Shape(); + + ASSERT_TRUE(aCone.IsDone()) << "Truncated cone creation failed"; + ASSERT_FALSE(aShape.IsNull()) << "Resulting shape is null"; + + BRepCheck_Analyzer anAnalyzer(aShape); + EXPECT_TRUE(anAnalyzer.IsValid()) << "Truncated cone shape is not valid"; +} + +TEST(BRepPrimAPI_MakeConeTest, FullConeFaceCount) +{ + BRepPrimAPI_MakeCone aCone(gp_Ax2(), 5.0, 0.0, 10.0); + TopoDS_Shape aShape = aCone.Shape(); + ASSERT_TRUE(aCone.IsDone()); + + int aFaceCount = 0; + for (TopExp_Explorer anExp(aShape, TopAbs_FACE); anExp.More(); anExp.Next()) + { + aFaceCount++; + } + EXPECT_EQ(aFaceCount, 2) << "Full cone should have 2 faces (lateral + base)"; +} + +TEST(BRepPrimAPI_MakeConeTest, TruncatedConeFaceCount) +{ + BRepPrimAPI_MakeCone aCone(gp_Ax2(), 5.0, 2.0, 10.0); + TopoDS_Shape aShape = aCone.Shape(); + ASSERT_TRUE(aCone.IsDone()); + + int aFaceCount = 0; + for (TopExp_Explorer anExp(aShape, TopAbs_FACE); anExp.More(); anExp.Next()) + { + aFaceCount++; + } + EXPECT_EQ(aFaceCount, 3) << "Truncated cone should have 3 faces (lateral + 2 bases)"; +} + +TEST(BRepPrimAPI_MakeConeTest, TruncatedConeVolume) +{ + const double aR1 = 5.0; + const double aR2 = 2.0; + const double aH = 10.0; + + BRepPrimAPI_MakeCone aCone(gp_Ax2(), aR1, aR2, aH); + TopoDS_Shape aShape = aCone.Shape(); + ASSERT_TRUE(aCone.IsDone()); + + GProp_GProps aProps; + BRepGProp::VolumeProperties(aShape, aProps); + + // V = PI * H / 3 * (R1^2 + R1*R2 + R2^2) + const double anExpectedVolume = M_PI * aH / 3.0 * (aR1 * aR1 + aR1 * aR2 + aR2 * aR2); + EXPECT_NEAR(aProps.Mass(), anExpectedVolume, Precision::Confusion()); +} + +TEST(BRepPrimAPI_MakeConeTest, PartialCone) +{ + BRepPrimAPI_MakeCone aCone(gp_Ax2(), 5.0, 2.0, 10.0, M_PI); + TopoDS_Shape aShape = aCone.Shape(); + + ASSERT_TRUE(aCone.IsDone()) << "Partial cone creation failed"; + ASSERT_FALSE(aShape.IsNull()) << "Resulting shape is null"; + + BRepCheck_Analyzer anAnalyzer(aShape); + EXPECT_TRUE(anAnalyzer.IsValid()) << "Partial cone shape is not valid"; + + int aFaceCount = 0; + for (TopExp_Explorer anExp(aShape, TopAbs_FACE); anExp.More(); anExp.Next()) + { + aFaceCount++; + } + EXPECT_GT(aFaceCount, 3) << "Partial cone should have more than 3 faces"; +} diff --git a/src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeCylinder_Test.cxx b/src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeCylinder_Test.cxx new file mode 100644 index 0000000000..8de812c1ee --- /dev/null +++ b/src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeCylinder_Test.cxx @@ -0,0 +1,99 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(BRepPrimAPI_MakeCylinderTest, FullCylinder) +{ + const double aRadius = 5.0; + const double aHeight = 10.0; + BRepPrimAPI_MakeCylinder aCylinder(aRadius, aHeight); + TopoDS_Shape aShape = aCylinder.Shape(); + + ASSERT_TRUE(aCylinder.IsDone()) << "Full cylinder creation failed"; + ASSERT_FALSE(aShape.IsNull()) << "Resulting shape is null"; + + BRepCheck_Analyzer anAnalyzer(aShape); + EXPECT_TRUE(anAnalyzer.IsValid()) << "Full cylinder shape is not valid"; +} + +TEST(BRepPrimAPI_MakeCylinderTest, FaceCount) +{ + BRepPrimAPI_MakeCylinder aCylinder(5.0, 10.0); + TopoDS_Shape aShape = aCylinder.Shape(); + ASSERT_TRUE(aCylinder.IsDone()); + + int aFaceCount = 0; + for (TopExp_Explorer anExp(aShape, TopAbs_FACE); anExp.More(); anExp.Next()) + { + aFaceCount++; + } + // Full cylinder: 1 lateral + 2 caps = 3 + EXPECT_EQ(aFaceCount, 3) << "Full cylinder should have 3 faces (lateral + 2 caps)"; +} + +TEST(BRepPrimAPI_MakeCylinderTest, Volume) +{ + const double aRadius = 5.0; + const double aHeight = 10.0; + BRepPrimAPI_MakeCylinder aCylinder(aRadius, aHeight); + TopoDS_Shape aShape = aCylinder.Shape(); + ASSERT_TRUE(aCylinder.IsDone()); + + GProp_GProps aProps; + BRepGProp::VolumeProperties(aShape, aProps); + double anExpectedVolume = M_PI * aRadius * aRadius * aHeight; + EXPECT_NEAR(aProps.Mass(), anExpectedVolume, 0.01); +} + +TEST(BRepPrimAPI_MakeCylinderTest, PartialCylinder_AngleLimited) +{ + const double aRadius = 5.0; + const double aHeight = 10.0; + // Half cylinder: angle = PI + BRepPrimAPI_MakeCylinder aCylinder(aRadius, aHeight, M_PI); + TopoDS_Shape aShape = aCylinder.Shape(); + + ASSERT_TRUE(aCylinder.IsDone()) << "Partial cylinder creation failed"; + ASSERT_FALSE(aShape.IsNull()); + + BRepCheck_Analyzer anAnalyzer(aShape); + EXPECT_TRUE(anAnalyzer.IsValid()) << "Partial cylinder shape is not valid"; + + // Partial cylinder should have more faces: 1 lateral + 2 caps + 2 planar sides = 5 + int aFaceCount = 0; + for (TopExp_Explorer anExp(aShape, TopAbs_FACE); anExp.More(); anExp.Next()) + { + aFaceCount++; + } + EXPECT_EQ(aFaceCount, 5) << "Half cylinder should have 5 faces"; +} + +TEST(BRepPrimAPI_MakeCylinderTest, ShapeValidity) +{ + BRepPrimAPI_MakeCylinder aCylinder(100.0, 200.0); + TopoDS_Shape aShape = aCylinder.Shape(); + ASSERT_TRUE(aCylinder.IsDone()); + + BRepCheck_Analyzer anAnalyzer(aShape); + EXPECT_TRUE(anAnalyzer.IsValid()) << "Large cylinder shape is not valid"; +} diff --git a/src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeSphere_Test.cxx b/src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeSphere_Test.cxx new file mode 100644 index 0000000000..d4ce80f131 --- /dev/null +++ b/src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeSphere_Test.cxx @@ -0,0 +1,102 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(BRepPrimAPI_MakeSphereTest, FullSphere) +{ + const double aRadius = 5.0; + BRepPrimAPI_MakeSphere aSphere(aRadius); + TopoDS_Shape aShape = aSphere.Shape(); + + ASSERT_TRUE(aSphere.IsDone()) << "Full sphere creation failed"; + ASSERT_FALSE(aShape.IsNull()) << "Resulting shape is null"; + + BRepCheck_Analyzer anAnalyzer(aShape); + EXPECT_TRUE(anAnalyzer.IsValid()) << "Full sphere shape is not valid"; +} + +TEST(BRepPrimAPI_MakeSphereTest, FaceCount) +{ + BRepPrimAPI_MakeSphere aSphere(5.0); + TopoDS_Shape aShape = aSphere.Shape(); + ASSERT_TRUE(aSphere.IsDone()); + + int aFaceCount = 0; + for (TopExp_Explorer anExp(aShape, TopAbs_FACE); anExp.More(); anExp.Next()) + { + aFaceCount++; + } + EXPECT_EQ(aFaceCount, 1) << "Full sphere should have 1 face"; +} + +TEST(BRepPrimAPI_MakeSphereTest, Volume) +{ + const double aRadius = 5.0; + BRepPrimAPI_MakeSphere aSphere(aRadius); + TopoDS_Shape aShape = aSphere.Shape(); + ASSERT_TRUE(aSphere.IsDone()); + + GProp_GProps aProps; + BRepGProp::VolumeProperties(aShape, aProps); + double anExpectedVolume = (4.0 / 3.0) * M_PI * aRadius * aRadius * aRadius; + EXPECT_NEAR(aProps.Mass(), anExpectedVolume, 0.01); +} + +TEST(BRepPrimAPI_MakeSphereTest, PartialSphere_AngleLimited) +{ + const double aRadius = 5.0; + // Half sphere: angle from 0 to PI + BRepPrimAPI_MakeSphere aSphere(aRadius, M_PI); + TopoDS_Shape aShape = aSphere.Shape(); + + ASSERT_TRUE(aSphere.IsDone()) << "Partial sphere creation failed"; + ASSERT_FALSE(aShape.IsNull()); + + BRepCheck_Analyzer anAnalyzer(aShape); + EXPECT_TRUE(anAnalyzer.IsValid()) << "Partial sphere shape is not valid"; + + // Partial sphere should have more faces than a full sphere + int aFaceCount = 0; + for (TopExp_Explorer anExp(aShape, TopAbs_FACE); anExp.More(); anExp.Next()) + { + aFaceCount++; + } + EXPECT_GT(aFaceCount, 1) << "Partial sphere should have more than 1 face"; +} + +TEST(BRepPrimAPI_MakeSphereTest, CenterOfMass) +{ + const double aRadius = 5.0; + BRepPrimAPI_MakeSphere aSphere(aRadius); + TopoDS_Shape aShape = aSphere.Shape(); + ASSERT_TRUE(aSphere.IsDone()); + + GProp_GProps aProps; + BRepGProp::VolumeProperties(aShape, aProps); + gp_Pnt aCOM = aProps.CentreOfMass(); + + // Center of mass of full sphere should be at origin + EXPECT_NEAR(aCOM.X(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aCOM.Y(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aCOM.Z(), 0.0, Precision::Confusion()); +} diff --git a/src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeWedge_Test.cxx b/src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeWedge_Test.cxx new file mode 100644 index 0000000000..25291bc92a --- /dev/null +++ b/src/ModelingAlgorithms/TKPrim/GTests/BRepPrimAPI_MakeWedge_Test.cxx @@ -0,0 +1,94 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(BRepPrimAPI_MakeWedgeTest, WedgeFromDimensions) +{ + BRepPrimAPI_MakeWedge aWedge(10.0, 10.0, 10.0, 5.0); + TopoDS_Shape aShape = aWedge.Shape(); + + ASSERT_TRUE(aWedge.IsDone()) << "Wedge creation failed"; + ASSERT_FALSE(aShape.IsNull()) << "Resulting shape is null"; + + BRepCheck_Analyzer anAnalyzer(aShape); + EXPECT_TRUE(anAnalyzer.IsValid()) << "Wedge shape is not valid"; +} + +TEST(BRepPrimAPI_MakeWedgeTest, WedgeFaceCount_Ltx5) +{ + BRepPrimAPI_MakeWedge aWedge(10.0, 10.0, 10.0, 5.0); + TopoDS_Shape aShape = aWedge.Shape(); + ASSERT_TRUE(aWedge.IsDone()); + + int aFaceCount = 0; + for (TopExp_Explorer anExp(aShape, TopAbs_FACE); anExp.More(); anExp.Next()) + { + aFaceCount++; + } + EXPECT_EQ(aFaceCount, 6) << "Wedge with ltx=5 should have 6 faces"; +} + +TEST(BRepPrimAPI_MakeWedgeTest, WedgeFaceCount_Ltx0) +{ + BRepPrimAPI_MakeWedge aWedge(10.0, 10.0, 10.0, 0.0); + TopoDS_Shape aShape = aWedge.Shape(); + ASSERT_TRUE(aWedge.IsDone()); + + int aFaceCount = 0; + for (TopExp_Explorer anExp(aShape, TopAbs_FACE); anExp.More(); anExp.Next()) + { + aFaceCount++; + } + EXPECT_EQ(aFaceCount, 5) << "Wedge with ltx=0 should have 5 faces (top degenerates to a line)"; +} + +TEST(BRepPrimAPI_MakeWedgeTest, WedgeVolume) +{ + const double aDx = 10.0; + const double aDy = 10.0; + const double aDz = 10.0; + const double aLtx = 5.0; + + BRepPrimAPI_MakeWedge aWedge(aDx, aDy, aDz, aLtx); + TopoDS_Shape aShape = aWedge.Shape(); + ASSERT_TRUE(aWedge.IsDone()); + + GProp_GProps aProps; + BRepGProp::VolumeProperties(aShape, aProps); + + // Volume = dy * dz * (dx + ltx) / 2 + const double anExpectedVolume = aDy * aDz * (aDx + aLtx) / 2.0; + EXPECT_NEAR(aProps.Mass(), anExpectedVolume, Precision::Confusion()); +} + +TEST(BRepPrimAPI_MakeWedgeTest, WedgeFullParams) +{ + BRepPrimAPI_MakeWedge aWedge(20.0, 10.0, 20.0, 5.0, 5.0, 15.0, 15.0); + TopoDS_Shape aShape = aWedge.Shape(); + + ASSERT_TRUE(aWedge.IsDone()) << "Wedge with full parameters creation failed"; + ASSERT_FALSE(aShape.IsNull()) << "Resulting shape is null"; + + BRepCheck_Analyzer anAnalyzer(aShape); + EXPECT_TRUE(anAnalyzer.IsValid()) << "Wedge with full parameters shape is not valid"; +} diff --git a/src/ModelingAlgorithms/TKPrim/GTests/FILES.cmake b/src/ModelingAlgorithms/TKPrim/GTests/FILES.cmake index ad7e38cc0f..e9c2c2fdc9 100644 --- a/src/ModelingAlgorithms/TKPrim/GTests/FILES.cmake +++ b/src/ModelingAlgorithms/TKPrim/GTests/FILES.cmake @@ -2,6 +2,11 @@ set(OCCT_TKPrim_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}") set(OCCT_TKPrim_GTests_FILES + BRepPrimAPI_MakeBox_Test.cxx + BRepPrimAPI_MakeCone_Test.cxx + BRepPrimAPI_MakeCylinder_Test.cxx BRepPrimAPI_MakePrism_Test.cxx + BRepPrimAPI_MakeSphere_Test.cxx BRepPrimAPI_MakeTorus_Test.cxx + BRepPrimAPI_MakeWedge_Test.cxx ) diff --git a/src/ModelingAlgorithms/TKShHealing/GTests/FILES.cmake b/src/ModelingAlgorithms/TKShHealing/GTests/FILES.cmake index 38e6309ab1..2cc385f0db 100644 --- a/src/ModelingAlgorithms/TKShHealing/GTests/FILES.cmake +++ b/src/ModelingAlgorithms/TKShHealing/GTests/FILES.cmake @@ -3,6 +3,8 @@ set(OCCT_TKShHealing_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}") set(OCCT_TKShHealing_GTests_FILES ShapeAnalysis_CanonicalRecognition_Test.cxx + ShapeAnalysis_Edge_Test.cxx ShapeConstruct_ProjectCurveOnSurface_Test.cxx + ShapeFix_Shape_Test.cxx ShapeUpgrade_UnifySameDomain_Test.cxx ) diff --git a/src/ModelingAlgorithms/TKShHealing/GTests/ShapeAnalysis_Edge_Test.cxx b/src/ModelingAlgorithms/TKShHealing/GTests/ShapeAnalysis_Edge_Test.cxx new file mode 100644 index 0000000000..3150375041 --- /dev/null +++ b/src/ModelingAlgorithms/TKShHealing/GTests/ShapeAnalysis_Edge_Test.cxx @@ -0,0 +1,91 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(ShapeAnalysis_EdgeTest, HasCurve3d) +{ + BRepBuilderAPI_MakeEdge aMakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(10.0, 0.0, 0.0)); + ASSERT_TRUE(aMakeEdge.IsDone()); + const TopoDS_Edge& anEdge = aMakeEdge.Edge(); + + ShapeAnalysis_Edge anAnalyzer; + EXPECT_TRUE(anAnalyzer.HasCurve3d(anEdge)); +} + +TEST(ShapeAnalysis_EdgeTest, FirstVertex_LastVertex) +{ + BRepBuilderAPI_MakeEdge aMakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(10.0, 0.0, 0.0)); + ASSERT_TRUE(aMakeEdge.IsDone()); + const TopoDS_Edge& anEdge = aMakeEdge.Edge(); + + ShapeAnalysis_Edge anAnalyzer; + const TopoDS_Vertex aFirstVertex = anAnalyzer.FirstVertex(anEdge); + const TopoDS_Vertex aLastVertex = anAnalyzer.LastVertex(anEdge); + + EXPECT_FALSE(aFirstVertex.IsNull()); + EXPECT_FALSE(aLastVertex.IsNull()); +} + +TEST(ShapeAnalysis_EdgeTest, IsClosed_OpenEdge) +{ + BRepBuilderAPI_MakeEdge aMakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(10.0, 0.0, 0.0)); + ASSERT_TRUE(aMakeEdge.IsDone()); + const TopoDS_Edge& anEdge = aMakeEdge.Edge(); + + ShapeAnalysis_Edge anAnalyzer; + EXPECT_FALSE(anAnalyzer.IsClosed3d(anEdge)); +} + +TEST(ShapeAnalysis_EdgeTest, IsClosed_ClosedEdge) +{ + occ::handle aCircle = new Geom_Circle(gp_Ax2(gp_Pnt(0.0, 0.0, 0.0), gp::DZ()), 5.0); + BRepBuilderAPI_MakeEdge aMakeEdge(aCircle); + ASSERT_TRUE(aMakeEdge.IsDone()); + const TopoDS_Edge& anEdge = aMakeEdge.Edge(); + + ShapeAnalysis_Edge anAnalyzer; + EXPECT_TRUE(anAnalyzer.IsClosed3d(anEdge)); +} + +TEST(ShapeAnalysis_EdgeTest, IsSeam_NonSeam) +{ + BRepPrimAPI_MakeBox aMakeBox(10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aMakeBox.Shape(); + ASSERT_TRUE(aMakeBox.IsDone()); + + TopExp_Explorer aFaceExp(aBox, TopAbs_FACE); + ASSERT_TRUE(aFaceExp.More()); + const TopoDS_Face& aFace = TopoDS::Face(aFaceExp.Current()); + + TopExp_Explorer anEdgeExp(aFace, TopAbs_EDGE); + ASSERT_TRUE(anEdgeExp.More()); + const TopoDS_Edge& anEdge = TopoDS::Edge(anEdgeExp.Current()); + + ShapeAnalysis_Edge anAnalyzer; + EXPECT_FALSE(anAnalyzer.IsSeam(anEdge, aFace)); +} diff --git a/src/ModelingAlgorithms/TKShHealing/GTests/ShapeFix_Shape_Test.cxx b/src/ModelingAlgorithms/TKShHealing/GTests/ShapeFix_Shape_Test.cxx new file mode 100644 index 0000000000..31fd12f288 --- /dev/null +++ b/src/ModelingAlgorithms/TKShHealing/GTests/ShapeFix_Shape_Test.cxx @@ -0,0 +1,94 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(ShapeFix_ShapeTest, FixValidBox) +{ + BRepPrimAPI_MakeBox aMakeBox(10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aMakeBox.Shape(); + ASSERT_TRUE(aMakeBox.IsDone()); + + occ::handle aFixer = new ShapeFix_Shape(aBox); + aFixer->Perform(); + const TopoDS_Shape aResult = aFixer->Shape(); + ASSERT_FALSE(aResult.IsNull()); + + BRepCheck_Analyzer anAnalyzer(aResult); + EXPECT_TRUE(anAnalyzer.IsValid()); +} + +TEST(ShapeFix_ShapeTest, StatusAfterFix) +{ + BRepPrimAPI_MakeBox aMakeBox(10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aMakeBox.Shape(); + ASSERT_TRUE(aMakeBox.IsDone()); + + occ::handle aFixer = new ShapeFix_Shape(aBox); + aFixer->Perform(); + + // A valid box should not require any failure-level fixes + EXPECT_FALSE(aFixer->Status(ShapeExtend_FAIL)); +} + +TEST(ShapeFix_ShapeTest, SetPrecision) +{ + occ::handle aFixer = new ShapeFix_Shape(); + + const double aPrecision = 0.01; + const double aMinTolerance = 0.001; + const double aMaxTolerance = 0.1; + + aFixer->SetPrecision(aPrecision); + aFixer->SetMinTolerance(aMinTolerance); + aFixer->SetMaxTolerance(aMaxTolerance); + + EXPECT_NEAR(aFixer->Precision(), aPrecision, Precision::Confusion()); + EXPECT_NEAR(aFixer->MinTolerance(), aMinTolerance, Precision::Confusion()); + EXPECT_NEAR(aFixer->MaxTolerance(), aMaxTolerance, Precision::Confusion()); +} + +TEST(ShapeFix_ShapeTest, FixCompound) +{ + BRepPrimAPI_MakeBox aMakeBox1(10.0, 10.0, 10.0); + const TopoDS_Shape& aBox1 = aMakeBox1.Shape(); + ASSERT_TRUE(aMakeBox1.IsDone()); + + BRepPrimAPI_MakeBox aMakeBox2(gp_Pnt(20.0, 0.0, 0.0), 5.0, 5.0, 5.0); + const TopoDS_Shape& aBox2 = aMakeBox2.Shape(); + ASSERT_TRUE(aMakeBox2.IsDone()); + + BRep_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + aBuilder.Add(aCompound, aBox1); + aBuilder.Add(aCompound, aBox2); + + occ::handle aFixer = new ShapeFix_Shape(aCompound); + aFixer->Perform(); + const TopoDS_Shape aResult = aFixer->Shape(); + ASSERT_FALSE(aResult.IsNull()); + + BRepCheck_Analyzer anAnalyzer(aResult); + EXPECT_TRUE(anAnalyzer.IsValid()); +} diff --git a/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepBuilderAPI_Copy_Test.cxx b/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepBuilderAPI_Copy_Test.cxx new file mode 100644 index 0000000000..b4e6f6c455 --- /dev/null +++ b/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepBuilderAPI_Copy_Test.cxx @@ -0,0 +1,106 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(BRepBuilderAPI_CopyTest, CopyIsValid) +{ + BRepPrimAPI_MakeBox aMakeBox(10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aMakeBox.Shape(); + ASSERT_TRUE(aMakeBox.IsDone()) << "Box creation failed"; + + BRepBuilderAPI_Copy aCopier(aBox); + const TopoDS_Shape& aCopy = aCopier.Shape(); + ASSERT_FALSE(aCopy.IsNull()) << "Copied shape is null"; + + BRepCheck_Analyzer anAnalyzer(aCopy); + EXPECT_TRUE(anAnalyzer.IsValid()) << "Copied shape should be valid"; +} + +TEST(BRepBuilderAPI_CopyTest, CopyVolume) +{ + BRepPrimAPI_MakeBox aMakeBox(10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aMakeBox.Shape(); + ASSERT_TRUE(aMakeBox.IsDone()) << "Box creation failed"; + + GProp_GProps aOriginalProps; + BRepGProp::VolumeProperties(aBox, aOriginalProps); + double anOriginalVolume = aOriginalProps.Mass(); + + BRepBuilderAPI_Copy aCopier(aBox); + const TopoDS_Shape& aCopy = aCopier.Shape(); + ASSERT_FALSE(aCopy.IsNull()) << "Copied shape is null"; + + GProp_GProps aCopyProps; + BRepGProp::VolumeProperties(aCopy, aCopyProps); + double aCopyVolume = aCopyProps.Mass(); + + EXPECT_NEAR(aCopyVolume, anOriginalVolume, Precision::Confusion()) + << "Copy volume should match original"; +} + +TEST(BRepBuilderAPI_CopyTest, CopyIsDistinct) +{ + BRepPrimAPI_MakeBox aMakeBox(10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aMakeBox.Shape(); + ASSERT_TRUE(aMakeBox.IsDone()) << "Box creation failed"; + + BRepBuilderAPI_Copy aCopier(aBox); + const TopoDS_Shape& aCopy = aCopier.Shape(); + ASSERT_FALSE(aCopy.IsNull()) << "Copied shape is null"; + + EXPECT_FALSE(aCopy.IsEqual(aBox)) << "Copy should not be equal to original (different TShape)"; +} + +TEST(BRepBuilderAPI_CopyTest, CopyGeomTrue) +{ + BRepPrimAPI_MakeBox aMakeBox(10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aMakeBox.Shape(); + ASSERT_TRUE(aMakeBox.IsDone()) << "Box creation failed"; + + BRepBuilderAPI_Copy aCopier(aBox, true); + const TopoDS_Shape& aCopy = aCopier.Shape(); + ASSERT_FALSE(aCopy.IsNull()) << "Copied shape is null"; + + GProp_GProps aOriginalProps; + BRepGProp::VolumeProperties(aBox, aOriginalProps); + + GProp_GProps aCopyProps; + BRepGProp::VolumeProperties(aCopy, aCopyProps); + + EXPECT_NEAR(aCopyProps.Mass(), aOriginalProps.Mass(), Precision::Confusion()) + << "Deep copy volume should match original"; +} + +TEST(BRepBuilderAPI_CopyTest, CopyGeomFalse) +{ + BRepPrimAPI_MakeBox aMakeBox(10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aMakeBox.Shape(); + ASSERT_TRUE(aMakeBox.IsDone()) << "Box creation failed"; + + BRepBuilderAPI_Copy aCopier(aBox, false); + const TopoDS_Shape& aCopy = aCopier.Shape(); + ASSERT_FALSE(aCopy.IsNull()) << "Copied shape is null"; + + BRepCheck_Analyzer anAnalyzer(aCopy); + EXPECT_TRUE(anAnalyzer.IsValid()) << "Shallow copy should produce a valid shape"; +} diff --git a/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepBuilderAPI_MakeEdge_Test.cxx b/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepBuilderAPI_MakeEdge_Test.cxx new file mode 100644 index 0000000000..fd80caf220 --- /dev/null +++ b/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepBuilderAPI_MakeEdge_Test.cxx @@ -0,0 +1,132 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(BRepBuilderAPI_MakeEdgeTest, LinearEdge_TwoPoints) +{ + gp_Pnt aP1(0.0, 0.0, 0.0); + gp_Pnt aP2(10.0, 0.0, 0.0); + + BRepBuilderAPI_MakeEdge aMakeEdge(aP1, aP2); + ASSERT_TRUE(aMakeEdge.IsDone()) << "Linear edge creation failed"; + + TopoDS_Edge anEdge = aMakeEdge.Edge(); + ASSERT_FALSE(anEdge.IsNull()) << "Resulting edge is null"; + + // Verify edge length + GProp_GProps aProps; + BRepGProp::LinearProperties(anEdge, aProps); + EXPECT_NEAR(aProps.Mass(), 10.0, Precision::Confusion()) << "Edge length should be 10"; +} + +TEST(BRepBuilderAPI_MakeEdgeTest, CircularEdge_Full) +{ + gp_Ax2 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + occ::handle aCircle = new Geom_Circle(anAxis, 5.0); + + BRepBuilderAPI_MakeEdge aMakeEdge(aCircle); + ASSERT_TRUE(aMakeEdge.IsDone()) << "Full circular edge creation failed"; + + TopoDS_Edge anEdge = aMakeEdge.Edge(); + ASSERT_FALSE(anEdge.IsNull()); + + // Full circle length = 2*PI*R + GProp_GProps aProps; + BRepGProp::LinearProperties(anEdge, aProps); + EXPECT_NEAR(aProps.Mass(), 2.0 * M_PI * 5.0, Precision::Confusion()); +} + +TEST(BRepBuilderAPI_MakeEdgeTest, CircularEdge_Trimmed) +{ + gp_Ax2 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + occ::handle aCircle = new Geom_Circle(anAxis, 5.0); + + // Half circle: 0 to PI + BRepBuilderAPI_MakeEdge aMakeEdge(aCircle, 0.0, M_PI); + ASSERT_TRUE(aMakeEdge.IsDone()) << "Trimmed circular edge creation failed"; + + TopoDS_Edge anEdge = aMakeEdge.Edge(); + ASSERT_FALSE(anEdge.IsNull()); + + // Half circle length = PI*R + GProp_GProps aProps; + BRepGProp::LinearProperties(anEdge, aProps); + EXPECT_NEAR(aProps.Mass(), M_PI * 5.0, Precision::Confusion()); +} + +TEST(BRepBuilderAPI_MakeEdgeTest, EdgeFromLine_WithBounds) +{ + occ::handle aLine = new Geom_Line(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + + BRepBuilderAPI_MakeEdge aMakeEdge(aLine, 0.0, 7.0); + ASSERT_TRUE(aMakeEdge.IsDone()) << "Edge from line with bounds failed"; + + TopoDS_Edge anEdge = aMakeEdge.Edge(); + ASSERT_FALSE(anEdge.IsNull()); + + GProp_GProps aProps; + BRepGProp::LinearProperties(anEdge, aProps); + EXPECT_NEAR(aProps.Mass(), 7.0, Precision::Confusion()); +} + +TEST(BRepBuilderAPI_MakeEdgeTest, VertexExtraction) +{ + gp_Pnt aP1(0.0, 0.0, 0.0); + gp_Pnt aP2(10.0, 0.0, 0.0); + + BRepBuilderAPI_MakeEdge aMakeEdge(aP1, aP2); + ASSERT_TRUE(aMakeEdge.IsDone()); + + TopoDS_Edge anEdge = aMakeEdge.Edge(); + TopoDS_Vertex aV1, aV2; + TopExp::Vertices(anEdge, aV1, aV2); + + ASSERT_FALSE(aV1.IsNull()) << "First vertex is null"; + ASSERT_FALSE(aV2.IsNull()) << "Last vertex is null"; + + gp_Pnt aFirstPnt = BRep_Tool::Pnt(aV1); + gp_Pnt aLastPnt = BRep_Tool::Pnt(aV2); + + EXPECT_TRUE(aFirstPnt.IsEqual(aP1, Precision::Confusion())); + EXPECT_TRUE(aLastPnt.IsEqual(aP2, Precision::Confusion())); +} + +TEST(BRepBuilderAPI_MakeEdgeTest, ToleranceCheck) +{ + gp_Pnt aP1(0.0, 0.0, 0.0); + gp_Pnt aP2(10.0, 0.0, 0.0); + + BRepBuilderAPI_MakeEdge aMakeEdge(aP1, aP2); + ASSERT_TRUE(aMakeEdge.IsDone()); + + TopoDS_Edge anEdge = aMakeEdge.Edge(); + double aTol = BRep_Tool::Tolerance(anEdge); + EXPECT_GT(aTol, 0.0) << "Edge tolerance should be positive"; + EXPECT_LE(aTol, Precision::Confusion()) << "Edge tolerance should not exceed confusion"; +} diff --git a/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepBuilderAPI_MakeFace_Test.cxx b/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepBuilderAPI_MakeFace_Test.cxx new file mode 100644 index 0000000000..48764659fa --- /dev/null +++ b/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepBuilderAPI_MakeFace_Test.cxx @@ -0,0 +1,116 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(BRepBuilderAPI_MakeFaceTest, FaceFromPlane) +{ + gp_Pln aPln(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + BRepBuilderAPI_MakeFace aMakeFace(aPln); + ASSERT_TRUE(aMakeFace.IsDone()) << "Face from plane creation failed"; + + TopoDS_Face aFace = aMakeFace.Face(); + ASSERT_FALSE(aFace.IsNull()) << "Resulting face is null"; +} + +TEST(BRepBuilderAPI_MakeFaceTest, FaceFromWire) +{ + // Create a rectangular wire in XY plane + gp_Pnt aP1(0.0, 0.0, 0.0); + gp_Pnt aP2(10.0, 0.0, 0.0); + gp_Pnt aP3(10.0, 5.0, 0.0); + gp_Pnt aP4(0.0, 5.0, 0.0); + + TopoDS_Edge anE1 = BRepBuilderAPI_MakeEdge(aP1, aP2).Edge(); + TopoDS_Edge anE2 = BRepBuilderAPI_MakeEdge(aP2, aP3).Edge(); + TopoDS_Edge anE3 = BRepBuilderAPI_MakeEdge(aP3, aP4).Edge(); + TopoDS_Edge anE4 = BRepBuilderAPI_MakeEdge(aP4, aP1).Edge(); + + BRepBuilderAPI_MakeWire aMakeWire; + aMakeWire.Add(anE1); + aMakeWire.Add(anE2); + aMakeWire.Add(anE3); + aMakeWire.Add(anE4); + ASSERT_TRUE(aMakeWire.IsDone()) << "Wire creation failed"; + + BRepBuilderAPI_MakeFace aMakeFace(aMakeWire.Wire()); + ASSERT_TRUE(aMakeFace.IsDone()) << "Face from wire creation failed"; + + TopoDS_Face aFace = aMakeFace.Face(); + ASSERT_FALSE(aFace.IsNull()); + + BRepCheck_Analyzer anAnalyzer(aFace); + EXPECT_TRUE(anAnalyzer.IsValid()) << "Face from wire is not valid"; + + // Area should be 10 * 5 = 50 + GProp_GProps aProps; + BRepGProp::SurfaceProperties(aFace, aProps); + EXPECT_NEAR(aProps.Mass(), 50.0, Precision::Confusion()); +} + +TEST(BRepBuilderAPI_MakeFaceTest, FaceFromGeomPlane_WithBounds) +{ + occ::handle aGeomPlane = new Geom_Plane(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + BRepBuilderAPI_MakeFace aMakeFace(aGeomPlane, 0.0, 10.0, 0.0, 5.0, Precision::Confusion()); + ASSERT_TRUE(aMakeFace.IsDone()) << "Face from Geom_Plane with bounds failed"; + + TopoDS_Face aFace = aMakeFace.Face(); + ASSERT_FALSE(aFace.IsNull()); + + BRepCheck_Analyzer anAnalyzer(aFace); + EXPECT_TRUE(anAnalyzer.IsValid()) << "Bounded face is not valid"; + + GProp_GProps aProps; + BRepGProp::SurfaceProperties(aFace, aProps); + EXPECT_NEAR(aProps.Mass(), 50.0, Precision::Confusion()); +} + +TEST(BRepBuilderAPI_MakeFaceTest, FaceFromCylindricalSurface) +{ + gp_Ax3 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + occ::handle aCylSurf = new Geom_CylindricalSurface(anAxis, 5.0); + + // Create a bounded face: U from 0 to 2*PI, V from 0 to 10 + BRepBuilderAPI_MakeFace aMakeFace(aCylSurf, 0.0, 2.0 * M_PI, 0.0, 10.0, Precision::Confusion()); + ASSERT_TRUE(aMakeFace.IsDone()) << "Face from cylindrical surface failed"; + + TopoDS_Face aFace = aMakeFace.Face(); + ASSERT_FALSE(aFace.IsNull()); + + BRepCheck_Analyzer anAnalyzer(aFace); + EXPECT_TRUE(anAnalyzer.IsValid()) << "Cylindrical face is not valid"; + + // Area of cylinder: 2*PI*R*H = 2*PI*5*10 = 100*PI + GProp_GProps aProps; + BRepGProp::SurfaceProperties(aFace, aProps); + EXPECT_NEAR(aProps.Mass(), 2.0 * M_PI * 5.0 * 10.0, 0.01); +} diff --git a/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepBuilderAPI_Transform_Test.cxx b/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepBuilderAPI_Transform_Test.cxx new file mode 100644 index 0000000000..30fd891009 --- /dev/null +++ b/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepBuilderAPI_Transform_Test.cxx @@ -0,0 +1,135 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(BRepBuilderAPI_TransformTest, Translate) +{ + BRepPrimAPI_MakeBox aMakeBox(10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aMakeBox.Shape(); + ASSERT_TRUE(aMakeBox.IsDone()) << "Box creation failed"; + + gp_Trsf aTrsf; + aTrsf.SetTranslation(gp_Vec(100.0, 0.0, 0.0)); + + BRepBuilderAPI_Transform aTransform(aBox, aTrsf); + const TopoDS_Shape& aResult = aTransform.Shape(); + ASSERT_FALSE(aResult.IsNull()) << "Transformed shape is null"; + + GProp_GProps aProps; + BRepGProp::VolumeProperties(aResult, aProps); + gp_Pnt aCenterOfMass = aProps.CentreOfMass(); + + EXPECT_NEAR(aCenterOfMass.X(), 105.0, Precision::Confusion()) + << "Center of mass X should be shifted by 100"; + EXPECT_NEAR(aCenterOfMass.Y(), 5.0, Precision::Confusion()); + EXPECT_NEAR(aCenterOfMass.Z(), 5.0, Precision::Confusion()); +} + +TEST(BRepBuilderAPI_TransformTest, Rotate) +{ + BRepPrimAPI_MakeBox aMakeBox(10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aMakeBox.Shape(); + ASSERT_TRUE(aMakeBox.IsDone()) << "Box creation failed"; + + gp_Trsf aTrsf; + gp_Ax1 aZAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + aTrsf.SetRotation(aZAxis, M_PI / 2.0); + + BRepBuilderAPI_Transform aTransform(aBox, aTrsf); + const TopoDS_Shape& aResult = aTransform.Shape(); + ASSERT_FALSE(aResult.IsNull()) << "Transformed shape is null"; + + GProp_GProps aProps; + BRepGProp::VolumeProperties(aResult, aProps); + gp_Pnt aCenterOfMass = aProps.CentreOfMass(); + + EXPECT_NEAR(aCenterOfMass.X(), -5.0, Precision::Confusion()) + << "Center of mass X should be ~-5 after 90deg rotation"; + EXPECT_NEAR(aCenterOfMass.Y(), 5.0, Precision::Confusion()) + << "Center of mass Y should be ~5 after 90deg rotation"; +} + +TEST(BRepBuilderAPI_TransformTest, Scale) +{ + BRepPrimAPI_MakeBox aMakeBox(10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aMakeBox.Shape(); + ASSERT_TRUE(aMakeBox.IsDone()) << "Box creation failed"; + + gp_Trsf aTrsf; + aTrsf.SetScale(gp_Pnt(0.0, 0.0, 0.0), 2.0); + + BRepBuilderAPI_Transform aTransform(aBox, aTrsf); + const TopoDS_Shape& aResult = aTransform.Shape(); + ASSERT_FALSE(aResult.IsNull()) << "Transformed shape is null"; + + GProp_GProps aProps; + BRepGProp::VolumeProperties(aResult, aProps); + double aVolume = aProps.Mass(); + + EXPECT_NEAR(aVolume, 8000.0, Precision::Confusion()) + << "Volume should be 8x original (2^3 * 1000)"; +} + +TEST(BRepBuilderAPI_TransformTest, Mirror) +{ + BRepPrimAPI_MakeBox aMakeBox(gp_Pnt(10.0, 0.0, 0.0), 10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aMakeBox.Shape(); + ASSERT_TRUE(aMakeBox.IsDone()) << "Box creation failed"; + + gp_Trsf aTrsf; + gp_Ax2 aYZPlane(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + aTrsf.SetMirror(aYZPlane); + + BRepBuilderAPI_Transform aTransform(aBox, aTrsf); + const TopoDS_Shape& aResult = aTransform.Shape(); + ASSERT_FALSE(aResult.IsNull()) << "Transformed shape is null"; + + GProp_GProps aProps; + BRepGProp::VolumeProperties(aResult, aProps); + gp_Pnt aCenterOfMass = aProps.CentreOfMass(); + + EXPECT_LT(aCenterOfMass.X(), 0.0) + << "Center of mass X should be negative after mirroring through YZ plane"; +} + +TEST(BRepBuilderAPI_TransformTest, ShapeValidity) +{ + BRepPrimAPI_MakeBox aMakeBox(10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aMakeBox.Shape(); + ASSERT_TRUE(aMakeBox.IsDone()) << "Box creation failed"; + + gp_Trsf aTrsf; + aTrsf.SetTranslation(gp_Vec(50.0, 50.0, 50.0)); + + BRepBuilderAPI_Transform aTransform(aBox, aTrsf); + const TopoDS_Shape& aResult = aTransform.Shape(); + ASSERT_FALSE(aResult.IsNull()) << "Transformed shape is null"; + + BRepCheck_Analyzer anAnalyzer(aResult); + EXPECT_TRUE(anAnalyzer.IsValid()) << "Transformed shape should be valid"; +} diff --git a/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepClass3d_SolidClassifier_Test.cxx b/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepClass3d_SolidClassifier_Test.cxx new file mode 100644 index 0000000000..179a4abd54 --- /dev/null +++ b/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepClass3d_SolidClassifier_Test.cxx @@ -0,0 +1,83 @@ +// 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 +#include +#include +#include +#include +#include +#include + +#include + +TEST(BRepClass3d_SolidClassifierTest, PointInside_Box) +{ + BRepPrimAPI_MakeBox aMakeBox(gp_Pnt(0.0, 0.0, 0.0), 10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aMakeBox.Shape(); + ASSERT_TRUE(aMakeBox.IsDone()) << "Box creation failed"; + + BRepClass3d_SolidClassifier aClassifier(aBox); + aClassifier.Perform(gp_Pnt(5.0, 5.0, 5.0), Precision::Confusion()); + + EXPECT_EQ(aClassifier.State(), TopAbs_IN) << "Point (5,5,5) should be inside the box"; +} + +TEST(BRepClass3d_SolidClassifierTest, PointOutside_Box) +{ + BRepPrimAPI_MakeBox aMakeBox(gp_Pnt(0.0, 0.0, 0.0), 10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aMakeBox.Shape(); + ASSERT_TRUE(aMakeBox.IsDone()) << "Box creation failed"; + + BRepClass3d_SolidClassifier aClassifier(aBox); + aClassifier.Perform(gp_Pnt(20.0, 20.0, 20.0), Precision::Confusion()); + + EXPECT_EQ(aClassifier.State(), TopAbs_OUT) << "Point (20,20,20) should be outside the box"; +} + +TEST(BRepClass3d_SolidClassifierTest, PointOnFace_Box) +{ + BRepPrimAPI_MakeBox aMakeBox(gp_Pnt(0.0, 0.0, 0.0), 10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aMakeBox.Shape(); + ASSERT_TRUE(aMakeBox.IsDone()) << "Box creation failed"; + + BRepClass3d_SolidClassifier aClassifier(aBox); + aClassifier.Perform(gp_Pnt(5.0, 5.0, 0.0), Precision::Confusion()); + + EXPECT_EQ(aClassifier.State(), TopAbs_ON) + << "Point (5,5,0) should be on the bottom face of the box"; +} + +TEST(BRepClass3d_SolidClassifierTest, PointInside_Sphere) +{ + BRepPrimAPI_MakeSphere aMakeSphere(10.0); + const TopoDS_Shape& aSphere = aMakeSphere.Shape(); + ASSERT_TRUE(aMakeSphere.IsDone()) << "Sphere creation failed"; + + BRepClass3d_SolidClassifier aClassifier(aSphere); + aClassifier.Perform(gp_Pnt(0.0, 0.0, 0.0), Precision::Confusion()); + + EXPECT_EQ(aClassifier.State(), TopAbs_IN) << "Origin should be inside the sphere"; +} + +TEST(BRepClass3d_SolidClassifierTest, PerformInfinitePoint) +{ + BRepPrimAPI_MakeBox aMakeBox(gp_Pnt(0.0, 0.0, 0.0), 10.0, 10.0, 10.0); + const TopoDS_Shape& aBox = aMakeBox.Shape(); + ASSERT_TRUE(aMakeBox.IsDone()) << "Box creation failed"; + + BRepClass3d_SolidClassifier aClassifier(aBox); + aClassifier.PerformInfinitePoint(Precision::Confusion()); + + EXPECT_EQ(aClassifier.State(), TopAbs_OUT) << "Infinite point should be outside the box"; +} diff --git a/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepGProp_Test.cxx b/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepGProp_Test.cxx new file mode 100644 index 0000000000..e332bd04f8 --- /dev/null +++ b/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepGProp_Test.cxx @@ -0,0 +1,117 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(BRepGPropTest, LinearProperties_EdgeLength) +{ + gp_Pnt aP1(0.0, 0.0, 0.0); + gp_Pnt aP2(3.0, 4.0, 0.0); + + BRepBuilderAPI_MakeEdge aMakeEdge(aP1, aP2); + ASSERT_TRUE(aMakeEdge.IsDone()); + + GProp_GProps aProps; + BRepGProp::LinearProperties(aMakeEdge.Edge(), aProps); + EXPECT_NEAR(aProps.Mass(), 5.0, Precision::Confusion()) << "Edge length should be 5"; +} + +TEST(BRepGPropTest, SurfaceProperties_BoxFaceArea) +{ + BRepPrimAPI_MakeBox aBox(10.0, 20.0, 30.0); + TopoDS_Shape aShape = aBox.Shape(); + ASSERT_TRUE(aBox.IsDone()); + + // Total surface area = 2*(10*20 + 10*30 + 20*30) = 2*(200+300+600) = 2200 + GProp_GProps aProps; + BRepGProp::SurfaceProperties(aShape, aProps); + EXPECT_NEAR(aProps.Mass(), 2200.0, Precision::Confusion()); +} + +TEST(BRepGPropTest, VolumeProperties_UnitBox) +{ + BRepPrimAPI_MakeBox aBox(1.0, 1.0, 1.0); + TopoDS_Shape aShape = aBox.Shape(); + ASSERT_TRUE(aBox.IsDone()); + + GProp_GProps aProps; + BRepGProp::VolumeProperties(aShape, aProps); + EXPECT_NEAR(aProps.Mass(), 1.0, Precision::Confusion()) << "Unit box volume should be 1"; +} + +TEST(BRepGPropTest, VolumeProperties_Sphere) +{ + const double aRadius = 5.0; + BRepPrimAPI_MakeSphere aSphere(aRadius); + TopoDS_Shape aShape = aSphere.Shape(); + ASSERT_TRUE(aSphere.IsDone()); + + GProp_GProps aProps; + BRepGProp::VolumeProperties(aShape, aProps); + double anExpectedVolume = (4.0 / 3.0) * M_PI * aRadius * aRadius * aRadius; + EXPECT_NEAR(aProps.Mass(), anExpectedVolume, 0.01) << "Sphere volume mismatch"; +} + +TEST(BRepGPropTest, VolumeProperties_BoxCenterOfMass) +{ + // Box from (0,0,0) to (10,10,10) + BRepPrimAPI_MakeBox aBox(10.0, 10.0, 10.0); + TopoDS_Shape aShape = aBox.Shape(); + ASSERT_TRUE(aBox.IsDone()); + + GProp_GProps aProps; + BRepGProp::VolumeProperties(aShape, aProps); + gp_Pnt aCOM = aProps.CentreOfMass(); + + // Center of mass should be at (5, 5, 5) + EXPECT_NEAR(aCOM.X(), 5.0, Precision::Confusion()); + EXPECT_NEAR(aCOM.Y(), 5.0, Precision::Confusion()); + EXPECT_NEAR(aCOM.Z(), 5.0, Precision::Confusion()); +} + +TEST(BRepGPropTest, LinearProperties_SkipShared) +{ + BRepPrimAPI_MakeBox aBox(10.0, 10.0, 10.0); + TopoDS_Shape aShape = aBox.Shape(); + ASSERT_TRUE(aBox.IsDone()); + + // With SkipShared = false, shared edges are counted multiple times + GProp_GProps aPropsNotSkipped; + BRepGProp::LinearProperties(aShape, aPropsNotSkipped, false); + + // With SkipShared = true, each edge is counted once + GProp_GProps aPropsSkipped; + BRepGProp::LinearProperties(aShape, aPropsSkipped, true); + + // Box has 12 edges, each of length 10 = total 120 + EXPECT_NEAR(aPropsSkipped.Mass(), 120.0, Precision::Confusion()) + << "Total edge length of 10x10x10 box with SkipShared=true should be 120"; + + // Without SkipShared, each edge is counted for each face it belongs to (2 faces per edge) + // So total = 240 + EXPECT_NEAR(aPropsNotSkipped.Mass(), 240.0, Precision::Confusion()) + << "Total edge length with SkipShared=false should be double"; +} diff --git a/src/ModelingAlgorithms/TKTopAlgo/GTests/FILES.cmake b/src/ModelingAlgorithms/TKTopAlgo/GTests/FILES.cmake index 17aaf59d01..c046438554 100644 --- a/src/ModelingAlgorithms/TKTopAlgo/GTests/FILES.cmake +++ b/src/ModelingAlgorithms/TKTopAlgo/GTests/FILES.cmake @@ -2,7 +2,13 @@ set(OCCT_TKTopAlgo_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}") set(OCCT_TKTopAlgo_GTests_FILES + BRepBuilderAPI_Copy_Test.cxx + BRepBuilderAPI_MakeEdge_Test.cxx + BRepBuilderAPI_MakeFace_Test.cxx BRepBuilderAPI_MakeWire_Test.cxx + BRepBuilderAPI_Transform_Test.cxx + BRepClass3d_SolidClassifier_Test.cxx + BRepGProp_Test.cxx BRepLib_MakeWire_Test.cxx BRepOffsetAPI_ThruSections_Test.cxx ) diff --git a/src/ModelingData/TKBRep/GTests/BRep_Tool_Test.cxx b/src/ModelingData/TKBRep/GTests/BRep_Tool_Test.cxx new file mode 100644 index 0000000000..7dcf182330 --- /dev/null +++ b/src/ModelingData/TKBRep/GTests/BRep_Tool_Test.cxx @@ -0,0 +1,160 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(BRep_Tool_Test, Pnt_FromVertex) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 20.0, 30.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + TopExp_Explorer anExp(aBox, TopAbs_VERTEX); + ASSERT_TRUE(anExp.More()); + + const TopoDS_Vertex& aVertex = TopoDS::Vertex(anExp.Current()); + gp_Pnt aPnt = BRep_Tool::Pnt(aVertex); + + // The point coordinates should be within the box bounds [0,10] x [0,20] x [0,30] + EXPECT_GE(aPnt.X(), -Precision::Confusion()); + EXPECT_LE(aPnt.X(), 10.0 + Precision::Confusion()); + EXPECT_GE(aPnt.Y(), -Precision::Confusion()); + EXPECT_LE(aPnt.Y(), 20.0 + Precision::Confusion()); + EXPECT_GE(aPnt.Z(), -Precision::Confusion()); + EXPECT_LE(aPnt.Z(), 30.0 + Precision::Confusion()); +} + +TEST(BRep_Tool_Test, Tolerance_Vertex) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 20.0, 30.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + TopExp_Explorer anExp(aBox, TopAbs_VERTEX); + ASSERT_TRUE(anExp.More()); + + const TopoDS_Vertex& aVertex = TopoDS::Vertex(anExp.Current()); + double aTol = BRep_Tool::Tolerance(aVertex); + EXPECT_GE(aTol, 0.0); +} + +TEST(BRep_Tool_Test, Tolerance_Edge) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 20.0, 30.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + TopExp_Explorer anExp(aBox, TopAbs_EDGE); + ASSERT_TRUE(anExp.More()); + + const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current()); + double aTol = BRep_Tool::Tolerance(anEdge); + EXPECT_GE(aTol, 0.0); +} + +TEST(BRep_Tool_Test, Tolerance_Face) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 20.0, 30.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + TopExp_Explorer anExp(aBox, TopAbs_FACE); + ASSERT_TRUE(anExp.More()); + + const TopoDS_Face& aFace = TopoDS::Face(anExp.Current()); + double aTol = BRep_Tool::Tolerance(aFace); + EXPECT_GE(aTol, 0.0); +} + +TEST(BRep_Tool_Test, Curve_FromEdge) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 20.0, 30.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + TopExp_Explorer anExp(aBox, TopAbs_EDGE); + ASSERT_TRUE(anExp.More()); + + const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current()); + double aFirst = 0.0; + double aLast = 0.0; + occ::handle aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); + + EXPECT_FALSE(aCurve.IsNull()) << "Curve from a box edge should not be null"; + EXPECT_LT(aFirst, aLast) << "First parameter should be less than last parameter"; +} + +TEST(BRep_Tool_Test, Surface_FromFace) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 20.0, 30.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + TopExp_Explorer anExp(aBox, TopAbs_FACE); + ASSERT_TRUE(anExp.More()); + + const TopoDS_Face& aFace = TopoDS::Face(anExp.Current()); + occ::handle aSurface = BRep_Tool::Surface(aFace); + + EXPECT_FALSE(aSurface.IsNull()) << "Surface from a box face should not be null"; +} + +TEST(BRep_Tool_Test, IsClosed_CircleEdge) +{ + occ::handle aCircle = new Geom_Circle(gp_Ax2(gp_Pnt(0.0, 0.0, 0.0), gp::DZ()), 5.0); + BRepBuilderAPI_MakeEdge anEdgeMaker(aCircle); + ASSERT_TRUE(anEdgeMaker.IsDone()); + + const TopoDS_Edge& anEdge = anEdgeMaker.Edge(); + EXPECT_TRUE(BRep_Tool::IsClosed(anEdge)) << "A full circle edge should be closed"; +} + +TEST(BRep_Tool_Test, IsClosed_LineEdge) +{ + BRepBuilderAPI_MakeEdge anEdgeMaker(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(10.0, 0.0, 0.0)); + ASSERT_TRUE(anEdgeMaker.IsDone()); + + const TopoDS_Edge& anEdge = anEdgeMaker.Edge(); + EXPECT_FALSE(BRep_Tool::IsClosed(anEdge)) << "A line segment edge should not be closed"; +} + +TEST(BRep_Tool_Test, Degenerated) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 20.0, 30.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + TopExp_Explorer anExp(aBox, TopAbs_EDGE); + ASSERT_TRUE(anExp.More()); + + const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current()); + EXPECT_FALSE(BRep_Tool::Degenerated(anEdge)) << "Box edges should not be degenerated"; +} diff --git a/src/ModelingData/TKBRep/GTests/FILES.cmake b/src/ModelingData/TKBRep/GTests/FILES.cmake index 23e163c70d..21626778fd 100644 --- a/src/ModelingData/TKBRep/GTests/FILES.cmake +++ b/src/ModelingData/TKBRep/GTests/FILES.cmake @@ -2,7 +2,9 @@ set(OCCT_TKBRep_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}") set(OCCT_TKBRep_GTests_FILES + BRep_Tool_Test.cxx BRepAdaptor_CompCurve_Test.cxx + TopExp_Test.cxx TopoDS_Builder_Test.cxx TopoDS_Edge_Test.cxx TopoDS_Iterator_Test.cxx diff --git a/src/ModelingData/TKBRep/GTests/TopExp_Test.cxx b/src/ModelingData/TKBRep/GTests/TopExp_Test.cxx new file mode 100644 index 0000000000..5e90d72ca9 --- /dev/null +++ b/src/ModelingData/TKBRep/GTests/TopExp_Test.cxx @@ -0,0 +1,152 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(TopExp_Test, MapShapes_Faces) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 20.0, 30.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + NCollection_IndexedMap aFaceMap; + TopExp::MapShapes(aBox, TopAbs_FACE, aFaceMap); + + EXPECT_EQ(aFaceMap.Extent(), 6) << "A box should have exactly 6 faces"; +} + +TEST(TopExp_Test, MapShapes_Edges) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 20.0, 30.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + NCollection_IndexedMap anEdgeMap; + TopExp::MapShapes(aBox, TopAbs_EDGE, anEdgeMap); + + EXPECT_EQ(anEdgeMap.Extent(), 12) << "A box should have exactly 12 edges"; +} + +TEST(TopExp_Test, MapShapes_Vertices) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 20.0, 30.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + NCollection_IndexedMap aVertexMap; + TopExp::MapShapes(aBox, TopAbs_VERTEX, aVertexMap); + + EXPECT_EQ(aVertexMap.Extent(), 8) << "A box should have exactly 8 vertices"; +} + +TEST(TopExp_Test, FirstVertex_LastVertex) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 20.0, 30.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + TopExp_Explorer anExp(aBox, TopAbs_EDGE); + ASSERT_TRUE(anExp.More()); + + const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current()); + + TopoDS_Vertex aFirstVertex = TopExp::FirstVertex(anEdge); + TopoDS_Vertex aLastVertex = TopExp::LastVertex(anEdge); + + EXPECT_FALSE(aFirstVertex.IsNull()) << "First vertex should not be null"; + EXPECT_FALSE(aLastVertex.IsNull()) << "Last vertex should not be null"; + EXPECT_FALSE(aFirstVertex.IsSame(aLastVertex)) + << "First and last vertices of a box edge should be distinct"; +} + +TEST(TopExp_Test, Vertices) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 20.0, 30.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + TopExp_Explorer anExp(aBox, TopAbs_EDGE); + ASSERT_TRUE(anExp.More()); + + const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current()); + + TopoDS_Vertex aV1, aV2; + TopExp::Vertices(anEdge, aV1, aV2); + + EXPECT_FALSE(aV1.IsNull()) << "First vertex from Vertices() should not be null"; + EXPECT_FALSE(aV2.IsNull()) << "Second vertex from Vertices() should not be null"; +} + +TEST(TopExp_Test, CommonVertex) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 20.0, 30.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + NCollection_IndexedMap anEdgeMap; + TopExp::MapShapes(aBox, TopAbs_EDGE, anEdgeMap); + ASSERT_GE(anEdgeMap.Extent(), 2); + + // Find two adjacent edges (sharing a common vertex) + bool isFound = false; + for (int i = 1; i <= anEdgeMap.Extent() && !isFound; ++i) + { + const TopoDS_Edge& anEdge1 = TopoDS::Edge(anEdgeMap(i)); + for (int j = i + 1; j <= anEdgeMap.Extent() && !isFound; ++j) + { + const TopoDS_Edge& anEdge2 = TopoDS::Edge(anEdgeMap(j)); + TopoDS_Vertex aCommonVertex; + if (TopExp::CommonVertex(anEdge1, anEdge2, aCommonVertex)) + { + EXPECT_FALSE(aCommonVertex.IsNull()) << "Common vertex should not be null"; + isFound = true; + } + } + } + + EXPECT_TRUE(isFound) << "Should find at least one pair of adjacent edges in a box"; +} + +TEST(TopExp_Test, MapShapesAndAncestors) +{ + BRepPrimAPI_MakeBox aBoxMaker(10.0, 20.0, 30.0); + const TopoDS_Shape& aBox = aBoxMaker.Shape(); + ASSERT_TRUE(aBoxMaker.IsDone()); + + NCollection_IndexedDataMap, TopTools_ShapeMapHasher> + anEdgeFaceMap; + TopExp::MapShapesAndAncestors(aBox, TopAbs_EDGE, TopAbs_FACE, anEdgeFaceMap); + + EXPECT_EQ(anEdgeFaceMap.Extent(), 12) << "A box should have 12 edges in the ancestor map"; + + // Each edge of a box is shared by exactly 2 faces + for (int i = 1; i <= anEdgeFaceMap.Extent(); ++i) + { + const NCollection_List& aFaceList = anEdgeFaceMap(i); + EXPECT_EQ(aFaceList.Extent(), 2) << "Each box edge should be shared by exactly 2 faces"; + } +} diff --git a/src/ModelingData/TKG3d/GTests/FILES.cmake b/src/ModelingData/TKG3d/GTests/FILES.cmake index 11763dad59..c3e8678aa4 100644 --- a/src/ModelingData/TKG3d/GTests/FILES.cmake +++ b/src/ModelingData/TKG3d/GTests/FILES.cmake @@ -6,9 +6,12 @@ set(OCCT_TKG3d_GTests_FILES Geom_BezierSurface_Test.cxx Geom_BSplineCurve_Test.cxx Geom_BSplineSurface_Test.cxx + Geom_Circle_Test.cxx Geom_CurveEval_Test.cxx + Geom_Line_Test.cxx Geom_OffsetCurve_Test.cxx Geom_OffsetSurface_Test.cxx + Geom_Plane_Test.cxx Geom_SurfaceEval_Test.cxx GeomAdaptor_Curve_Test.cxx GeomAPI_ExtremaCurveCurve_Test.cxx diff --git a/src/ModelingData/TKG3d/GTests/Geom_Circle_Test.cxx b/src/ModelingData/TKG3d/GTests/Geom_Circle_Test.cxx new file mode 100644 index 0000000000..6887941aa8 --- /dev/null +++ b/src/ModelingData/TKG3d/GTests/Geom_Circle_Test.cxx @@ -0,0 +1,135 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(Geom_CircleTest, Constructor) +{ + gp_Ax2 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + occ::handle aCircle = new Geom_Circle(anAxis, 5.0); + ASSERT_FALSE(aCircle.IsNull()); + EXPECT_NEAR(aCircle->Radius(), 5.0, Precision::Confusion()); +} + +TEST(Geom_CircleTest, Center) +{ + gp_Pnt aCenter(1.0, 2.0, 3.0); + gp_Ax2 anAxis(aCenter, gp_Dir(0.0, 0.0, 1.0)); + occ::handle aCircle = new Geom_Circle(anAxis, 5.0); + EXPECT_TRUE(aCircle->Circ().Location().IsEqual(aCenter, Precision::Confusion())); +} + +TEST(Geom_CircleTest, D0Evaluation) +{ + gp_Ax2 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + occ::handle aCircle = new Geom_Circle(anAxis, 1.0); + + gp_Pnt aPnt; + + // At parameter 0: point should be (1,0,0) for unit circle in XY plane + aCircle->D0(0.0, aPnt); + EXPECT_NEAR(aPnt.X(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aPnt.Y(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aPnt.Z(), 0.0, Precision::Confusion()); + + // At parameter PI/2: point should be (0,1,0) + aCircle->D0(M_PI_2, aPnt); + EXPECT_NEAR(aPnt.X(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aPnt.Y(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aPnt.Z(), 0.0, Precision::Confusion()); + + // At parameter PI: point should be (-1,0,0) + aCircle->D0(M_PI, aPnt); + EXPECT_NEAR(aPnt.X(), -1.0, Precision::Confusion()); + EXPECT_NEAR(aPnt.Y(), 0.0, Precision::Confusion()); + + // At parameter 3*PI/2: point should be (0,-1,0) + aCircle->D0(3.0 * M_PI_2, aPnt); + EXPECT_NEAR(aPnt.X(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aPnt.Y(), -1.0, Precision::Confusion()); +} + +TEST(Geom_CircleTest, D1Evaluation) +{ + gp_Ax2 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + occ::handle aCircle = new Geom_Circle(anAxis, 1.0); + + gp_Pnt aPnt; + gp_Vec aV1; + + // At parameter 0: tangent should be (0,1,0) for unit circle + aCircle->D1(0.0, aPnt, aV1); + EXPECT_NEAR(aV1.X(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aV1.Y(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aV1.Z(), 0.0, Precision::Confusion()); +} + +TEST(Geom_CircleTest, D2Evaluation) +{ + gp_Ax2 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + occ::handle aCircle = new Geom_Circle(anAxis, 1.0); + + gp_Pnt aPnt; + gp_Vec aV1, aV2; + + // At parameter 0: second derivative should be (-1,0,0) pointing toward center + aCircle->D2(0.0, aPnt, aV1, aV2); + EXPECT_NEAR(aV2.X(), -1.0, Precision::Confusion()); + EXPECT_NEAR(aV2.Y(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aV2.Z(), 0.0, Precision::Confusion()); +} + +TEST(Geom_CircleTest, Reverse) +{ + gp_Ax2 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + occ::handle aCircle = new Geom_Circle(anAxis, 1.0); + + double aParam = M_PI_4; + double aReversedParam = aCircle->ReversedParameter(aParam); + // For a circle: reversed parameter = 2*PI - U + EXPECT_NEAR(aReversedParam, 2.0 * M_PI - aParam, Precision::Confusion()); +} + +TEST(Geom_CircleTest, Transform) +{ + gp_Ax2 anAxis(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + occ::handle aCircle = new Geom_Circle(anAxis, 5.0); + + gp_Trsf aTrsf; + aTrsf.SetScale(gp_Pnt(0.0, 0.0, 0.0), 2.0); + aCircle->Transform(aTrsf); + EXPECT_NEAR(aCircle->Radius(), 10.0, Precision::Confusion()); +} + +TEST(Geom_CircleTest, Copy) +{ + gp_Ax2 anAxis(gp_Pnt(1.0, 2.0, 3.0), gp_Dir(0.0, 0.0, 1.0)); + occ::handle aCircle = new Geom_Circle(anAxis, 7.0); + + occ::handle aCopy = aCircle->Copy(); + ASSERT_FALSE(aCopy.IsNull()); + occ::handle aCopyCircle = occ::down_cast(aCopy); + ASSERT_FALSE(aCopyCircle.IsNull()); + EXPECT_NEAR(aCopyCircle->Radius(), 7.0, Precision::Confusion()); + EXPECT_TRUE( + aCopyCircle->Circ().Location().IsEqual(gp_Pnt(1.0, 2.0, 3.0), Precision::Confusion())); +} diff --git a/src/ModelingData/TKG3d/GTests/Geom_Line_Test.cxx b/src/ModelingData/TKG3d/GTests/Geom_Line_Test.cxx new file mode 100644 index 0000000000..38e4966c7d --- /dev/null +++ b/src/ModelingData/TKG3d/GTests/Geom_Line_Test.cxx @@ -0,0 +1,119 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(Geom_LineTest, ConstructFromAx1) +{ + gp_Ax1 anAx1(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + occ::handle aLine = new Geom_Line(anAx1); + ASSERT_FALSE(aLine.IsNull()); + + gp_Pnt aLoc = aLine->Lin().Location(); + EXPECT_TRUE(aLoc.IsEqual(gp_Pnt(0.0, 0.0, 0.0), Precision::Confusion())); +} + +TEST(Geom_LineTest, ConstructFromPointAndDir) +{ + occ::handle aLine = new Geom_Line(gp_Pnt(1.0, 2.0, 3.0), gp_Dir(0.0, 0.0, 1.0)); + ASSERT_FALSE(aLine.IsNull()); + + gp_Pnt aLoc = aLine->Lin().Location(); + EXPECT_TRUE(aLoc.IsEqual(gp_Pnt(1.0, 2.0, 3.0), Precision::Confusion())); + EXPECT_TRUE(aLine->Lin().Direction().IsEqual(gp_Dir(0.0, 0.0, 1.0), Precision::Angular())); +} + +TEST(Geom_LineTest, D0Evaluation) +{ + occ::handle aLine = new Geom_Line(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + gp_Pnt aPnt; + aLine->D0(5.0, aPnt); + EXPECT_NEAR(aPnt.X(), 5.0, Precision::Confusion()); + EXPECT_NEAR(aPnt.Y(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aPnt.Z(), 0.0, Precision::Confusion()); +} + +TEST(Geom_LineTest, D1Evaluation) +{ + occ::handle aLine = new Geom_Line(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 1.0, 0.0)); + gp_Pnt aPnt; + gp_Vec aV1; + aLine->D1(3.0, aPnt, aV1); + EXPECT_NEAR(aPnt.Y(), 3.0, Precision::Confusion()); + // First derivative is the direction vector (constant for a line) + EXPECT_NEAR(aV1.X(), 0.0, Precision::Confusion()); + EXPECT_NEAR(aV1.Y(), 1.0, Precision::Confusion()); + EXPECT_NEAR(aV1.Z(), 0.0, Precision::Confusion()); +} + +TEST(Geom_LineTest, D2Evaluation) +{ + occ::handle aLine = new Geom_Line(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + gp_Pnt aPnt; + gp_Vec aV1, aV2; + aLine->D2(1.0, aPnt, aV1, aV2); + // Second derivative of a line is zero + EXPECT_NEAR(aV2.Magnitude(), 0.0, Precision::Confusion()); +} + +TEST(Geom_LineTest, InfiniteParameters) +{ + occ::handle aLine = new Geom_Line(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + EXPECT_EQ(aLine->FirstParameter(), -Precision::Infinite()); + EXPECT_EQ(aLine->LastParameter(), Precision::Infinite()); +} + +TEST(Geom_LineTest, Reverse) +{ + occ::handle aLine = new Geom_Line(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + aLine->Reverse(); + EXPECT_TRUE(aLine->Lin().Direction().IsEqual(gp_Dir(-1.0, 0.0, 0.0), Precision::Angular())); +} + +TEST(Geom_LineTest, Reversed) +{ + occ::handle aLine = new Geom_Line(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + occ::handle aReversed = aLine->Reversed(); + ASSERT_FALSE(aReversed.IsNull()); + occ::handle aRevLine = occ::down_cast(aReversed); + ASSERT_FALSE(aRevLine.IsNull()); + EXPECT_TRUE(aRevLine->Lin().Direction().IsEqual(gp_Dir(-1.0, 0.0, 0.0), Precision::Angular())); +} + +TEST(Geom_LineTest, Transform) +{ + occ::handle aLine = new Geom_Line(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + gp_Trsf aTrsf; + aTrsf.SetTranslation(gp_Vec(0.0, 0.0, 5.0)); + aLine->Transform(aTrsf); + EXPECT_NEAR(aLine->Lin().Location().Z(), 5.0, Precision::Confusion()); +} + +TEST(Geom_LineTest, Copy) +{ + occ::handle aLine = new Geom_Line(gp_Pnt(1.0, 2.0, 3.0), gp_Dir(0.0, 0.0, 1.0)); + occ::handle aCopy = aLine->Copy(); + ASSERT_FALSE(aCopy.IsNull()); + occ::handle aCopyLine = occ::down_cast(aCopy); + ASSERT_FALSE(aCopyLine.IsNull()); + EXPECT_TRUE(aCopyLine->Lin().Location().IsEqual(gp_Pnt(1.0, 2.0, 3.0), Precision::Confusion())); +} diff --git a/src/ModelingData/TKG3d/GTests/Geom_Plane_Test.cxx b/src/ModelingData/TKG3d/GTests/Geom_Plane_Test.cxx new file mode 100644 index 0000000000..5f3b4ad592 --- /dev/null +++ b/src/ModelingData/TKG3d/GTests/Geom_Plane_Test.cxx @@ -0,0 +1,111 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(Geom_PlaneTest, ConstructFromAx3) +{ + gp_Ax3 anAx3(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + occ::handle aPlane = new Geom_Plane(anAx3); + ASSERT_FALSE(aPlane.IsNull()); + EXPECT_TRUE(aPlane->Location().IsEqual(gp_Pnt(0.0, 0.0, 0.0), Precision::Confusion())); +} + +TEST(Geom_PlaneTest, ConstructFromPointAndDir) +{ + occ::handle aPlane = new Geom_Plane(gp_Pnt(1.0, 2.0, 3.0), gp_Dir(0.0, 0.0, 1.0)); + ASSERT_FALSE(aPlane.IsNull()); + EXPECT_TRUE(aPlane->Location().IsEqual(gp_Pnt(1.0, 2.0, 3.0), Precision::Confusion())); +} + +TEST(Geom_PlaneTest, D0Evaluation) +{ + occ::handle aPlane = new Geom_Plane(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Pnt aPnt; + + // XY plane at origin: D0(U,V) = (U,V,0) for default axis + aPlane->D0(3.0, 4.0, aPnt); + EXPECT_NEAR(aPnt.X(), 3.0, Precision::Confusion()); + EXPECT_NEAR(aPnt.Y(), 4.0, Precision::Confusion()); + EXPECT_NEAR(aPnt.Z(), 0.0, Precision::Confusion()); +} + +TEST(Geom_PlaneTest, Coefficients) +{ + occ::handle aPlane = new Geom_Plane(gp_Pnt(0.0, 0.0, 5.0), gp_Dir(0.0, 0.0, 1.0)); + double anA, aB, aC, aD; + aPlane->Coefficients(anA, aB, aC, aD); + EXPECT_NEAR(anA, 0.0, Precision::Confusion()); + EXPECT_NEAR(aB, 0.0, Precision::Confusion()); + EXPECT_NEAR(aC, 1.0, Precision::Confusion()); + EXPECT_NEAR(aD, -5.0, Precision::Confusion()); +} + +TEST(Geom_PlaneTest, UIso) +{ + occ::handle aPlane = new Geom_Plane(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + occ::handle aUIso = aPlane->UIso(2.0); + ASSERT_FALSE(aUIso.IsNull()); + + // UIso at U=2 on XY plane should be a line at x=2, varying in Y + occ::handle aLine = occ::down_cast(aUIso); + ASSERT_FALSE(aLine.IsNull()); + + gp_Pnt aPnt; + aLine->D0(0.0, aPnt); + EXPECT_NEAR(aPnt.X(), 2.0, Precision::Confusion()); +} + +TEST(Geom_PlaneTest, VIso) +{ + occ::handle aPlane = new Geom_Plane(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + occ::handle aVIso = aPlane->VIso(3.0); + ASSERT_FALSE(aVIso.IsNull()); + + // VIso at V=3 on XY plane should be a line at y=3, varying in X + occ::handle aLine = occ::down_cast(aVIso); + ASSERT_FALSE(aLine.IsNull()); + + gp_Pnt aPnt; + aLine->D0(0.0, aPnt); + EXPECT_NEAR(aPnt.Y(), 3.0, Precision::Confusion()); +} + +TEST(Geom_PlaneTest, Transform) +{ + occ::handle aPlane = new Geom_Plane(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + gp_Trsf aTrsf; + aTrsf.SetTranslation(gp_Vec(0.0, 0.0, 10.0)); + aPlane->Transform(aTrsf); + EXPECT_NEAR(aPlane->Location().Z(), 10.0, Precision::Confusion()); +} + +TEST(Geom_PlaneTest, Copy) +{ + occ::handle aPlane = new Geom_Plane(gp_Pnt(1.0, 2.0, 3.0), gp_Dir(0.0, 0.0, 1.0)); + occ::handle aCopy = aPlane->Copy(); + ASSERT_FALSE(aCopy.IsNull()); + occ::handle aCopyPlane = occ::down_cast(aCopy); + ASSERT_FALSE(aCopyPlane.IsNull()); + EXPECT_TRUE(aCopyPlane->Location().IsEqual(gp_Pnt(1.0, 2.0, 3.0), Precision::Confusion())); +} diff --git a/src/ModelingData/TKGeomBase/GTests/FILES.cmake b/src/ModelingData/TKGeomBase/GTests/FILES.cmake index d7f8d2ea5b..9a075c7574 100644 --- a/src/ModelingData/TKGeomBase/GTests/FILES.cmake +++ b/src/ModelingData/TKGeomBase/GTests/FILES.cmake @@ -4,7 +4,9 @@ set(OCCT_TKGeomBase_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}") set(OCCT_TKGeomBase_GTests_FILES BndLib_Test.cxx Extrema_ExtPC_Test.cxx + GCPnts_AbscissaPoint_Test.cxx GeomConvert_CompCurveToBSplineCurve_Test.cxx + GeomConvert_Test.cxx Hermit_Test.cxx IntAna_IntQuadQuad_Test.cxx ) diff --git a/src/ModelingData/TKGeomBase/GTests/GCPnts_AbscissaPoint_Test.cxx b/src/ModelingData/TKGeomBase/GTests/GCPnts_AbscissaPoint_Test.cxx new file mode 100644 index 0000000000..9eba3a21fa --- /dev/null +++ b/src/ModelingData/TKGeomBase/GTests/GCPnts_AbscissaPoint_Test.cxx @@ -0,0 +1,80 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(GCPnts_AbscissaPointTest, LineLength) +{ + occ::handle aLine = new Geom_Line(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + GeomAdaptor_Curve anAdaptor(aLine, 0.0, 10.0); + + const double aLength = GCPnts_AbscissaPoint::Length(anAdaptor); + + EXPECT_NEAR(aLength, 10.0, Precision::Confusion()); +} + +TEST(GCPnts_AbscissaPointTest, CircleArcLength) +{ + occ::handle aCircle = + new Geom_Circle(gp_Ax2(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)), 1.0); + GeomAdaptor_Curve anAdaptor(aCircle, 0.0, M_PI); + + const double aLength = GCPnts_AbscissaPoint::Length(anAdaptor); + + EXPECT_NEAR(aLength, M_PI, Precision::Confusion()); +} + +TEST(GCPnts_AbscissaPointTest, FullCircleLength) +{ + occ::handle aCircle = + new Geom_Circle(gp_Ax2(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)), 5.0); + GeomAdaptor_Curve anAdaptor(aCircle, 0.0, 2.0 * M_PI); + + const double aLength = GCPnts_AbscissaPoint::Length(anAdaptor); + + EXPECT_NEAR(aLength, 2.0 * M_PI * 5.0, Precision::Confusion()); +} + +TEST(GCPnts_AbscissaPointTest, ParameterAtAbscissa_Line) +{ + occ::handle aLine = new Geom_Line(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + GeomAdaptor_Curve anAdaptor(aLine, 0.0, 10.0); + + GCPnts_AbscissaPoint anAbscissa(anAdaptor, 5.0, 0.0); + + ASSERT_TRUE(anAbscissa.IsDone()); + const double aParam = anAbscissa.Parameter(); + EXPECT_NEAR(aParam, 5.0, Precision::Confusion()); +} + +TEST(GCPnts_AbscissaPointTest, ParameterAtAbscissa_Circle) +{ + occ::handle aCircle = + new Geom_Circle(gp_Ax2(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)), 1.0); + GeomAdaptor_Curve anAdaptor(aCircle, 0.0, 2.0 * M_PI); + + GCPnts_AbscissaPoint anAbscissa(anAdaptor, M_PI / 2.0, 0.0); + + ASSERT_TRUE(anAbscissa.IsDone()); + const double aParam = anAbscissa.Parameter(); + EXPECT_NEAR(aParam, M_PI / 2.0, Precision::Confusion()); +} diff --git a/src/ModelingData/TKGeomBase/GTests/GeomConvert_Test.cxx b/src/ModelingData/TKGeomBase/GTests/GeomConvert_Test.cxx new file mode 100644 index 0000000000..26f98418e1 --- /dev/null +++ b/src/ModelingData/TKGeomBase/GTests/GeomConvert_Test.cxx @@ -0,0 +1,78 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +TEST(GeomConvertTest, CircleToBSpline) +{ + occ::handle aCircle = + new Geom_Circle(gp_Ax2(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)), 5.0); + + occ::handle aBSpline = GeomConvert::CurveToBSplineCurve(aCircle); + + ASSERT_FALSE(aBSpline.IsNull()); + + gp_Pnt aOrigPnt; + aCircle->D0(0.0, aOrigPnt); + gp_Pnt aBSplinePnt; + aBSpline->D0(0.0, aBSplinePnt); + + EXPECT_NEAR(aOrigPnt.Distance(aBSplinePnt), 0.0, Precision::Confusion()); +} + +TEST(GeomConvertTest, LineToBSpline) +{ + occ::handle aLine = new Geom_Line(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)); + occ::handle aTrimmed = new Geom_TrimmedCurve(aLine, 0.0, 10.0); + + occ::handle aBSpline = GeomConvert::CurveToBSplineCurve(aTrimmed); + + ASSERT_FALSE(aBSpline.IsNull()); + + gp_Pnt aPnt; + aBSpline->D0(5.0, aPnt); + const gp_Pnt anExpectedPnt(5.0, 0.0, 0.0); + + EXPECT_NEAR(aPnt.Distance(anExpectedPnt), 0.0, Precision::Confusion()); +} + +TEST(GeomConvertTest, PlaneToBSplineSurface) +{ + occ::handle aPlane = new Geom_Plane(gp::XOY()); + occ::handle aTrimmed = + new Geom_RectangularTrimmedSurface(aPlane, 0.0, 10.0, 0.0, 10.0); + + occ::handle aBSurf = GeomConvert::SurfaceToBSplineSurface(aTrimmed); + + ASSERT_FALSE(aBSurf.IsNull()); + + gp_Pnt aPnt; + aBSurf->D0(5.0, 5.0, aPnt); + const gp_Pnt anExpectedPnt(5.0, 5.0, 0.0); + + EXPECT_NEAR(aPnt.Distance(anExpectedPnt), 0.0, Precision::Confusion()); +} diff --git a/src/ModelingData/TKGeomBase/GTests/Hermit_Test.cxx b/src/ModelingData/TKGeomBase/GTests/Hermit_Test.cxx index 37f3d046e6..c3a924b258 100644 --- a/src/ModelingData/TKGeomBase/GTests/Hermit_Test.cxx +++ b/src/ModelingData/TKGeomBase/GTests/Hermit_Test.cxx @@ -24,9 +24,9 @@ // Helper to create a simple rational BSpline curve (degree 2, 3 poles) // with weights that produce distinct endpoint weight values. -static Handle(Geom_BSplineCurve) MakeRationalBSpline3D(const double theW1, - const double theW2, - const double theW3) +static occ::handle MakeRationalBSpline3D(const double theW1, + const double theW2, + const double theW3) { NCollection_Array1 aPoles(1, 3); aPoles(1) = gp_Pnt(0.0, 0.0, 0.0); @@ -50,9 +50,9 @@ static Handle(Geom_BSplineCurve) MakeRationalBSpline3D(const double theW1, } // Helper to create a simple rational BSpline 2D curve (degree 2, 3 poles). -static Handle(Geom2d_BSplineCurve) MakeRationalBSpline2D(const double theW1, - const double theW2, - const double theW3) +static occ::handle MakeRationalBSpline2D(const double theW1, + const double theW2, + const double theW3) { NCollection_Array1 aPoles(1, 3); aPoles(1) = gp_Pnt2d(0.0, 0.0); @@ -78,9 +78,9 @@ static Handle(Geom2d_BSplineCurve) MakeRationalBSpline2D(const double theW1, TEST(HermitTest, Solution3D_UniformWeights_ReturnsValidCurve) { // Uniform weights => weight function is constant 1.0 everywhere - Handle(Geom_BSplineCurve) aBS = MakeRationalBSpline3D(1.0, 1.0, 1.0); + occ::handle aBS = MakeRationalBSpline3D(1.0, 1.0, 1.0); - Handle(Geom2d_BSplineCurve) aResult = Hermit::Solution(aBS); + occ::handle aResult = Hermit::Solution(aBS); ASSERT_FALSE(aResult.IsNull()); EXPECT_GE(aResult->NbPoles(), 4); @@ -97,9 +97,9 @@ TEST(HermitTest, Solution3D_UniformWeights_ReturnsValidCurve) TEST(HermitTest, Solution3D_DistinctWeights_ReturnsValidCurve) { // Different weights at endpoints: w(0)=2, w(1)=3 - Handle(Geom_BSplineCurve) aBS = MakeRationalBSpline3D(2.0, 1.5, 3.0); + occ::handle aBS = MakeRationalBSpline3D(2.0, 1.5, 3.0); - Handle(Geom2d_BSplineCurve) aResult = Hermit::Solution(aBS); + occ::handle aResult = Hermit::Solution(aBS); ASSERT_FALSE(aResult.IsNull()); @@ -114,9 +114,9 @@ TEST(HermitTest, Solution3D_DistinctWeights_ReturnsValidCurve) TEST(HermitTest, Solution3D_HighWeightRatio_Endpoint) { // Large weight ratio: w(0) small, w(1) large - tests the Pole0 < Pole3 branch - Handle(Geom_BSplineCurve) aBS = MakeRationalBSpline3D(0.5, 1.0, 5.0); + occ::handle aBS = MakeRationalBSpline3D(0.5, 1.0, 5.0); - Handle(Geom2d_BSplineCurve) aResult = Hermit::Solution(aBS); + occ::handle aResult = Hermit::Solution(aBS); ASSERT_FALSE(aResult.IsNull()); @@ -131,9 +131,9 @@ TEST(HermitTest, Solution3D_HighWeightRatio_Endpoint) TEST(HermitTest, Solution3D_ReversedWeightRatio_Endpoint) { // Reversed ratio: w(0) large, w(1) small - tests the Pole0 > Pole3 branch - Handle(Geom_BSplineCurve) aBS = MakeRationalBSpline3D(5.0, 1.0, 0.5); + occ::handle aBS = MakeRationalBSpline3D(5.0, 1.0, 0.5); - Handle(Geom2d_BSplineCurve) aResult = Hermit::Solution(aBS); + occ::handle aResult = Hermit::Solution(aBS); ASSERT_FALSE(aResult.IsNull()); @@ -147,9 +147,9 @@ TEST(HermitTest, Solution3D_ReversedWeightRatio_Endpoint) TEST(HermitTest, Solution3D_PositivePoles) { // The result curve should have all positive Y coordinates (positive denominator) - Handle(Geom_BSplineCurve) aBS = MakeRationalBSpline3D(2.0, 3.0, 1.5); + occ::handle aBS = MakeRationalBSpline3D(2.0, 3.0, 1.5); - Handle(Geom2d_BSplineCurve) aResult = Hermit::Solution(aBS); + occ::handle aResult = Hermit::Solution(aBS); ASSERT_FALSE(aResult.IsNull()); for (int i = 1; i <= aResult->NbPoles(); ++i) @@ -160,9 +160,9 @@ TEST(HermitTest, Solution3D_PositivePoles) TEST(HermitTest, Solution2D_UniformWeights_ReturnsValidCurve) { - Handle(Geom2d_BSplineCurve) aBS = MakeRationalBSpline2D(1.0, 1.0, 1.0); + occ::handle aBS = MakeRationalBSpline2D(1.0, 1.0, 1.0); - Handle(Geom2d_BSplineCurve) aResult = Hermit::Solution(aBS); + occ::handle aResult = Hermit::Solution(aBS); ASSERT_FALSE(aResult.IsNull()); @@ -175,9 +175,9 @@ TEST(HermitTest, Solution2D_UniformWeights_ReturnsValidCurve) TEST(HermitTest, Solution2D_DistinctWeights_ReturnsValidCurve) { - Handle(Geom2d_BSplineCurve) aBS = MakeRationalBSpline2D(2.0, 1.5, 3.0); + occ::handle aBS = MakeRationalBSpline2D(2.0, 1.5, 3.0); - Handle(Geom2d_BSplineCurve) aResult = Hermit::Solution(aBS); + occ::handle aResult = Hermit::Solution(aBS); ASSERT_FALSE(aResult.IsNull()); @@ -191,9 +191,9 @@ TEST(HermitTest, Solution2D_DistinctWeights_ReturnsValidCurve) TEST(HermitTest, Solution2D_HighWeightRatio_Endpoint) { // Large ratio tests the Pole0 < Pole3 branch in 2D PolyTest - Handle(Geom2d_BSplineCurve) aBS = MakeRationalBSpline2D(0.5, 1.0, 5.0); + occ::handle aBS = MakeRationalBSpline2D(0.5, 1.0, 5.0); - Handle(Geom2d_BSplineCurve) aResult = Hermit::Solution(aBS); + occ::handle aResult = Hermit::Solution(aBS); ASSERT_FALSE(aResult.IsNull()); @@ -206,7 +206,7 @@ TEST(HermitTest, Solution2D_HighWeightRatio_Endpoint) TEST(HermitTest, Solutionbis_UniformWeights_KnotsUnchanged) { - Handle(Geom_BSplineCurve) aBS = MakeRationalBSpline3D(1.0, 1.0, 1.0); + occ::handle aBS = MakeRationalBSpline3D(1.0, 1.0, 1.0); double aKnotmin = 0.0; double aKnotmax = 1.0; @@ -222,7 +222,7 @@ TEST(HermitTest, Solutionbis_UniformWeights_KnotsUnchanged) TEST(HermitTest, Solutionbis_DistinctWeights_ReturnsValidKnots) { - Handle(Geom_BSplineCurve) aBS = MakeRationalBSpline3D(2.0, 1.5, 3.0); + occ::handle aBS = MakeRationalBSpline3D(2.0, 1.5, 3.0); double aKnotmin = 0.0; double aKnotmax = 1.0; @@ -237,9 +237,9 @@ TEST(HermitTest, Solutionbis_DistinctWeights_ReturnsValidKnots) TEST(HermitTest, Solution3D_Symmetric_WeightsProduceSymmetricResult) { // Symmetric weights: w(0) == w(1), so a(0) == a(1) - Handle(Geom_BSplineCurve) aBS = MakeRationalBSpline3D(2.0, 1.0, 2.0); + occ::handle aBS = MakeRationalBSpline3D(2.0, 1.0, 2.0); - Handle(Geom2d_BSplineCurve) aResult = Hermit::Solution(aBS); + occ::handle aResult = Hermit::Solution(aBS); ASSERT_FALSE(aResult.IsNull());