Modeling Data - Add GeomProp package for modern 3D curve and surface differential properties (#1115)

Add new GeomProp package to TKG3d following the same C++17 std::variant-dispatched
pattern as Geom2dProp (TKG2d) for computing local differential properties
of 3D curves and surfaces without exceptions.

New package GeomProp (TKG3d) provides:
- GeomProp: Result structs (TangentResult, CurvatureResult, NormalResult,
  CentreResult, CurveAnalysis for curves; SurfaceNormalResult,
  SurfaceCurvatureResult, MeanGaussianResult for surfaces) and
  geometry-agnostic free functions for property computation from derivatives.
- GeomProp_Curve: Unified variant dispatcher that auto-detects curve type
  from Geom_Curve or Adaptor3d_Curve and delegates to specialized evaluators.
  Owns the GeomAdaptor_Curve handle and passes non-owning raw pointers to
  per-geometry classes.
- GeomProp_Surface: Unified variant dispatcher that auto-detects surface type
  from Geom_Surface or Adaptor3d_Surface and delegates to specialized evaluators.
  Owns the GeomAdaptor_Surface handle with non-owning raw pointers.
- Per-geometry curve evaluators (9 types matching GeomAbs_CurveType):
  Line (header-only), Circle (header-only), Ellipse, Hyperbola, Parabola,
  BezierCurve, BSplineCurve, OffsetCurve, OtherCurve.
- Per-geometry surface evaluators (11 types matching GeomAbs_SurfaceType):
  Plane (header-only), Cylinder (header-only), Sphere (header-only),
  Cone, Torus, BezierSurface, BSplineSurface, SurfaceOfRevolution,
  SurfaceOfExtrusion, OffsetSurface, OtherSurface.
- Surface curvatures computed via first/second fundamental forms with
  correct sign convention consistent with surface normal orientation.
  Principal directions derived from the shape operator (Weingarten map).

48 GTests covering free functions, curve/surface dispatchers,
cross-validation against GeomLProp_CLProps (8 curve types) and
GeomLProp_SLProps (6 surface types).
This commit is contained in:
Pasukhin Dmitry
2026-02-24 18:51:11 +00:00
committed by GitHub
parent 3266a82318
commit 55db67c60d
47 changed files with 6139 additions and 0 deletions
@@ -44,4 +44,7 @@ set(OCCT_TKG3d_GTests_FILES
GeomGridEval_Torus_Test.cxx
GeomHash_CurveHasher_Test.cxx
GeomHash_SurfaceHasher_Test.cxx
GeomProp_Test.cxx
GeomProp_VsCLProps_Test.cxx
GeomProp_VsSLProps_Test.cxx
)
@@ -0,0 +1,523 @@
// 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.
// Unit tests for GeomProp free functions and result structures.
#include <Geom_BezierCurve.hxx>
#include <Geom_BSplineCurve.hxx>
#include <Geom_BSplineSurface.hxx>
#include <Geom_Circle.hxx>
#include <Geom_ConicalSurface.hxx>
#include <Geom_CylindricalSurface.hxx>
#include <Geom_Ellipse.hxx>
#include <Geom_Hyperbola.hxx>
#include <Geom_Line.hxx>
#include <Geom_OffsetCurve.hxx>
#include <Geom_Parabola.hxx>
#include <Geom_Plane.hxx>
#include <Geom_SphericalSurface.hxx>
#include <Geom_ToroidalSurface.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <GeomProp.hxx>
#include <GeomProp_Curve.hxx>
#include <GeomProp_Surface.hxx>
#include <gp_Ax2.hxx>
#include <gp_Ax3.hxx>
#include <gp_Circ.hxx>
#include <gp_Dir.hxx>
#include <gp_Elips.hxx>
#include <gp_Hypr.hxx>
#include <gp_Lin.hxx>
#include <gp_Parab.hxx>
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
#include <NCollection_Array1.hxx>
#include <Precision.hxx>
#include <cmath>
#include <gtest/gtest.h>
// ============================================================================
// Free function tests - ComputeTangent
// ============================================================================
TEST(GeomPropTest, ComputeTangent_D1NonZero)
{
const gp_Vec aD1(1.0, 0.0, 0.0);
const gp_Vec aD2(0.0, 1.0, 0.0);
const gp_Vec aD3(0.0, 0.0, 1.0);
const GeomProp::TangentResult aRes =
GeomProp::ComputeTangent(aD1, aD2, aD3, Precision::Confusion());
ASSERT_TRUE(aRes.IsDefined);
EXPECT_NEAR(aRes.Direction.X(), 1.0, Precision::Confusion());
EXPECT_NEAR(aRes.Direction.Y(), 0.0, Precision::Confusion());
EXPECT_NEAR(aRes.Direction.Z(), 0.0, Precision::Confusion());
}
TEST(GeomPropTest, ComputeTangent_D1Zero_D2NonZero)
{
const gp_Vec aD1(0.0, 0.0, 0.0);
const gp_Vec aD2(0.0, 1.0, 0.0);
const gp_Vec aD3(0.0, 0.0, 1.0);
const GeomProp::TangentResult aRes =
GeomProp::ComputeTangent(aD1, aD2, aD3, Precision::Confusion());
ASSERT_TRUE(aRes.IsDefined);
EXPECT_NEAR(aRes.Direction.Y(), 1.0, Precision::Confusion());
}
TEST(GeomPropTest, ComputeTangent_AllZero)
{
const gp_Vec aD1(0.0, 0.0, 0.0);
const gp_Vec aD2(0.0, 0.0, 0.0);
const gp_Vec aD3(0.0, 0.0, 0.0);
const GeomProp::TangentResult aRes =
GeomProp::ComputeTangent(aD1, aD2, aD3, Precision::Confusion());
EXPECT_FALSE(aRes.IsDefined);
}
// ============================================================================
// Free function tests - ComputeCurvature
// ============================================================================
TEST(GeomPropTest, ComputeCurvature_CircularArc)
{
// At (1,0,0) on unit circle in XY plane: D1=(0,1,0), D2=(-1,0,0)
const gp_Vec aD1(0.0, 1.0, 0.0);
const gp_Vec aD2(-1.0, 0.0, 0.0);
const GeomProp::CurvatureResult aRes =
GeomProp::ComputeCurvature(aD1, aD2, Precision::Confusion());
ASSERT_TRUE(aRes.IsDefined);
EXPECT_FALSE(aRes.IsInfinite);
EXPECT_NEAR(aRes.Value, 1.0, 1.0e-10);
}
TEST(GeomPropTest, ComputeCurvature_ZeroD1)
{
const gp_Vec aD1(0.0, 0.0, 0.0);
const gp_Vec aD2(1.0, 0.0, 0.0);
const GeomProp::CurvatureResult aRes =
GeomProp::ComputeCurvature(aD1, aD2, Precision::Confusion());
EXPECT_TRUE(aRes.IsDefined);
EXPECT_TRUE(aRes.IsInfinite);
}
TEST(GeomPropTest, ComputeCurvature_StraightLine)
{
const gp_Vec aD1(1.0, 0.0, 0.0);
const gp_Vec aD2(0.0, 0.0, 0.0);
const GeomProp::CurvatureResult aRes =
GeomProp::ComputeCurvature(aD1, aD2, Precision::Confusion());
EXPECT_TRUE(aRes.IsDefined);
EXPECT_NEAR(aRes.Value, 0.0, Precision::Confusion());
}
// ============================================================================
// Free function tests - ComputeNormal
// ============================================================================
TEST(GeomPropTest, ComputeNormal_CircularArc)
{
const gp_Vec aD1(0.0, 1.0, 0.0);
const gp_Vec aD2(-1.0, 0.0, 0.0);
const GeomProp::NormalResult aRes = GeomProp::ComputeNormal(aD1, aD2, Precision::Confusion());
ASSERT_TRUE(aRes.IsDefined);
EXPECT_NEAR(aRes.Direction.X(), -1.0, Precision::Confusion());
}
// ============================================================================
// Free function tests - ComputeSurfaceNormal
// ============================================================================
TEST(GeomPropTest, ComputeSurfaceNormal_XYPlane)
{
const gp_Vec aD1U(1.0, 0.0, 0.0);
const gp_Vec aD1V(0.0, 1.0, 0.0);
const GeomProp::SurfaceNormalResult aRes =
GeomProp::ComputeSurfaceNormal(aD1U, aD1V, Precision::Confusion());
ASSERT_TRUE(aRes.IsDefined);
EXPECT_NEAR(std::abs(aRes.Direction.Z()), 1.0, Precision::Confusion());
}
TEST(GeomPropTest, ComputeSurfaceNormal_DegeneratePoint)
{
const gp_Vec aD1U(0.0, 0.0, 0.0);
const gp_Vec aD1V(0.0, 1.0, 0.0);
const GeomProp::SurfaceNormalResult aRes =
GeomProp::ComputeSurfaceNormal(aD1U, aD1V, Precision::Confusion());
EXPECT_FALSE(aRes.IsDefined);
}
// ============================================================================
// Free function tests - ComputeMeanGaussian
// ============================================================================
TEST(GeomPropTest, ComputeMeanGaussian_Sphere)
{
// At north pole of unit sphere, D1U and D1V are orthogonal unit vectors
const gp_Vec aD1U(1.0, 0.0, 0.0);
const gp_Vec aD1V(0.0, 1.0, 0.0);
const gp_Vec aD2U(0.0, 0.0, -1.0);
const gp_Vec aD2V(0.0, 0.0, -1.0);
const gp_Vec aDUV(0.0, 0.0, 0.0);
const GeomProp::MeanGaussianResult aRes =
GeomProp::ComputeMeanGaussian(aD1U, aD1V, aD2U, aD2V, aDUV, Precision::Confusion());
ASSERT_TRUE(aRes.IsDefined);
EXPECT_NEAR(aRes.MeanCurvature, -1.0, 1.0e-10);
EXPECT_NEAR(aRes.GaussianCurvature, 1.0, 1.0e-10);
}
// ============================================================================
// GeomProp_Curve - initialization and basic queries
// ============================================================================
TEST(GeomPropCurveTest, UninitializedState)
{
GeomProp_Curve aProp;
EXPECT_FALSE(aProp.IsInitialized());
}
TEST(GeomPropCurveTest, InitializeFromNullHandle)
{
GeomProp_Curve aProp;
occ::handle<Geom_Curve> aNullCurve;
aProp.Initialize(aNullCurve);
EXPECT_FALSE(aProp.IsInitialized());
}
TEST(GeomPropCurveTest, Line_ZeroCurvature)
{
occ::handle<Geom_Line> aLine = new Geom_Line(gp_Pnt(0, 0, 0), gp_Dir(1, 0, 0));
GeomProp_Curve aProp;
aProp.Initialize(aLine);
ASSERT_TRUE(aProp.IsInitialized());
EXPECT_EQ(aProp.GetType(), GeomAbs_Line);
const GeomProp::CurvatureResult aCurv = aProp.Curvature(0.5, Precision::Confusion());
EXPECT_TRUE(aCurv.IsDefined);
EXPECT_NEAR(aCurv.Value, 0.0, Precision::Confusion());
}
TEST(GeomPropCurveTest, Circle_ConstantCurvature)
{
const double aRadius = 5.0;
gp_Circ aCirc(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), aRadius);
occ::handle<Geom_Circle> aCircle = new Geom_Circle(aCirc);
GeomProp_Curve aProp;
aProp.Initialize(aCircle);
ASSERT_TRUE(aProp.IsInitialized());
EXPECT_EQ(aProp.GetType(), GeomAbs_Circle);
const GeomProp::CurvatureResult aCurv = aProp.Curvature(1.0, Precision::Confusion());
ASSERT_TRUE(aCurv.IsDefined);
EXPECT_NEAR(aCurv.Value, 1.0 / aRadius, 1.0e-10);
}
TEST(GeomPropCurveTest, Ellipse_CurvatureExtrema)
{
const double aMajor = 10.0;
const double aMinor = 5.0;
gp_Elips anElips(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), aMajor, aMinor);
occ::handle<Geom_Ellipse> anEllipse = new Geom_Ellipse(anElips);
GeomProp_Curve aProp;
aProp.Initialize(anEllipse);
ASSERT_TRUE(aProp.IsInitialized());
const GeomProp::CurveAnalysis aResult = aProp.FindCurvatureExtrema();
ASSERT_TRUE(aResult.IsDone);
EXPECT_EQ(aResult.Points.Length(), 4);
}
TEST(GeomPropCurveTest, Hyperbola_SingleExtremum)
{
gp_Hypr anHypr(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), 6.0, 3.0);
occ::handle<Geom_Hyperbola> aHyperbola = new Geom_Hyperbola(anHypr);
GeomProp_Curve aProp;
aProp.Initialize(aHyperbola);
ASSERT_TRUE(aProp.IsInitialized());
const GeomProp::CurveAnalysis aResult = aProp.FindCurvatureExtrema();
ASSERT_TRUE(aResult.IsDone);
EXPECT_EQ(aResult.Points.Length(), 1);
EXPECT_NEAR(aResult.Points[0].Parameter, 0.0, Precision::Confusion());
}
TEST(GeomPropCurveTest, Parabola_SingleExtremum)
{
gp_Parab aParab(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), 2.0);
occ::handle<Geom_Parabola> aParabola = new Geom_Parabola(aParab);
GeomProp_Curve aProp;
aProp.Initialize(aParabola);
ASSERT_TRUE(aProp.IsInitialized());
const GeomProp::CurveAnalysis aResult = aProp.FindCurvatureExtrema();
ASSERT_TRUE(aResult.IsDone);
EXPECT_EQ(aResult.Points.Length(), 1);
EXPECT_NEAR(aResult.Points[0].Parameter, 0.0, Precision::Confusion());
}
TEST(GeomPropCurveTest, Circle_NoExtrema)
{
gp_Circ aCirc(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), 5.0);
occ::handle<Geom_Circle> aCircle = new Geom_Circle(aCirc);
GeomProp_Curve aProp;
aProp.Initialize(aCircle);
const GeomProp::CurveAnalysis aResult = aProp.FindCurvatureExtrema();
ASSERT_TRUE(aResult.IsDone);
EXPECT_EQ(aResult.Points.Length(), 0);
}
TEST(GeomPropCurveTest, Circle_NoInflections)
{
gp_Circ aCirc(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), 5.0);
occ::handle<Geom_Circle> aCircle = new Geom_Circle(aCirc);
GeomProp_Curve aProp;
aProp.Initialize(aCircle);
const GeomProp::CurveAnalysis aResult = aProp.FindInflections();
ASSERT_TRUE(aResult.IsDone);
EXPECT_EQ(aResult.Points.Length(), 0);
}
TEST(GeomPropCurveTest, BezierCurve_Inflections)
{
NCollection_Array1<gp_Pnt> aPoles(1, 4);
aPoles(1) = gp_Pnt(0, 0, 0);
aPoles(2) = gp_Pnt(1, 2, 0);
aPoles(3) = gp_Pnt(3, -1, 0);
aPoles(4) = gp_Pnt(4, 1, 0);
occ::handle<Geom_BezierCurve> aBezier = new Geom_BezierCurve(aPoles);
GeomProp_Curve aProp;
aProp.Initialize(aBezier);
ASSERT_TRUE(aProp.IsInitialized());
EXPECT_EQ(aProp.GetType(), GeomAbs_BezierCurve);
const GeomProp::CurveAnalysis aResult = aProp.FindInflections();
ASSERT_TRUE(aResult.IsDone);
EXPECT_GE(aResult.Points.Length(), 1);
}
TEST(GeomPropCurveTest, Line_TangentDirection)
{
occ::handle<Geom_Line> aLine = new Geom_Line(gp_Pnt(0, 0, 0), gp_Dir(0, 1, 0));
GeomProp_Curve aProp;
aProp.Initialize(aLine);
const GeomProp::TangentResult aTan = aProp.Tangent(5.0, Precision::Confusion());
ASSERT_TRUE(aTan.IsDefined);
EXPECT_NEAR(aTan.Direction.Y(), 1.0, Precision::Confusion());
}
TEST(GeomPropCurveTest, Circle_Normal)
{
gp_Circ aCirc(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), 5.0);
occ::handle<Geom_Circle> aCircle = new Geom_Circle(aCirc);
GeomProp_Curve aProp;
aProp.Initialize(aCircle);
// At param=0, point is (5,0,0), normal should point toward center (-1,0,0)
const GeomProp::NormalResult aNorm = aProp.Normal(0.0, Precision::Confusion());
ASSERT_TRUE(aNorm.IsDefined);
EXPECT_NEAR(aNorm.Direction.X(), -1.0, 1.0e-6);
}
TEST(GeomPropCurveTest, Circle_CentreOfCurvature)
{
gp_Circ aCirc(gp_Ax2(gp_Pnt(1, 2, 3), gp_Dir(0, 0, 1)), 5.0);
occ::handle<Geom_Circle> aCircle = new Geom_Circle(aCirc);
GeomProp_Curve aProp;
aProp.Initialize(aCircle);
const GeomProp::CentreResult aCentre = aProp.CentreOfCurvature(0.0, Precision::Confusion());
ASSERT_TRUE(aCentre.IsDefined);
EXPECT_NEAR(aCentre.Centre.X(), 1.0, 1.0e-6);
EXPECT_NEAR(aCentre.Centre.Y(), 2.0, 1.0e-6);
EXPECT_NEAR(aCentre.Centre.Z(), 3.0, 1.0e-6);
}
// ============================================================================
// GeomProp_Surface - initialization and basic queries
// ============================================================================
TEST(GeomPropSurfaceTest, UninitializedState)
{
GeomProp_Surface aProp;
EXPECT_FALSE(aProp.IsInitialized());
}
TEST(GeomPropSurfaceTest, InitializeFromNullHandle)
{
GeomProp_Surface aProp;
occ::handle<Geom_Surface> aNullSurf;
aProp.Initialize(aNullSurf);
EXPECT_FALSE(aProp.IsInitialized());
}
TEST(GeomPropSurfaceTest, Plane_ZeroCurvatures)
{
occ::handle<Geom_Plane> aPlane = new Geom_Plane(gp_Ax3());
GeomProp_Surface aProp;
aProp.Initialize(aPlane);
ASSERT_TRUE(aProp.IsInitialized());
EXPECT_EQ(aProp.GetType(), GeomAbs_Plane);
const GeomProp::SurfaceCurvatureResult aCurv = aProp.Curvatures(0.0, 0.0, Precision::Confusion());
ASSERT_TRUE(aCurv.IsDefined);
EXPECT_TRUE(aCurv.IsUmbilic);
EXPECT_NEAR(aCurv.MinCurvature, 0.0, Precision::Confusion());
EXPECT_NEAR(aCurv.MaxCurvature, 0.0, Precision::Confusion());
}
TEST(GeomPropSurfaceTest, Plane_Normal)
{
occ::handle<Geom_Plane> aPlane = new Geom_Plane(gp_Ax3());
GeomProp_Surface aProp;
aProp.Initialize(aPlane);
const GeomProp::SurfaceNormalResult aNorm = aProp.Normal(0.0, 0.0, Precision::Confusion());
ASSERT_TRUE(aNorm.IsDefined);
EXPECT_NEAR(std::abs(aNorm.Direction.Z()), 1.0, Precision::Confusion());
}
TEST(GeomPropSurfaceTest, Plane_MeanGaussian)
{
occ::handle<Geom_Plane> aPlane = new Geom_Plane(gp_Ax3());
GeomProp_Surface aProp;
aProp.Initialize(aPlane);
const GeomProp::MeanGaussianResult aRes = aProp.MeanGaussian(0.0, 0.0, Precision::Confusion());
ASSERT_TRUE(aRes.IsDefined);
EXPECT_NEAR(aRes.MeanCurvature, 0.0, Precision::Confusion());
EXPECT_NEAR(aRes.GaussianCurvature, 0.0, Precision::Confusion());
}
TEST(GeomPropSurfaceTest, Sphere_ConstantCurvature)
{
const double aRadius = 5.0;
occ::handle<Geom_SphericalSurface> aSphere = new Geom_SphericalSurface(gp_Ax3(), aRadius);
GeomProp_Surface aProp;
aProp.Initialize(aSphere);
ASSERT_TRUE(aProp.IsInitialized());
EXPECT_EQ(aProp.GetType(), GeomAbs_Sphere);
// Curvature sign depends on normal orientation. For outward-pointing normal,
// convex surfaces have negative curvature (center on opposite side of normal).
const GeomProp::SurfaceCurvatureResult aCurv = aProp.Curvatures(0.5, 0.5, Precision::Confusion());
ASSERT_TRUE(aCurv.IsDefined);
EXPECT_NEAR(std::abs(aCurv.MinCurvature), 1.0 / aRadius, 1.0e-10);
EXPECT_NEAR(std::abs(aCurv.MaxCurvature), 1.0 / aRadius, 1.0e-10);
}
TEST(GeomPropSurfaceTest, Sphere_MeanGaussian)
{
const double aRadius = 5.0;
occ::handle<Geom_SphericalSurface> aSphere = new Geom_SphericalSurface(gp_Ax3(), aRadius);
GeomProp_Surface aProp;
aProp.Initialize(aSphere);
const GeomProp::MeanGaussianResult aRes = aProp.MeanGaussian(0.5, 0.5, Precision::Confusion());
ASSERT_TRUE(aRes.IsDefined);
EXPECT_NEAR(std::abs(aRes.MeanCurvature), 1.0 / aRadius, 1.0e-10);
EXPECT_NEAR(aRes.GaussianCurvature, 1.0 / (aRadius * aRadius), 1.0e-10);
}
TEST(GeomPropSurfaceTest, Cylinder_Curvatures)
{
const double aRadius = 3.0;
occ::handle<Geom_CylindricalSurface> aCyl = new Geom_CylindricalSurface(gp_Ax3(), aRadius);
GeomProp_Surface aProp;
aProp.Initialize(aCyl);
ASSERT_TRUE(aProp.IsInitialized());
EXPECT_EQ(aProp.GetType(), GeomAbs_Cylinder);
const GeomProp::SurfaceCurvatureResult aCurv = aProp.Curvatures(0.5, 1.0, Precision::Confusion());
ASSERT_TRUE(aCurv.IsDefined);
// One curvature is zero (along axis), the other is non-zero (1/R with sign from normal).
const double aAbsMin = std::abs(aCurv.MinCurvature);
const double aAbsMax = std::abs(aCurv.MaxCurvature);
EXPECT_TRUE(aAbsMin < 1.0e-10 || aAbsMax < 1.0e-10);
EXPECT_NEAR(std::max(aAbsMin, aAbsMax), 1.0 / aRadius, 1.0e-10);
}
TEST(GeomPropSurfaceTest, Cylinder_MeanGaussian)
{
const double aRadius = 3.0;
occ::handle<Geom_CylindricalSurface> aCyl = new Geom_CylindricalSurface(gp_Ax3(), aRadius);
GeomProp_Surface aProp;
aProp.Initialize(aCyl);
const GeomProp::MeanGaussianResult aRes = aProp.MeanGaussian(0.5, 1.0, Precision::Confusion());
ASSERT_TRUE(aRes.IsDefined);
EXPECT_NEAR(std::abs(aRes.MeanCurvature), 1.0 / (2.0 * aRadius), 1.0e-10);
EXPECT_NEAR(aRes.GaussianCurvature, 0.0, Precision::Confusion());
}
TEST(GeomPropSurfaceTest, Cone_CurvaturesVaryAlongV)
{
gp_Ax3 anAx3;
occ::handle<Geom_ConicalSurface> aCone = new Geom_ConicalSurface(anAx3, M_PI / 6.0, 5.0);
GeomProp_Surface aProp;
aProp.Initialize(aCone);
ASSERT_TRUE(aProp.IsInitialized());
EXPECT_EQ(aProp.GetType(), GeomAbs_Cone);
const GeomProp::SurfaceCurvatureResult aCurv1 =
aProp.Curvatures(0.5, 0.0, Precision::Confusion());
const GeomProp::SurfaceCurvatureResult aCurv2 =
aProp.Curvatures(0.5, 5.0, Precision::Confusion());
ASSERT_TRUE(aCurv1.IsDefined);
ASSERT_TRUE(aCurv2.IsDefined);
// One curvature is zero (along ruling), the other varies with V.
// The magnitude of the non-zero curvature should decrease with V (larger radius).
const double aNonZero1 = std::max(std::abs(aCurv1.MinCurvature), std::abs(aCurv1.MaxCurvature));
const double aNonZero2 = std::max(std::abs(aCurv2.MinCurvature), std::abs(aCurv2.MaxCurvature));
EXPECT_GT(aNonZero1, aNonZero2);
}
TEST(GeomPropSurfaceTest, Torus_CurvaturesVaryAlongV)
{
const double aMajor = 10.0;
const double aMinor = 3.0;
occ::handle<Geom_ToroidalSurface> aTorus = new Geom_ToroidalSurface(gp_Ax3(), aMajor, aMinor);
GeomProp_Surface aProp;
aProp.Initialize(aTorus);
ASSERT_TRUE(aProp.IsInitialized());
EXPECT_EQ(aProp.GetType(), GeomAbs_Torus);
// At V=0 (outer edge): k1=1/r, k2=1/(R+r)
const GeomProp::MeanGaussianResult aRes0 = aProp.MeanGaussian(0.0, 0.0, Precision::Confusion());
ASSERT_TRUE(aRes0.IsDefined);
EXPECT_GT(aRes0.GaussianCurvature, 0.0); // Both curvatures positive at outer edge
// At V=PI (inner edge): k1=1/r, k2=-1/(R-r) (negative)
const GeomProp::MeanGaussianResult aResPI = aProp.MeanGaussian(0.0, M_PI, Precision::Confusion());
ASSERT_TRUE(aResPI.IsDefined);
EXPECT_LT(aResPI.GaussianCurvature, 0.0); // Negative Gaussian curvature at inner edge
}
@@ -0,0 +1,248 @@
// 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.
// Cross-validation tests comparing GeomProp_Curve against GeomLProp_CLProps
// for local curve differential properties (tangent, curvature, normal, centre).
#include <Geom_BezierCurve.hxx>
#include <Geom_BSplineCurve.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Ellipse.hxx>
#include <Geom_Hyperbola.hxx>
#include <Geom_Line.hxx>
#include <Geom_OffsetCurve.hxx>
#include <Geom_Parabola.hxx>
#include <GeomLProp_CLProps.hxx>
#include <GeomProp.hxx>
#include <GeomProp_Curve.hxx>
#include <gp_Ax2.hxx>
#include <gp_Circ.hxx>
#include <gp_Dir.hxx>
#include <gp_Elips.hxx>
#include <gp_Hypr.hxx>
#include <gp_Parab.hxx>
#include <NCollection_Array1.hxx>
#include <Precision.hxx>
#include <cmath>
#include <gtest/gtest.h>
namespace
{
constexpr double THE_LIN_TOL = Precision::PConfusion();
constexpr double THE_CURV_TOL = 1.0e-8;
constexpr double THE_DIR_TOL = 1.0e-6;
constexpr double THE_POINT_TOL = 1.0e-6;
//! Compare tangent from new GeomProp_Curve vs old GeomLProp_CLProps.
void compareTangent(const occ::handle<Geom_Curve>& theCurve, const double theParam)
{
GeomProp_Curve aProp;
aProp.Initialize(theCurve);
const GeomProp::TangentResult aNew = aProp.Tangent(theParam, THE_LIN_TOL);
GeomLProp_CLProps anOld(theCurve, theParam, 2, THE_LIN_TOL);
if (anOld.IsTangentDefined())
{
ASSERT_TRUE(aNew.IsDefined) << "New tangent undefined but old is defined at param=" << theParam;
gp_Dir anOldDir;
anOld.Tangent(anOldDir);
// Tangent directions may differ by sign
const double aDot = aNew.Direction.Dot(anOldDir);
EXPECT_NEAR(std::abs(aDot), 1.0, THE_DIR_TOL)
<< "Tangent direction mismatch at param=" << theParam;
}
}
//! Compare curvature from new GeomProp_Curve vs old GeomLProp_CLProps.
void compareCurvature(const occ::handle<Geom_Curve>& theCurve, const double theParam)
{
GeomProp_Curve aProp;
aProp.Initialize(theCurve);
const GeomProp::CurvatureResult aNew = aProp.Curvature(theParam, THE_LIN_TOL);
GeomLProp_CLProps anOld(theCurve, theParam, 2, THE_LIN_TOL);
if (anOld.IsTangentDefined())
{
ASSERT_TRUE(aNew.IsDefined) << "New curvature undefined at param=" << theParam;
EXPECT_NEAR(aNew.Value, anOld.Curvature(), THE_CURV_TOL)
<< "Curvature mismatch at param=" << theParam;
}
}
//! Compare normal from new GeomProp_Curve vs old GeomLProp_CLProps.
void compareNormal(const occ::handle<Geom_Curve>& theCurve, const double theParam)
{
GeomProp_Curve aProp;
aProp.Initialize(theCurve);
const GeomProp::NormalResult aNew = aProp.Normal(theParam, THE_LIN_TOL);
GeomLProp_CLProps anOld(theCurve, theParam, 2, THE_LIN_TOL);
if (anOld.IsTangentDefined() && std::abs(anOld.Curvature()) > THE_LIN_TOL)
{
ASSERT_TRUE(aNew.IsDefined) << "New normal undefined at param=" << theParam;
gp_Dir anOldNorm;
anOld.Normal(anOldNorm);
const double aDot = aNew.Direction.Dot(anOldNorm);
EXPECT_NEAR(std::abs(aDot), 1.0, THE_DIR_TOL)
<< "Normal direction mismatch at param=" << theParam;
}
}
//! Compare centre of curvature from new vs old.
void compareCentre(const occ::handle<Geom_Curve>& theCurve, const double theParam)
{
GeomProp_Curve aProp;
aProp.Initialize(theCurve);
const GeomProp::CentreResult aNew = aProp.CentreOfCurvature(theParam, THE_LIN_TOL);
GeomLProp_CLProps anOld(theCurve, theParam, 2, THE_LIN_TOL);
if (anOld.IsTangentDefined() && std::abs(anOld.Curvature()) > THE_LIN_TOL)
{
ASSERT_TRUE(aNew.IsDefined) << "New centre undefined at param=" << theParam;
gp_Pnt anOldCentre;
anOld.CentreOfCurvature(anOldCentre);
EXPECT_NEAR(aNew.Centre.Distance(anOldCentre), 0.0, THE_POINT_TOL)
<< "Centre mismatch at param=" << theParam;
}
}
//! Run all comparisons at several parameter values.
void compareAll(const occ::handle<Geom_Curve>& theCurve,
const double theFirst,
const double theLast,
const int theNbSamples = 10)
{
const double aStep = (theLast - theFirst) / theNbSamples;
for (int i = 0; i <= theNbSamples; ++i)
{
const double aParam = theFirst + i * aStep;
compareTangent(theCurve, aParam);
compareCurvature(theCurve, aParam);
compareNormal(theCurve, aParam);
compareCentre(theCurve, aParam);
}
}
} // namespace
// ============================================================================
// Line
// ============================================================================
TEST(GeomProp_VsCLPropsTest, Line)
{
occ::handle<Geom_Line> aLine = new Geom_Line(gp_Pnt(0, 0, 0), gp_Dir(1, 1, 0));
compareAll(aLine, -5.0, 5.0);
}
// ============================================================================
// Circle
// ============================================================================
TEST(GeomProp_VsCLPropsTest, Circle)
{
gp_Circ aCirc(gp_Ax2(gp_Pnt(1, 2, 3), gp_Dir(0, 0, 1)), 5.0);
occ::handle<Geom_Circle> aCircle = new Geom_Circle(aCirc);
compareAll(aCircle, 0.0, 2.0 * M_PI);
}
// ============================================================================
// Ellipse
// ============================================================================
TEST(GeomProp_VsCLPropsTest, Ellipse)
{
gp_Elips anElips(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), 10.0, 5.0);
occ::handle<Geom_Ellipse> anEllipse = new Geom_Ellipse(anElips);
compareAll(anEllipse, 0.0, 2.0 * M_PI);
}
// ============================================================================
// Hyperbola
// ============================================================================
TEST(GeomProp_VsCLPropsTest, Hyperbola)
{
gp_Hypr anHypr(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), 6.0, 3.0);
occ::handle<Geom_Hyperbola> aHyperbola = new Geom_Hyperbola(anHypr);
compareAll(aHyperbola, -2.0, 2.0);
}
// ============================================================================
// Parabola
// ============================================================================
TEST(GeomProp_VsCLPropsTest, Parabola)
{
gp_Parab aParab(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), 2.0);
occ::handle<Geom_Parabola> aParabola = new Geom_Parabola(aParab);
compareAll(aParabola, -5.0, 5.0);
}
// ============================================================================
// Bezier
// ============================================================================
TEST(GeomProp_VsCLPropsTest, BezierCubic)
{
NCollection_Array1<gp_Pnt> aPoles(1, 4);
aPoles(1) = gp_Pnt(0, 0, 0);
aPoles(2) = gp_Pnt(1, 2, 1);
aPoles(3) = gp_Pnt(3, -1, 0);
aPoles(4) = gp_Pnt(4, 1, 1);
occ::handle<Geom_BezierCurve> aBezier = new Geom_BezierCurve(aPoles);
compareAll(aBezier, 0.0, 1.0);
}
// ============================================================================
// BSpline
// ============================================================================
TEST(GeomProp_VsCLPropsTest, BSplineCubic)
{
NCollection_Array1<gp_Pnt> aPoles(1, 6);
aPoles(1) = gp_Pnt(0, 0, 0);
aPoles(2) = gp_Pnt(1, 3, 0);
aPoles(3) = gp_Pnt(2, 1, 1);
aPoles(4) = gp_Pnt(3, 4, 0);
aPoles(5) = gp_Pnt(4, 2, 1);
aPoles(6) = gp_Pnt(5, 0, 0);
NCollection_Array1<double> aKnots(1, 4);
aKnots(1) = 0.0;
aKnots(2) = 0.33;
aKnots(3) = 0.66;
aKnots(4) = 1.0;
NCollection_Array1<int> aMults(1, 4);
aMults(1) = 4;
aMults(2) = 1;
aMults(3) = 1;
aMults(4) = 4;
occ::handle<Geom_BSplineCurve> aBSpline = new Geom_BSplineCurve(aPoles, aKnots, aMults, 3);
compareAll(aBSpline, 0.0, 1.0);
}
// ============================================================================
// Offset curve
// ============================================================================
TEST(GeomProp_VsCLPropsTest, OffsetCircle)
{
gp_Circ aCirc(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), 5.0);
occ::handle<Geom_Circle> aCircle = new Geom_Circle(aCirc);
occ::handle<Geom_OffsetCurve> anOffset = new Geom_OffsetCurve(aCircle, 2.0, gp_Dir(0, 0, 1));
compareAll(anOffset, 0.0, 2.0 * M_PI);
}
@@ -0,0 +1,213 @@
// 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.
// Cross-validation tests comparing GeomProp_Surface against GeomLProp_SLProps
// for local surface differential properties (normal, curvatures).
#include <Geom_BSplineSurface.hxx>
#include <NCollection_Array2.hxx>
#include <Geom_ConicalSurface.hxx>
#include <Geom_CylindricalSurface.hxx>
#include <Geom_Plane.hxx>
#include <Geom_SphericalSurface.hxx>
#include <Geom_ToroidalSurface.hxx>
#include <GeomLProp_SLProps.hxx>
#include <GeomProp.hxx>
#include <GeomProp_Surface.hxx>
#include <gp_Ax3.hxx>
#include <NCollection_Array1.hxx>
#include <Precision.hxx>
#include <cmath>
#include <gtest/gtest.h>
namespace
{
constexpr double THE_LIN_TOL = Precision::PConfusion();
constexpr double THE_CURV_TOL = 1.0e-6;
constexpr double THE_DIR_TOL = 1.0e-4;
//! Compare surface normal from new GeomProp_Surface vs old GeomLProp_SLProps.
void compareNormal(const occ::handle<Geom_Surface>& theSurf, const double theU, const double theV)
{
GeomProp_Surface aProp;
aProp.Initialize(theSurf);
const GeomProp::SurfaceNormalResult aNew = aProp.Normal(theU, theV, THE_LIN_TOL);
GeomLProp_SLProps anOld(theSurf, theU, theV, 2, THE_LIN_TOL);
if (anOld.IsNormalDefined())
{
ASSERT_TRUE(aNew.IsDefined) << "New normal undefined at (" << theU << "," << theV << ")";
const gp_Dir anOldNorm = anOld.Normal();
const double aDot = aNew.Direction.Dot(anOldNorm);
EXPECT_NEAR(std::abs(aDot), 1.0, THE_DIR_TOL)
<< "Normal mismatch at (" << theU << "," << theV << ")";
}
}
//! Compare curvatures from new GeomProp_Surface vs old GeomLProp_SLProps.
void compareCurvatures(const occ::handle<Geom_Surface>& theSurf,
const double theU,
const double theV)
{
GeomProp_Surface aProp;
aProp.Initialize(theSurf);
const GeomProp::SurfaceCurvatureResult aNew = aProp.Curvatures(theU, theV, THE_LIN_TOL);
GeomLProp_SLProps anOld(theSurf, theU, theV, 2, THE_LIN_TOL);
if (anOld.IsCurvatureDefined())
{
ASSERT_TRUE(aNew.IsDefined) << "New curvatures undefined at (" << theU << "," << theV << ")";
EXPECT_NEAR(aNew.MinCurvature, anOld.MinCurvature(), THE_CURV_TOL)
<< "MinCurvature mismatch at (" << theU << "," << theV << ")";
EXPECT_NEAR(aNew.MaxCurvature, anOld.MaxCurvature(), THE_CURV_TOL)
<< "MaxCurvature mismatch at (" << theU << "," << theV << ")";
// Note: IsUmbilic comparison intentionally omitted - the flag is tolerance-dependent
// and may differ between implementations while curvature values agree.
}
}
//! Compare mean and Gaussian curvatures.
void compareMeanGaussian(const occ::handle<Geom_Surface>& theSurf,
const double theU,
const double theV)
{
GeomProp_Surface aProp;
aProp.Initialize(theSurf);
const GeomProp::MeanGaussianResult aNew = aProp.MeanGaussian(theU, theV, THE_LIN_TOL);
GeomLProp_SLProps anOld(theSurf, theU, theV, 2, THE_LIN_TOL);
if (anOld.IsCurvatureDefined())
{
ASSERT_TRUE(aNew.IsDefined) << "New MeanGaussian undefined at (" << theU << "," << theV << ")";
EXPECT_NEAR(aNew.MeanCurvature, anOld.MeanCurvature(), THE_CURV_TOL)
<< "Mean curvature mismatch at (" << theU << "," << theV << ")";
EXPECT_NEAR(aNew.GaussianCurvature, anOld.GaussianCurvature(), THE_CURV_TOL)
<< "Gaussian curvature mismatch at (" << theU << "," << theV << ")";
}
}
//! Run all surface comparisons at a grid of parameter values.
void compareAllSurface(const occ::handle<Geom_Surface>& theSurf,
const double theUMin,
const double theUMax,
const double theVMin,
const double theVMax,
const int theNbU = 5,
const int theNbV = 5)
{
const double aUStep = (theUMax - theUMin) / theNbU;
const double aVStep = (theVMax - theVMin) / theNbV;
for (int i = 0; i <= theNbU; ++i)
{
for (int j = 0; j <= theNbV; ++j)
{
const double aU = theUMin + i * aUStep;
const double aV = theVMin + j * aVStep;
compareNormal(theSurf, aU, aV);
compareCurvatures(theSurf, aU, aV);
compareMeanGaussian(theSurf, aU, aV);
}
}
}
} // namespace
// ============================================================================
// Plane
// ============================================================================
TEST(GeomProp_VsSLPropsTest, Plane)
{
occ::handle<Geom_Plane> aPlane = new Geom_Plane(gp_Ax3());
compareAllSurface(aPlane, -5.0, 5.0, -5.0, 5.0);
}
// ============================================================================
// Sphere
// ============================================================================
TEST(GeomProp_VsSLPropsTest, Sphere)
{
occ::handle<Geom_SphericalSurface> aSphere = new Geom_SphericalSurface(gp_Ax3(), 5.0);
// Avoid poles where D1U degenerates
compareAllSurface(aSphere, 0.0, 2.0 * M_PI, -M_PI / 3.0, M_PI / 3.0);
}
// ============================================================================
// Cylinder
// ============================================================================
TEST(GeomProp_VsSLPropsTest, Cylinder)
{
occ::handle<Geom_CylindricalSurface> aCyl = new Geom_CylindricalSurface(gp_Ax3(), 3.0);
compareAllSurface(aCyl, 0.0, 2.0 * M_PI, -5.0, 5.0);
}
// ============================================================================
// Cone
// ============================================================================
TEST(GeomProp_VsSLPropsTest, Cone)
{
occ::handle<Geom_ConicalSurface> aCone = new Geom_ConicalSurface(gp_Ax3(), M_PI / 6.0, 5.0);
// Stay away from the apex (at V = -R/sin(alpha) = -10)
compareAllSurface(aCone, 0.0, 2.0 * M_PI, 0.0, 10.0);
}
// ============================================================================
// Torus
// ============================================================================
TEST(GeomProp_VsSLPropsTest, Torus)
{
occ::handle<Geom_ToroidalSurface> aTorus = new Geom_ToroidalSurface(gp_Ax3(), 10.0, 3.0);
compareAllSurface(aTorus, 0.0, 2.0 * M_PI, 0.0, 2.0 * M_PI);
}
// ============================================================================
// BSpline Surface
// ============================================================================
TEST(GeomProp_VsSLPropsTest, BSplineSurface)
{
// Simple 4x4 bicubic patch
NCollection_Array2<gp_Pnt> aPoles(1, 4, 1, 4);
NCollection_Array1<double> aUKnots(1, 2), aVKnots(1, 2);
NCollection_Array1<int> aUMults(1, 2), aVMults(1, 2);
aUKnots(1) = 0.0;
aUKnots(2) = 1.0;
aVKnots(1) = 0.0;
aVKnots(2) = 1.0;
aUMults(1) = 4;
aUMults(2) = 4;
aVMults(1) = 4;
aVMults(2) = 4;
for (int i = 1; i <= 4; ++i)
{
for (int j = 1; j <= 4; ++j)
{
const double aX = i - 1;
const double aY = j - 1;
const double aZ = std::sin((i - 1) * 0.5) * std::cos((j - 1) * 0.5);
aPoles.SetValue(i, j, gp_Pnt(aX, aY, aZ));
}
}
occ::handle<Geom_BSplineSurface> aSurf =
new Geom_BSplineSurface(aPoles, aUKnots, aVKnots, aUMults, aVMults, 3, 3);
compareAllSurface(aSurf, 0.0, 1.0, 0.0, 1.0, 4, 4);
}
@@ -0,0 +1,46 @@
# Source files for GeomProp package
set(OCCT_GeomProp_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
set(OCCT_GeomProp_FILES
GeomProp.hxx
GeomProp.cxx
GeomProp_BezierCurve.hxx
GeomProp_BezierCurve.cxx
GeomProp_BezierSurface.hxx
GeomProp_BezierSurface.cxx
GeomProp_BSplineCurve.hxx
GeomProp_BSplineCurve.cxx
GeomProp_BSplineSurface.hxx
GeomProp_BSplineSurface.cxx
GeomProp_Circle.hxx
GeomProp_Cone.hxx
GeomProp_Cone.cxx
GeomProp_Curve.hxx
GeomProp_Curve.cxx
GeomProp_Cylinder.hxx
GeomProp_Ellipse.hxx
GeomProp_Ellipse.cxx
GeomProp_Hyperbola.hxx
GeomProp_Hyperbola.cxx
GeomProp_Line.hxx
GeomProp_OffsetCurve.hxx
GeomProp_OffsetCurve.cxx
GeomProp_OffsetSurface.hxx
GeomProp_OffsetSurface.cxx
GeomProp_OtherCurve.hxx
GeomProp_OtherCurve.cxx
GeomProp_OtherSurface.hxx
GeomProp_OtherSurface.cxx
GeomProp_Parabola.hxx
GeomProp_Parabola.cxx
GeomProp_Plane.hxx
GeomProp_Sphere.hxx
GeomProp_Surface.hxx
GeomProp_Surface.cxx
GeomProp_SurfaceOfExtrusion.hxx
GeomProp_SurfaceOfExtrusion.cxx
GeomProp_SurfaceOfRevolution.hxx
GeomProp_SurfaceOfRevolution.cxx
GeomProp_Torus.hxx
GeomProp_Torus.cxx
)
@@ -0,0 +1,315 @@
// 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 <GeomProp.hxx>
#include <cmath>
//==================================================================================================
GeomProp::TangentResult GeomProp::ComputeTangent(const gp_Vec& theD1,
const gp_Vec& theD2,
const gp_Vec& theD3,
const double theTol)
{
const double aTol2 = theTol * theTol;
// Try first derivative
if (theD1.SquareMagnitude() > aTol2)
{
return {gp_Dir(theD1), true};
}
// Try second derivative
if (theD2.SquareMagnitude() > aTol2)
{
return {gp_Dir(theD2), true};
}
// Try third derivative
if (theD3.SquareMagnitude() > aTol2)
{
return {gp_Dir(theD3), true};
}
return {{}, false};
}
//==================================================================================================
GeomProp::CurvatureResult GeomProp::ComputeCurvature(const gp_Vec& theD1,
const gp_Vec& theD2,
const double theTol)
{
const double aTol2 = theTol * theTol;
const double aDD1 = theD1.SquareMagnitude();
// If first derivative is null, curvature is infinite (singular point).
if (aDD1 <= aTol2)
{
return {0.0, true, true};
}
const double aDD2 = theD2.SquareMagnitude();
// If second derivative is null, curvature is zero.
if (aDD2 <= aTol2)
{
return {0.0, true, false};
}
// Cross product magnitude squared: |D1 x D2|^2
const gp_Vec aCross = theD1.Crossed(theD2);
const double aN = aCross.SquareMagnitude();
// If D1 and D2 are collinear, curvature is zero.
const double aT = aN / aDD1 / aDD2;
if (aT <= aTol2)
{
return {0.0, true, false};
}
// Curvature = |D1 x D2| / |D1|^3
const double aCurvature = std::sqrt(aN) / aDD1 / std::sqrt(aDD1);
return {aCurvature, true, false};
}
//==================================================================================================
GeomProp::NormalResult GeomProp::ComputeNormal(const gp_Vec& theD1,
const gp_Vec& theD2,
const double theTol)
{
// First compute curvature to check if normal is defined.
const CurvatureResult aCurvRes = ComputeCurvature(theD1, theD2, theTol);
if (!aCurvRes.IsDefined || aCurvRes.IsInfinite || std::abs(aCurvRes.Value) <= theTol)
{
return {{}, false};
}
// Normal = D2 * (D1.D1) - D1 * (D1.D2)
// This is equivalent to (D1 x D2) x D1 using the vector triple product identity.
const gp_Vec aNorm = theD2 * theD1.Dot(theD1) - theD1 * theD1.Dot(theD2);
if (aNorm.SquareMagnitude() <= theTol * theTol)
{
return {{}, false};
}
return {gp_Dir(aNorm), true};
}
//==================================================================================================
GeomProp::CentreResult GeomProp::ComputeCentreOfCurvature(const gp_Pnt& thePnt,
const gp_Vec& theD1,
const gp_Vec& theD2,
const double theTol)
{
const CurvatureResult aCurvRes = ComputeCurvature(theD1, theD2, theTol);
if (!aCurvRes.IsDefined || aCurvRes.IsInfinite || std::abs(aCurvRes.Value) <= theTol)
{
return {{}, false};
}
// Normal vector (unnormalized) = D2 * (D1.D1) - D1 * (D1.D2)
gp_Vec aNorm = theD2 * theD1.Dot(theD1) - theD1 * theD1.Dot(theD2);
aNorm.Normalize();
aNorm.Divide(aCurvRes.Value);
return {thePnt.Translated(aNorm), true};
}
//==================================================================================================
GeomProp::SurfaceNormalResult GeomProp::ComputeSurfaceNormal(const gp_Vec& theD1U,
const gp_Vec& theD1V,
const double theTol)
{
const gp_Vec aCross = theD1U.Crossed(theD1V);
if (aCross.SquareMagnitude() <= theTol * theTol)
{
return {{}, false};
}
return {gp_Dir(aCross), true};
}
//==================================================================================================
GeomProp::SurfaceCurvatureResult GeomProp::ComputeSurfaceCurvatures(const gp_Vec& theD1U,
const gp_Vec& theD1V,
const gp_Vec& theD2U,
const gp_Vec& theD2V,
const gp_Vec& theDUV,
const double theTol)
{
// Compute surface normal.
const SurfaceNormalResult aNormRes = ComputeSurfaceNormal(theD1U, theD1V, theTol);
if (!aNormRes.IsDefined)
{
return {};
}
const gp_Vec aNormal(aNormRes.Direction);
// First fundamental form coefficients.
const double aE = theD1U.Dot(theD1U);
const double aF = theD1U.Dot(theD1V);
const double aG = theD1V.Dot(theD1V);
// Second fundamental form coefficients.
const double aL = aNormal.Dot(theD2U);
const double aM = aNormal.Dot(theDUV);
const double aN_ = aNormal.Dot(theD2V);
// Discriminant of first fundamental form.
const double aDet = aE * aG - aF * aF;
if (std::abs(aDet) <= theTol * theTol)
{
return {};
}
// Mean curvature: H = (EN - 2FM + GL) / (2 * det)
const double aH = (aE * aN_ - 2.0 * aF * aM + aG * aL) / (2.0 * aDet);
// Gaussian curvature: K = (LN - M^2) / det
const double aK = (aL * aN_ - aM * aM) / aDet;
// Principal curvatures from: k^2 - 2Hk + K = 0
const double aDiscriminant = aH * aH - aK;
SurfaceCurvatureResult aResult;
aResult.IsDefined = true;
if (aDiscriminant <= theTol * theTol)
{
// Umbilic point: both principal curvatures are equal.
aResult.MinCurvature = aH;
aResult.MaxCurvature = aH;
aResult.IsUmbilic = true;
// At umbilic points, directions are undefined - use U and V directions.
if (theD1U.SquareMagnitude() > theTol * theTol)
{
aResult.MinDirection = gp_Dir(theD1U);
}
if (theD1V.SquareMagnitude() > theTol * theTol)
{
aResult.MaxDirection = gp_Dir(theD1V);
}
return aResult;
}
const double aSqrtDisc = std::sqrt(std::max(aDiscriminant, 0.0));
const double aK1 = aH - aSqrtDisc; // min curvature
const double aK2 = aH + aSqrtDisc; // max curvature
aResult.MinCurvature = aK1;
aResult.MaxCurvature = aK2;
aResult.IsUmbilic = false;
// Compute principal directions from the shape operator (Weingarten map).
// For each principal curvature k, the principal direction (a, b) satisfies:
// (L - kE)*a + (M - kF)*b = 0
// (M - kF)*a + (N - kG)*b = 0
// We pick the equation with the largest coefficient to avoid division by near-zero.
for (int i = 0; i < 2; ++i)
{
const double aKi = (i == 0) ? aK1 : aK2;
const double aCoeffA = aL - aKi * aE;
const double aCoeffB = aM - aKi * aF;
// TODO: aCoeffC is always equal to aCoeffB (symmetric shape operator matrix).
// Consider removing the redundant variable and using aCoeffB directly.
const double aCoeffC = aM - aKi * aF;
const double aCoeffD = aN_ - aKi * aG;
gp_Vec aDir;
if (std::abs(aCoeffA) > std::abs(aCoeffD))
{
// From first equation: a*coeff_a + b*coeff_b = 0 => b/a = -coeff_a/coeff_b
if (std::abs(aCoeffB) > theTol)
{
aDir = theD1U * (-aCoeffB) + theD1V * aCoeffA;
}
else
{
aDir = theD1V;
}
}
else
{
// From second equation: a*coeff_c + b*coeff_d = 0 => a/b = -coeff_d/coeff_c
if (std::abs(aCoeffC) > theTol)
{
aDir = theD1U * aCoeffD + theD1V * (-aCoeffC);
}
else
{
aDir = theD1U;
}
}
if (aDir.SquareMagnitude() > theTol * theTol)
{
if (i == 0)
{
aResult.MinDirection = gp_Dir(aDir);
}
else
{
aResult.MaxDirection = gp_Dir(aDir);
}
}
}
return aResult;
}
//==================================================================================================
GeomProp::MeanGaussianResult GeomProp::ComputeMeanGaussian(const gp_Vec& theD1U,
const gp_Vec& theD1V,
const gp_Vec& theD2U,
const gp_Vec& theD2V,
const gp_Vec& theDUV,
const double theTol)
{
// Compute surface normal.
const SurfaceNormalResult aNormRes = ComputeSurfaceNormal(theD1U, theD1V, theTol);
if (!aNormRes.IsDefined)
{
return {};
}
const gp_Vec aNormal(aNormRes.Direction);
// First fundamental form coefficients.
const double aE = theD1U.Dot(theD1U);
const double aF = theD1U.Dot(theD1V);
const double aG = theD1V.Dot(theD1V);
// Second fundamental form coefficients.
const double aL = aNormal.Dot(theD2U);
const double aM = aNormal.Dot(theDUV);
const double aN_ = aNormal.Dot(theD2V);
// Discriminant of first fundamental form.
const double aDet = aE * aG - aF * aF;
if (std::abs(aDet) <= theTol * theTol)
{
return {};
}
MeanGaussianResult aResult;
aResult.IsDefined = true;
aResult.MeanCurvature = (aE * aN_ - 2.0 * aF * aM + aG * aL) / (2.0 * aDet);
aResult.GaussianCurvature = (aL * aN_ - aM * aM) / aDet;
return aResult;
}
@@ -0,0 +1,212 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_HeaderFile
#define _GeomProp_HeaderFile
#include <gp_Dir.hxx>
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
#include <NCollection_DynamicArray.hxx>
#include <Standard.hxx>
//! @brief Namespace containing result structures and free functions for 3D curve
//! and surface differential property computation.
//!
//! Provides lightweight result structures with explicit validity flags instead of
//! exception-based APIs, and geometry-agnostic free functions that compute local
//! differential properties from derivative vectors.
namespace GeomProp
{
// ============================================================================
// Curve result structures
// ============================================================================
//! Result of tangent direction computation.
struct TangentResult
{
gp_Dir Direction; //!< Tangent direction (valid only when IsDefined is true)
bool IsDefined = false; //!< True if the tangent is well-defined
};
//! Result of curvature computation.
struct CurvatureResult
{
double Value = 0.0; //!< Curvature value (valid only when IsDefined is true)
bool IsDefined = false; //!< True if curvature could be computed
bool IsInfinite = false; //!< True if first derivative is null (singular point)
};
//! Result of normal direction computation.
struct NormalResult
{
gp_Dir Direction; //!< Normal direction (valid only when IsDefined is true)
bool IsDefined = false; //!< True if the normal is well-defined
};
//! Result of centre of curvature computation.
struct CentreResult
{
gp_Pnt Centre; //!< Centre of curvature (valid only when IsDefined is true)
bool IsDefined = false; //!< True if the centre is well-defined
};
//! Type of a special curve point (curvature extremum or inflection).
enum class CIType
{
Inflection, //!< Inflection point (curvature changes sign)
MinCurvature, //!< Local minimum of the radius of curvature (maximum of |curvature|)
MaxCurvature //!< Local maximum of the radius of curvature (minimum of |curvature|)
};
//! A special point on a curve with its parameter and type.
struct CurveSpecialPoint
{
double Parameter = 0.0; //!< Curve parameter
CIType Type = CIType::Inflection; //!< Point type
};
//! Result of global curve analysis (curvature extrema and inflection points).
struct CurveAnalysis
{
NCollection_DynamicArray<CurveSpecialPoint> Points; //!< Special points sorted by parameter
bool IsDone = false; //!< True if analysis completed
};
// ============================================================================
// Surface result structures
// ============================================================================
//! Result of surface normal computation.
struct SurfaceNormalResult
{
gp_Dir Direction; //!< Surface normal direction (valid only when IsDefined is true)
bool IsDefined = false; //!< True if the normal is well-defined
};
//! Result of surface principal curvature computation.
struct SurfaceCurvatureResult
{
double MinCurvature = 0.0; //!< Minimum principal curvature (valid only when IsDefined is true)
double MaxCurvature = 0.0; //!< Maximum principal curvature (valid only when IsDefined is true)
gp_Dir MinDirection; //!< Direction of minimum curvature (valid only when IsDefined is true)
gp_Dir MaxDirection; //!< Direction of maximum curvature (valid only when IsDefined is true)
bool IsDefined = false; //!< True if curvatures could be computed
bool IsUmbilic = false; //!< True if the point is umbilic (all curvatures equal)
};
//! Result of mean and Gaussian curvature computation.
struct MeanGaussianResult
{
double MeanCurvature = 0.0; //!< Mean curvature H = (k1 + k2) / 2
double GaussianCurvature = 0.0; //!< Gaussian curvature K = k1 * k2
bool IsDefined = false; //!< True if curvatures could be computed
};
// ============================================================================
// Curve free functions
// ============================================================================
//! Compute tangent direction from derivative vectors.
//! Tries D1 first; if D1 magnitude^2 <= theTol^2, tries D2, then D3.
//! @param[in] theD1 first derivative vector
//! @param[in] theD2 second derivative vector
//! @param[in] theD3 third derivative vector
//! @param[in] theTol linear tolerance for zero-vector detection
//! @return tangent result with validity flag
Standard_EXPORT TangentResult ComputeTangent(const gp_Vec& theD1,
const gp_Vec& theD2,
const gp_Vec& theD3,
double theTol);
//! Compute curvature from first and second derivative vectors.
//! Curvature = |D1 x D2| / |D1|^3
//! @param[in] theD1 first derivative vector
//! @param[in] theD2 second derivative vector
//! @param[in] theTol linear tolerance for zero-vector detection
//! @return curvature result with validity and infinity flags
Standard_EXPORT CurvatureResult ComputeCurvature(const gp_Vec& theD1,
const gp_Vec& theD2,
double theTol);
//! Compute normal direction from first and second derivative vectors.
//! Normal = D1 x (D2 x D1) (normalized), perpendicular to tangent pointing toward center.
//! @param[in] theD1 first derivative vector
//! @param[in] theD2 second derivative vector
//! @param[in] theTol linear tolerance for zero-vector detection
//! @return normal result with validity flag
Standard_EXPORT NormalResult ComputeNormal(const gp_Vec& theD1, const gp_Vec& theD2, double theTol);
//! Compute centre of curvature from point and derivative vectors.
//! Centre = Point + Normal / Curvature
//! @param[in] thePnt point on the curve
//! @param[in] theD1 first derivative vector
//! @param[in] theD2 second derivative vector
//! @param[in] theTol linear tolerance for zero-vector detection
//! @return centre result with validity flag
Standard_EXPORT CentreResult ComputeCentreOfCurvature(const gp_Pnt& thePnt,
const gp_Vec& theD1,
const gp_Vec& theD2,
double theTol);
// ============================================================================
// Surface free functions
// ============================================================================
//! Compute surface normal from first partial derivatives.
//! Normal = D1U x D1V (normalized).
//! @param[in] theD1U first partial derivative in U direction
//! @param[in] theD1V first partial derivative in V direction
//! @param[in] theTol linear tolerance for zero-vector detection
//! @return surface normal result with validity flag
Standard_EXPORT SurfaceNormalResult ComputeSurfaceNormal(const gp_Vec& theD1U,
const gp_Vec& theD1V,
double theTol);
//! Compute principal curvatures and directions from surface derivatives.
//! Uses first and second fundamental forms to compute principal curvatures.
//! @param[in] theD1U first partial derivative in U direction
//! @param[in] theD1V first partial derivative in V direction
//! @param[in] theD2U second partial derivative in U direction
//! @param[in] theD2V second partial derivative in V direction
//! @param[in] theDUV mixed partial derivative
//! @param[in] theTol linear tolerance for zero-vector detection
//! @return surface curvature result with principal curvatures and directions
Standard_EXPORT SurfaceCurvatureResult ComputeSurfaceCurvatures(const gp_Vec& theD1U,
const gp_Vec& theD1V,
const gp_Vec& theD2U,
const gp_Vec& theD2V,
const gp_Vec& theDUV,
double theTol);
//! Compute mean and Gaussian curvatures from surface derivatives.
//! Mean curvature H = (EN - 2FM + GL) / (2(EG - F^2))
//! Gaussian curvature K = (LN - M^2) / (EG - F^2)
//! @param[in] theD1U first partial derivative in U direction
//! @param[in] theD1V first partial derivative in V direction
//! @param[in] theD2U second partial derivative in U direction
//! @param[in] theD2V second partial derivative in V direction
//! @param[in] theDUV mixed partial derivative
//! @param[in] theTol linear tolerance for zero-vector detection
//! @return mean and Gaussian curvature result
Standard_EXPORT MeanGaussianResult ComputeMeanGaussian(const gp_Vec& theD1U,
const gp_Vec& theD1V,
const gp_Vec& theD2U,
const gp_Vec& theD2V,
const gp_Vec& theDUV,
double theTol);
} // namespace GeomProp
#endif // _GeomProp_HeaderFile
@@ -0,0 +1,441 @@
// 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 <GeomProp_BSplineCurve.hxx>
#include <GeomAbs_Shape.hxx>
#include <gp.hxx>
#include <MathRoot_Brent.hxx>
#include <MathRoot_Multiple.hxx>
#include <NCollection_Array1.hxx>
#include <Precision.hxx>
#include <cmath>
namespace
{
constexpr double THE_CURVATURE_DERIV_COEFF = 3.0; //!< Coefficient in d(KC)/dU formula
constexpr double THE_DIFF_STEP_DIVISOR = 100.0; //!< Divisor for numerical differentiation step
constexpr double THE_D2_MAGNITUDE_THRESHOLD = 1.0e-4; //!< Threshold for second derivative magnitude
constexpr double THE_EPSILON_SCALE = 1.0e-4; //!< Scale factor for epsilon relative to domain
constexpr int THE_EXTREMA_NB_SAMPLES = 100; //!< Number of samples for curvature extrema search
constexpr int THE_INFLECTION_NB_SAMPLES = 30; //!< Number of samples for inflection search
constexpr double THE_INFLECTION_TOLERANCE = 1.0e-6; //!< Tolerance for inflection point finding
//! Function for finding curvature extrema: F = d(curvature)/dU = 0
class FuncCurExt
{
public:
FuncCurExt(const GeomAdaptor_Curve* theCurve, const double theTol)
: myCurve(theCurve),
myEpsX(theTol)
{
}
bool Value(const double X, double& F)
{
gp_Pnt aP;
gp_Vec aV1, aV2, aV3;
myCurve->D3(X, aP, aV1, aV2, aV3);
const gp_Vec aCPV1V2 = aV1.Crossed(aV2);
const double aCPMag = aCPV1V2.Magnitude();
const gp_Vec aCPV1V3 = aV1.Crossed(aV3);
const double aV1V2 = aV1.Dot(aV2);
const double aV1V1 = aV1.SquareMagnitude();
const double aNV1 = std::sqrt(aV1V1);
const double aV13 = aV1V1 * aNV1;
const double aV15 = aV13 * aV1V1;
if (aV15 < gp::Resolution())
{
return false;
}
if (aCPMag < gp::Resolution())
{
F = aCPV1V3.Magnitude() / aV13;
return true;
}
const double aDCrossDU = aCPV1V2.Dot(aCPV1V3) / aCPMag;
F = aDCrossDU / aV13 - THE_CURVATURE_DERIV_COEFF * aCPMag * aV1V2 / aV15;
return true;
}
bool Values(const double X, double& F, double& D)
{
double aDx = myEpsX / THE_DIFF_STEP_DIVISOR;
if (X + aDx > myCurve->LastParameter())
{
aDx = -aDx;
}
Value(X, F);
double aF2;
Value(X + aDx, aF2);
D = (aF2 - F) / aDx;
return true;
}
bool IsMinKC(const double X) const
{
gp_Pnt aP;
gp_Vec aV1, aV2, aV3;
myCurve->D3(X, aP, aV1, aV2, aV3);
const double aV1V1 = aV1.SquareMagnitude();
const double aNV1 = std::sqrt(aV1V1);
const double aV13 = aV1V1 * aNV1;
if (aV13 < gp::Resolution())
{
return false;
}
const double aKC = aV1.Crossed(aV2).Magnitude() / aV13;
double aDx = myEpsX;
if (X + aDx > myCurve->LastParameter())
{
aDx = -aDx;
}
myCurve->D3(X + aDx, aP, aV1, aV2, aV3);
const double aV1V1n = aV1.SquareMagnitude();
const double aNV1n = std::sqrt(aV1V1n);
const double aV13n = aV1V1n * aNV1n;
if (aV13n < gp::Resolution())
{
return false;
}
const double aKP = aV1.Crossed(aV2).Magnitude() / aV13n;
return std::abs(aKC) > std::abs(aKP);
}
private:
const GeomAdaptor_Curve* myCurve;
double myEpsX;
};
//! Function for finding inflection points: F = |V1 x V2| / (||V1|| * ||V2||) = 0
class FuncCurNul
{
public:
FuncCurNul(const GeomAdaptor_Curve* theCurve)
: myCurve(theCurve)
{
}
bool Value(const double X, double& F)
{
double aD;
return Values(X, F, aD);
}
bool Values(const double X, double& F, double& D)
{
gp_Pnt aP;
gp_Vec aV1, aV2, aV3;
myCurve->D3(X, aP, aV1, aV2, aV3);
const gp_Vec aCPV1V2 = aV1.Crossed(aV2);
const double aCPMag = aCPV1V2.Magnitude();
const gp_Vec aCPV1V3 = aV1.Crossed(aV3);
const double aV1V2 = aV1.Dot(aV2);
const double aV2V3 = aV2.Dot(aV3);
const double aNV1 = aV1.Magnitude();
const double aNV2 = aV2.Magnitude();
F = 0.0;
D = 0.0;
if (aNV2 < THE_D2_MAGNITUDE_THRESHOLD)
{
return true;
}
if (aNV1 * aNV2 < gp::Resolution())
{
return false;
}
F = aCPMag / (aNV1 * aNV2);
if (aCPMag < gp::Resolution())
{
D = aCPV1V3.Magnitude() / (aNV1 * aNV2);
}
else
{
const double aDCrossDU = aCPV1V2.Dot(aCPV1V3) / aCPMag;
D = (aDCrossDU - aCPMag * aV1V2 / (aNV1 * aNV1) - aCPMag * aV2V3 / (aNV2 * aNV2))
/ (aNV1 * aNV2);
}
return true;
}
private:
const GeomAdaptor_Curve* myCurve;
};
//! Perform numeric curvature extrema finding on a curve interval.
void numericCurvatureExtrema(const GeomAdaptor_Curve* theCurve,
const double theUMin,
const double theUMax,
GeomProp::CurveAnalysis& theResult)
{
const double aEpsH = THE_EPSILON_SCALE * (theUMax - theUMin);
FuncCurExt aFunc(theCurve, aEpsH);
MathRoot::MultipleConfig aConfig;
aConfig.NbSamples = THE_EXTREMA_NB_SAMPLES;
aConfig.XTolerance = aEpsH;
aConfig.FTolerance = aEpsH;
MathRoot::MultipleResult aRoots =
MathRoot::FindAllRootsWithDerivative(aFunc, theUMin, theUMax, aConfig);
if (aRoots.IsDone())
{
for (int j = 0; j < aRoots.NbRoots(); ++j)
{
double aParam = aRoots[j];
MathUtils::Config aBrentCfg;
aBrentCfg.XTolerance = Precision::PConfusion();
aBrentCfg.FTolerance = Precision::PConfusion();
auto aBrent = MathRoot::Brent(aFunc, aParam - aEpsH, aParam + aEpsH, aBrentCfg);
if (aBrent.IsDone() && aBrent.Root.has_value())
{
aParam = *aBrent.Root;
}
const bool aIsMin = aFunc.IsMinKC(aParam);
const GeomProp::CIType aType =
aIsMin ? GeomProp::CIType::MinCurvature : GeomProp::CIType::MaxCurvature;
theResult.Points.Append({aParam, aType});
}
}
else
{
theResult.IsDone = false;
}
}
//! Perform numeric inflection finding on a curve interval.
void numericInflections(const GeomAdaptor_Curve* theCurve,
const double theUMin,
const double theUMax,
GeomProp::CurveAnalysis& theResult)
{
FuncCurNul aFunc(theCurve);
MathRoot::MultipleConfig aConfig;
aConfig.NbSamples = THE_INFLECTION_NB_SAMPLES;
aConfig.XTolerance = THE_INFLECTION_TOLERANCE;
aConfig.FTolerance = THE_INFLECTION_TOLERANCE;
MathRoot::MultipleResult aRoots = MathRoot::FindAllRoots(aFunc, theUMin, theUMax, aConfig);
if (aRoots.IsDone())
{
for (int j = 0; j < aRoots.NbRoots(); ++j)
{
theResult.Points.Append({aRoots[j], GeomProp::CIType::Inflection});
}
}
else
{
theResult.IsDone = false;
}
}
//! Remove duplicate points that may appear at shared interval boundaries.
void removeDuplicatePoints(GeomProp::CurveAnalysis& theResult, const double theTol)
{
const int aNbPts = theResult.Points.Size();
if (aNbPts <= 1)
{
return;
}
bool aHasDuplicates = false;
for (int i = 1; i < aNbPts && !aHasDuplicates; ++i)
{
for (int j = 0; j < i; ++j)
{
if (std::abs(theResult.Points[i].Parameter - theResult.Points[j].Parameter) < theTol)
{
aHasDuplicates = true;
break;
}
}
}
if (!aHasDuplicates)
{
return;
}
NCollection_DynamicArray<GeomProp::CurveSpecialPoint> aFiltered;
aFiltered.Append(theResult.Points[0]);
for (int i = 1; i < aNbPts; ++i)
{
bool aIsDuplicate = false;
for (int j = static_cast<int>(aFiltered.Size()) - 1; j >= 0; --j)
{
if (std::abs(theResult.Points[i].Parameter - aFiltered[j].Parameter) < theTol)
{
aIsDuplicate = true;
break;
}
}
if (!aIsDuplicate)
{
aFiltered.Append(theResult.Points[i]);
}
}
theResult.Points = std::move(aFiltered);
}
} // namespace
//==================================================================================================
GeomProp::TangentResult GeomProp_BSplineCurve::Tangent(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2, aD3;
myAdaptor->D3(theParam, aPnt, aD1, aD2, aD3);
return GeomProp::ComputeTangent(aD1, aD2, aD3, theTol);
}
//==================================================================================================
GeomProp::CurvatureResult GeomProp_BSplineCurve::Curvature(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {0.0, false, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeCurvature(aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::NormalResult GeomProp_BSplineCurve::Normal(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeNormal(aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::CentreResult GeomProp_BSplineCurve::CentreOfCurvature(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeCentreOfCurvature(aPnt, aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::CurveAnalysis GeomProp_BSplineCurve::FindCurvatureExtrema() const
{
GeomProp::CurveAnalysis aResult;
aResult.IsDone = true;
if (myAdaptor == nullptr)
{
aResult.IsDone = false;
return aResult;
}
if (myAdaptor->Continuity() >= GeomAbs_C3)
{
numericCurvatureExtrema(myAdaptor,
myAdaptor->FirstParameter(),
myAdaptor->LastParameter(),
aResult);
}
else
{
// Subdivide into C3 intervals.
const int aNbInt = myAdaptor->NbIntervals(GeomAbs_C3);
NCollection_Array1<double> aParams(1, aNbInt + 1);
myAdaptor->Intervals(aParams, GeomAbs_C3);
for (int i = 1; i <= aNbInt; ++i)
{
numericCurvatureExtrema(myAdaptor, aParams(i), aParams(i + 1), aResult);
}
const double aEpsH =
THE_EPSILON_SCALE * (myAdaptor->LastParameter() - myAdaptor->FirstParameter());
removeDuplicatePoints(aResult, aEpsH);
}
return aResult;
}
//==================================================================================================
GeomProp::CurveAnalysis GeomProp_BSplineCurve::FindInflections() const
{
GeomProp::CurveAnalysis aResult;
aResult.IsDone = true;
if (myAdaptor == nullptr)
{
aResult.IsDone = false;
return aResult;
}
if (myAdaptor->Continuity() >= GeomAbs_C3)
{
numericInflections(myAdaptor, myAdaptor->FirstParameter(), myAdaptor->LastParameter(), aResult);
}
else
{
const int aNbInt = myAdaptor->NbIntervals(GeomAbs_C3);
NCollection_Array1<double> aParams(1, aNbInt + 1);
myAdaptor->Intervals(aParams, GeomAbs_C3);
for (int i = 1; i <= aNbInt; ++i)
{
numericInflections(myAdaptor, aParams(i), aParams(i + 1), aResult);
}
removeDuplicatePoints(aResult, THE_INFLECTION_TOLERANCE);
}
return aResult;
}
@@ -0,0 +1,76 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_BSplineCurve_HeaderFile
#define _GeomProp_BSplineCurve_HeaderFile
#include <GeomAdaptor_Curve.hxx>
#include <GeomProp.hxx>
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Local differential properties for a 3D B-spline curve.
//!
//! Uses numeric root-finding for curvature extrema and inflection points.
//! For B-splines with continuity less than C3, the parameter range is subdivided
//! into C3 intervals for more robust root-finding.
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object. This class does not manage
//! the adaptor's lifetime.
class GeomProp_BSplineCurve
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the 3D curve adaptor (must wrap a B-spline curve, must not be null)
GeomProp_BSplineCurve(const GeomAdaptor_Curve* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_BSplineCurve(const GeomProp_BSplineCurve&) = delete;
GeomProp_BSplineCurve& operator=(const GeomProp_BSplineCurve&) = delete;
GeomProp_BSplineCurve(GeomProp_BSplineCurve&&) = delete;
GeomProp_BSplineCurve& operator=(GeomProp_BSplineCurve&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Curve* Adaptor() const { return myAdaptor; }
//! Compute tangent at given parameter.
Standard_EXPORT GeomProp::TangentResult Tangent(double theParam, double theTol) const;
//! Compute curvature at given parameter.
Standard_EXPORT GeomProp::CurvatureResult Curvature(double theParam, double theTol) const;
//! Compute normal at given parameter.
Standard_EXPORT GeomProp::NormalResult Normal(double theParam, double theTol) const;
//! Compute centre of curvature at given parameter.
Standard_EXPORT GeomProp::CentreResult CentreOfCurvature(double theParam, double theTol) const;
//! Find curvature extrema using numeric root-finding.
//! For non-C3 B-splines, subdivides into C3 intervals.
Standard_EXPORT GeomProp::CurveAnalysis FindCurvatureExtrema() const;
//! Find inflection points using numeric root-finding.
//! For non-C3 B-splines, subdivides into C3 intervals.
Standard_EXPORT GeomProp::CurveAnalysis FindInflections() const;
private:
const GeomAdaptor_Curve* myAdaptor;
};
#endif // _GeomProp_BSplineCurve_HeaderFile
@@ -0,0 +1,62 @@
// 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 <GeomProp_BSplineSurface.hxx>
//==================================================================================================
GeomProp::SurfaceNormalResult GeomProp_BSplineSurface::Normal(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V;
myAdaptor->D1(theU, theV, aPnt, aD1U, aD1V);
return GeomProp::ComputeSurfaceNormal(aD1U, aD1V, theTol);
}
//==================================================================================================
GeomProp::SurfaceCurvatureResult GeomProp_BSplineSurface::Curvatures(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeSurfaceCurvatures(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
//==================================================================================================
GeomProp::MeanGaussianResult GeomProp_BSplineSurface::MeanGaussian(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeMeanGaussian(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
@@ -0,0 +1,68 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_BSplineSurface_HeaderFile
#define _GeomProp_BSplineSurface_HeaderFile
#include <GeomAdaptor_Surface.hxx>
#include <GeomProp.hxx>
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Local differential properties for a B-spline surface.
//!
//! Uses numeric evaluation from adaptor derivatives.
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object.
class GeomProp_BSplineSurface
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the surface adaptor (must not be null)
GeomProp_BSplineSurface(const GeomAdaptor_Surface* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_BSplineSurface(const GeomProp_BSplineSurface&) = delete;
GeomProp_BSplineSurface& operator=(const GeomProp_BSplineSurface&) = delete;
GeomProp_BSplineSurface(GeomProp_BSplineSurface&&) = delete;
GeomProp_BSplineSurface& operator=(GeomProp_BSplineSurface&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Surface* Adaptor() const { return myAdaptor; }
//! Compute surface normal at given parameter.
Standard_EXPORT GeomProp::SurfaceNormalResult Normal(double theU,
double theV,
double theTol) const;
//! Compute principal curvatures at given parameter.
Standard_EXPORT GeomProp::SurfaceCurvatureResult Curvatures(double theU,
double theV,
double theTol) const;
//! Compute mean and Gaussian curvatures at given parameter.
Standard_EXPORT GeomProp::MeanGaussianResult MeanGaussian(double theU,
double theV,
double theTol) const;
private:
const GeomAdaptor_Surface* myAdaptor;
};
#endif // _GeomProp_BSplineSurface_HeaderFile
@@ -0,0 +1,373 @@
// 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 <GeomProp_BezierCurve.hxx>
#include <gp.hxx>
#include <MathRoot_Brent.hxx>
#include <MathRoot_Multiple.hxx>
#include <Precision.hxx>
#include <cmath>
namespace
{
constexpr double THE_CURVATURE_DERIV_COEFF = 3.0; //!< Coefficient in d(KC)/dU formula
constexpr double THE_DIFF_STEP_DIVISOR = 100.0; //!< Divisor for numerical differentiation step
constexpr double THE_D2_MAGNITUDE_THRESHOLD = 1.0e-4; //!< Threshold for second derivative magnitude
constexpr double THE_EPSILON_SCALE = 1.0e-4; //!< Scale factor for epsilon relative to domain
constexpr int THE_EXTREMA_NB_SAMPLES = 100; //!< Number of samples for curvature extrema search
constexpr int THE_INFLECTION_NB_SAMPLES = 30; //!< Number of samples for inflection search
constexpr double THE_INFLECTION_TOLERANCE = 1.0e-6; //!< Tolerance for inflection point finding
//! Function for finding curvature extrema: F = d(curvature)/dU = 0
//! In 3D: KC = |V1 x V2| / ||V1||^3
//! F = d KC / dU
class FuncCurExt
{
public:
FuncCurExt(const GeomAdaptor_Curve* theCurve, const double theTol)
: myCurve(theCurve),
myEpsX(theTol)
{
}
bool Value(const double X, double& F)
{
gp_Pnt aP;
gp_Vec aV1, aV2, aV3;
myCurve->D3(X, aP, aV1, aV2, aV3);
// In 3D: |V1 x V2| = magnitude of cross product vector
const gp_Vec aCPV1V2 = aV1.Crossed(aV2);
const double aCPMag = aCPV1V2.Magnitude();
const gp_Vec aCPV1V3 = aV1.Crossed(aV3);
const double aV1V2 = aV1.Dot(aV2);
const double aV1V1 = aV1.SquareMagnitude();
const double aNV1 = std::sqrt(aV1V1);
const double aV13 = aV1V1 * aNV1;
const double aV15 = aV13 * aV1V1;
if (aV15 < gp::Resolution())
{
return false;
}
// d(KC)/dU for 3D curves.
// KC = |V1 x V2| / |V1|^3
// dKC/dU = d|V1xV2|/dU / |V1|^3 - 3 * |V1xV2| * (V1.V2) / |V1|^5
// d|V1xV2|/dU = (V1xV2).(V1xV3) / |V1xV2|
if (aCPMag < gp::Resolution())
{
// Cross product is zero - inflection or straight region.
// Use simplified formula.
F = aCPV1V3.Magnitude() / aV13;
return true;
}
const double aDCrossDU = aCPV1V2.Dot(aCPV1V3) / aCPMag;
F = aDCrossDU / aV13 - THE_CURVATURE_DERIV_COEFF * aCPMag * aV1V2 / aV15;
return true;
}
bool Values(const double X, double& F, double& D)
{
double aDx = myEpsX / THE_DIFF_STEP_DIVISOR;
if (X + aDx > myCurve->LastParameter())
{
aDx = -aDx;
}
Value(X, F);
double aF2;
Value(X + aDx, aF2);
D = (aF2 - F) / aDx;
return true;
}
//! Test if parameter corresponds to a minimum of the radius of curvature
//! (maximum of |curvature|) by comparison with a neighboring point.
bool IsMinKC(const double X) const
{
gp_Pnt aP;
gp_Vec aV1, aV2, aV3;
myCurve->D3(X, aP, aV1, aV2, aV3);
const double aCPMag = aV1.Crossed(aV2).Magnitude();
const double aV1V1 = aV1.SquareMagnitude();
const double aNV1 = std::sqrt(aV1V1);
const double aV13 = aV1V1 * aNV1;
if (aV13 < gp::Resolution())
{
return false;
}
const double aKC = aCPMag / aV13;
double aDx = myEpsX;
if (X + aDx > myCurve->LastParameter())
{
aDx = -aDx;
}
myCurve->D3(X + aDx, aP, aV1, aV2, aV3);
const double aCPMagN = aV1.Crossed(aV2).Magnitude();
const double aV1V1n = aV1.SquareMagnitude();
const double aNV1n = std::sqrt(aV1V1n);
const double aV13n = aV1V1n * aNV1n;
if (aV13n < gp::Resolution())
{
return false;
}
const double aKP = aCPMagN / aV13n;
return std::abs(aKC) > std::abs(aKP);
}
private:
const GeomAdaptor_Curve* myCurve;
double myEpsX;
};
//! Function for finding inflection points: F = |V1 x V2| / (||V1|| * ||V2||) = 0
class FuncCurNul
{
public:
FuncCurNul(const GeomAdaptor_Curve* theCurve)
: myCurve(theCurve)
{
}
bool Value(const double X, double& F)
{
double aD;
return Values(X, F, aD);
}
bool Values(const double X, double& F, double& D)
{
gp_Pnt aP;
gp_Vec aV1, aV2, aV3;
myCurve->D3(X, aP, aV1, aV2, aV3);
const gp_Vec aCPV1V2 = aV1.Crossed(aV2);
const double aCPMag = aCPV1V2.Magnitude();
const gp_Vec aCPV1V3 = aV1.Crossed(aV3);
const double aV1V2 = aV1.Dot(aV2);
const double aV2V3 = aV2.Dot(aV3);
const double aNV1 = aV1.Magnitude();
const double aNV2 = aV2.Magnitude();
F = 0.0;
D = 0.0;
if (aNV2 < THE_D2_MAGNITUDE_THRESHOLD)
{
return true;
}
if (aNV1 * aNV2 < gp::Resolution())
{
return false;
}
F = aCPMag / (aNV1 * aNV2);
// Derivative of |V1xV2|/(|V1|*|V2|) w.r.t. parameter
if (aCPMag < gp::Resolution())
{
D = aCPV1V3.Magnitude() / (aNV1 * aNV2);
}
else
{
const double aDCrossDU = aCPV1V2.Dot(aCPV1V3) / aCPMag;
D = (aDCrossDU - aCPMag * aV1V2 / (aNV1 * aNV1) - aCPMag * aV2V3 / (aNV2 * aNV2))
/ (aNV1 * aNV2);
}
return true;
}
private:
const GeomAdaptor_Curve* myCurve;
};
//! Perform numeric curvature extrema finding on a curve interval.
void numericCurvatureExtrema(const GeomAdaptor_Curve* theCurve,
const double theUMin,
const double theUMax,
GeomProp::CurveAnalysis& theResult)
{
const double aEpsH = THE_EPSILON_SCALE * (theUMax - theUMin);
FuncCurExt aFunc(theCurve, aEpsH);
MathRoot::MultipleConfig aConfig;
aConfig.NbSamples = THE_EXTREMA_NB_SAMPLES;
aConfig.XTolerance = aEpsH;
aConfig.FTolerance = aEpsH;
MathRoot::MultipleResult aRoots =
MathRoot::FindAllRootsWithDerivative(aFunc, theUMin, theUMax, aConfig);
if (aRoots.IsDone())
{
for (int j = 0; j < aRoots.NbRoots(); ++j)
{
double aParam = aRoots[j];
// Refine the solution.
MathUtils::Config aBrentCfg;
aBrentCfg.XTolerance = Precision::PConfusion();
aBrentCfg.FTolerance = Precision::PConfusion();
auto aBrent = MathRoot::Brent(aFunc, aParam - aEpsH, aParam + aEpsH, aBrentCfg);
if (aBrent.IsDone() && aBrent.Root.has_value())
{
aParam = *aBrent.Root;
}
const bool aIsMin = aFunc.IsMinKC(aParam);
const GeomProp::CIType aType =
aIsMin ? GeomProp::CIType::MinCurvature : GeomProp::CIType::MaxCurvature;
theResult.Points.Append({aParam, aType});
}
}
else
{
theResult.IsDone = false;
}
}
//! Perform numeric inflection finding on a curve interval.
void numericInflections(const GeomAdaptor_Curve* theCurve,
const double theUMin,
const double theUMax,
GeomProp::CurveAnalysis& theResult)
{
FuncCurNul aFunc(theCurve);
MathRoot::MultipleConfig aConfig;
aConfig.NbSamples = THE_INFLECTION_NB_SAMPLES;
aConfig.XTolerance = THE_INFLECTION_TOLERANCE;
aConfig.FTolerance = THE_INFLECTION_TOLERANCE;
MathRoot::MultipleResult aRoots = MathRoot::FindAllRoots(aFunc, theUMin, theUMax, aConfig);
if (aRoots.IsDone())
{
for (int j = 0; j < aRoots.NbRoots(); ++j)
{
theResult.Points.Append({aRoots[j], GeomProp::CIType::Inflection});
}
}
else
{
theResult.IsDone = false;
}
}
} // namespace
//==================================================================================================
GeomProp::TangentResult GeomProp_BezierCurve::Tangent(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2, aD3;
myAdaptor->D3(theParam, aPnt, aD1, aD2, aD3);
return GeomProp::ComputeTangent(aD1, aD2, aD3, theTol);
}
//==================================================================================================
GeomProp::CurvatureResult GeomProp_BezierCurve::Curvature(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {0.0, false, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeCurvature(aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::NormalResult GeomProp_BezierCurve::Normal(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeNormal(aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::CentreResult GeomProp_BezierCurve::CentreOfCurvature(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeCentreOfCurvature(aPnt, aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::CurveAnalysis GeomProp_BezierCurve::FindCurvatureExtrema() const
{
GeomProp::CurveAnalysis aResult;
aResult.IsDone = true;
if (myAdaptor == nullptr)
{
aResult.IsDone = false;
return aResult;
}
numericCurvatureExtrema(myAdaptor,
myAdaptor->FirstParameter(),
myAdaptor->LastParameter(),
aResult);
return aResult;
}
//==================================================================================================
GeomProp::CurveAnalysis GeomProp_BezierCurve::FindInflections() const
{
GeomProp::CurveAnalysis aResult;
aResult.IsDone = true;
if (myAdaptor == nullptr)
{
aResult.IsDone = false;
return aResult;
}
numericInflections(myAdaptor, myAdaptor->FirstParameter(), myAdaptor->LastParameter(), aResult);
return aResult;
}
@@ -0,0 +1,72 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_BezierCurve_HeaderFile
#define _GeomProp_BezierCurve_HeaderFile
#include <GeomAdaptor_Curve.hxx>
#include <GeomProp.hxx>
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Local differential properties for a 3D Bezier curve.
//!
//! Uses numeric root-finding for curvature extrema and inflection points.
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object. This class does not manage
//! the adaptor's lifetime.
class GeomProp_BezierCurve
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the 3D curve adaptor (must wrap a Bezier curve, must not be null)
GeomProp_BezierCurve(const GeomAdaptor_Curve* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_BezierCurve(const GeomProp_BezierCurve&) = delete;
GeomProp_BezierCurve& operator=(const GeomProp_BezierCurve&) = delete;
GeomProp_BezierCurve(GeomProp_BezierCurve&&) = delete;
GeomProp_BezierCurve& operator=(GeomProp_BezierCurve&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Curve* Adaptor() const { return myAdaptor; }
//! Compute tangent at given parameter.
Standard_EXPORT GeomProp::TangentResult Tangent(double theParam, double theTol) const;
//! Compute curvature at given parameter.
Standard_EXPORT GeomProp::CurvatureResult Curvature(double theParam, double theTol) const;
//! Compute normal at given parameter.
Standard_EXPORT GeomProp::NormalResult Normal(double theParam, double theTol) const;
//! Compute centre of curvature at given parameter.
Standard_EXPORT GeomProp::CentreResult CentreOfCurvature(double theParam, double theTol) const;
//! Find curvature extrema using numeric root-finding.
Standard_EXPORT GeomProp::CurveAnalysis FindCurvatureExtrema() const;
//! Find inflection points using numeric root-finding.
Standard_EXPORT GeomProp::CurveAnalysis FindInflections() const;
private:
const GeomAdaptor_Curve* myAdaptor;
};
#endif // _GeomProp_BezierCurve_HeaderFile
@@ -0,0 +1,62 @@
// 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 <GeomProp_BezierSurface.hxx>
//==================================================================================================
GeomProp::SurfaceNormalResult GeomProp_BezierSurface::Normal(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V;
myAdaptor->D1(theU, theV, aPnt, aD1U, aD1V);
return GeomProp::ComputeSurfaceNormal(aD1U, aD1V, theTol);
}
//==================================================================================================
GeomProp::SurfaceCurvatureResult GeomProp_BezierSurface::Curvatures(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeSurfaceCurvatures(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
//==================================================================================================
GeomProp::MeanGaussianResult GeomProp_BezierSurface::MeanGaussian(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeMeanGaussian(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
@@ -0,0 +1,68 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_BezierSurface_HeaderFile
#define _GeomProp_BezierSurface_HeaderFile
#include <GeomAdaptor_Surface.hxx>
#include <GeomProp.hxx>
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Local differential properties for a Bezier surface.
//!
//! Uses numeric evaluation from adaptor derivatives.
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object.
class GeomProp_BezierSurface
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the surface adaptor (must not be null)
GeomProp_BezierSurface(const GeomAdaptor_Surface* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_BezierSurface(const GeomProp_BezierSurface&) = delete;
GeomProp_BezierSurface& operator=(const GeomProp_BezierSurface&) = delete;
GeomProp_BezierSurface(GeomProp_BezierSurface&&) = delete;
GeomProp_BezierSurface& operator=(GeomProp_BezierSurface&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Surface* Adaptor() const { return myAdaptor; }
//! Compute surface normal at given parameter.
Standard_EXPORT GeomProp::SurfaceNormalResult Normal(double theU,
double theV,
double theTol) const;
//! Compute principal curvatures at given parameter.
Standard_EXPORT GeomProp::SurfaceCurvatureResult Curvatures(double theU,
double theV,
double theTol) const;
//! Compute mean and Gaussian curvatures at given parameter.
Standard_EXPORT GeomProp::MeanGaussianResult MeanGaussian(double theU,
double theV,
double theTol) const;
private:
const GeomAdaptor_Surface* myAdaptor;
};
#endif // _GeomProp_BezierSurface_HeaderFile
@@ -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.
#ifndef _GeomProp_Circle_HeaderFile
#define _GeomProp_Circle_HeaderFile
#include <GeomAdaptor_Curve.hxx>
#include <GeomProp.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Local differential properties for a 3D circle.
//!
//! A circle has constant curvature = 1/R, well-defined tangent and normal
//! at every point, and no curvature extrema or inflection points.
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object. This class does not manage
//! the adaptor's lifetime.
class GeomProp_Circle
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the 3D curve adaptor (must wrap a circle, must not be null)
GeomProp_Circle(const GeomAdaptor_Curve* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_Circle(const GeomProp_Circle&) = delete;
GeomProp_Circle& operator=(const GeomProp_Circle&) = delete;
GeomProp_Circle(GeomProp_Circle&&) = delete;
GeomProp_Circle& operator=(GeomProp_Circle&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Curve* Adaptor() const { return myAdaptor; }
//! Compute tangent at given parameter.
//! @param[in] theParam curve parameter
//! @param[in] theTol tolerance (unused for circle)
//! @return tangent result (always defined)
GeomProp::TangentResult Tangent(double theParam, double theTol) const
{
(void)theTol;
gp_Pnt aPnt;
gp_Vec aD1;
myAdaptor->D1(theParam, aPnt, aD1);
return {gp_Dir(aD1), true};
}
//! Compute curvature at given parameter.
//! For a circle, curvature = 1/R (constant).
//! @param[in] theParam curve parameter (unused)
//! @param[in] theTol tolerance (unused)
//! @return curvature result (always defined, constant)
GeomProp::CurvatureResult Curvature(double theParam, double theTol) const
{
(void)theParam;
(void)theTol;
return {1.0 / myAdaptor->Circle().Radius(), true, false};
}
//! Compute normal at given parameter.
//! @param[in] theParam curve parameter
//! @param[in] theTol tolerance (unused)
//! @return normal result (always defined)
GeomProp::NormalResult Normal(double theParam, double theTol) const
{
(void)theTol;
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
// Normal = D2 * (D1.D1) - D1 * (D1.D2)
const gp_Vec aNorm = aD2 * aD1.Dot(aD1) - aD1 * aD1.Dot(aD2);
return {gp_Dir(aNorm), true};
}
//! Compute centre of curvature at given parameter.
//! For a circle, the centre of curvature is the geometric centre.
//! @param[in] theParam curve parameter (unused)
//! @param[in] theTol tolerance (unused)
//! @return centre result (always the circle centre)
GeomProp::CentreResult CentreOfCurvature(double theParam, double theTol) const
{
(void)theParam;
(void)theTol;
return {myAdaptor->Circle().Location(), true};
}
//! Find curvature extrema on the circle.
//! A circle has constant curvature, so no extrema.
//! @return empty analysis (always done)
GeomProp::CurveAnalysis FindCurvatureExtrema() const { return {{}, true}; }
//! Find inflection points on the circle.
//! A circle has no inflection points.
//! @return empty analysis (always done)
GeomProp::CurveAnalysis FindInflections() const { return {{}, true}; }
private:
const GeomAdaptor_Curve* myAdaptor;
};
#endif // _GeomProp_Circle_HeaderFile
@@ -0,0 +1,62 @@
// 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 <GeomProp_Cone.hxx>
//==================================================================================================
GeomProp::SurfaceNormalResult GeomProp_Cone::Normal(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V;
myAdaptor->D1(theU, theV, aPnt, aD1U, aD1V);
return GeomProp::ComputeSurfaceNormal(aD1U, aD1V, theTol);
}
//==================================================================================================
GeomProp::SurfaceCurvatureResult GeomProp_Cone::Curvatures(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeSurfaceCurvatures(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
//==================================================================================================
GeomProp::MeanGaussianResult GeomProp_Cone::MeanGaussian(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeMeanGaussian(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
@@ -0,0 +1,74 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_Cone_HeaderFile
#define _GeomProp_Cone_HeaderFile
#include <GeomAdaptor_Surface.hxx>
#include <GeomProp.hxx>
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Local differential properties for a conical surface.
//!
//! Uses analytical formulas where possible; the curvature
//! varies along the meridian (V direction).
//! Min principal curvature = 0 (along the ruling direction).
//! Max principal curvature = cos(alpha) / R(V), where alpha is the half-angle
//! and R(V) is the radius at parameter V.
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object.
class GeomProp_Cone
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the surface adaptor (must not be null)
GeomProp_Cone(const GeomAdaptor_Surface* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_Cone(const GeomProp_Cone&) = delete;
GeomProp_Cone& operator=(const GeomProp_Cone&) = delete;
GeomProp_Cone(GeomProp_Cone&&) = delete;
GeomProp_Cone& operator=(GeomProp_Cone&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Surface* Adaptor() const { return myAdaptor; }
//! Compute surface normal at given parameter.
//! TODO: At the apex (V = -R/sin(alpha)), D1U degenerates and Normal returns IsDefined=false.
//! Could use analytical normal for this special case.
Standard_EXPORT GeomProp::SurfaceNormalResult Normal(double theU,
double theV,
double theTol) const;
//! Compute principal curvatures at given parameter.
Standard_EXPORT GeomProp::SurfaceCurvatureResult Curvatures(double theU,
double theV,
double theTol) const;
//! Compute mean and Gaussian curvatures at given parameter.
Standard_EXPORT GeomProp::MeanGaussianResult MeanGaussian(double theU,
double theV,
double theTol) const;
private:
const GeomAdaptor_Surface* myAdaptor;
};
#endif // _GeomProp_Cone_HeaderFile
@@ -0,0 +1,213 @@
// 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 <GeomProp_Curve.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <Geom_TrimmedCurve.hxx>
//==================================================================================================
void GeomProp_Curve::Initialize(const Adaptor3d_Curve& theCurve)
{
if (theCurve.IsKind(STANDARD_TYPE(GeomAdaptor_Curve)))
{
const auto& aGeomAdaptor = static_cast<const GeomAdaptor_Curve&>(theCurve);
myAdaptor = new GeomAdaptor_Curve(aGeomAdaptor);
initFromAdaptor();
return;
}
// For non-GeomAdaptor, set uninitialized.
myAdaptor.Nullify();
myCurveType = theCurve.GetType();
myEvaluator.emplace<std::monostate>();
}
//==================================================================================================
void GeomProp_Curve::Initialize(const occ::handle<Geom_Curve>& theCurve)
{
if (theCurve.IsNull())
{
myAdaptor.Nullify();
myEvaluator.emplace<std::monostate>();
myCurveType = GeomAbs_OtherCurve;
return;
}
myAdaptor = new GeomAdaptor_Curve(theCurve);
initFromAdaptor();
}
//==================================================================================================
void GeomProp_Curve::initFromAdaptor()
{
myCurveType = myAdaptor->GetType();
const GeomAdaptor_Curve* aPtr = myAdaptor.get();
switch (myCurveType)
{
case GeomAbs_Line:
myEvaluator.emplace<GeomProp_Line>(aPtr);
break;
case GeomAbs_Circle:
myEvaluator.emplace<GeomProp_Circle>(aPtr);
break;
case GeomAbs_Ellipse:
myEvaluator.emplace<GeomProp_Ellipse>(aPtr);
break;
case GeomAbs_Hyperbola:
myEvaluator.emplace<GeomProp_Hyperbola>(aPtr);
break;
case GeomAbs_Parabola:
myEvaluator.emplace<GeomProp_Parabola>(aPtr);
break;
case GeomAbs_BezierCurve:
myEvaluator.emplace<GeomProp_BezierCurve>(aPtr);
break;
case GeomAbs_BSplineCurve:
myEvaluator.emplace<GeomProp_BSplineCurve>(aPtr);
break;
case GeomAbs_OffsetCurve:
myEvaluator.emplace<GeomProp_OffsetCurve>(aPtr);
break;
default:
myEvaluator.emplace<GeomProp_OtherCurve>(aPtr);
break;
}
}
//==================================================================================================
bool GeomProp_Curve::IsInitialized() const
{
return !std::holds_alternative<std::monostate>(myEvaluator);
}
//==================================================================================================
GeomProp::TangentResult GeomProp_Curve::Tangent(const double theParam, const double theTol) const
{
return std::visit(
[theParam, theTol](const auto& theEval) -> GeomProp::TangentResult {
using T = std::decay_t<decltype(theEval)>;
if constexpr (std::is_same_v<T, std::monostate>)
{
return {{}, false};
}
else
{
return theEval.Tangent(theParam, theTol);
}
},
myEvaluator);
}
//==================================================================================================
GeomProp::CurvatureResult GeomProp_Curve::Curvature(const double theParam,
const double theTol) const
{
return std::visit(
[theParam, theTol](const auto& theEval) -> GeomProp::CurvatureResult {
using T = std::decay_t<decltype(theEval)>;
if constexpr (std::is_same_v<T, std::monostate>)
{
return {0.0, false, false};
}
else
{
return theEval.Curvature(theParam, theTol);
}
},
myEvaluator);
}
//==================================================================================================
GeomProp::NormalResult GeomProp_Curve::Normal(const double theParam, const double theTol) const
{
return std::visit(
[theParam, theTol](const auto& theEval) -> GeomProp::NormalResult {
using T = std::decay_t<decltype(theEval)>;
if constexpr (std::is_same_v<T, std::monostate>)
{
return {{}, false};
}
else
{
return theEval.Normal(theParam, theTol);
}
},
myEvaluator);
}
//==================================================================================================
GeomProp::CentreResult GeomProp_Curve::CentreOfCurvature(const double theParam,
const double theTol) const
{
return std::visit(
[theParam, theTol](const auto& theEval) -> GeomProp::CentreResult {
using T = std::decay_t<decltype(theEval)>;
if constexpr (std::is_same_v<T, std::monostate>)
{
return {{}, false};
}
else
{
return theEval.CentreOfCurvature(theParam, theTol);
}
},
myEvaluator);
}
//==================================================================================================
GeomProp::CurveAnalysis GeomProp_Curve::FindCurvatureExtrema() const
{
return std::visit(
[](const auto& theEval) -> GeomProp::CurveAnalysis {
using T = std::decay_t<decltype(theEval)>;
if constexpr (std::is_same_v<T, std::monostate>)
{
return {{}, false};
}
else
{
return theEval.FindCurvatureExtrema();
}
},
myEvaluator);
}
//==================================================================================================
GeomProp::CurveAnalysis GeomProp_Curve::FindInflections() const
{
return std::visit(
[](const auto& theEval) -> GeomProp::CurveAnalysis {
using T = std::decay_t<decltype(theEval)>;
if constexpr (std::is_same_v<T, std::monostate>)
{
return {{}, false};
}
else
{
return theEval.FindInflections();
}
},
myEvaluator);
}
@@ -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.
#ifndef _GeomProp_Curve_HeaderFile
#define _GeomProp_Curve_HeaderFile
#include <Adaptor3d_Curve.hxx>
#include <Geom_Curve.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <GeomAbs_CurveType.hxx>
#include <GeomProp.hxx>
#include <GeomProp_BezierCurve.hxx>
#include <GeomProp_BSplineCurve.hxx>
#include <GeomProp_Circle.hxx>
#include <GeomProp_Ellipse.hxx>
#include <GeomProp_Hyperbola.hxx>
#include <GeomProp_Line.hxx>
#include <GeomProp_OffsetCurve.hxx>
#include <GeomProp_OtherCurve.hxx>
#include <GeomProp_Parabola.hxx>
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
#include <variant>
//! @brief Unified local differential property evaluator for any 3D curve.
//!
//! Uses std::variant for compile-time type safety and zero heap allocation
//! for the evaluator itself. Automatically detects curve type from
//! Adaptor3d_Curve or Geom_Curve and dispatches to the appropriate
//! specialized evaluator.
//!
//! Supported curve types with optimized evaluation:
//! - Line: Trivial (zero curvature, constant tangent)
//! - Circle: Constant curvature 1/R
//! - Ellipse: Analytical curvature extrema at vertices
//! - Hyperbola: Analytical curvature extremum at vertex
//! - Parabola: Analytical curvature extremum at vertex
//! - BezierCurve: Numeric curvature extrema/inflection finding
//! - BSplineCurve: Numeric with C3 interval subdivision
//! - OffsetCurve: Numeric approach
//! - Other: Fallback using Geom_Curve virtual D1/D2/D3
//!
//! Usage:
//! @code
//! GeomProp_Curve aProp;
//! aProp.Initialize(myGeomCurve);
//! GeomProp::CurvatureResult aCurv = aProp.Curvature(0.5, Precision::Confusion());
//! if (aCurv.IsDefined)
//! {
//! double aValue = aCurv.Value;
//! }
//! @endcode
class GeomProp_Curve
{
public:
DEFINE_STANDARD_ALLOC
//! Variant type holding all possible 3D curve property evaluators.
using EvaluatorVariant = std::variant<std::monostate,
GeomProp_Line,
GeomProp_Circle,
GeomProp_Ellipse,
GeomProp_Hyperbola,
GeomProp_Parabola,
GeomProp_BezierCurve,
GeomProp_BSplineCurve,
GeomProp_OffsetCurve,
GeomProp_OtherCurve>;
//! Default constructor - uninitialized state.
GeomProp_Curve()
: myEvaluator(std::monostate{}),
myCurveType(GeomAbs_OtherCurve)
{
}
//! Non-copyable and non-movable.
GeomProp_Curve(const GeomProp_Curve&) = delete;
GeomProp_Curve& operator=(const GeomProp_Curve&) = delete;
GeomProp_Curve(GeomProp_Curve&&) = delete;
GeomProp_Curve& operator=(GeomProp_Curve&&) = delete;
//! Initialize from 3D adaptor reference (auto-detects curve type).
//! For GeomAdaptor_Curve, extracts underlying Geom_Curve for optimized evaluation.
//! @param[in] theCurve 3D curve adaptor reference
Standard_EXPORT void Initialize(const Adaptor3d_Curve& theCurve);
//! Initialize from geometry handle (auto-detects curve type).
//! @param[in] theCurve 3D geometry to evaluate
Standard_EXPORT void Initialize(const occ::handle<Geom_Curve>& theCurve);
//! Returns true if properly initialized.
Standard_EXPORT bool IsInitialized() const;
//! Returns the detected curve type.
GeomAbs_CurveType GetType() const { return myCurveType; }
//! Compute tangent at given parameter.
//! @param[in] theParam curve parameter
//! @param[in] theTol linear tolerance
//! @return tangent result with validity flag
Standard_EXPORT GeomProp::TangentResult Tangent(double theParam, double theTol) const;
//! Compute curvature at given parameter.
//! @param[in] theParam curve parameter
//! @param[in] theTol linear tolerance
//! @return curvature result with validity and infinity flags
Standard_EXPORT GeomProp::CurvatureResult Curvature(double theParam, double theTol) const;
//! Compute normal at given parameter.
//! @param[in] theParam curve parameter
//! @param[in] theTol linear tolerance
//! @return normal result with validity flag
Standard_EXPORT GeomProp::NormalResult Normal(double theParam, double theTol) const;
//! Compute centre of curvature at given parameter.
//! @param[in] theParam curve parameter
//! @param[in] theTol linear tolerance
//! @return centre result with validity flag
Standard_EXPORT GeomProp::CentreResult CentreOfCurvature(double theParam, double theTol) const;
//! Find curvature extrema on the curve.
//! @return analysis result with special points sorted by parameter
Standard_EXPORT GeomProp::CurveAnalysis FindCurvatureExtrema() const;
//! Find inflection points on the curve.
//! @return analysis result with inflection points sorted by parameter
Standard_EXPORT GeomProp::CurveAnalysis FindInflections() const;
private:
//! Initialize from stored adaptor (dispatches to per-geometry evaluator).
//! Must be called after myAdaptor is set. Per-geometry evaluators receive
//! a non-owning pointer to myAdaptor; their lifetime is managed by the variant.
Standard_EXPORT void initFromAdaptor();
occ::handle<GeomAdaptor_Curve> myAdaptor; //!< Owns the adaptor (ensures lifetime).
EvaluatorVariant myEvaluator; //!< Per-geometry evaluator (non-owning pointer to myAdaptor).
GeomAbs_CurveType myCurveType;
};
#endif // _GeomProp_Curve_HeaderFile
@@ -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.
#ifndef _GeomProp_Cylinder_HeaderFile
#define _GeomProp_Cylinder_HeaderFile
#include <GeomAdaptor_Surface.hxx>
#include <GeomProp.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Local differential properties for a cylindrical surface.
//!
//! Analytical implementation with constant principal curvatures:
//! - Min curvature = 0 (along the axis direction)
//! - Max curvature = 1/R (along the circular cross-section)
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object.
class GeomProp_Cylinder
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the surface adaptor (must not be null)
GeomProp_Cylinder(const GeomAdaptor_Surface* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_Cylinder(const GeomProp_Cylinder&) = delete;
GeomProp_Cylinder& operator=(const GeomProp_Cylinder&) = delete;
GeomProp_Cylinder(GeomProp_Cylinder&&) = delete;
GeomProp_Cylinder& operator=(GeomProp_Cylinder&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Surface* Adaptor() const { return myAdaptor; }
//! Compute surface normal at given (U, V) parameter.
//! For a cylinder, the normal is radially outward from the axis.
//! TODO: Could use analytical normal (radial direction from axis) for degenerate D1 cases,
//! though in practice cylinder D1 never degenerates.
GeomProp::SurfaceNormalResult Normal(double theU, double theV, double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V;
myAdaptor->D1(theU, theV, aPnt, aD1U, aD1V);
return GeomProp::ComputeSurfaceNormal(aD1U, aD1V, theTol);
}
//! Compute principal curvatures using fundamental forms for correct sign convention.
GeomProp::SurfaceCurvatureResult Curvatures(double theU, double theV, double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeSurfaceCurvatures(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
//! Compute mean and Gaussian curvatures using fundamental forms for correct sign convention.
GeomProp::MeanGaussianResult MeanGaussian(double theU, double theV, double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeMeanGaussian(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
private:
const GeomAdaptor_Surface* myAdaptor;
};
#endif // _GeomProp_Cylinder_HeaderFile
@@ -0,0 +1,120 @@
// 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 <GeomProp_Ellipse.hxx>
#include <ElCLib.hxx>
#include <cmath>
namespace
{
constexpr int THE_ELLIPSE_NB_EXTREMA = 4; //!< Number of curvature extrema on full ellipse
constexpr double THE_ELLIPSE_PERIOD = 2.0 * M_PI; //!< One full period of ellipse parameter
} // namespace
//==================================================================================================
GeomProp::TangentResult GeomProp_Ellipse::Tangent(const double theParam, const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2, aD3;
myAdaptor->D3(theParam, aPnt, aD1, aD2, aD3);
return GeomProp::ComputeTangent(aD1, aD2, aD3, theTol);
}
//==================================================================================================
GeomProp::CurvatureResult GeomProp_Ellipse::Curvature(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {0.0, false, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeCurvature(aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::NormalResult GeomProp_Ellipse::Normal(const double theParam, const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeNormal(aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::CentreResult GeomProp_Ellipse::CentreOfCurvature(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeCentreOfCurvature(aPnt, aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::CurveAnalysis GeomProp_Ellipse::FindCurvatureExtrema() const
{
GeomProp::CurveAnalysis aResult;
aResult.IsDone = true;
if (myAdaptor == nullptr)
{
aResult.IsDone = false;
return aResult;
}
const double aUFirst = myAdaptor->FirstParameter();
const double aULast = myAdaptor->LastParameter();
const double aUFPlus2PI = aUFirst + THE_ELLIPSE_PERIOD;
// Ellipse curvature extrema at 0, PI/2, PI, 3*PI/2
// At 0 and PI (major axis endpoints): min radius of curvature -> max |curvature| -> MinCurvature
// At PI/2 and 3*PI/2 (minor axis endpoints): max radius of curvature -> min |curvature| ->
// MaxCurvature
const double aCandidates[] = {0.0, M_PI / 2.0, M_PI, 3.0 * M_PI / 2.0};
const bool aIsMin[] = {true, false, true, false};
for (int i = 0; i < THE_ELLIPSE_NB_EXTREMA; ++i)
{
const double aU = ElCLib::InPeriod(aCandidates[i], aUFirst, aUFPlus2PI);
if (aU >= aUFirst && aU <= aULast)
{
const GeomProp::CIType aType =
aIsMin[i] ? GeomProp::CIType::MinCurvature : GeomProp::CIType::MaxCurvature;
aResult.Points.Append({aU, aType});
}
}
return aResult;
}
@@ -0,0 +1,76 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_Ellipse_HeaderFile
#define _GeomProp_Ellipse_HeaderFile
#include <GeomAdaptor_Curve.hxx>
#include <GeomProp.hxx>
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Local differential properties for a 3D ellipse.
//!
//! An ellipse has analytically known curvature extrema at the four vertices:
//! - Parameter 0 and PI: endpoints of major axis (min radius of curvature)
//! - Parameter PI/2 and 3*PI/2: endpoints of minor axis (max radius of curvature)
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object. This class does not manage
//! the adaptor's lifetime.
class GeomProp_Ellipse
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the 3D curve adaptor (must wrap an ellipse, must not be null)
GeomProp_Ellipse(const GeomAdaptor_Curve* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_Ellipse(const GeomProp_Ellipse&) = delete;
GeomProp_Ellipse& operator=(const GeomProp_Ellipse&) = delete;
GeomProp_Ellipse(GeomProp_Ellipse&&) = delete;
GeomProp_Ellipse& operator=(GeomProp_Ellipse&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Curve* Adaptor() const { return myAdaptor; }
//! Compute tangent at given parameter.
Standard_EXPORT GeomProp::TangentResult Tangent(double theParam, double theTol) const;
//! Compute curvature at given parameter.
Standard_EXPORT GeomProp::CurvatureResult Curvature(double theParam, double theTol) const;
//! Compute normal at given parameter.
Standard_EXPORT GeomProp::NormalResult Normal(double theParam, double theTol) const;
//! Compute centre of curvature at given parameter.
Standard_EXPORT GeomProp::CentreResult CentreOfCurvature(double theParam, double theTol) const;
//! Find curvature extrema on the ellipse.
//! Extrema occur analytically at 0, PI/2, PI, and 3*PI/2, filtered to [FirstParam, LastParam].
Standard_EXPORT GeomProp::CurveAnalysis FindCurvatureExtrema() const;
//! Find inflection points on the ellipse.
//! An ellipse has no inflection points.
GeomProp::CurveAnalysis FindInflections() const { return {{}, true}; }
private:
const GeomAdaptor_Curve* myAdaptor;
};
#endif // _GeomProp_Ellipse_HeaderFile
@@ -0,0 +1,98 @@
// 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 <GeomProp_Hyperbola.hxx>
//==================================================================================================
GeomProp::TangentResult GeomProp_Hyperbola::Tangent(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2, aD3;
myAdaptor->D3(theParam, aPnt, aD1, aD2, aD3);
return GeomProp::ComputeTangent(aD1, aD2, aD3, theTol);
}
//==================================================================================================
GeomProp::CurvatureResult GeomProp_Hyperbola::Curvature(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {0.0, false, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeCurvature(aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::NormalResult GeomProp_Hyperbola::Normal(const double theParam, const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeNormal(aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::CentreResult GeomProp_Hyperbola::CentreOfCurvature(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeCentreOfCurvature(aPnt, aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::CurveAnalysis GeomProp_Hyperbola::FindCurvatureExtrema() const
{
GeomProp::CurveAnalysis aResult;
aResult.IsDone = true;
if (myAdaptor == nullptr)
{
aResult.IsDone = false;
return aResult;
}
const double aUFirst = myAdaptor->FirstParameter();
const double aULast = myAdaptor->LastParameter();
// Hyperbola has maximum |curvature| at parameter 0 (vertex).
if (aUFirst <= 0.0 && aULast >= 0.0)
{
aResult.Points.Append({0.0, GeomProp::CIType::MinCurvature});
}
return aResult;
}
@@ -0,0 +1,75 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_Hyperbola_HeaderFile
#define _GeomProp_Hyperbola_HeaderFile
#include <GeomAdaptor_Curve.hxx>
#include <GeomProp.hxx>
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Local differential properties for a 3D hyperbola.
//!
//! A hyperbola has a single curvature extremum (maximum |curvature|) at parameter 0
//! (the vertex). No inflection points exist.
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object. This class does not manage
//! the adaptor's lifetime.
class GeomProp_Hyperbola
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the 3D curve adaptor (must wrap a hyperbola, must not be null)
GeomProp_Hyperbola(const GeomAdaptor_Curve* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_Hyperbola(const GeomProp_Hyperbola&) = delete;
GeomProp_Hyperbola& operator=(const GeomProp_Hyperbola&) = delete;
GeomProp_Hyperbola(GeomProp_Hyperbola&&) = delete;
GeomProp_Hyperbola& operator=(GeomProp_Hyperbola&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Curve* Adaptor() const { return myAdaptor; }
//! Compute tangent at given parameter.
Standard_EXPORT GeomProp::TangentResult Tangent(double theParam, double theTol) const;
//! Compute curvature at given parameter.
Standard_EXPORT GeomProp::CurvatureResult Curvature(double theParam, double theTol) const;
//! Compute normal at given parameter.
Standard_EXPORT GeomProp::NormalResult Normal(double theParam, double theTol) const;
//! Compute centre of curvature at given parameter.
Standard_EXPORT GeomProp::CentreResult CentreOfCurvature(double theParam, double theTol) const;
//! Find curvature extrema on the hyperbola.
//! Single extremum at parameter 0 (the vertex), if within parameter range.
Standard_EXPORT GeomProp::CurveAnalysis FindCurvatureExtrema() const;
//! Find inflection points on the hyperbola.
//! A hyperbola has no inflection points.
GeomProp::CurveAnalysis FindInflections() const { return {{}, true}; }
private:
const GeomAdaptor_Curve* myAdaptor;
};
#endif // _GeomProp_Hyperbola_HeaderFile
@@ -0,0 +1,112 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_Line_HeaderFile
#define _GeomProp_Line_HeaderFile
#include <GeomAdaptor_Curve.hxx>
#include <GeomProp.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Local differential properties for a 3D line.
//!
//! A line has constant tangent, zero curvature, undefined normal and centre.
//! No curvature extrema or inflection points exist.
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object. This class does not manage
//! the adaptor's lifetime.
class GeomProp_Line
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the 3D curve adaptor (must wrap a line, must not be null)
GeomProp_Line(const GeomAdaptor_Curve* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_Line(const GeomProp_Line&) = delete;
GeomProp_Line& operator=(const GeomProp_Line&) = delete;
GeomProp_Line(GeomProp_Line&&) = delete;
GeomProp_Line& operator=(GeomProp_Line&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Curve* Adaptor() const { return myAdaptor; }
//! Compute tangent at given parameter.
//! For a line, the tangent is always the line direction.
//! @param[in] theParam curve parameter (unused)
//! @param[in] theTol tolerance (unused)
//! @return tangent result (always defined)
GeomProp::TangentResult Tangent(double theParam, double theTol) const
{
(void)theParam;
(void)theTol;
return {myAdaptor->Line().Direction(), true};
}
//! Compute curvature at given parameter.
//! For a line, curvature is always zero.
//! @param[in] theParam curve parameter (unused)
//! @param[in] theTol tolerance (unused)
//! @return curvature result (always zero)
GeomProp::CurvatureResult Curvature(double theParam, double theTol) const
{
(void)theParam;
(void)theTol;
return {0.0, true, false};
}
//! Compute normal at given parameter.
//! For a line, the normal is undefined (zero curvature).
//! @param[in] theParam curve parameter (unused)
//! @param[in] theTol tolerance (unused)
//! @return normal result (always undefined)
GeomProp::NormalResult Normal(double theParam, double theTol) const
{
(void)theParam;
(void)theTol;
return {{}, false};
}
//! Compute centre of curvature at given parameter.
//! For a line, the centre is undefined (zero curvature).
//! @param[in] theParam curve parameter (unused)
//! @param[in] theTol tolerance (unused)
//! @return centre result (always undefined)
GeomProp::CentreResult CentreOfCurvature(double theParam, double theTol) const
{
(void)theParam;
(void)theTol;
return {{}, false};
}
//! Find curvature extrema on the line.
//! A line has no curvature extrema.
//! @return empty analysis (always done)
GeomProp::CurveAnalysis FindCurvatureExtrema() const { return {{}, true}; }
//! Find inflection points on the line.
//! A line has no inflection points.
//! @return empty analysis (always done)
GeomProp::CurveAnalysis FindInflections() const { return {{}, true}; }
private:
const GeomAdaptor_Curve* myAdaptor;
};
#endif // _GeomProp_Line_HeaderFile
@@ -0,0 +1,340 @@
// 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 <GeomProp_OffsetCurve.hxx>
#include <gp.hxx>
#include <MathRoot_Brent.hxx>
#include <MathRoot_Multiple.hxx>
#include <Precision.hxx>
#include <cmath>
namespace
{
constexpr double THE_CURVATURE_DERIV_COEFF = 3.0;
constexpr double THE_DIFF_STEP_DIVISOR = 100.0;
constexpr double THE_D2_MAGNITUDE_THRESHOLD = 1.0e-4;
constexpr double THE_EPSILON_SCALE = 1.0e-4;
constexpr int THE_EXTREMA_NB_SAMPLES = 100;
constexpr int THE_INFLECTION_NB_SAMPLES = 30;
constexpr double THE_INFLECTION_TOLERANCE = 1.0e-6;
//! Function for finding curvature extrema on offset curves.
class FuncCurExt
{
public:
FuncCurExt(const GeomAdaptor_Curve* theCurve, const double theTol)
: myCurve(theCurve),
myEpsX(theTol)
{
}
bool Value(const double X, double& F)
{
gp_Pnt aP;
gp_Vec aV1, aV2, aV3;
myCurve->D3(X, aP, aV1, aV2, aV3);
const gp_Vec aCPV1V2 = aV1.Crossed(aV2);
const double aCPMag = aCPV1V2.Magnitude();
const gp_Vec aCPV1V3 = aV1.Crossed(aV3);
const double aV1V2 = aV1.Dot(aV2);
const double aV1V1 = aV1.SquareMagnitude();
const double aNV1 = std::sqrt(aV1V1);
const double aV13 = aV1V1 * aNV1;
const double aV15 = aV13 * aV1V1;
if (aV15 < gp::Resolution())
{
return false;
}
if (aCPMag < gp::Resolution())
{
F = aCPV1V3.Magnitude() / aV13;
return true;
}
const double aDCrossDU = aCPV1V2.Dot(aCPV1V3) / aCPMag;
F = aDCrossDU / aV13 - THE_CURVATURE_DERIV_COEFF * aCPMag * aV1V2 / aV15;
return true;
}
bool Values(const double X, double& F, double& D)
{
double aDx = myEpsX / THE_DIFF_STEP_DIVISOR;
if (X + aDx > myCurve->LastParameter())
{
aDx = -aDx;
}
Value(X, F);
double aF2;
Value(X + aDx, aF2);
D = (aF2 - F) / aDx;
return true;
}
bool IsMinKC(const double X) const
{
gp_Pnt aP;
gp_Vec aV1, aV2, aV3;
myCurve->D3(X, aP, aV1, aV2, aV3);
const double aV1V1 = aV1.SquareMagnitude();
const double aNV1 = std::sqrt(aV1V1);
const double aV13 = aV1V1 * aNV1;
if (aV13 < gp::Resolution())
{
return false;
}
const double aKC = aV1.Crossed(aV2).Magnitude() / aV13;
double aDx = myEpsX;
if (X + aDx > myCurve->LastParameter())
{
aDx = -aDx;
}
myCurve->D3(X + aDx, aP, aV1, aV2, aV3);
const double aV1V1n = aV1.SquareMagnitude();
const double aNV1n = std::sqrt(aV1V1n);
const double aV13n = aV1V1n * aNV1n;
if (aV13n < gp::Resolution())
{
return false;
}
const double aKP = aV1.Crossed(aV2).Magnitude() / aV13n;
return std::abs(aKC) > std::abs(aKP);
}
private:
const GeomAdaptor_Curve* myCurve;
double myEpsX;
};
//! Function for finding inflection points on offset curves.
class FuncCurNul
{
public:
FuncCurNul(const GeomAdaptor_Curve* theCurve)
: myCurve(theCurve)
{
}
bool Value(const double X, double& F)
{
double aD;
return Values(X, F, aD);
}
bool Values(const double X, double& F, double& D)
{
gp_Pnt aP;
gp_Vec aV1, aV2, aV3;
myCurve->D3(X, aP, aV1, aV2, aV3);
const gp_Vec aCPV1V2 = aV1.Crossed(aV2);
const double aCPMag = aCPV1V2.Magnitude();
const gp_Vec aCPV1V3 = aV1.Crossed(aV3);
const double aV1V2 = aV1.Dot(aV2);
const double aV2V3 = aV2.Dot(aV3);
const double aNV1 = aV1.Magnitude();
const double aNV2 = aV2.Magnitude();
F = 0.0;
D = 0.0;
if (aNV2 < THE_D2_MAGNITUDE_THRESHOLD)
{
return true;
}
if (aNV1 * aNV2 < gp::Resolution())
{
return false;
}
F = aCPMag / (aNV1 * aNV2);
if (aCPMag < gp::Resolution())
{
D = aCPV1V3.Magnitude() / (aNV1 * aNV2);
}
else
{
const double aDCrossDU = aCPV1V2.Dot(aCPV1V3) / aCPMag;
D = (aDCrossDU - aCPMag * aV1V2 / (aNV1 * aNV1) - aCPMag * aV2V3 / (aNV2 * aNV2))
/ (aNV1 * aNV2);
}
return true;
}
private:
const GeomAdaptor_Curve* myCurve;
};
} // namespace
//==================================================================================================
GeomProp::TangentResult GeomProp_OffsetCurve::Tangent(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2, aD3;
myAdaptor->D3(theParam, aPnt, aD1, aD2, aD3);
return GeomProp::ComputeTangent(aD1, aD2, aD3, theTol);
}
//==================================================================================================
GeomProp::CurvatureResult GeomProp_OffsetCurve::Curvature(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {0.0, false, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeCurvature(aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::NormalResult GeomProp_OffsetCurve::Normal(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeNormal(aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::CentreResult GeomProp_OffsetCurve::CentreOfCurvature(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeCentreOfCurvature(aPnt, aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::CurveAnalysis GeomProp_OffsetCurve::FindCurvatureExtrema() const
{
GeomProp::CurveAnalysis aResult;
aResult.IsDone = true;
if (myAdaptor == nullptr)
{
aResult.IsDone = false;
return aResult;
}
const double aUMin = myAdaptor->FirstParameter();
const double aUMax = myAdaptor->LastParameter();
const double aEpsH = THE_EPSILON_SCALE * (aUMax - aUMin);
FuncCurExt aFunc(myAdaptor, aEpsH);
MathRoot::MultipleConfig aConfig;
aConfig.NbSamples = THE_EXTREMA_NB_SAMPLES;
aConfig.XTolerance = aEpsH;
aConfig.FTolerance = aEpsH;
MathRoot::MultipleResult aRoots =
MathRoot::FindAllRootsWithDerivative(aFunc, aUMin, aUMax, aConfig);
if (aRoots.IsDone())
{
for (int j = 0; j < aRoots.NbRoots(); ++j)
{
double aParam = aRoots[j];
MathUtils::Config aBrentCfg;
aBrentCfg.XTolerance = Precision::PConfusion();
aBrentCfg.FTolerance = Precision::PConfusion();
auto aBrent = MathRoot::Brent(aFunc, aParam - aEpsH, aParam + aEpsH, aBrentCfg);
if (aBrent.IsDone() && aBrent.Root.has_value())
{
aParam = *aBrent.Root;
}
const bool aIsMin = aFunc.IsMinKC(aParam);
const GeomProp::CIType aType =
aIsMin ? GeomProp::CIType::MinCurvature : GeomProp::CIType::MaxCurvature;
aResult.Points.Append({aParam, aType});
}
}
else
{
aResult.IsDone = false;
}
return aResult;
}
//==================================================================================================
GeomProp::CurveAnalysis GeomProp_OffsetCurve::FindInflections() const
{
GeomProp::CurveAnalysis aResult;
aResult.IsDone = true;
if (myAdaptor == nullptr)
{
aResult.IsDone = false;
return aResult;
}
FuncCurNul aFunc(myAdaptor);
MathRoot::MultipleConfig aConfig;
aConfig.NbSamples = THE_INFLECTION_NB_SAMPLES;
aConfig.XTolerance = THE_INFLECTION_TOLERANCE;
aConfig.FTolerance = THE_INFLECTION_TOLERANCE;
MathRoot::MultipleResult aRoots =
MathRoot::FindAllRoots(aFunc, myAdaptor->FirstParameter(), myAdaptor->LastParameter(), aConfig);
if (aRoots.IsDone())
{
for (int j = 0; j < aRoots.NbRoots(); ++j)
{
aResult.Points.Append({aRoots[j], GeomProp::CIType::Inflection});
}
}
else
{
aResult.IsDone = false;
}
return aResult;
}
@@ -0,0 +1,73 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_OffsetCurve_HeaderFile
#define _GeomProp_OffsetCurve_HeaderFile
#include <GeomAdaptor_Curve.hxx>
#include <GeomProp.hxx>
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Local differential properties for a 3D offset curve.
//!
//! Uses numeric root-finding for curvature extrema and inflection points.
//! Local properties are computed from the offset curve's own D1/D2/D3.
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object. This class does not manage
//! the adaptor's lifetime.
class GeomProp_OffsetCurve
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the 3D curve adaptor (must wrap an offset curve, must not be null)
GeomProp_OffsetCurve(const GeomAdaptor_Curve* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_OffsetCurve(const GeomProp_OffsetCurve&) = delete;
GeomProp_OffsetCurve& operator=(const GeomProp_OffsetCurve&) = delete;
GeomProp_OffsetCurve(GeomProp_OffsetCurve&&) = delete;
GeomProp_OffsetCurve& operator=(GeomProp_OffsetCurve&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Curve* Adaptor() const { return myAdaptor; }
//! Compute tangent at given parameter.
Standard_EXPORT GeomProp::TangentResult Tangent(double theParam, double theTol) const;
//! Compute curvature at given parameter.
Standard_EXPORT GeomProp::CurvatureResult Curvature(double theParam, double theTol) const;
//! Compute normal at given parameter.
Standard_EXPORT GeomProp::NormalResult Normal(double theParam, double theTol) const;
//! Compute centre of curvature at given parameter.
Standard_EXPORT GeomProp::CentreResult CentreOfCurvature(double theParam, double theTol) const;
//! Find curvature extrema using numeric root-finding.
Standard_EXPORT GeomProp::CurveAnalysis FindCurvatureExtrema() const;
//! Find inflection points using numeric root-finding.
Standard_EXPORT GeomProp::CurveAnalysis FindInflections() const;
private:
const GeomAdaptor_Curve* myAdaptor;
};
#endif // _GeomProp_OffsetCurve_HeaderFile
@@ -0,0 +1,62 @@
// 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 <GeomProp_OffsetSurface.hxx>
//==================================================================================================
GeomProp::SurfaceNormalResult GeomProp_OffsetSurface::Normal(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V;
myAdaptor->D1(theU, theV, aPnt, aD1U, aD1V);
return GeomProp::ComputeSurfaceNormal(aD1U, aD1V, theTol);
}
//==================================================================================================
GeomProp::SurfaceCurvatureResult GeomProp_OffsetSurface::Curvatures(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeSurfaceCurvatures(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
//==================================================================================================
GeomProp::MeanGaussianResult GeomProp_OffsetSurface::MeanGaussian(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeMeanGaussian(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
@@ -0,0 +1,68 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_OffsetSurface_HeaderFile
#define _GeomProp_OffsetSurface_HeaderFile
#include <GeomAdaptor_Surface.hxx>
#include <GeomProp.hxx>
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Local differential properties for an offset surface.
//!
//! Uses numeric evaluation from adaptor derivatives.
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object.
class GeomProp_OffsetSurface
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the surface adaptor (must not be null)
GeomProp_OffsetSurface(const GeomAdaptor_Surface* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_OffsetSurface(const GeomProp_OffsetSurface&) = delete;
GeomProp_OffsetSurface& operator=(const GeomProp_OffsetSurface&) = delete;
GeomProp_OffsetSurface(GeomProp_OffsetSurface&&) = delete;
GeomProp_OffsetSurface& operator=(GeomProp_OffsetSurface&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Surface* Adaptor() const { return myAdaptor; }
//! Compute surface normal at given parameter.
Standard_EXPORT GeomProp::SurfaceNormalResult Normal(double theU,
double theV,
double theTol) const;
//! Compute principal curvatures at given parameter.
Standard_EXPORT GeomProp::SurfaceCurvatureResult Curvatures(double theU,
double theV,
double theTol) const;
//! Compute mean and Gaussian curvatures at given parameter.
Standard_EXPORT GeomProp::MeanGaussianResult MeanGaussian(double theU,
double theV,
double theTol) const;
private:
const GeomAdaptor_Surface* myAdaptor;
};
#endif // _GeomProp_OffsetSurface_HeaderFile
@@ -0,0 +1,339 @@
// 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 <GeomProp_OtherCurve.hxx>
#include <gp.hxx>
#include <MathRoot_Brent.hxx>
#include <MathRoot_Multiple.hxx>
#include <Precision.hxx>
#include <cmath>
namespace
{
constexpr double THE_CURVATURE_DERIV_COEFF = 3.0;
constexpr double THE_DIFF_STEP_DIVISOR = 100.0;
constexpr double THE_D2_MAGNITUDE_THRESHOLD = 1.0e-4;
constexpr double THE_EPSILON_SCALE = 1.0e-4;
constexpr int THE_EXTREMA_NB_SAMPLES = 100;
constexpr int THE_INFLECTION_NB_SAMPLES = 30;
constexpr double THE_INFLECTION_TOLERANCE = 1.0e-6;
//! Function for finding curvature extrema.
class FuncCurExt
{
public:
FuncCurExt(const GeomAdaptor_Curve* theCurve, const double theTol)
: myCurve(theCurve),
myEpsX(theTol)
{
}
bool Value(const double X, double& F)
{
gp_Pnt aP;
gp_Vec aV1, aV2, aV3;
myCurve->D3(X, aP, aV1, aV2, aV3);
const gp_Vec aCPV1V2 = aV1.Crossed(aV2);
const double aCPMag = aCPV1V2.Magnitude();
const gp_Vec aCPV1V3 = aV1.Crossed(aV3);
const double aV1V2 = aV1.Dot(aV2);
const double aV1V1 = aV1.SquareMagnitude();
const double aNV1 = std::sqrt(aV1V1);
const double aV13 = aV1V1 * aNV1;
const double aV15 = aV13 * aV1V1;
if (aV15 < gp::Resolution())
{
return false;
}
if (aCPMag < gp::Resolution())
{
F = aCPV1V3.Magnitude() / aV13;
return true;
}
const double aDCrossDU = aCPV1V2.Dot(aCPV1V3) / aCPMag;
F = aDCrossDU / aV13 - THE_CURVATURE_DERIV_COEFF * aCPMag * aV1V2 / aV15;
return true;
}
bool Values(const double X, double& F, double& D)
{
double aDx = myEpsX / THE_DIFF_STEP_DIVISOR;
if (X + aDx > myCurve->LastParameter())
{
aDx = -aDx;
}
Value(X, F);
double aF2;
Value(X + aDx, aF2);
D = (aF2 - F) / aDx;
return true;
}
bool IsMinKC(const double X) const
{
gp_Pnt aP;
gp_Vec aV1, aV2, aV3;
myCurve->D3(X, aP, aV1, aV2, aV3);
const double aV1V1 = aV1.SquareMagnitude();
const double aNV1 = std::sqrt(aV1V1);
const double aV13 = aV1V1 * aNV1;
if (aV13 < gp::Resolution())
{
return false;
}
const double aKC = aV1.Crossed(aV2).Magnitude() / aV13;
double aDx = myEpsX;
if (X + aDx > myCurve->LastParameter())
{
aDx = -aDx;
}
myCurve->D3(X + aDx, aP, aV1, aV2, aV3);
const double aV1V1n = aV1.SquareMagnitude();
const double aNV1n = std::sqrt(aV1V1n);
const double aV13n = aV1V1n * aNV1n;
if (aV13n < gp::Resolution())
{
return false;
}
const double aKP = aV1.Crossed(aV2).Magnitude() / aV13n;
return std::abs(aKC) > std::abs(aKP);
}
private:
const GeomAdaptor_Curve* myCurve;
double myEpsX;
};
//! Function for finding inflection points.
class FuncCurNul
{
public:
FuncCurNul(const GeomAdaptor_Curve* theCurve)
: myCurve(theCurve)
{
}
bool Value(const double X, double& F)
{
double aD;
return Values(X, F, aD);
}
bool Values(const double X, double& F, double& D)
{
gp_Pnt aP;
gp_Vec aV1, aV2, aV3;
myCurve->D3(X, aP, aV1, aV2, aV3);
const gp_Vec aCPV1V2 = aV1.Crossed(aV2);
const double aCPMag = aCPV1V2.Magnitude();
const gp_Vec aCPV1V3 = aV1.Crossed(aV3);
const double aV1V2 = aV1.Dot(aV2);
const double aV2V3 = aV2.Dot(aV3);
const double aNV1 = aV1.Magnitude();
const double aNV2 = aV2.Magnitude();
F = 0.0;
D = 0.0;
if (aNV2 < THE_D2_MAGNITUDE_THRESHOLD)
{
return true;
}
if (aNV1 * aNV2 < gp::Resolution())
{
return false;
}
F = aCPMag / (aNV1 * aNV2);
if (aCPMag < gp::Resolution())
{
D = aCPV1V3.Magnitude() / (aNV1 * aNV2);
}
else
{
const double aDCrossDU = aCPV1V2.Dot(aCPV1V3) / aCPMag;
D = (aDCrossDU - aCPMag * aV1V2 / (aNV1 * aNV1) - aCPMag * aV2V3 / (aNV2 * aNV2))
/ (aNV1 * aNV2);
}
return true;
}
private:
const GeomAdaptor_Curve* myCurve;
};
} // namespace
//==================================================================================================
GeomProp::TangentResult GeomProp_OtherCurve::Tangent(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2, aD3;
myAdaptor->D3(theParam, aPnt, aD1, aD2, aD3);
return GeomProp::ComputeTangent(aD1, aD2, aD3, theTol);
}
//==================================================================================================
GeomProp::CurvatureResult GeomProp_OtherCurve::Curvature(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {0.0, false, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeCurvature(aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::NormalResult GeomProp_OtherCurve::Normal(const double theParam, const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeNormal(aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::CentreResult GeomProp_OtherCurve::CentreOfCurvature(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeCentreOfCurvature(aPnt, aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::CurveAnalysis GeomProp_OtherCurve::FindCurvatureExtrema() const
{
GeomProp::CurveAnalysis aResult;
aResult.IsDone = true;
if (myAdaptor == nullptr)
{
aResult.IsDone = false;
return aResult;
}
const double aUMin = myAdaptor->FirstParameter();
const double aUMax = myAdaptor->LastParameter();
const double aEpsH = THE_EPSILON_SCALE * (aUMax - aUMin);
FuncCurExt aFunc(myAdaptor, aEpsH);
MathRoot::MultipleConfig aConfig;
aConfig.NbSamples = THE_EXTREMA_NB_SAMPLES;
aConfig.XTolerance = aEpsH;
aConfig.FTolerance = aEpsH;
MathRoot::MultipleResult aRoots =
MathRoot::FindAllRootsWithDerivative(aFunc, aUMin, aUMax, aConfig);
if (aRoots.IsDone())
{
for (int j = 0; j < aRoots.NbRoots(); ++j)
{
double aParam = aRoots[j];
MathUtils::Config aBrentCfg;
aBrentCfg.XTolerance = Precision::PConfusion();
aBrentCfg.FTolerance = Precision::PConfusion();
auto aBrent = MathRoot::Brent(aFunc, aParam - aEpsH, aParam + aEpsH, aBrentCfg);
if (aBrent.IsDone() && aBrent.Root.has_value())
{
aParam = *aBrent.Root;
}
const bool aIsMin = aFunc.IsMinKC(aParam);
const GeomProp::CIType aType =
aIsMin ? GeomProp::CIType::MinCurvature : GeomProp::CIType::MaxCurvature;
aResult.Points.Append({aParam, aType});
}
}
else
{
aResult.IsDone = false;
}
return aResult;
}
//==================================================================================================
GeomProp::CurveAnalysis GeomProp_OtherCurve::FindInflections() const
{
GeomProp::CurveAnalysis aResult;
aResult.IsDone = true;
if (myAdaptor == nullptr)
{
aResult.IsDone = false;
return aResult;
}
FuncCurNul aFunc(myAdaptor);
MathRoot::MultipleConfig aConfig;
aConfig.NbSamples = THE_INFLECTION_NB_SAMPLES;
aConfig.XTolerance = THE_INFLECTION_TOLERANCE;
aConfig.FTolerance = THE_INFLECTION_TOLERANCE;
MathRoot::MultipleResult aRoots =
MathRoot::FindAllRoots(aFunc, myAdaptor->FirstParameter(), myAdaptor->LastParameter(), aConfig);
if (aRoots.IsDone())
{
for (int j = 0; j < aRoots.NbRoots(); ++j)
{
aResult.Points.Append({aRoots[j], GeomProp::CIType::Inflection});
}
}
else
{
aResult.IsDone = false;
}
return aResult;
}
@@ -0,0 +1,73 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_OtherCurve_HeaderFile
#define _GeomProp_OtherCurve_HeaderFile
#include <GeomAdaptor_Curve.hxx>
#include <GeomProp.hxx>
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Fallback local differential properties for any 3D curve type.
//!
//! Uses adaptor D1/D2/D3 methods for property computation
//! and numeric root-finding for curvature extrema and inflection points.
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object. This class does not manage
//! the adaptor's lifetime.
class GeomProp_OtherCurve
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the 3D curve adaptor (must not be null)
GeomProp_OtherCurve(const GeomAdaptor_Curve* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_OtherCurve(const GeomProp_OtherCurve&) = delete;
GeomProp_OtherCurve& operator=(const GeomProp_OtherCurve&) = delete;
GeomProp_OtherCurve(GeomProp_OtherCurve&&) = delete;
GeomProp_OtherCurve& operator=(GeomProp_OtherCurve&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Curve* Adaptor() const { return myAdaptor; }
//! Compute tangent at given parameter.
Standard_EXPORT GeomProp::TangentResult Tangent(double theParam, double theTol) const;
//! Compute curvature at given parameter.
Standard_EXPORT GeomProp::CurvatureResult Curvature(double theParam, double theTol) const;
//! Compute normal at given parameter.
Standard_EXPORT GeomProp::NormalResult Normal(double theParam, double theTol) const;
//! Compute centre of curvature at given parameter.
Standard_EXPORT GeomProp::CentreResult CentreOfCurvature(double theParam, double theTol) const;
//! Find curvature extrema using numeric root-finding.
Standard_EXPORT GeomProp::CurveAnalysis FindCurvatureExtrema() const;
//! Find inflection points using numeric root-finding.
Standard_EXPORT GeomProp::CurveAnalysis FindInflections() const;
private:
const GeomAdaptor_Curve* myAdaptor;
};
#endif // _GeomProp_OtherCurve_HeaderFile
@@ -0,0 +1,62 @@
// 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 <GeomProp_OtherSurface.hxx>
//==================================================================================================
GeomProp::SurfaceNormalResult GeomProp_OtherSurface::Normal(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V;
myAdaptor->D1(theU, theV, aPnt, aD1U, aD1V);
return GeomProp::ComputeSurfaceNormal(aD1U, aD1V, theTol);
}
//==================================================================================================
GeomProp::SurfaceCurvatureResult GeomProp_OtherSurface::Curvatures(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeSurfaceCurvatures(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
//==================================================================================================
GeomProp::MeanGaussianResult GeomProp_OtherSurface::MeanGaussian(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeMeanGaussian(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
@@ -0,0 +1,68 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_OtherSurface_HeaderFile
#define _GeomProp_OtherSurface_HeaderFile
#include <GeomAdaptor_Surface.hxx>
#include <GeomProp.hxx>
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Fallback local differential properties for any surface type.
//!
//! Uses adaptor D1/D2 methods for property computation.
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object.
class GeomProp_OtherSurface
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the surface adaptor (must not be null)
GeomProp_OtherSurface(const GeomAdaptor_Surface* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_OtherSurface(const GeomProp_OtherSurface&) = delete;
GeomProp_OtherSurface& operator=(const GeomProp_OtherSurface&) = delete;
GeomProp_OtherSurface(GeomProp_OtherSurface&&) = delete;
GeomProp_OtherSurface& operator=(GeomProp_OtherSurface&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Surface* Adaptor() const { return myAdaptor; }
//! Compute surface normal at given parameter.
Standard_EXPORT GeomProp::SurfaceNormalResult Normal(double theU,
double theV,
double theTol) const;
//! Compute principal curvatures at given parameter.
Standard_EXPORT GeomProp::SurfaceCurvatureResult Curvatures(double theU,
double theV,
double theTol) const;
//! Compute mean and Gaussian curvatures at given parameter.
Standard_EXPORT GeomProp::MeanGaussianResult MeanGaussian(double theU,
double theV,
double theTol) const;
private:
const GeomAdaptor_Surface* myAdaptor;
};
#endif // _GeomProp_OtherSurface_HeaderFile
@@ -0,0 +1,97 @@
// 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 <GeomProp_Parabola.hxx>
//==================================================================================================
GeomProp::TangentResult GeomProp_Parabola::Tangent(const double theParam, const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2, aD3;
myAdaptor->D3(theParam, aPnt, aD1, aD2, aD3);
return GeomProp::ComputeTangent(aD1, aD2, aD3, theTol);
}
//==================================================================================================
GeomProp::CurvatureResult GeomProp_Parabola::Curvature(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {0.0, false, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeCurvature(aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::NormalResult GeomProp_Parabola::Normal(const double theParam, const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeNormal(aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::CentreResult GeomProp_Parabola::CentreOfCurvature(const double theParam,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1, aD2;
myAdaptor->D2(theParam, aPnt, aD1, aD2);
return GeomProp::ComputeCentreOfCurvature(aPnt, aD1, aD2, theTol);
}
//==================================================================================================
GeomProp::CurveAnalysis GeomProp_Parabola::FindCurvatureExtrema() const
{
GeomProp::CurveAnalysis aResult;
aResult.IsDone = true;
if (myAdaptor == nullptr)
{
aResult.IsDone = false;
return aResult;
}
const double aUFirst = myAdaptor->FirstParameter();
const double aULast = myAdaptor->LastParameter();
// Parabola has maximum |curvature| at parameter 0 (vertex).
if (aUFirst <= 0.0 && aULast >= 0.0)
{
aResult.Points.Append({0.0, GeomProp::CIType::MinCurvature});
}
return aResult;
}
@@ -0,0 +1,75 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_Parabola_HeaderFile
#define _GeomProp_Parabola_HeaderFile
#include <GeomAdaptor_Curve.hxx>
#include <GeomProp.hxx>
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Local differential properties for a 3D parabola.
//!
//! A parabola has a single curvature extremum (maximum |curvature|) at parameter 0
//! (the vertex). No inflection points exist.
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object. This class does not manage
//! the adaptor's lifetime.
class GeomProp_Parabola
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the 3D curve adaptor (must wrap a parabola, must not be null)
GeomProp_Parabola(const GeomAdaptor_Curve* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_Parabola(const GeomProp_Parabola&) = delete;
GeomProp_Parabola& operator=(const GeomProp_Parabola&) = delete;
GeomProp_Parabola(GeomProp_Parabola&&) = delete;
GeomProp_Parabola& operator=(GeomProp_Parabola&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Curve* Adaptor() const { return myAdaptor; }
//! Compute tangent at given parameter.
Standard_EXPORT GeomProp::TangentResult Tangent(double theParam, double theTol) const;
//! Compute curvature at given parameter.
Standard_EXPORT GeomProp::CurvatureResult Curvature(double theParam, double theTol) const;
//! Compute normal at given parameter.
Standard_EXPORT GeomProp::NormalResult Normal(double theParam, double theTol) const;
//! Compute centre of curvature at given parameter.
Standard_EXPORT GeomProp::CentreResult CentreOfCurvature(double theParam, double theTol) const;
//! Find curvature extrema on the parabola.
//! Single extremum at parameter 0 (the vertex), if within parameter range.
Standard_EXPORT GeomProp::CurveAnalysis FindCurvatureExtrema() const;
//! Find inflection points on the parabola.
//! A parabola has no inflection points.
GeomProp::CurveAnalysis FindInflections() const { return {{}, true}; }
private:
const GeomAdaptor_Curve* myAdaptor;
};
#endif // _GeomProp_Parabola_HeaderFile
@@ -0,0 +1,98 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_Plane_HeaderFile
#define _GeomProp_Plane_HeaderFile
#include <GeomAdaptor_Surface.hxx>
#include <GeomProp.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Local differential properties for a plane surface.
//!
//! Trivial implementation: constant normal, zero curvatures everywhere.
//! All properties are computed analytically without numerical evaluation.
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object.
class GeomProp_Plane
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the surface adaptor (must not be null)
GeomProp_Plane(const GeomAdaptor_Surface* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_Plane(const GeomProp_Plane&) = delete;
GeomProp_Plane& operator=(const GeomProp_Plane&) = delete;
GeomProp_Plane(GeomProp_Plane&&) = delete;
GeomProp_Plane& operator=(GeomProp_Plane&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Surface* Adaptor() const { return myAdaptor; }
//! Compute surface normal. Constant for a plane.
//! Uses D1U x D1V cross product to ensure correct sign for flipped planes.
GeomProp::SurfaceNormalResult Normal(double theU, double theV, double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V;
myAdaptor->D1(theU, theV, aPnt, aD1U, aD1V);
return GeomProp::ComputeSurfaceNormal(aD1U, aD1V, theTol);
}
//! Compute principal curvatures. Both are zero for a plane.
GeomProp::SurfaceCurvatureResult Curvatures(double /*theU*/,
double /*theV*/,
double /*theTol*/) const
{
if (myAdaptor == nullptr)
{
return {};
}
GeomProp::SurfaceCurvatureResult aResult;
aResult.MinCurvature = 0.0;
aResult.MaxCurvature = 0.0;
aResult.MinDirection = myAdaptor->Plane().Position().XDirection();
aResult.MaxDirection = myAdaptor->Plane().Position().YDirection();
aResult.IsDefined = true;
aResult.IsUmbilic = true;
return aResult;
}
//! Compute mean and Gaussian curvatures. Both are zero for a plane.
GeomProp::MeanGaussianResult MeanGaussian(double /*theU*/,
double /*theV*/,
double /*theTol*/) const
{
if (myAdaptor == nullptr)
{
return {};
}
return {0.0, 0.0, true};
}
private:
const GeomAdaptor_Surface* myAdaptor;
};
#endif // _GeomProp_Plane_HeaderFile
@@ -0,0 +1,95 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_Sphere_HeaderFile
#define _GeomProp_Sphere_HeaderFile
#include <GeomAdaptor_Surface.hxx>
#include <GeomProp.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Local differential properties for a spherical surface.
//!
//! Analytical implementation: constant curvature 1/R, umbilic everywhere.
//! Both principal curvatures equal 1/R.
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object.
class GeomProp_Sphere
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the surface adaptor (must not be null)
GeomProp_Sphere(const GeomAdaptor_Surface* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_Sphere(const GeomProp_Sphere&) = delete;
GeomProp_Sphere& operator=(const GeomProp_Sphere&) = delete;
GeomProp_Sphere(GeomProp_Sphere&&) = delete;
GeomProp_Sphere& operator=(GeomProp_Sphere&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Surface* Adaptor() const { return myAdaptor; }
//! Compute surface normal at given (U, V) parameter.
//! For a sphere, the normal is radially outward from the center.
//! TODO: At poles (V = +/-PI/2), D1U degenerates and Normal returns IsDefined=false.
//! Could use analytical normal (radial direction from center) for these special cases.
GeomProp::SurfaceNormalResult Normal(double theU, double theV, double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V;
myAdaptor->D1(theU, theV, aPnt, aD1U, aD1V);
return GeomProp::ComputeSurfaceNormal(aD1U, aD1V, theTol);
}
//! Compute principal curvatures using fundamental forms for correct sign convention.
GeomProp::SurfaceCurvatureResult Curvatures(double theU, double theV, double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeSurfaceCurvatures(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
//! Compute mean and Gaussian curvatures using fundamental forms for correct sign convention.
GeomProp::MeanGaussianResult MeanGaussian(double theU, double theV, double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeMeanGaussian(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
private:
const GeomAdaptor_Surface* myAdaptor;
};
#endif // _GeomProp_Sphere_HeaderFile
@@ -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 <GeomProp_Surface.hxx>
#include <GeomAdaptor_Surface.hxx>
//==================================================================================================
void GeomProp_Surface::Initialize(const Adaptor3d_Surface& theSurface)
{
if (theSurface.IsKind(STANDARD_TYPE(GeomAdaptor_Surface)))
{
const auto& aGeomAdaptor = static_cast<const GeomAdaptor_Surface&>(theSurface);
myAdaptor = new GeomAdaptor_Surface(aGeomAdaptor);
initFromAdaptor();
return;
}
// For non-GeomAdaptor, set uninitialized.
myAdaptor.Nullify();
mySurfaceType = theSurface.GetType();
myEvaluator.emplace<std::monostate>();
}
//==================================================================================================
void GeomProp_Surface::Initialize(const occ::handle<Geom_Surface>& theSurface)
{
if (theSurface.IsNull())
{
myAdaptor.Nullify();
myEvaluator.emplace<std::monostate>();
mySurfaceType = GeomAbs_OtherSurface;
return;
}
myAdaptor = new GeomAdaptor_Surface(theSurface);
initFromAdaptor();
}
//==================================================================================================
void GeomProp_Surface::initFromAdaptor()
{
mySurfaceType = myAdaptor->GetType();
const GeomAdaptor_Surface* aPtr = myAdaptor.get();
switch (mySurfaceType)
{
case GeomAbs_Plane:
myEvaluator.emplace<GeomProp_Plane>(aPtr);
break;
case GeomAbs_Cylinder:
myEvaluator.emplace<GeomProp_Cylinder>(aPtr);
break;
case GeomAbs_Cone:
myEvaluator.emplace<GeomProp_Cone>(aPtr);
break;
case GeomAbs_Sphere:
myEvaluator.emplace<GeomProp_Sphere>(aPtr);
break;
case GeomAbs_Torus:
myEvaluator.emplace<GeomProp_Torus>(aPtr);
break;
case GeomAbs_BezierSurface:
myEvaluator.emplace<GeomProp_BezierSurface>(aPtr);
break;
case GeomAbs_BSplineSurface:
myEvaluator.emplace<GeomProp_BSplineSurface>(aPtr);
break;
case GeomAbs_SurfaceOfRevolution:
myEvaluator.emplace<GeomProp_SurfaceOfRevolution>(aPtr);
break;
case GeomAbs_SurfaceOfExtrusion:
myEvaluator.emplace<GeomProp_SurfaceOfExtrusion>(aPtr);
break;
case GeomAbs_OffsetSurface:
myEvaluator.emplace<GeomProp_OffsetSurface>(aPtr);
break;
default:
myEvaluator.emplace<GeomProp_OtherSurface>(aPtr);
break;
}
}
//==================================================================================================
bool GeomProp_Surface::IsInitialized() const
{
return !std::holds_alternative<std::monostate>(myEvaluator);
}
//==================================================================================================
GeomProp::SurfaceNormalResult GeomProp_Surface::Normal(const double theU,
const double theV,
const double theTol) const
{
return std::visit(
[theU, theV, theTol](const auto& theEval) -> GeomProp::SurfaceNormalResult {
using T = std::decay_t<decltype(theEval)>;
if constexpr (std::is_same_v<T, std::monostate>)
{
return {{}, false};
}
else
{
return theEval.Normal(theU, theV, theTol);
}
},
myEvaluator);
}
//==================================================================================================
GeomProp::SurfaceCurvatureResult GeomProp_Surface::Curvatures(const double theU,
const double theV,
const double theTol) const
{
return std::visit(
[theU, theV, theTol](const auto& theEval) -> GeomProp::SurfaceCurvatureResult {
using T = std::decay_t<decltype(theEval)>;
if constexpr (std::is_same_v<T, std::monostate>)
{
return {};
}
else
{
return theEval.Curvatures(theU, theV, theTol);
}
},
myEvaluator);
}
//==================================================================================================
GeomProp::MeanGaussianResult GeomProp_Surface::MeanGaussian(const double theU,
const double theV,
const double theTol) const
{
return std::visit(
[theU, theV, theTol](const auto& theEval) -> GeomProp::MeanGaussianResult {
using T = std::decay_t<decltype(theEval)>;
if constexpr (std::is_same_v<T, std::monostate>)
{
return {};
}
else
{
return theEval.MeanGaussian(theU, theV, theTol);
}
},
myEvaluator);
}
@@ -0,0 +1,154 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_Surface_HeaderFile
#define _GeomProp_Surface_HeaderFile
#include <Adaptor3d_Surface.hxx>
#include <Geom_Surface.hxx>
#include <GeomAdaptor_Surface.hxx>
#include <GeomAbs_SurfaceType.hxx>
#include <GeomProp.hxx>
#include <GeomProp_BezierSurface.hxx>
#include <GeomProp_BSplineSurface.hxx>
#include <GeomProp_Cone.hxx>
#include <GeomProp_Cylinder.hxx>
#include <GeomProp_OffsetSurface.hxx>
#include <GeomProp_OtherSurface.hxx>
#include <GeomProp_Plane.hxx>
#include <GeomProp_Sphere.hxx>
#include <GeomProp_SurfaceOfExtrusion.hxx>
#include <GeomProp_SurfaceOfRevolution.hxx>
#include <GeomProp_Torus.hxx>
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
#include <variant>
//! @brief Unified local differential property evaluator for any 3D surface.
//!
//! Uses std::variant for compile-time type safety and zero heap allocation
//! for the evaluator itself. Automatically detects surface type from
//! Adaptor3d_Surface or Geom_Surface and dispatches to the appropriate
//! specialized evaluator.
//!
//! Supported surface types with optimized evaluation:
//! - Plane: Trivial (constant normal, zero curvatures)
//! - Cylinder: Constant principal curvatures (0 and 1/R)
//! - Cone: Analytical curvatures (vary along meridian)
//! - Sphere: Constant curvature 1/R, umbilic
//! - Torus: Analytical curvatures (vary along meridian)
//! - BezierSurface: Numeric from derivatives
//! - BSplineSurface: Numeric from derivatives
//! - SurfaceOfRevolution: Numeric from derivatives
//! - SurfaceOfExtrusion: Numeric from derivatives
//! - OffsetSurface: Numeric from derivatives
//! - Other: Fallback using adaptor derivatives
//!
//! Usage:
//! @code
//! GeomProp_Surface aProp;
//! aProp.Initialize(myGeomSurface);
//! GeomProp::SurfaceCurvatureResult aCurv = aProp.Curvatures(0.5, 0.5, Precision::Confusion());
//! if (aCurv.IsDefined)
//! {
//! double aMinK = aCurv.MinCurvature;
//! double aMaxK = aCurv.MaxCurvature;
//! }
//! @endcode
class GeomProp_Surface
{
public:
DEFINE_STANDARD_ALLOC
//! Variant type holding all possible 3D surface property evaluators.
using EvaluatorVariant = std::variant<std::monostate,
GeomProp_Plane,
GeomProp_Cylinder,
GeomProp_Cone,
GeomProp_Sphere,
GeomProp_Torus,
GeomProp_BezierSurface,
GeomProp_BSplineSurface,
GeomProp_SurfaceOfRevolution,
GeomProp_SurfaceOfExtrusion,
GeomProp_OffsetSurface,
GeomProp_OtherSurface>;
//! Default constructor - uninitialized state.
GeomProp_Surface()
: myEvaluator(std::monostate{}),
mySurfaceType(GeomAbs_OtherSurface)
{
}
//! Non-copyable and non-movable.
GeomProp_Surface(const GeomProp_Surface&) = delete;
GeomProp_Surface& operator=(const GeomProp_Surface&) = delete;
GeomProp_Surface(GeomProp_Surface&&) = delete;
GeomProp_Surface& operator=(GeomProp_Surface&&) = delete;
//! Initialize from 3D adaptor reference (auto-detects surface type).
//! For GeomAdaptor_Surface, extracts underlying Geom_Surface for optimized evaluation.
//! @param[in] theSurface 3D surface adaptor reference
Standard_EXPORT void Initialize(const Adaptor3d_Surface& theSurface);
//! Initialize from geometry handle (auto-detects surface type).
//! @param[in] theSurface 3D geometry to evaluate
Standard_EXPORT void Initialize(const occ::handle<Geom_Surface>& theSurface);
//! Returns true if properly initialized.
Standard_EXPORT bool IsInitialized() const;
//! Returns the detected surface type.
GeomAbs_SurfaceType GetType() const { return mySurfaceType; }
//! Compute surface normal at given (U, V) parameter.
//! @param[in] theU U parameter on the surface
//! @param[in] theV V parameter on the surface
//! @param[in] theTol linear tolerance
//! @return surface normal result with validity flag
Standard_EXPORT GeomProp::SurfaceNormalResult Normal(double theU,
double theV,
double theTol) const;
//! Compute principal curvatures at given (U, V) parameter.
//! @param[in] theU U parameter on the surface
//! @param[in] theV V parameter on the surface
//! @param[in] theTol linear tolerance
//! @return curvature result with principal curvatures and directions
Standard_EXPORT GeomProp::SurfaceCurvatureResult Curvatures(double theU,
double theV,
double theTol) const;
//! Compute mean and Gaussian curvatures at given (U, V) parameter.
//! @param[in] theU U parameter on the surface
//! @param[in] theV V parameter on the surface
//! @param[in] theTol linear tolerance
//! @return mean and Gaussian curvature result
Standard_EXPORT GeomProp::MeanGaussianResult MeanGaussian(double theU,
double theV,
double theTol) const;
private:
//! Initialize from stored adaptor (dispatches to per-geometry evaluator).
//! Must be called after myAdaptor is set. Per-geometry evaluators receive
//! a non-owning pointer to myAdaptor; their lifetime is managed by the variant.
Standard_EXPORT void initFromAdaptor();
occ::handle<GeomAdaptor_Surface> myAdaptor; //!< Owns the adaptor (ensures lifetime).
EvaluatorVariant myEvaluator; //!< Per-geometry evaluator (non-owning pointer to myAdaptor).
GeomAbs_SurfaceType mySurfaceType;
};
#endif // _GeomProp_Surface_HeaderFile
@@ -0,0 +1,62 @@
// 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 <GeomProp_SurfaceOfExtrusion.hxx>
//==================================================================================================
GeomProp::SurfaceNormalResult GeomProp_SurfaceOfExtrusion::Normal(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V;
myAdaptor->D1(theU, theV, aPnt, aD1U, aD1V);
return GeomProp::ComputeSurfaceNormal(aD1U, aD1V, theTol);
}
//==================================================================================================
GeomProp::SurfaceCurvatureResult GeomProp_SurfaceOfExtrusion::Curvatures(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeSurfaceCurvatures(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
//==================================================================================================
GeomProp::MeanGaussianResult GeomProp_SurfaceOfExtrusion::MeanGaussian(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeMeanGaussian(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
@@ -0,0 +1,68 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_SurfaceOfExtrusion_HeaderFile
#define _GeomProp_SurfaceOfExtrusion_HeaderFile
#include <GeomAdaptor_Surface.hxx>
#include <GeomProp.hxx>
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Local differential properties for a surface of extrusion.
//!
//! Uses numeric evaluation from adaptor derivatives.
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object.
class GeomProp_SurfaceOfExtrusion
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the surface adaptor (must not be null)
GeomProp_SurfaceOfExtrusion(const GeomAdaptor_Surface* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_SurfaceOfExtrusion(const GeomProp_SurfaceOfExtrusion&) = delete;
GeomProp_SurfaceOfExtrusion& operator=(const GeomProp_SurfaceOfExtrusion&) = delete;
GeomProp_SurfaceOfExtrusion(GeomProp_SurfaceOfExtrusion&&) = delete;
GeomProp_SurfaceOfExtrusion& operator=(GeomProp_SurfaceOfExtrusion&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Surface* Adaptor() const { return myAdaptor; }
//! Compute surface normal at given parameter.
Standard_EXPORT GeomProp::SurfaceNormalResult Normal(double theU,
double theV,
double theTol) const;
//! Compute principal curvatures at given parameter.
Standard_EXPORT GeomProp::SurfaceCurvatureResult Curvatures(double theU,
double theV,
double theTol) const;
//! Compute mean and Gaussian curvatures at given parameter.
Standard_EXPORT GeomProp::MeanGaussianResult MeanGaussian(double theU,
double theV,
double theTol) const;
private:
const GeomAdaptor_Surface* myAdaptor;
};
#endif // _GeomProp_SurfaceOfExtrusion_HeaderFile
@@ -0,0 +1,62 @@
// 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 <GeomProp_SurfaceOfRevolution.hxx>
//==================================================================================================
GeomProp::SurfaceNormalResult GeomProp_SurfaceOfRevolution::Normal(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V;
myAdaptor->D1(theU, theV, aPnt, aD1U, aD1V);
return GeomProp::ComputeSurfaceNormal(aD1U, aD1V, theTol);
}
//==================================================================================================
GeomProp::SurfaceCurvatureResult GeomProp_SurfaceOfRevolution::Curvatures(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeSurfaceCurvatures(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
//==================================================================================================
GeomProp::MeanGaussianResult GeomProp_SurfaceOfRevolution::MeanGaussian(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeMeanGaussian(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
@@ -0,0 +1,68 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_SurfaceOfRevolution_HeaderFile
#define _GeomProp_SurfaceOfRevolution_HeaderFile
#include <GeomAdaptor_Surface.hxx>
#include <GeomProp.hxx>
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Local differential properties for a surface of revolution.
//!
//! Uses numeric evaluation from adaptor derivatives.
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object.
class GeomProp_SurfaceOfRevolution
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the surface adaptor (must not be null)
GeomProp_SurfaceOfRevolution(const GeomAdaptor_Surface* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_SurfaceOfRevolution(const GeomProp_SurfaceOfRevolution&) = delete;
GeomProp_SurfaceOfRevolution& operator=(const GeomProp_SurfaceOfRevolution&) = delete;
GeomProp_SurfaceOfRevolution(GeomProp_SurfaceOfRevolution&&) = delete;
GeomProp_SurfaceOfRevolution& operator=(GeomProp_SurfaceOfRevolution&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Surface* Adaptor() const { return myAdaptor; }
//! Compute surface normal at given parameter.
Standard_EXPORT GeomProp::SurfaceNormalResult Normal(double theU,
double theV,
double theTol) const;
//! Compute principal curvatures at given parameter.
Standard_EXPORT GeomProp::SurfaceCurvatureResult Curvatures(double theU,
double theV,
double theTol) const;
//! Compute mean and Gaussian curvatures at given parameter.
Standard_EXPORT GeomProp::MeanGaussianResult MeanGaussian(double theU,
double theV,
double theTol) const;
private:
const GeomAdaptor_Surface* myAdaptor;
};
#endif // _GeomProp_SurfaceOfRevolution_HeaderFile
@@ -0,0 +1,62 @@
// 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 <GeomProp_Torus.hxx>
//==================================================================================================
GeomProp::SurfaceNormalResult GeomProp_Torus::Normal(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {{}, false};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V;
myAdaptor->D1(theU, theV, aPnt, aD1U, aD1V);
return GeomProp::ComputeSurfaceNormal(aD1U, aD1V, theTol);
}
//==================================================================================================
GeomProp::SurfaceCurvatureResult GeomProp_Torus::Curvatures(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeSurfaceCurvatures(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
//==================================================================================================
GeomProp::MeanGaussianResult GeomProp_Torus::MeanGaussian(const double theU,
const double theV,
const double theTol) const
{
if (myAdaptor == nullptr)
{
return {};
}
gp_Pnt aPnt;
gp_Vec aD1U, aD1V, aD2U, aD2V, aD2UV;
myAdaptor->D2(theU, theV, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV);
return GeomProp::ComputeMeanGaussian(aD1U, aD1V, aD2U, aD2V, aD2UV, theTol);
}
@@ -0,0 +1,71 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _GeomProp_Torus_HeaderFile
#define _GeomProp_Torus_HeaderFile
#include <GeomAdaptor_Surface.hxx>
#include <GeomProp.hxx>
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
//! @brief Local differential properties for a toroidal surface.
//!
//! Uses analytical formulas. Curvature varies along the meridian (V direction):
//! - k1 = 1/r (constant, along the minor circle direction)
//! - k2 = cos(V) / (R + r*cos(V)) (varies, along the major circle direction)
//! where R is the major radius and r is the minor radius.
//!
//! @warning The caller must ensure that the adaptor pointer remains valid
//! for the entire lifetime of this object.
class GeomProp_Torus
{
public:
DEFINE_STANDARD_ALLOC
//! Constructor with adaptor pointer (non-owning).
//! @param theAdaptor the surface adaptor (must not be null)
GeomProp_Torus(const GeomAdaptor_Surface* theAdaptor)
: myAdaptor(theAdaptor)
{
}
//! Non-copyable and non-movable.
GeomProp_Torus(const GeomProp_Torus&) = delete;
GeomProp_Torus& operator=(const GeomProp_Torus&) = delete;
GeomProp_Torus(GeomProp_Torus&&) = delete;
GeomProp_Torus& operator=(GeomProp_Torus&&) = delete;
//! Returns the adaptor pointer.
const GeomAdaptor_Surface* Adaptor() const { return myAdaptor; }
//! Compute surface normal at given parameter.
Standard_EXPORT GeomProp::SurfaceNormalResult Normal(double theU,
double theV,
double theTol) const;
//! Compute principal curvatures at given parameter.
Standard_EXPORT GeomProp::SurfaceCurvatureResult Curvatures(double theU,
double theV,
double theTol) const;
//! Compute mean and Gaussian curvatures at given parameter.
Standard_EXPORT GeomProp::MeanGaussianResult MeanGaussian(double theU,
double theV,
double theTol) const;
private:
const GeomAdaptor_Surface* myAdaptor;
};
#endif // _GeomProp_Torus_HeaderFile
+1
View File
@@ -11,4 +11,5 @@ set(OCCT_TKG3d_LIST_OF_PACKAGES
GProp
GeomHash
GeomEval
GeomProp
)