Loading files
f2929057eThis file is pinned to the selected release. Download the original to open it in your design tool.
// 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 <Geom2d_Circle.hxx>
#include <Geom2d_Ellipse.hxx>
#include <Geom2d_Hyperbola.hxx>
#include <GeomLProp_CurAndInf2d.hxx>
#include <Geom2d_Parabola.hxx>
#include <gp_Ax2d.hxx>
#include <gp_Circ2d.hxx>
#include <gp_Dir2d.hxx>
#include <gp_Elips2d.hxx>
#include <gp_Hypr2d.hxx>
#include <gp_Parab2d.hxx>
#include <gp_Pnt2d.hxx>
#include <LProp_CIType.hxx>
#include <Precision.hxx>
#include <cmath>
#include <gtest/gtest.h>
class GeomLProp_CurAndInf2dTest : public ::testing::Test
{
protected:
void SetUp() override
{
// Circle centered at origin, radius 5
gp_Circ2d aCirc(gp_Ax2d(gp_Pnt2d(0.0, 0.0), gp_Dir2d(1.0, 0.0)), 5.0);
myCircle = new Geom2d_Circle(aCirc);
// Ellipse centered at origin, major radius 10, minor radius 3
gp_Elips2d anElips(gp_Ax2d(gp_Pnt2d(0.0, 0.0), gp_Dir2d(1.0, 0.0)), 10.0, 3.0);
myEllipse = new Geom2d_Ellipse(anElips);
gp_Hypr2d aHypr(gp_Ax2d(gp_Pnt2d(0.0, 0.0), gp_Dir2d(1.0, 0.0)), 6.0, 3.0);
myHyperbola = new Geom2d_Hyperbola(aHypr);
gp_Parab2d aParab(gp_Ax2d(gp_Pnt2d(0.0, 0.0), gp_Dir2d(1.0, 0.0)), 2.0);
myParabola = new Geom2d_Parabola(aParab);
}
occ::handle<Geom2d_Circle> myCircle;
occ::handle<Geom2d_Ellipse> myEllipse;
occ::handle<Geom2d_Hyperbola> myHyperbola;
occ::handle<Geom2d_Parabola> myParabola;
};
TEST_F(GeomLProp_CurAndInf2dTest, Circle_Perform_NoInflections)
{
// A circle has constant curvature: no inflections or extrema
GeomLProp_CurAndInf2d aAnalyzer;
aAnalyzer.Perform(myCircle);
EXPECT_TRUE(aAnalyzer.IsDone());
EXPECT_EQ(aAnalyzer.NbPoints(), 0);
}
TEST_F(GeomLProp_CurAndInf2dTest, Circle_PerformInf_NoInflections)
{
GeomLProp_CurAndInf2d aAnalyzer;
aAnalyzer.PerformInf(myCircle);
EXPECT_TRUE(aAnalyzer.IsDone());
EXPECT_EQ(aAnalyzer.NbPoints(), 0);
}
TEST_F(GeomLProp_CurAndInf2dTest, Circle_PerformCurExt_NoExtrema)
{
GeomLProp_CurAndInf2d aAnalyzer;
aAnalyzer.PerformCurExt(myCircle);
EXPECT_TRUE(aAnalyzer.IsDone());
EXPECT_EQ(aAnalyzer.NbPoints(), 0);
}
TEST_F(GeomLProp_CurAndInf2dTest, Ellipse_PerformCurExt_HasExtrema)
{
// An ellipse has 4 curvature extrema:
// 2 maxima (at ends of minor axis) and 2 minima (at ends of major axis)
GeomLProp_CurAndInf2d aAnalyzer;
aAnalyzer.PerformCurExt(myEllipse);
EXPECT_TRUE(aAnalyzer.IsDone());
EXPECT_EQ(aAnalyzer.NbPoints(), 4);
}
TEST_F(GeomLProp_CurAndInf2dTest, Ellipse_PerformCurExt_Types)
{
GeomLProp_CurAndInf2d aAnalyzer;
aAnalyzer.PerformCurExt(myEllipse);
ASSERT_TRUE(aAnalyzer.IsDone());
ASSERT_EQ(aAnalyzer.NbPoints(), 4);
// Count min and max curvature points
int aNbMin = 0;
int aNbMax = 0;
for (int i = 1; i <= aAnalyzer.NbPoints(); ++i)
{
const LProp_CIType aType = aAnalyzer.Type(i);
if (aType == LProp_MinCur)
{
++aNbMin;
}
else if (aType == LProp_MaxCur)
{
++aNbMax;
}
}
EXPECT_EQ(aNbMin, 2);
EXPECT_EQ(aNbMax, 2);
}
TEST_F(GeomLProp_CurAndInf2dTest, Ellipse_PerformCurExt_Parameters)
{
GeomLProp_CurAndInf2d aAnalyzer;
aAnalyzer.PerformCurExt(myEllipse);
ASSERT_TRUE(aAnalyzer.IsDone());
ASSERT_EQ(aAnalyzer.NbPoints(), 4);
// Parameters should be sorted in increasing order
for (int i = 1; i < aAnalyzer.NbPoints(); ++i)
{
EXPECT_LT(aAnalyzer.Parameter(i), aAnalyzer.Parameter(i + 1));
}
}
TEST_F(GeomLProp_CurAndInf2dTest, Ellipse_PerformInf_NoInflections)
{
// An ellipse is a convex curve, so it has no inflection points
GeomLProp_CurAndInf2d aAnalyzer;
aAnalyzer.PerformInf(myEllipse);
EXPECT_TRUE(aAnalyzer.IsDone());
EXPECT_EQ(aAnalyzer.NbPoints(), 0);
}
TEST_F(GeomLProp_CurAndInf2dTest, Ellipse_Perform_CombinedResult)
{
// Perform computes both inflections and curvature extrema
GeomLProp_CurAndInf2d aAnalyzer;
aAnalyzer.Perform(myEllipse);
EXPECT_TRUE(aAnalyzer.IsDone());
// Ellipse: 4 extrema, 0 inflections
EXPECT_EQ(aAnalyzer.NbPoints(), 4);
}
TEST_F(GeomLProp_CurAndInf2dTest, Ellipse_CurvatureExtremaAtExpectedParameters)
{
// For an ellipse with major axis along X:
// Curvature extrema at U = 0, PI/2, PI, 3*PI/2
GeomLProp_CurAndInf2d aAnalyzer;
aAnalyzer.PerformCurExt(myEllipse);
ASSERT_TRUE(aAnalyzer.IsDone());
ASSERT_EQ(aAnalyzer.NbPoints(), 4);
const double anExpectedParams[] = {0.0, M_PI / 2.0, M_PI, 3.0 * M_PI / 2.0};
for (int i = 1; i <= 4; ++i)
{
EXPECT_NEAR(aAnalyzer.Parameter(i), anExpectedParams[i - 1], 1e-6);
}
}
TEST_F(GeomLProp_CurAndInf2dTest, Hyperbola_PerformCurExt_VertexOnly)
{
GeomLProp_CurAndInf2d aAnalyzer;
aAnalyzer.PerformCurExt(myHyperbola);
ASSERT_TRUE(aAnalyzer.IsDone());
ASSERT_EQ(aAnalyzer.NbPoints(), 1);
EXPECT_NEAR(aAnalyzer.Parameter(1), 0.0, Precision::PConfusion());
EXPECT_EQ(aAnalyzer.Type(1), LProp_MinCur);
}
TEST_F(GeomLProp_CurAndInf2dTest, Hyperbola_PerformInf_NoInflections)
{
GeomLProp_CurAndInf2d aAnalyzer;
aAnalyzer.PerformInf(myHyperbola);
EXPECT_TRUE(aAnalyzer.IsDone());
EXPECT_EQ(aAnalyzer.NbPoints(), 0);
}
TEST_F(GeomLProp_CurAndInf2dTest, Parabola_PerformCurExt_VertexOnly)
{
GeomLProp_CurAndInf2d aAnalyzer;
aAnalyzer.PerformCurExt(myParabola);
ASSERT_TRUE(aAnalyzer.IsDone());
ASSERT_EQ(aAnalyzer.NbPoints(), 1);
EXPECT_NEAR(aAnalyzer.Parameter(1), 0.0, Precision::PConfusion());
EXPECT_EQ(aAnalyzer.Type(1), LProp_MinCur);
}
TEST_F(GeomLProp_CurAndInf2dTest, PerformInf_ClearsPreviousExtrema)
{
GeomLProp_CurAndInf2d aAnalyzer;
aAnalyzer.PerformCurExt(myEllipse);
ASSERT_TRUE(aAnalyzer.IsDone());
ASSERT_EQ(aAnalyzer.NbPoints(), 4);
aAnalyzer.PerformInf(myEllipse);
EXPECT_TRUE(aAnalyzer.IsDone());
EXPECT_EQ(aAnalyzer.NbPoints(), 0);
}