]> OCCT Git - occt.git/commitdiff
Modeling - ElCLib Optimization and testing #471
authorPasukhin Dmitry <dpasukhi@opencascade.com>
Mon, 31 Mar 2025 11:55:04 +0000 (12:55 +0100)
committerGitHub <noreply@github.com>
Mon, 31 Mar 2025 11:55:04 +0000 (12:55 +0100)
- Created a new test file ElCLib_Test.cxx to implement unit tests for various functions in the ElCLib class.
- Added tests for InPeriod, AdjustPeriodic, Line3D, Circle3D, Ellipse3D, Hyperbola3D, Parabola3D, and To3dConversion methods.
- Improved performance for the ElCLib methods

src/FoundationClasses/TKMath/ElCLib/ElCLib.cxx
src/FoundationClasses/TKMath/GTests/ElCLib_Test.cxx [new file with mode: 0644]
src/FoundationClasses/TKMath/GTests/FILES.cmake

index e77cd827fd58d5fc66f827e831ef9bac195c2d87..b959ae1a2f491c0e743f9903273ab9335f416eb3 100644 (file)
 #include <gp_Vec.hxx>
 #include <gp_Vec2d.hxx>
 
-static Standard_Real PIPI = M_PI + M_PI;
+namespace
+{
+static constexpr Standard_Real PIPI = M_PI + M_PI;
+}
 
 //=======================================================================
 // function : InPeriod
@@ -78,7 +81,9 @@ Standard_Real ElCLib::InPeriod(const Standard_Real theU,
   const Standard_Real aPeriod = theULast - theUFirst;
 
   if (aPeriod < Epsilon(theULast))
+  {
     return theU;
+  }
 
   return Max(theUFirst, theU + aPeriod * Ceiling((theUFirst - theU) / aPeriod));
 }
@@ -98,9 +103,9 @@ void ElCLib::AdjustPeriodic(const Standard_Real UFirst,
     return;
   }
 
-  Standard_Real period = ULast - UFirst;
+  const Standard_Real aPeriod = ULast - UFirst;
 
-  if (period < Epsilon(ULast))
+  if (aPeriod < Epsilon(ULast))
   {
     // In order to avoid FLT_Overflow exception
     // (test bugs moddata_1 bug22757)
@@ -109,12 +114,16 @@ void ElCLib::AdjustPeriodic(const Standard_Real UFirst,
     return;
   }
 
-  U1 -= Floor((U1 - UFirst) / period) * period;
+  U1 -= Floor((U1 - UFirst) / aPeriod) * aPeriod;
   if (ULast - U1 < Preci)
-    U1 -= period;
-  U2 -= Floor((U2 - U1) / period) * period;
+  {
+    U1 -= aPeriod;
+  }
+  U2 -= Floor((U2 - U1) / aPeriod) * aPeriod;
   if (U2 - U1 < Preci)
-    U2 += period;
+  {
+    U2 += aPeriod;
+  }
 }
 
 //=================================================================================================
@@ -130,11 +139,11 @@ gp_Pnt ElCLib::LineValue(const Standard_Real U, const gp_Ax1& Pos)
 
 gp_Pnt ElCLib::CircleValue(const Standard_Real U, const gp_Ax2& Pos, const Standard_Real Radius)
 {
-  const gp_XYZ& XDir = Pos.XDirection().XYZ();
-  const gp_XYZ& YDir = Pos.YDirection().XYZ();
-  const gp_XYZ& PLoc = Pos.Location().XYZ();
-  Standard_Real A1   = Radius * cos(U);
-  Standard_Real A2   = Radius * sin(U);
+  const gp_XYZ&       XDir = Pos.XDirection().XYZ();
+  const gp_XYZ&       YDir = Pos.YDirection().XYZ();
+  const gp_XYZ&       PLoc = Pos.Location().XYZ();
+  const Standard_Real A1   = Radius * cos(U);
+  const Standard_Real A2   = Radius * sin(U);
   return gp_Pnt(A1 * XDir.X() + A2 * YDir.X() + PLoc.X(),
                 A1 * XDir.Y() + A2 * YDir.Y() + PLoc.Y(),
                 A1 * XDir.Z() + A2 * YDir.Z() + PLoc.Z());
@@ -147,11 +156,11 @@ gp_Pnt ElCLib::EllipseValue(const Standard_Real U,
                             const Standard_Real MajorRadius,
                             const Standard_Real MinorRadius)
 {
-  const gp_XYZ& XDir = Pos.XDirection().XYZ();
-  const gp_XYZ& YDir = Pos.YDirection().XYZ();
-  const gp_XYZ& PLoc = Pos.Location().XYZ();
-  Standard_Real A1   = MajorRadius * cos(U);
-  Standard_Real A2   = MinorRadius * sin(U);
+  const gp_XYZ&       XDir = Pos.XDirection().XYZ();
+  const gp_XYZ&       YDir = Pos.YDirection().XYZ();
+  const gp_XYZ&       PLoc = Pos.Location().XYZ();
+  const Standard_Real A1   = MajorRadius * cos(U);
+  const Standard_Real A2   = MinorRadius * sin(U);
   return gp_Pnt(A1 * XDir.X() + A2 * YDir.X() + PLoc.X(),
                 A1 * XDir.Y() + A2 * YDir.Y() + PLoc.Y(),
                 A1 * XDir.Z() + A2 * YDir.Z() + PLoc.Z());
@@ -164,11 +173,11 @@ gp_Pnt ElCLib::HyperbolaValue(const Standard_Real U,
                               const Standard_Real MajorRadius,
                               const Standard_Real MinorRadius)
 {
-  const gp_XYZ& XDir = Pos.XDirection().XYZ();
-  const gp_XYZ& YDir = Pos.YDirection().XYZ();
-  const gp_XYZ& PLoc = Pos.Location().XYZ();
-  Standard_Real A1   = MajorRadius * Cosh(U);
-  Standard_Real A2   = MinorRadius * Sinh(U);
+  const gp_XYZ&       XDir = Pos.XDirection().XYZ();
+  const gp_XYZ&       YDir = Pos.YDirection().XYZ();
+  const gp_XYZ&       PLoc = Pos.Location().XYZ();
+  const Standard_Real A1   = MajorRadius * Cosh(U);
+  const Standard_Real A2   = MinorRadius * Sinh(U);
   return gp_Pnt(A1 * XDir.X() + A2 * YDir.X() + PLoc.X(),
                 A1 * XDir.Y() + A2 * YDir.Y() + PLoc.Y(),
                 A1 * XDir.Z() + A2 * YDir.Z() + PLoc.Z());
@@ -184,10 +193,10 @@ gp_Pnt ElCLib::ParabolaValue(const Standard_Real U, const gp_Ax2& Pos, const Sta
     const gp_XYZ& PLoc = Pos.Location().XYZ();
     return gp_Pnt(U * XDir.X() + PLoc.X(), U * XDir.Y() + PLoc.Y(), U * XDir.Z() + PLoc.Z());
   }
-  const gp_XYZ& XDir = Pos.XDirection().XYZ();
-  const gp_XYZ& YDir = Pos.YDirection().XYZ();
-  const gp_XYZ& PLoc = Pos.Location().XYZ();
-  Standard_Real A1   = U * U / (4.0 * Focal);
+  const gp_XYZ&       XDir = Pos.XDirection().XYZ();
+  const gp_XYZ&       YDir = Pos.YDirection().XYZ();
+  const gp_XYZ&       PLoc = Pos.Location().XYZ();
+  const Standard_Real A1   = U * U / (4.0 * Focal);
   return gp_Pnt(A1 * XDir.X() + U * YDir.X() + PLoc.X(),
                 A1 * XDir.Y() + U * YDir.Y() + PLoc.Y(),
                 A1 * XDir.Z() + U * YDir.Z() + PLoc.Z());
@@ -211,11 +220,11 @@ void ElCLib::CircleD1(const Standard_Real U,
                       gp_Pnt&             P,
                       gp_Vec&             V1)
 {
-  Standard_Real Xc = Radius * Cos(U);
-  Standard_Real Yc = Radius * Sin(U);
-  gp_XYZ        Coord0;
-  gp_XYZ        Coord1(Pos.XDirection().XYZ());
-  gp_XYZ        Coord2(Pos.YDirection().XYZ());
+  const Standard_Real Xc = Radius * Cos(U);
+  const Standard_Real Yc = Radius * Sin(U);
+  const gp_XYZ&       Coord1(Pos.XDirection().XYZ());
+  const gp_XYZ&       Coord2(Pos.YDirection().XYZ());
+  gp_XYZ              Coord0;
   // Point courant :
   Coord0.SetLinearForm(Xc, Coord1, Yc, Coord2, Pos.Location().XYZ());
   P.SetXYZ(Coord0);
@@ -233,11 +242,11 @@ void ElCLib::EllipseD1(const Standard_Real U,
                        gp_Pnt&             P,
                        gp_Vec&             V1)
 {
-  Standard_Real Xc = Cos(U);
-  Standard_Real Yc = Sin(U);
-  gp_XYZ        Coord0;
-  gp_XYZ        Coord1(Pos.XDirection().XYZ());
-  gp_XYZ        Coord2(Pos.YDirection().XYZ());
+  const Standard_Real Xc = Cos(U);
+  const Standard_Real Yc = Sin(U);
+  const gp_XYZ&       Coord1(Pos.XDirection().XYZ());
+  const gp_XYZ&       Coord2(Pos.YDirection().XYZ());
+  gp_XYZ              Coord0;
   // Point courant :
   Coord0.SetLinearForm(Xc * MajorRadius, Coord1, Yc * MinorRadius, Coord2, Pos.Location().XYZ());
   P.SetXYZ(Coord0);
@@ -255,11 +264,11 @@ void ElCLib::HyperbolaD1(const Standard_Real U,
                          gp_Pnt&             P,
                          gp_Vec&             V1)
 {
-  Standard_Real Xc = Cosh(U);
-  Standard_Real Yc = Sinh(U);
-  gp_XYZ        Coord0;
-  gp_XYZ        Coord1(Pos.XDirection().XYZ());
-  gp_XYZ        Coord2(Pos.YDirection().XYZ());
+  const Standard_Real Xc = Cosh(U);
+  const Standard_Real Yc = Sinh(U);
+  const gp_XYZ&       Coord1(Pos.XDirection().XYZ());
+  const gp_XYZ&       Coord2(Pos.YDirection().XYZ());
+  gp_XYZ              Coord0;
   // Point courant :
   Coord0.SetLinearForm(Xc * MajorRadius, Coord1, Yc * MinorRadius, Coord2, Pos.Location().XYZ());
   P.SetXYZ(Coord0);
@@ -276,7 +285,6 @@ void ElCLib::ParabolaD1(const Standard_Real U,
                         gp_Pnt&             P,
                         gp_Vec&             V1)
 {
-  gp_XYZ Coord0;
   gp_XYZ Coord1(Pos.XDirection().XYZ());
   if (Focal == 0.0)
   { // Parabole degenere en une droite
@@ -287,7 +295,8 @@ void ElCLib::ParabolaD1(const Standard_Real U,
   }
   else
   {
-    gp_XYZ Coord2(Pos.YDirection().XYZ());
+    gp_XYZ        Coord0;
+    const gp_XYZ& Coord2(Pos.YDirection().XYZ());
     Coord0.SetLinearForm(U / (2.0 * Focal), Coord1, Coord2);
     V1.SetXYZ(Coord0);
     Coord0.SetLinearForm((U * U) / (4.0 * Focal), Coord1, U, Coord2, Pos.Location().XYZ());
@@ -304,11 +313,11 @@ void ElCLib::CircleD2(const Standard_Real U,
                       gp_Vec&             V1,
                       gp_Vec&             V2)
 {
-  Standard_Real Xc = Radius * cos(U);
-  Standard_Real Yc = Radius * sin(U);
-  gp_XYZ        Coord0;
-  gp_XYZ        Coord1(Pos.XDirection().XYZ());
-  gp_XYZ        Coord2(Pos.YDirection().XYZ());
+  const Standard_Real Xc = Radius * cos(U);
+  const Standard_Real Yc = Radius * sin(U);
+  const gp_XYZ&       Coord1(Pos.XDirection().XYZ());
+  const gp_XYZ&       Coord2(Pos.YDirection().XYZ());
+  gp_XYZ              Coord0;
   // Point courant :
   Coord0.SetLinearForm(Xc, Coord1, Yc, Coord2, Pos.Location().XYZ());
   P.SetXYZ(Coord0);
@@ -330,11 +339,11 @@ void ElCLib::EllipseD2(const Standard_Real U,
                        gp_Vec&             V1,
                        gp_Vec&             V2)
 {
-  Standard_Real Xc = cos(U);
-  Standard_Real Yc = sin(U);
-  gp_XYZ        Coord0;
-  gp_XYZ        Coord1(Pos.XDirection().XYZ());
-  gp_XYZ        Coord2(Pos.YDirection().XYZ());
+  const Standard_Real Xc = cos(U);
+  const Standard_Real Yc = sin(U);
+  const gp_XYZ&       Coord1(Pos.XDirection().XYZ());
+  const gp_XYZ&       Coord2(Pos.YDirection().XYZ());
+  gp_XYZ              Coord0;
   // Point courant :
   Coord0.SetLinearForm(Xc * MajorRadius, Coord1, Yc * MinorRadius, Coord2, Pos.Location().XYZ());
   P.SetXYZ(Coord0);
@@ -356,11 +365,11 @@ void ElCLib::HyperbolaD2(const Standard_Real U,
                          gp_Vec&             V1,
                          gp_Vec&             V2)
 {
-  Standard_Real Xc = Cosh(U);
-  Standard_Real Yc = Sinh(U);
-  gp_XYZ        Coord0;
-  gp_XYZ        Coord1(Pos.XDirection().XYZ());
-  gp_XYZ        Coord2(Pos.YDirection().XYZ());
+  const Standard_Real Xc = Cosh(U);
+  const Standard_Real Yc = Sinh(U);
+  const gp_XYZ&       Coord1(Pos.XDirection().XYZ());
+  const gp_XYZ&       Coord2(Pos.YDirection().XYZ());
+  gp_XYZ              Coord0;
 
   // Point courant et D2:
   Coord0.SetLinearForm(Xc * MajorRadius, Coord1, Yc * MinorRadius, Coord2);
@@ -381,7 +390,6 @@ void ElCLib::ParabolaD2(const Standard_Real U,
                         gp_Vec&             V1,
                         gp_Vec&             V2)
 {
-  gp_XYZ Coord0(0.0, 0.0, 0.0);
   gp_XYZ Coord1(Pos.XDirection().XYZ());
   if (Focal == 0.0)
   {
@@ -393,7 +401,8 @@ void ElCLib::ParabolaD2(const Standard_Real U,
   }
   else
   {
-    gp_XYZ Coord2(Pos.YDirection().XYZ());
+    gp_XYZ        Coord0;
+    const gp_XYZ& Coord2(Pos.YDirection().XYZ());
     Coord0.SetLinearForm((U * U) / (4.0 * Focal), Coord1, U, Coord2, Pos.Location().XYZ());
     P.SetXYZ(Coord0);
     Coord0.SetLinearForm(U / (2.0 * Focal), Coord1, Coord2);
@@ -413,11 +422,11 @@ void ElCLib::CircleD3(const Standard_Real U,
                       gp_Vec&             V2,
                       gp_Vec&             V3)
 {
-  Standard_Real Xc = Radius * cos(U);
-  Standard_Real Yc = Radius * sin(U);
-  gp_XYZ        Coord0;
-  gp_XYZ        Coord1(Pos.XDirection().XYZ());
-  gp_XYZ        Coord2(Pos.YDirection().XYZ());
+  const Standard_Real Xc = Radius * cos(U);
+  const Standard_Real Yc = Radius * sin(U);
+  const gp_XYZ&       Coord1(Pos.XDirection().XYZ());
+  const gp_XYZ&       Coord2(Pos.YDirection().XYZ());
+  gp_XYZ              Coord0;
   // Point Courant :
   Coord0.SetLinearForm(Xc, Coord1, Yc, Coord2, Pos.Location().XYZ());
   P.SetXYZ(Coord0);
@@ -443,11 +452,11 @@ void ElCLib::EllipseD3(const Standard_Real U,
                        gp_Vec&             V2,
                        gp_Vec&             V3)
 {
-  Standard_Real Xc = cos(U);
-  Standard_Real Yc = sin(U);
-  gp_XYZ        Coord0;
-  gp_XYZ        Coord1(Pos.XDirection().XYZ());
-  gp_XYZ        Coord2(Pos.YDirection().XYZ());
+  const Standard_Real Xc = cos(U);
+  const Standard_Real Yc = sin(U);
+  const gp_XYZ&       Coord1(Pos.XDirection().XYZ());
+  const gp_XYZ&       Coord2(Pos.YDirection().XYZ());
+  gp_XYZ              Coord0;
   // Point Courant :
   Coord0.SetLinearForm(Xc * MajorRadius, Coord1, Yc * MinorRadius, Coord2, Pos.Location().XYZ());
   P.SetXYZ(Coord0);
@@ -473,11 +482,11 @@ void ElCLib::HyperbolaD3(const Standard_Real U,
                          gp_Vec&             V2,
                          gp_Vec&             V3)
 {
-  Standard_Real Xc = Cosh(U);
-  Standard_Real Yc = Sinh(U);
-  gp_XYZ        Coord0;
-  gp_XYZ        Coord1(Pos.XDirection().XYZ());
-  gp_XYZ        Coord2(Pos.YDirection().XYZ());
+  const Standard_Real Xc = Cosh(U);
+  const Standard_Real Yc = Sinh(U);
+  const gp_XYZ&       Coord1(Pos.XDirection().XYZ());
+  const gp_XYZ&       Coord2(Pos.YDirection().XYZ());
+  gp_XYZ              Coord0;
   // Point courant et D2 :
   Coord0.SetLinearForm(Xc * MajorRadius, Coord1, Yc * MinorRadius, Coord2);
   V2.SetXYZ(Coord0);
@@ -502,11 +511,11 @@ gp_Pnt2d ElCLib::LineValue(const Standard_Real U, const gp_Ax2d& Pos)
 
 gp_Pnt2d ElCLib::CircleValue(const Standard_Real U, const gp_Ax22d& Pos, const Standard_Real Radius)
 {
-  const gp_XY&  XDir = Pos.XDirection().XY();
-  const gp_XY&  YDir = Pos.YDirection().XY();
-  const gp_XY&  PLoc = Pos.Location().XY();
-  Standard_Real A1   = Radius * cos(U);
-  Standard_Real A2   = Radius * sin(U);
+  const gp_XY&        XDir = Pos.XDirection().XY();
+  const gp_XY&        YDir = Pos.YDirection().XY();
+  const gp_XY&        PLoc = Pos.Location().XY();
+  const Standard_Real A1   = Radius * cos(U);
+  const Standard_Real A2   = Radius * sin(U);
   return gp_Pnt2d(A1 * XDir.X() + A2 * YDir.X() + PLoc.X(),
                   A1 * XDir.Y() + A2 * YDir.Y() + PLoc.Y());
 }
@@ -518,11 +527,11 @@ gp_Pnt2d ElCLib::EllipseValue(const Standard_Real U,
                               const Standard_Real MajorRadius,
                               const Standard_Real MinorRadius)
 {
-  const gp_XY&  XDir = Pos.XDirection().XY();
-  const gp_XY&  YDir = Pos.YDirection().XY();
-  const gp_XY&  PLoc = Pos.Location().XY();
-  Standard_Real A1   = MajorRadius * cos(U);
-  Standard_Real A2   = MinorRadius * sin(U);
+  const gp_XY&        XDir = Pos.XDirection().XY();
+  const gp_XY&        YDir = Pos.YDirection().XY();
+  const gp_XY&        PLoc = Pos.Location().XY();
+  const Standard_Real A1   = MajorRadius * cos(U);
+  const Standard_Real A2   = MinorRadius * sin(U);
   return gp_Pnt2d(A1 * XDir.X() + A2 * YDir.X() + PLoc.X(),
                   A1 * XDir.Y() + A2 * YDir.Y() + PLoc.Y());
 }
@@ -534,11 +543,11 @@ gp_Pnt2d ElCLib::HyperbolaValue(const Standard_Real U,
                                 const Standard_Real MajorRadius,
                                 const Standard_Real MinorRadius)
 {
-  const gp_XY&  XDir = Pos.XDirection().XY();
-  const gp_XY&  YDir = Pos.YDirection().XY();
-  const gp_XY&  PLoc = Pos.Location().XY();
-  Standard_Real A1   = MajorRadius * Cosh(U);
-  Standard_Real A2   = MinorRadius * Sinh(U);
+  const gp_XY&        XDir = Pos.XDirection().XY();
+  const gp_XY&        YDir = Pos.YDirection().XY();
+  const gp_XY&        PLoc = Pos.Location().XY();
+  const Standard_Real A1   = MajorRadius * Cosh(U);
+  const Standard_Real A2   = MinorRadius * Sinh(U);
   return gp_Pnt2d(A1 * XDir.X() + A2 * YDir.X() + PLoc.X(),
                   A1 * XDir.Y() + A2 * YDir.Y() + PLoc.Y());
 }
@@ -555,10 +564,10 @@ gp_Pnt2d ElCLib::ParabolaValue(const Standard_Real U,
     const gp_XY& PLoc = Pos.Location().XY();
     return gp_Pnt2d(U * XDir.X() + PLoc.X(), U * XDir.Y() + PLoc.Y());
   }
-  const gp_XY&  XDir = Pos.XDirection().XY();
-  const gp_XY&  YDir = Pos.YDirection().XY();
-  const gp_XY&  PLoc = Pos.Location().XY();
-  Standard_Real A1   = U * U / (4.0 * Focal);
+  const gp_XY&        XDir = Pos.XDirection().XY();
+  const gp_XY&        YDir = Pos.YDirection().XY();
+  const gp_XY&        PLoc = Pos.Location().XY();
+  const Standard_Real A1   = U * U / (4.0 * Focal);
   return gp_Pnt2d(A1 * XDir.X() + U * YDir.X() + PLoc.X(), A1 * XDir.Y() + U * YDir.Y() + PLoc.Y());
 }
 
@@ -580,11 +589,11 @@ void ElCLib::CircleD1(const Standard_Real U,
                       gp_Pnt2d&           P,
                       gp_Vec2d&           V1)
 {
-  gp_XY         Vxy;
-  gp_XY         Xdir(Pos.XDirection().XY());
-  gp_XY         Ydir(Pos.YDirection().XY());
-  Standard_Real Xc = Radius * cos(U);
-  Standard_Real Yc = Radius * sin(U);
+  const Standard_Real Xc = Radius * cos(U);
+  const Standard_Real Yc = Radius * sin(U);
+  const gp_XY&        Xdir(Pos.XDirection().XY());
+  const gp_XY&        Ydir(Pos.YDirection().XY());
+  gp_XY               Vxy;
   // Point courant :
   Vxy.SetLinearForm(Xc, Xdir, Yc, Ydir, Pos.Location().XY());
   P.SetXY(Vxy);
@@ -602,11 +611,11 @@ void ElCLib::EllipseD1(const Standard_Real U,
                        gp_Pnt2d&           P,
                        gp_Vec2d&           V1)
 {
-  gp_XY         Vxy;
-  gp_XY         Xdir((Pos.XDirection()).XY());
-  gp_XY         Ydir((Pos.YDirection()).XY());
-  Standard_Real Xc = cos(U);
-  Standard_Real Yc = sin(U);
+  const Standard_Real Xc = cos(U);
+  const Standard_Real Yc = sin(U);
+  const gp_XY&        Xdir((Pos.XDirection()).XY());
+  const gp_XY&        Ydir((Pos.YDirection()).XY());
+  gp_XY               Vxy;
   // Point courant :
   Vxy.SetLinearForm(Xc * MajorRadius, Xdir, Yc * MinorRadius, Ydir, Pos.Location().XY());
   P.SetXY(Vxy);
@@ -625,11 +634,11 @@ void ElCLib::HyperbolaD1(const Standard_Real U,
                          gp_Pnt2d&           P,
                          gp_Vec2d&           V1)
 {
-  gp_XY         Vxy;
-  gp_XY         Xdir((Pos.XDirection()).XY());
-  gp_XY         Ydir((Pos.YDirection()).XY());
-  Standard_Real Xc = Cosh(U);
-  Standard_Real Yc = Sinh(U);
+  const Standard_Real Xc = Cosh(U);
+  const Standard_Real Yc = Sinh(U);
+  const gp_XY&        Xdir((Pos.XDirection()).XY());
+  const gp_XY&        Ydir((Pos.YDirection()).XY());
+  gp_XY               Vxy;
   // Point courant :
   Vxy.SetLinearForm(Xc * MajorRadius, Xdir, Yc * MinorRadius, Ydir, Pos.Location().XY());
   P.SetXY(Vxy);
@@ -647,8 +656,8 @@ void ElCLib::ParabolaD1(const Standard_Real U,
                         gp_Pnt2d&           P,
                         gp_Vec2d&           V1)
 {
-  gp_XY Vxy;
-  gp_XY Xdir(Pos.XDirection().XY());
+  gp_XY        Vxy;
+  const gp_XY& Xdir(Pos.XDirection().XY());
   if (Focal == 0.0)
   { // Parabole degenere en une droite
     V1.SetXY(Xdir);
@@ -656,7 +665,7 @@ void ElCLib::ParabolaD1(const Standard_Real U,
   }
   else
   {
-    gp_XY Ydir(Pos.YDirection().XY());
+    const gp_XY& Ydir(Pos.YDirection().XY());
     Vxy.SetLinearForm(U / (2.0 * Focal), Xdir, Ydir);
     V1.SetXY(Vxy);
     Vxy.SetLinearForm((U * U) / (4.0 * Focal), Xdir, U, Ydir, Pos.Location().XY());
@@ -673,11 +682,11 @@ void ElCLib::CircleD2(const Standard_Real U,
                       gp_Vec2d&           V1,
                       gp_Vec2d&           V2)
 {
-  gp_XY         Vxy;
-  gp_XY         Xdir(Pos.XDirection().XY());
-  gp_XY         Ydir(Pos.YDirection().XY());
-  Standard_Real Xc = Radius * cos(U);
-  Standard_Real Yc = Radius * sin(U);
+  const gp_XY&        Xdir(Pos.XDirection().XY());
+  const gp_XY&        Ydir(Pos.YDirection().XY());
+  const Standard_Real Xc = Radius * cos(U);
+  const Standard_Real Yc = Radius * sin(U);
+  gp_XY               Vxy;
   // V2 :
   Vxy.SetLinearForm(Xc, Xdir, Yc, Ydir);
   V2.SetXY(Vxy);
@@ -700,11 +709,11 @@ void ElCLib::EllipseD2(const Standard_Real U,
                        gp_Vec2d&           V1,
                        gp_Vec2d&           V2)
 {
-  gp_XY         Vxy;
-  gp_XY         Xdir(Pos.XDirection().XY());
-  gp_XY         Ydir(Pos.YDirection().XY());
-  Standard_Real Xc = cos(U);
-  Standard_Real Yc = sin(U);
+  const gp_XY&        Xdir(Pos.XDirection().XY());
+  const gp_XY&        Ydir(Pos.YDirection().XY());
+  const Standard_Real Xc = cos(U);
+  const Standard_Real Yc = sin(U);
+  gp_XY               Vxy;
 
   // V2 :
   Vxy.SetLinearForm(Xc * MajorRadius, Xdir, Yc * MinorRadius, Ydir);
@@ -730,11 +739,11 @@ void ElCLib::HyperbolaD2(const Standard_Real U,
                          gp_Vec2d&           V1,
                          gp_Vec2d&           V2)
 {
-  gp_XY         Vxy;
-  gp_XY         Xdir(Pos.XDirection().XY());
-  gp_XY         Ydir(Pos.YDirection().XY());
-  Standard_Real Xc = Cosh(U);
-  Standard_Real Yc = Sinh(U);
+  const gp_XY&        Xdir(Pos.XDirection().XY());
+  const gp_XY&        Ydir(Pos.YDirection().XY());
+  const Standard_Real Xc = Cosh(U);
+  const Standard_Real Yc = Sinh(U);
+  gp_XY               Vxy;
 
   // V2 :
   Vxy.SetLinearForm(Xc * MajorRadius, Xdir, Yc * MinorRadius, Ydir);
@@ -758,8 +767,8 @@ void ElCLib::ParabolaD2(const Standard_Real U,
                         gp_Vec2d&           V1,
                         gp_Vec2d&           V2)
 {
-  gp_XY Vxy;
-  gp_XY Xdir(Pos.XDirection().XY());
+  gp_XY        Vxy;
+  const gp_XY& Xdir(Pos.XDirection().XY());
   if (Focal == 0.0)
   {
     V2.SetCoord(0.0, 0.0);
@@ -768,7 +777,7 @@ void ElCLib::ParabolaD2(const Standard_Real U,
   }
   else
   {
-    gp_XY Ydir(Pos.YDirection().XY());
+    const gp_XY& Ydir(Pos.YDirection().XY());
     Vxy = Xdir.Multiplied(1.0 / (2.0 * Focal));
     V2.SetXY(Vxy);
     Vxy.SetLinearForm(U, Vxy, Ydir);
@@ -789,11 +798,11 @@ void ElCLib::CircleD3(const Standard_Real U,
                       gp_Vec2d&           V2,
                       gp_Vec2d&           V3)
 {
-  gp_XY         Vxy;
-  gp_XY         Xdir(Pos.XDirection().XY());
-  gp_XY         Ydir(Pos.YDirection().XY());
-  Standard_Real Xc = Radius * cos(U);
-  Standard_Real Yc = Radius * sin(U);
+  gp_XY               Vxy;
+  const gp_XY&        Xdir(Pos.XDirection().XY());
+  const gp_XY&        Ydir(Pos.YDirection().XY());
+  const Standard_Real Xc = Radius * cos(U);
+  const Standard_Real Yc = Radius * sin(U);
 
   // V2 :
   Vxy.SetLinearForm(Xc, Xdir, Yc, Ydir);
@@ -824,11 +833,11 @@ void ElCLib::EllipseD3(const Standard_Real U,
                        gp_Vec2d&           V2,
                        gp_Vec2d&           V3)
 {
-  gp_XY         Vxy;
-  gp_XY         Xdir(Pos.XDirection().XY());
-  gp_XY         Ydir(Pos.YDirection().XY());
-  Standard_Real Xc = cos(U);
-  Standard_Real Yc = sin(U);
+  const gp_XY&        Xdir(Pos.XDirection().XY());
+  const gp_XY&        Ydir(Pos.YDirection().XY());
+  const Standard_Real Xc = cos(U);
+  const Standard_Real Yc = sin(U);
+  gp_XY               Vxy;
 
   // V2 :
   Vxy.SetLinearForm(Xc * MajorRadius, Xdir, Yc * MinorRadius, Ydir);
@@ -859,11 +868,11 @@ void ElCLib::HyperbolaD3(const Standard_Real U,
                          gp_Vec2d&           V2,
                          gp_Vec2d&           V3)
 {
-  gp_XY         Vxy;
-  gp_XY         Xdir(Pos.XDirection().XY());
-  gp_XY         Ydir(Pos.YDirection().XY());
-  Standard_Real Xc = Cosh(U);
-  Standard_Real Yc = Sinh(U);
+  const gp_XY&        Xdir(Pos.XDirection().XY());
+  const gp_XY&        Ydir(Pos.YDirection().XY());
+  const Standard_Real Xc = Cosh(U);
+  const Standard_Real Yc = Sinh(U);
+  gp_XY               Vxy;
 
   // V2 :
   Vxy.SetLinearForm(Xc * MajorRadius, Xdir, Yc * MinorRadius, Ydir);
@@ -1000,35 +1009,29 @@ gp_Vec ElCLib::ParabolaDN(const Standard_Real    U,
                           const Standard_Real    Focal,
                           const Standard_Integer N)
 {
-  if (N <= 2)
+  if (N > 2 || N <= 0)
   {
-    gp_XYZ Coord1(Pos.XDirection().XYZ());
-    if (N == 1)
-    {
-      if (Focal == 0.0)
-      {
-        return gp_Vec(Coord1);
-      }
-      else
-      {
-        Coord1.SetLinearForm(U / (2.0 * Focal), Coord1, Pos.YDirection().XYZ());
-        return gp_Vec(Coord1);
-      }
-    }
-    else if (N == 2)
+    return gp_Vec(0., 0., 0.);
+  }
+
+  gp_XYZ Coord1(Pos.XDirection().XYZ());
+  if (N == 1)
+  {
+    if (Focal == 0.0)
     {
-      if (Focal == 0.0)
-      {
-        return gp_Vec(0.0, 0.0, 0.0);
-      }
-      else
-      {
-        Coord1.Multiply(1.0 / (2.0 * Focal));
-        return gp_Vec(Coord1);
-      }
+      return gp_Vec(Coord1);
     }
+    Coord1.SetLinearForm(U / (2.0 * Focal), Coord1, Pos.YDirection().XYZ());
+    return gp_Vec(Coord1);
   }
-  return gp_Vec(0., 0., 0.);
+
+  if (Focal == 0.0)
+  {
+    return gp_Vec(0.0, 0.0, 0.0);
+  }
+
+  Coord1.Multiply(1.0 / (2.0 * Focal));
+  return gp_Vec(Coord1);
 }
 
 //=================================================================================================
@@ -1075,8 +1078,8 @@ gp_Vec2d ElCLib::CircleDN(const Standard_Real    U,
     Xc = Radius * -sin(U);
     Yc = Radius * cos(U);
   }
-  gp_XY Xdir(Pos.XDirection().XY());
-  gp_XY Ydir(Pos.YDirection().XY());
+  gp_XY        Xdir(Pos.XDirection().XY());
+  const gp_XY& Ydir(Pos.YDirection().XY());
   Xdir.SetLinearForm(Xc, Xdir, Yc, Ydir);
   return gp_Vec2d(Xdir);
 }
@@ -1115,8 +1118,8 @@ gp_Vec2d ElCLib::EllipseDN(const Standard_Real    U,
     Xc = MajorRadius * -sin(U);
     Yc = MinorRadius * cos(U);
   }
-  gp_XY Xdir(Pos.XDirection().XY());
-  gp_XY Ydir(Pos.YDirection().XY());
+  gp_XY        Xdir(Pos.XDirection().XY());
+  const gp_XY& Ydir(Pos.YDirection().XY());
   Xdir.SetLinearForm(Xc, Xdir, Yc, Ydir);
   return gp_Vec2d(Xdir);
 }
@@ -1140,8 +1143,8 @@ gp_Vec2d ElCLib::HyperbolaDN(const Standard_Real    U,
     Xc = MajorRadius * Cosh(U);
     Yc = MinorRadius * Sinh(U);
   }
-  gp_XY Xdir(Pos.XDirection().XY());
-  gp_XY Ydir(Pos.YDirection().XY());
+  gp_XY        Xdir(Pos.XDirection().XY());
+  const gp_XY& Ydir(Pos.YDirection().XY());
   Xdir.SetLinearForm(Xc, Xdir, Yc, Ydir);
   return gp_Vec2d(Xdir);
 }
@@ -1153,36 +1156,31 @@ gp_Vec2d ElCLib::ParabolaDN(const Standard_Real    U,
                             const Standard_Real    Focal,
                             const Standard_Integer N)
 {
-  if (N <= 2)
+  if (N > 2 || N <= 0)
   {
-    gp_XY Xdir(Pos.XDirection().XY());
-    if (N == 1)
-    {
-      if (Focal == 0.0)
-      {
-        return gp_Vec2d(Xdir);
-      }
-      else
-      {
-        gp_XY Ydir(Pos.YDirection().XY());
-        Xdir.SetLinearForm(U / (2.0 * Focal), Xdir, Ydir);
-        return gp_Vec2d(Xdir);
-      }
-    }
-    else if (N == 2)
+    return gp_Vec2d(0.0, 0.0);
+  }
+
+  gp_XY Xdir(Pos.XDirection().XY());
+  if (N == 1)
+  {
+    if (Focal == 0.0)
     {
-      if (Focal == 0.0)
-      {
-        return gp_Vec2d(0.0, 0.0);
-      }
-      else
-      {
-        Xdir.Multiply(1.0 / (2.0 * Focal));
-        return gp_Vec2d(Xdir);
-      }
+      return gp_Vec2d(Xdir);
     }
+
+    gp_XY Ydir(Pos.YDirection().XY());
+    Xdir.SetLinearForm(U / (2.0 * Focal), Xdir, Ydir);
+    return gp_Vec2d(Xdir);
   }
-  return gp_Vec2d(0.0, 0.0);
+
+  if (Focal == 0.0)
+  {
+    return gp_Vec2d(0.0, 0.0);
+  }
+
+  Xdir.Multiply(1.0 / (2.0 * Focal));
+  return gp_Vec2d(Xdir);
 }
 
 //=================================================================================================
@@ -1196,14 +1194,14 @@ Standard_Real ElCLib::LineParameter(const gp_Ax1& L, const gp_Pnt& P)
 
 Standard_Real ElCLib::CircleParameter(const gp_Ax2& Pos, const gp_Pnt& P)
 {
-  gp_Vec aVec(Pos.Location(), P);
+  const gp_Vec aVec(Pos.Location(), P);
   if (aVec.SquareMagnitude() < gp::Resolution())
     // coinciding points -> infinite number of parameters
     return 0.0;
 
   const gp_Dir& dir = Pos.Direction();
   // Project vector on circle's plane
-  gp_XYZ aVProj = dir.XYZ().CrossCrossed(aVec.XYZ(), dir.XYZ());
+  const gp_XYZ aVProj = dir.XYZ().CrossCrossed(aVec.XYZ(), dir.XYZ());
 
   if (aVProj.SquareModulus() < gp::Resolution())
     return 0.0;
@@ -1225,11 +1223,11 @@ Standard_Real ElCLib::EllipseParameter(const gp_Ax2&       Pos,
                                        const Standard_Real MinorRadius,
                                        const gp_Pnt&       P)
 {
-  gp_XYZ        OP    = P.XYZ() - Pos.Location().XYZ();
-  gp_XYZ        xaxis = Pos.XDirection().XYZ();
-  gp_XYZ        yaxis = Pos.YDirection().XYZ();
-  Standard_Real NY    = OP.Dot(yaxis);
-  Standard_Real NX    = OP.Dot(xaxis);
+  const gp_XYZ&       OP    = P.XYZ() - Pos.Location().XYZ();
+  const gp_XYZ&       xaxis = Pos.XDirection().XYZ();
+  gp_XYZ              yaxis = Pos.YDirection().XYZ();
+  const Standard_Real NY    = OP.Dot(yaxis);
+  const Standard_Real NX    = OP.Dot(xaxis);
 
   if ((Abs(NX) <= gp::Resolution()) && (Abs(NY) <= gp::Resolution()))
     //-- The point P is on the Axis of the Ellipse.
@@ -1253,7 +1251,7 @@ Standard_Real ElCLib::HyperbolaParameter(const gp_Ax2& Pos,
                                          const Standard_Real MinorRadius,
                                          const gp_Pnt&       P)
 {
-  Standard_Real sht = gp_Vec(Pos.Location(), P).Dot(gp_Vec(Pos.YDirection())) / MinorRadius;
+  const Standard_Real sht = gp_Vec(Pos.Location(), P).Dot(gp_Vec(Pos.YDirection())) / MinorRadius;
 
 #if defined(__QNX__)
   return std::asinh(sht);
@@ -1300,9 +1298,9 @@ Standard_Real ElCLib::EllipseParameter(const gp_Ax22d&     Pos,
 {
   gp_XY OP = P.XY();
   OP.Subtract(Pos.Location().XY());
-  gp_XY xaxis = Pos.XDirection().XY();
-  gp_XY yaxis = Pos.YDirection().XY();
-  gp_XY Om    = xaxis.Multiplied(OP.Dot(xaxis));
+  const gp_XY& xaxis = Pos.XDirection().XY();
+  gp_XY        yaxis = Pos.YDirection().XY();
+  gp_XY        Om    = xaxis.Multiplied(OP.Dot(xaxis));
   yaxis.Multiply((OP.Dot(yaxis)) * (MajorRadius / MinorRadius));
   Om.Add(yaxis);
   Standard_Real Teta = gp_Vec2d(xaxis).Angle(gp_Vec2d(Om));
@@ -1321,8 +1319,8 @@ Standard_Real ElCLib::HyperbolaParameter(const gp_Ax22d& Pos,
                                          const Standard_Real MinorRadius,
                                          const gp_Pnt2d&     P)
 {
-  gp_Vec2d      V(Pos.YDirection().XY());
-  Standard_Real sht = gp_Vec2d(Pos.Location(), P).Dot(V) / MinorRadius;
+  const gp_Vec2d&     V(Pos.YDirection().XY());
+  const Standard_Real sht = gp_Vec2d(Pos.Location(), P).Dot(V) / MinorRadius;
 #if defined(__QNX__)
   return std::asinh(sht);
 #else
@@ -1334,7 +1332,7 @@ Standard_Real ElCLib::HyperbolaParameter(const gp_Ax22d& Pos,
 
 Standard_Real ElCLib::ParabolaParameter(const gp_Ax22d& Pos, const gp_Pnt2d& P)
 {
-  gp_Vec2d Directrix(Pos.YDirection().XY());
+  const gp_Vec2d Directrix(Pos.YDirection().XY());
   return gp_Vec2d(Pos.Location(), P).Dot(Directrix);
 }
 
@@ -1375,8 +1373,8 @@ gp_Vec ElCLib::To3d(const gp_Ax2& Pos, const gp_Vec2d& V)
 
 gp_Ax1 ElCLib::To3d(const gp_Ax2& Pos, const gp_Ax2d& A)
 {
-  gp_Pnt P = ElCLib::To3d(Pos, A.Location());
-  gp_Vec V = ElCLib::To3d(Pos, A.Direction());
+  const gp_Pnt P = ElCLib::To3d(Pos, A.Location());
+  const gp_Vec V = ElCLib::To3d(Pos, A.Direction());
   return gp_Ax1(P, V);
 }
 
@@ -1384,9 +1382,9 @@ gp_Ax1 ElCLib::To3d(const gp_Ax2& Pos, const gp_Ax2d& A)
 
 gp_Ax2 ElCLib::To3d(const gp_Ax2& Pos, const gp_Ax22d& A)
 {
-  gp_Pnt P  = ElCLib::To3d(Pos, A.Location());
-  gp_Vec VX = ElCLib::To3d(Pos, A.XDirection());
-  gp_Vec VY = ElCLib::To3d(Pos, A.YDirection());
+  const gp_Pnt P  = ElCLib::To3d(Pos, A.Location());
+  const gp_Vec VX = ElCLib::To3d(Pos, A.XDirection());
+  const gp_Vec VY = ElCLib::To3d(Pos, A.YDirection());
   return gp_Ax2(P, VX.Crossed(VY), VX);
 }
 
diff --git a/src/FoundationClasses/TKMath/GTests/ElCLib_Test.cxx b/src/FoundationClasses/TKMath/GTests/ElCLib_Test.cxx
new file mode 100644 (file)
index 0000000..a0824cc
--- /dev/null
@@ -0,0 +1,331 @@
+// 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 <ElCLib.hxx>
+
+#include <gtest/gtest.h>
+#include <gp_Circ.hxx>
+#include <gp_Circ2d.hxx>
+#include <gp_Elips.hxx>
+#include <gp_Elips2d.hxx>
+#include <gp_Hypr.hxx>
+#include <gp_Hypr2d.hxx>
+#include <gp_Lin.hxx>
+#include <gp_Lin2d.hxx>
+#include <gp_Parab.hxx>
+#include <gp_Parab2d.hxx>
+#include <Standard_Real.hxx>
+#include <Standard_Integer.hxx>
+
+namespace
+{
+// Helper function for comparing points with tolerance
+void checkPointsEqual(const gp_Pnt&       theP1,
+                      const gp_Pnt&       theP2,
+                      const Standard_Real theTolerance = Precision::Confusion())
+{
+  EXPECT_NEAR(theP1.X(), theP2.X(), theTolerance);
+  EXPECT_NEAR(theP1.Y(), theP2.Y(), theTolerance);
+  EXPECT_NEAR(theP1.Z(), theP2.Z(), theTolerance);
+}
+
+// Helper function for comparing vectors with tolerance
+void checkVectorsEqual(const gp_Vec&       theV1,
+                       const gp_Vec&       theV2,
+                       const Standard_Real theTolerance = Precision::Confusion())
+{
+  EXPECT_NEAR(theV1.X(), theV2.X(), theTolerance);
+  EXPECT_NEAR(theV1.Y(), theV2.Y(), theTolerance);
+  EXPECT_NEAR(theV1.Z(), theV2.Z(), theTolerance);
+}
+
+// Helper function for comparing directions with tolerance
+void checkDirectorsEqual(const gp_Dir&       theD1,
+                         const gp_Dir&       theD2,
+                         const Standard_Real theTolerance = Precision::Confusion())
+{
+  EXPECT_NEAR(theD1.X(), theD2.X(), theTolerance);
+  EXPECT_NEAR(theD1.Y(), theD2.Y(), theTolerance);
+  EXPECT_NEAR(theD1.Z(), theD2.Z(), theTolerance);
+}
+} // namespace
+
+TEST(ElClibTests, InPeriod)
+{
+  // Test with standard range [0, 2π]
+  const Standard_Real PI2 = 2.0 * M_PI;
+
+  EXPECT_NEAR(ElCLib::InPeriod(0.5, 0.0, PI2), 0.5, Precision::Confusion());
+  EXPECT_NEAR(ElCLib::InPeriod(PI2 + 0.5, 0.0, PI2), 0.5, Precision::Confusion());
+  EXPECT_NEAR(ElCLib::InPeriod(-0.5, 0.0, PI2), PI2 - 0.5, Precision::Confusion());
+  EXPECT_NEAR(ElCLib::InPeriod(-PI2 - 0.5, 0.0, PI2), PI2 - 0.5, Precision::Confusion());
+
+  // Test with arbitrary range [1.5, 4.5]
+  EXPECT_NEAR(ElCLib::InPeriod(1.7, 1.5, 4.5), 1.7, Precision::Confusion());
+  EXPECT_NEAR(ElCLib::InPeriod(4.7, 1.5, 4.5), 1.7, Precision::Confusion());
+  EXPECT_NEAR(ElCLib::InPeriod(7.7, 1.5, 4.5), 1.7, Precision::Confusion());
+  EXPECT_NEAR(ElCLib::InPeriod(1.3, 1.5, 4.5), 4.3, Precision::Confusion());
+}
+
+TEST(ElClibTests, AdjustPeriodic)
+{
+  Standard_Real       U1, U2;
+  const Standard_Real PI2 = 2.0 * M_PI;
+
+  // Test with standard range [0, 2π]
+  // Case 1: U1 and U2 within range, no adjustment needed
+  U1 = 0.5;
+  U2 = 0.7;
+  ElCLib::AdjustPeriodic(0.0, PI2, Precision::Confusion(), U1, U2);
+  EXPECT_NEAR(U1, 0.5, Precision::Confusion());
+  EXPECT_NEAR(U2, 0.7, Precision::Confusion());
+
+  // Case 2: U1 within range, U2 outside range, should adjust U2 to be within period from U1
+  U1 = 0.5;
+  U2 = 0.5 + PI2 + 0.2;
+  ElCLib::AdjustPeriodic(0.0, PI2, Precision::Confusion(), U1, U2);
+  EXPECT_NEAR(U1, 0.5, Precision::Confusion());
+  // U2 is adjusted to U1 + period
+  EXPECT_NEAR(U2, 0.7, Precision::Confusion());
+
+  // Case 3: Both U1 and U2 outside range but within same period
+  U1 = 0.5 + PI2;
+  U2 = 0.7 + PI2;
+  ElCLib::AdjustPeriodic(0.0, PI2, Precision::Confusion(), U1, U2);
+  EXPECT_NEAR(U1, 0.5, Precision::Confusion());
+  EXPECT_NEAR(U2, 0.7, Precision::Confusion());
+
+  // Test with negative U1
+  U1 = -0.5;
+  U2 = 0.7;
+  ElCLib::AdjustPeriodic(0.0, PI2, Precision::Confusion(), U1, U2);
+  EXPECT_NEAR(U1, PI2 - 0.5, Precision::Confusion());
+  EXPECT_NEAR(U2, 0.7 + PI2, Precision::Confusion());
+
+  // Test where U2 is very close to U1 (should add a period to U2)
+  U1 = 1.0;
+  U2 = 1.0 + 0.5 * Precision::Confusion(); // Very close to U1
+  ElCLib::AdjustPeriodic(0.0, PI2, Precision::Confusion(), U1, U2);
+  EXPECT_NEAR(U1, 1.0, Precision::Confusion());
+  EXPECT_NEAR(U2, 1.0 + PI2, Precision::Confusion());
+}
+
+TEST(ElClibTests, Line3D)
+{
+  const gp_Pnt        aLoc(1.0, 2.0, 3.0);
+  const gp_Dir        aDir(0.0, 0.0, 1.0);
+  const gp_Lin        aLin(aLoc, aDir);
+  const Standard_Real aParam = 5.0;
+
+  // Test Value
+  const gp_Pnt aPoint = ElCLib::Value(aParam, aLin);
+  const gp_Pnt aExpectedPoint(1.0, 2.0, 8.0);
+  checkPointsEqual(aPoint, aExpectedPoint);
+
+  // Test D1
+  gp_Pnt aPointD1;
+  gp_Vec aVecD1;
+  ElCLib::D1(aParam, aLin, aPointD1, aVecD1);
+  checkPointsEqual(aPointD1, aExpectedPoint);
+  checkVectorsEqual(aVecD1, gp_Vec(aDir));
+
+  // Test DN
+  const gp_Vec aVecDN = ElCLib::DN(aParam, aLin, 1);
+  checkVectorsEqual(aVecDN, gp_Vec(aDir));
+  const gp_Vec aVecDN2 = ElCLib::DN(aParam, aLin, 2);
+  checkVectorsEqual(aVecDN2, gp_Vec(0.0, 0.0, 0.0));
+
+  // Test Parameter
+  const gp_Pnt        aTestPoint(1.0, 2.0, 10.0);
+  const Standard_Real aCalculatedParam = ElCLib::Parameter(aLin, aTestPoint);
+  EXPECT_NEAR(aCalculatedParam, 7.0, Precision::Confusion());
+}
+
+TEST(ElClibTests, Circle3D)
+{
+  const gp_Pnt        aLoc(0.0, 0.0, 0.0);
+  const gp_Dir        aDirZ(0.0, 0.0, 1.0);
+  const gp_Dir        aDirX(1.0, 0.0, 0.0);
+  const gp_Ax2        anAxis(aLoc, aDirZ, aDirX);
+  const Standard_Real aRadius = 2.0;
+  const gp_Circ       aCircle(anAxis, aRadius);
+  const Standard_Real aParam = M_PI / 4.0; // 45 degrees
+
+  // Test Value
+  const gp_Pnt aPoint = ElCLib::Value(aParam, aCircle);
+  const gp_Pnt aExpectedPoint(aRadius * cos(aParam), aRadius * sin(aParam), 0.0);
+  checkPointsEqual(aPoint, aExpectedPoint);
+
+  // Test D1
+  gp_Pnt aPointD1;
+  gp_Vec aVecD1;
+  ElCLib::D1(aParam, aCircle, aPointD1, aVecD1);
+  checkPointsEqual(aPointD1, aExpectedPoint);
+  const gp_Vec aExpectedVecD1(-aRadius * sin(aParam), aRadius * cos(aParam), 0.0);
+  checkVectorsEqual(aVecD1, aExpectedVecD1);
+
+  // Test D2
+  gp_Pnt aPointD2;
+  gp_Vec aVecD2_1, aVecD2_2;
+  ElCLib::D2(aParam, aCircle, aPointD2, aVecD2_1, aVecD2_2);
+  checkPointsEqual(aPointD2, aExpectedPoint);
+  checkVectorsEqual(aVecD2_1, aExpectedVecD1);
+  const gp_Vec aExpectedVecD2_2(-aRadius * cos(aParam), -aRadius * sin(aParam), 0.0);
+  checkVectorsEqual(aVecD2_2, aExpectedVecD2_2);
+
+  // Test D3
+  gp_Pnt aPointD3;
+  gp_Vec aVecD3_1, aVecD3_2, aVecD3_3;
+  ElCLib::D3(aParam, aCircle, aPointD3, aVecD3_1, aVecD3_2, aVecD3_3);
+  checkPointsEqual(aPointD3, aExpectedPoint);
+  checkVectorsEqual(aVecD3_1, aExpectedVecD1);
+  checkVectorsEqual(aVecD3_2, aExpectedVecD2_2);
+  const gp_Vec aExpectedVecD3_3(aRadius * sin(aParam), -aRadius * cos(aParam), 0.0);
+  checkVectorsEqual(aVecD3_3, aExpectedVecD3_3);
+
+  // Test DN
+  const gp_Vec aVecDN1 = ElCLib::DN(aParam, aCircle, 1);
+  checkVectorsEqual(aVecDN1, aExpectedVecD1);
+
+  const gp_Vec aVecDN2 = ElCLib::DN(aParam, aCircle, 2);
+  checkVectorsEqual(aVecDN2, aExpectedVecD2_2);
+
+  const gp_Vec aVecDN3 = ElCLib::DN(aParam, aCircle, 3);
+  checkVectorsEqual(aVecDN3, aExpectedVecD3_3);
+
+  // Test Parameter
+  const Standard_Real aCalculatedParam = ElCLib::Parameter(aCircle, aExpectedPoint);
+  EXPECT_NEAR(aCalculatedParam, aParam, Precision::Confusion());
+}
+
+TEST(ElClibTests, Ellipse3D)
+{
+  const gp_Pnt        aLoc(0.0, 0.0, 0.0);
+  const gp_Dir        aDirZ(0.0, 0.0, 1.0);
+  const gp_Dir        aDirX(1.0, 0.0, 0.0);
+  const gp_Ax2        anAxis(aLoc, aDirZ, aDirX);
+  const Standard_Real aMajorRadius = 3.0;
+  const Standard_Real aMinorRadius = 2.0;
+  const gp_Elips      anEllipse(anAxis, aMajorRadius, aMinorRadius);
+  const Standard_Real aParam = M_PI / 4.0; // 45 degrees
+
+  // Test Value
+  const gp_Pnt aPoint = ElCLib::Value(aParam, anEllipse);
+  const gp_Pnt aExpectedPoint(aMajorRadius * cos(aParam), aMinorRadius * sin(aParam), 0.0);
+  checkPointsEqual(aPoint, aExpectedPoint);
+
+  // Test D1
+  gp_Pnt aPointD1;
+  gp_Vec aVecD1;
+  ElCLib::D1(aParam, anEllipse, aPointD1, aVecD1);
+  checkPointsEqual(aPointD1, aExpectedPoint);
+  const gp_Vec aExpectedVecD1(-aMajorRadius * sin(aParam), aMinorRadius * cos(aParam), 0.0);
+  checkVectorsEqual(aVecD1, aExpectedVecD1);
+
+  // Test Parameter
+  const Standard_Real aCalculatedParam = ElCLib::Parameter(anEllipse, aExpectedPoint);
+  EXPECT_NEAR(aCalculatedParam, aParam, Precision::Confusion());
+}
+
+TEST(ElClibTests, Hyperbola3D)
+{
+  const gp_Pnt        aLoc(0.0, 0.0, 0.0);
+  const gp_Dir        aDirZ(0.0, 0.0, 1.0);
+  const gp_Dir        aDirX(1.0, 0.0, 0.0);
+  const gp_Ax2        anAxis(aLoc, aDirZ, aDirX);
+  const Standard_Real aMajorRadius = 3.0;
+  const Standard_Real aMinorRadius = 2.0;
+  const gp_Hypr       aHyperbola(anAxis, aMajorRadius, aMinorRadius);
+  const Standard_Real aParam = 0.5;
+
+  // Test Value
+  const gp_Pnt aPoint = ElCLib::Value(aParam, aHyperbola);
+  const gp_Pnt aExpectedPoint(aMajorRadius * cosh(aParam), aMinorRadius * sinh(aParam), 0.0);
+  checkPointsEqual(aPoint, aExpectedPoint);
+
+  // Test D1
+  gp_Pnt aPointD1;
+  gp_Vec aVecD1;
+  ElCLib::D1(aParam, aHyperbola, aPointD1, aVecD1);
+  checkPointsEqual(aPointD1, aExpectedPoint);
+  const gp_Vec aExpectedVecD1(aMajorRadius * sinh(aParam), aMinorRadius * cosh(aParam), 0.0);
+  checkVectorsEqual(aVecD1, aExpectedVecD1);
+
+  // Test Parameter
+  const Standard_Real aCalculatedParam = ElCLib::Parameter(aHyperbola, aExpectedPoint);
+  EXPECT_NEAR(aCalculatedParam, aParam, Precision::Confusion());
+}
+
+TEST(ElClibTests, Parabola3D)
+{
+  const gp_Pnt        aLoc(0.0, 0.0, 0.0);
+  const gp_Dir        aDirZ(0.0, 0.0, 1.0);
+  const gp_Dir        aDirX(1.0, 0.0, 0.0);
+  const gp_Ax2        anAxis(aLoc, aDirZ, aDirX);
+  const Standard_Real aFocal = 2.0;
+  const gp_Parab      aParabola(anAxis, aFocal);
+  const Standard_Real aParam = 3.0;
+
+  // Test Value
+  const gp_Pnt aPoint = ElCLib::Value(aParam, aParabola);
+  const gp_Pnt aExpectedPoint(aParam * aParam / (4.0 * aFocal), aParam, 0.0);
+  checkPointsEqual(aPoint, aExpectedPoint);
+
+  // Test D1
+  gp_Pnt aPointD1;
+  gp_Vec aVecD1;
+  ElCLib::D1(aParam, aParabola, aPointD1, aVecD1);
+  checkPointsEqual(aPointD1, aExpectedPoint);
+  const gp_Vec aExpectedVecD1(aParam / (2.0 * aFocal), 1.0, 0.0);
+  checkVectorsEqual(aVecD1, aExpectedVecD1);
+
+  // Test Parameter
+  const Standard_Real aCalculatedParam = ElCLib::Parameter(aParabola, aExpectedPoint);
+  EXPECT_NEAR(aCalculatedParam, aParam, Precision::Confusion());
+}
+
+TEST(ElClibTests, To3dConversion)
+{
+  const gp_Pnt aLoc(1.0, 2.0, 3.0);
+  const gp_Dir aDirZ(0.0, 0.0, 1.0);
+  const gp_Dir aDirX(1.0, 0.0, 0.0);
+  const gp_Ax2 anAxis(aLoc, aDirZ, aDirX);
+
+  // Test conversion of a point
+  const gp_Pnt2d aPnt2d(2.0, 3.0);
+  const gp_Pnt   aPnt3d = ElCLib::To3d(anAxis, aPnt2d);
+  const gp_Pnt   aExpectedPnt3d(3.0, 5.0, 3.0);
+  checkPointsEqual(aPnt3d, aExpectedPnt3d);
+
+  // Test conversion of a vector
+  const gp_Vec2d aVec2d(1.0, 2.0);
+  const gp_Vec   aVec3d = ElCLib::To3d(anAxis, aVec2d);
+  const gp_Vec   aExpectedVec3d(1.0, 2.0, 0.0);
+  checkVectorsEqual(aVec3d, aExpectedVec3d);
+
+  // Test conversion of a direction
+  const gp_Dir2d aDir2d(1.0, 2.0);
+  const gp_Dir   aDir3d = ElCLib::To3d(anAxis, aDir2d);
+  const gp_Dir   aExpectedDir3d(1.0 / sqrt(5.0), 2.0 / sqrt(5.0), 0.0);
+  checkDirectorsEqual(aDir3d, aExpectedDir3d, Precision::Confusion());
+
+  // Test conversion of a circle
+  const gp_Pnt2d      aLoc2d(0.0, 0.0);
+  const gp_Dir2d      aDir2dX(1.0, 0.0);
+  const gp_Ax22d      anAxis2d(aLoc2d, aDir2dX, true);
+  const Standard_Real aRadius = 2.0;
+  const gp_Circ2d     aCirc2d(anAxis2d, aRadius);
+  const gp_Circ       aCirc3d = ElCLib::To3d(anAxis, aCirc2d);
+  EXPECT_NEAR(aCirc3d.Radius(), aRadius, Precision::Confusion());
+  checkPointsEqual(aCirc3d.Location(), aLoc, Precision::Confusion());
+}
index 70c531bc74b5d3076ffff9ca018671e81cdcdb42..811a769e560a3517b57681903ec63a64de1bebf6 100644 (file)
@@ -2,4 +2,5 @@
 set(OCCT_TKMath_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
 
 set(OCCT_TKMath_GTests_FILES
+  ElCLib_Test.cxx
 )