Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-19 09:28:32

0001 // Copyright (c) 2025 OPEN CASCADE SAS
0002 //
0003 // This file is part of Open CASCADE Technology software library.
0004 //
0005 // This library is free software; you can redistribute it and/or modify it under
0006 // the terms of the GNU Lesser General Public License version 2.1 as published
0007 // by the Free Software Foundation, with special exception defined in the file
0008 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0009 // distribution for complete text of the license and disclaimer of any warranty.
0010 //
0011 // Alternatively, this file may be used under the terms of Open CASCADE
0012 // commercial license or contractual agreement.
0013 
0014 #ifndef _LProp_CurveUtils_HeaderFile
0015 #define _LProp_CurveUtils_HeaderFile
0016 
0017 #include <LProp_NotDefined.hxx>
0018 #include <LProp_Status.hxx>
0019 #include <Standard_Handle.hxx>
0020 
0021 #include <cmath>
0022 
0023 //! Template utility functions for CLProps curve local property computation.
0024 //! Provides access policies (DirectAccess, ToolAccess) and shared algorithms
0025 //! for evaluating derivatives, tangents, curvature, normals, and centres of curvature.
0026 namespace LProp_CurveUtils
0027 {
0028 
0029 // ==================== Deref helpers ====================
0030 
0031 //! Dereference by-value or reference types (identity).
0032 template <typename T>
0033 T& Deref(T& theObj)
0034 {
0035   return theObj;
0036 }
0037 
0038 //! Dereference occ::handle types.
0039 template <typename T>
0040 T& Deref(occ::handle<T>& theHandle)
0041 {
0042   return *theHandle;
0043 }
0044 
0045 //! Dereference const occ::handle types.
0046 template <typename T>
0047 const T& Deref(const occ::handle<T>& theHandle)
0048 {
0049   return *theHandle;
0050 }
0051 
0052 // ==================== Access Policies ====================
0053 
0054 //! Direct access policy: calls D0/D1/D2/D3 methods on the curve object.
0055 //! Works with occ::handle<T> and by-value curve types.
0056 struct DirectAccess
0057 {
0058   template <typename C, typename P>
0059   static void D0(C& theCurve, double theU, P& thePnt)
0060   {
0061     Deref(theCurve).D0(theU, thePnt);
0062   }
0063 
0064   template <typename C, typename P, typename V>
0065   static void D1(C& theCurve, double theU, P& thePnt, V& theV1)
0066   {
0067     Deref(theCurve).D1(theU, thePnt, theV1);
0068   }
0069 
0070   template <typename C, typename P, typename V>
0071   static void D2(C& theCurve, double theU, P& thePnt, V& theV1, V& theV2)
0072   {
0073     Deref(theCurve).D2(theU, thePnt, theV1, theV2);
0074   }
0075 
0076   template <typename C, typename P, typename V>
0077   static void D3(C& theCurve, double theU, P& thePnt, V& theV1, V& theV2, V& theV3)
0078   {
0079     Deref(theCurve).D3(theU, thePnt, theV1, theV2, theV3);
0080   }
0081 
0082   template <typename C>
0083   static double FirstParameter(C& theCurve)
0084   {
0085     return Deref(theCurve).FirstParameter();
0086   }
0087 
0088   template <typename C>
0089   static double LastParameter(C& theCurve)
0090   {
0091     return Deref(theCurve).LastParameter();
0092   }
0093 };
0094 
0095 //! Tool-based access policy: delegates to static Tool methods.
0096 //! Used for HLRBRep types where Tool class provides the interface.
0097 template <typename Tool>
0098 struct ToolAccess
0099 {
0100   template <typename C, typename P>
0101   static void D0(C& theCurve, double theU, P& thePnt)
0102   {
0103     Tool::Value(theCurve, theU, thePnt);
0104   }
0105 
0106   template <typename C, typename P, typename V>
0107   static void D1(C& theCurve, double theU, P& thePnt, V& theV1)
0108   {
0109     Tool::D1(theCurve, theU, thePnt, theV1);
0110   }
0111 
0112   template <typename C, typename P, typename V>
0113   static void D2(C& theCurve, double theU, P& thePnt, V& theV1, V& theV2)
0114   {
0115     Tool::D2(theCurve, theU, thePnt, theV1, theV2);
0116   }
0117 
0118   template <typename C, typename P, typename V>
0119   static void D3(C& theCurve, double theU, P& thePnt, V& theV1, V& theV2, V& theV3)
0120   {
0121     Tool::D3(theCurve, theU, thePnt, theV1, theV2, theV3);
0122   }
0123 
0124   template <typename C>
0125   static double FirstParameter(C& theCurve)
0126   {
0127     return Tool::FirstParameter(theCurve);
0128   }
0129 
0130   template <typename C>
0131   static double LastParameter(C& theCurve)
0132   {
0133     return Tool::LastParameter(theCurve);
0134   }
0135 };
0136 
0137 // ==================== Algorithm Utilities ====================
0138 
0139 //! Evaluate curve derivatives at parameter theU up to specified order.
0140 //! @param[in,out] theCurve    curve object
0141 //! @param[in]     theU        parameter value
0142 //! @param[in]     theOrder    maximum derivative order (0-3)
0143 //! @param[out]    thePnt      evaluated point
0144 //! @param[out]    theDerivArr derivative array (size >= theOrder)
0145 template <typename Access, typename Curve, typename Pnt, typename Vec>
0146 void EvalDerivatives(Curve& theCurve, double theU, int theOrder, Pnt& thePnt, Vec* theDerivArr)
0147 {
0148   switch (theOrder)
0149   {
0150     case 0:
0151       Access::D0(theCurve, theU, thePnt);
0152       break;
0153     case 1:
0154       Access::D1(theCurve, theU, thePnt, theDerivArr[0]);
0155       break;
0156     case 2:
0157       Access::D2(theCurve, theU, thePnt, theDerivArr[0], theDerivArr[1]);
0158       break;
0159     case 3:
0160       Access::D3(theCurve, theU, thePnt, theDerivArr[0], theDerivArr[1], theDerivArr[2]);
0161       break;
0162   }
0163 }
0164 
0165 //! Compute tangent direction with sign correction for higher-order derivatives.
0166 //! When the first significant derivative has order > 1, the sign of the tangent
0167 //! is determined by comparing with the chord direction near the point.
0168 //! @param[in,out] theCurve    curve object
0169 //! @param[in]     theU        current parameter
0170 //! @param[in]     theDerivArr derivative array
0171 //! @param[in]     theRefPnt   reference point (used only for type deduction)
0172 //! @param[in]     theSigOrder order of first significant derivative
0173 //! @param[out]    theDir      computed tangent direction
0174 template <typename Access, typename Curve, typename Vec, typename Pnt, typename Dir>
0175 void ComputeTangent(Curve&     theCurve,
0176                     double     theU,
0177                     const Vec* theDerivArr,
0178                     const Pnt& /*theRefPnt*/,
0179                     int  theSigOrder,
0180                     Dir& theDir)
0181 {
0182   if (theSigOrder == 1)
0183   {
0184     theDir = Dir(theDerivArr[0]);
0185     return;
0186   }
0187 
0188   constexpr double THE_DIVISION_FACTOR = 1.0e-3;
0189   constexpr double THE_MIN_STEP        = 1.0e-7;
0190 
0191   const double anUsupremum = Access::LastParameter(theCurve);
0192   const double anUinfimum  = Access::FirstParameter(theCurve);
0193 
0194   double aDu;
0195   if ((anUsupremum >= RealLast()) || (anUinfimum <= RealFirst()))
0196     aDu = 0.0;
0197   else
0198     aDu = anUsupremum - anUinfimum;
0199 
0200   const double aDelta = std::max(aDu * THE_DIVISION_FACTOR, THE_MIN_STEP);
0201 
0202   Vec aV = theDerivArr[theSigOrder - 1];
0203 
0204   double anOtherU;
0205   if (theU - anUinfimum < aDelta)
0206     anOtherU = theU + aDelta;
0207   else
0208     anOtherU = theU - aDelta;
0209 
0210   Pnt aP1, aP2;
0211   Access::D0(theCurve, std::min(theU, anOtherU), aP1);
0212   Access::D0(theCurve, std::max(theU, anOtherU), aP2);
0213 
0214   Vec aChord(aP1, aP2);
0215   if (aV.Dot(aChord) < 0.0)
0216     aV = -aV;
0217 
0218   theDir = Dir(aV);
0219 }
0220 
0221 //! Compute curvature from first and second derivatives.
0222 //! Returns |D1 x D2| / |D1|^3, or 0 if derivatives are collinear or D2 is null.
0223 //! @param[in]  theD1    first derivative
0224 //! @param[in]  theD2    second derivative
0225 //! @param[in]  theTolSq squared linear tolerance
0226 //! @return curvature value
0227 template <typename Vec>
0228 double ComputeCurvature(const Vec& theD1, const Vec& theD2, double theTolSq)
0229 {
0230   const double aDD1 = theD1.SquareMagnitude();
0231   const double aDD2 = theD2.SquareMagnitude();
0232 
0233   if (aDD2 <= theTolSq)
0234     return 0.0;
0235 
0236   const double aN = theD1.CrossSquareMagnitude(theD2);
0237   const double aT = aN / aDD1 / aDD2;
0238   if (aT <= theTolSq)
0239     return 0.0;
0240 
0241   return sqrt(aN) / aDD1 / sqrt(aDD1);
0242 }
0243 
0244 //! Compute normal direction from first and second derivatives.
0245 //! Normal = D2*(D1*D1) - D1*(D1*D2), using the vector triple product identity.
0246 //! @param[in]  theD1   first derivative
0247 //! @param[in]  theD2   second derivative
0248 //! @param[out] theDir  computed normal direction
0249 template <typename Vec, typename Dir>
0250 void ComputeNormal(const Vec& theD1, const Vec& theD2, Dir& theDir)
0251 {
0252   Vec aNorm = theD2 * (theD1 * theD1) - theD1 * (theD1 * theD2);
0253   theDir    = Dir(aNorm);
0254 }
0255 
0256 //! Compute centre of curvature from point, derivatives, and curvature.
0257 //! Centre = Point + Normal / Curvature.
0258 //! @param[in]  thePnt       current point
0259 //! @param[in]  theD1        first derivative
0260 //! @param[in]  theD2        second derivative
0261 //! @param[in]  theCurvature curvature value (must be non-zero)
0262 //! @param[out] theCentre    computed centre of curvature
0263 template <typename Vec, typename Pnt>
0264 void ComputeCentreOfCurvature(const Pnt& thePnt,
0265                               const Vec& theD1,
0266                               const Vec& theD2,
0267                               double     theCurvature,
0268                               Pnt&       theCentre)
0269 {
0270   Vec aNorm = theD2 * (theD1 * theD1) - theD1 * (theD1 * theD2);
0271   aNorm.Normalize();
0272   aNorm.Divide(theCurvature);
0273   theCentre = thePnt.Translated(aNorm);
0274 }
0275 
0276 // ==================== Higher-Level Method Wrappers ====================
0277 
0278 //! SetParameter wrapper: sets parameter, evaluates derivatives, resets tangent status.
0279 //! @param[in,out] theCurve    curve object
0280 //! @param[in]     theU        parameter value
0281 //! @param[out]    theStoredU  stored parameter field
0282 //! @param[in]     theDerOrder current derivative order
0283 //! @param[out]    thePnt      evaluated point
0284 //! @param[out]    theDerivArr derivative array
0285 //! @param[out]    theTanStatus tangent status field
0286 template <typename Access, typename Curve, typename Pnt, typename Vec>
0287 void SetParameter(Curve&        theCurve,
0288                   double        theU,
0289                   double&       theStoredU,
0290                   int           theDerOrder,
0291                   Pnt&          thePnt,
0292                   Vec*          theDerivArr,
0293                   LProp_Status& theTanStatus)
0294 {
0295   theStoredU = theU;
0296   EvalDerivatives<Access>(theCurve, theU, theDerOrder, thePnt, theDerivArr);
0297   theTanStatus = LProp_Undecided;
0298 }
0299 
0300 //! Ensure derivatives up to the required order are computed.
0301 //! @param[in,out] theCurve    curve object
0302 //! @param[in]     theU        parameter value
0303 //! @param[in,out] theDerOrder current derivative order (upgraded if needed)
0304 //! @param[in]     theRequired required derivative order
0305 //! @param[out]    thePnt      evaluated point
0306 //! @param[out]    theDerivArr derivative array
0307 //! @return reference to theDerivArr[theRequired-1]
0308 template <typename Access, typename Curve, typename Pnt, typename Vec>
0309 const Vec& EnsureDeriv(Curve& theCurve,
0310                        double theU,
0311                        int&   theDerOrder,
0312                        int    theRequired,
0313                        Pnt&   thePnt,
0314                        Vec*   theDerivArr)
0315 {
0316   if (theDerOrder < theRequired)
0317   {
0318     theDerOrder = theRequired;
0319     EvalDerivatives<Access>(theCurve, theU, theDerOrder, thePnt, theDerivArr);
0320   }
0321   return theDerivArr[theRequired - 1];
0322 }
0323 
0324 //! IsTangentDefined: searches for first non-null derivative.
0325 //! Calls theProps.D1(), theProps.D2(), theProps.D3() to upgrade derivatives as needed.
0326 //! @param[in,out] theProps     CLProps object
0327 //! @param[in]     theCN        continuity order
0328 //! @param[in]     theLinTol    linear tolerance
0329 //! @param[out]    theSigOrder  order of first significant derivative
0330 //! @param[in,out] theTanStatus tangent status field
0331 //! @return true if tangent is defined
0332 template <typename Vec, typename Props>
0333 bool IsTangentDefined(Props&        theProps,
0334                       int           theCN,
0335                       double        theLinTol,
0336                       int&          theSigOrder,
0337                       LProp_Status& theTanStatus)
0338 {
0339   if (theTanStatus == LProp_Undefined)
0340     return false;
0341   if (theTanStatus >= LProp_Defined)
0342     return true;
0343 
0344   const double aTolSq  = theLinTol * theLinTol;
0345   int          anOrder = 0;
0346   while (anOrder++ < 4)
0347   {
0348     if (theCN >= anOrder)
0349     {
0350       Vec aV;
0351       switch (anOrder)
0352       {
0353         case 1:
0354           aV = theProps.D1();
0355           break;
0356         case 2:
0357           aV = theProps.D2();
0358           break;
0359         case 3:
0360           aV = theProps.D3();
0361           break;
0362         default:
0363           theTanStatus = LProp_Undefined;
0364           return false;
0365       }
0366       if (aV.SquareMagnitude() > aTolSq)
0367       {
0368         theSigOrder  = anOrder;
0369         theTanStatus = LProp_Defined;
0370         return true;
0371       }
0372     }
0373     else
0374     {
0375       theTanStatus = LProp_Undefined;
0376       return false;
0377     }
0378   }
0379   return false;
0380 }
0381 
0382 //! Tangent: checks IsTangentDefined, then computes tangent direction.
0383 //! @param[in,out] theProps     CLProps object
0384 //! @param[in,out] theCurve     curve object
0385 //! @param[in]     theU         current parameter
0386 //! @param[in]     theDerivArr  derivative array
0387 //! @param[in]     theRefPnt    reference point (for type deduction)
0388 //! @param[in]     theSigOrder  order of first significant derivative
0389 //! @param[out]    theDir       computed tangent direction
0390 template <typename Access, typename Props, typename Curve, typename Vec, typename Pnt, typename Dir>
0391 void Tangent(Props&     theProps,
0392              Curve&     theCurve,
0393              double     theU,
0394              const Vec* theDerivArr,
0395              const Pnt& theRefPnt,
0396              const int& theSigOrder,
0397              Dir&       theDir)
0398 {
0399   if (!theProps.IsTangentDefined())
0400     throw LProp_NotDefined();
0401   ComputeTangent<Access>(theCurve, theU, theDerivArr, theRefPnt, theSigOrder, theDir);
0402 }
0403 
0404 //! Curvature: checks IsTangentDefined, returns RealLast if higher-order, else computes.
0405 //! @param[in,out] theProps     CLProps object
0406 //! @param[in]     theD1        first derivative
0407 //! @param[in]     theD2        second derivative
0408 //! @param[in]     theLinTol    linear tolerance
0409 //! @param[in]     theSigOrder  order of first significant derivative
0410 //! @param[out]    theCurvature curvature value field
0411 //! @return computed curvature
0412 template <typename Props, typename Vec>
0413 double Curvature(Props&     theProps,
0414                  const Vec& theD1,
0415                  const Vec& theD2,
0416                  double     theLinTol,
0417                  const int& theSigOrder,
0418                  double&    theCurvature)
0419 {
0420   const bool anIsDefined = theProps.IsTangentDefined();
0421   (void)anIsDefined;
0422   LProp_NotDefined_Raise_if(!anIsDefined, "CLProps::Curvature()");
0423   if (theSigOrder > 1)
0424     return RealLast();
0425   theCurvature = ComputeCurvature(theD1, theD2, theLinTol * theLinTol);
0426   return theCurvature;
0427 }
0428 
0429 //! Normal: checks curvature, then computes normal direction.
0430 //! @param[in,out] theProps  CLProps object
0431 //! @param[in]     theD1     first derivative
0432 //! @param[in]     theD2     second derivative
0433 //! @param[in]     theLinTol linear tolerance
0434 //! @param[out]    theDir    computed normal direction
0435 template <typename Props, typename Vec, typename Dir>
0436 void Normal(Props& theProps, const Vec& theD1, const Vec& theD2, double theLinTol, Dir& theDir)
0437 {
0438   const double aCurvature = theProps.Curvature();
0439   if (aCurvature == RealLast() || std::abs(aCurvature) <= theLinTol)
0440     throw LProp_NotDefined("CLProps::Normal(): Curvature is null or infinity");
0441   ComputeNormal(theD1, theD2, theDir);
0442 }
0443 
0444 //! CentreOfCurvature: checks curvature, then computes centre.
0445 //! @param[in,out] theProps     CLProps object
0446 //! @param[in]     thePnt       current point
0447 //! @param[in]     theD1        first derivative
0448 //! @param[in]     theD2        second derivative
0449 //! @param[in]     theLinTol    linear tolerance
0450 //! @param[in,out] theCurvature curvature value field
0451 //! @param[out]    theCentre    computed centre of curvature
0452 template <typename Props, typename Vec, typename Pnt>
0453 void CentreOfCurvature(Props&     theProps,
0454                        const Pnt& thePnt,
0455                        const Vec& theD1,
0456                        const Vec& theD2,
0457                        double     theLinTol,
0458                        double&    theCurvature,
0459                        Pnt&       theCentre)
0460 {
0461   if (std::abs(theProps.Curvature()) <= theLinTol)
0462     throw LProp_NotDefined();
0463   ComputeCentreOfCurvature(thePnt, theD1, theD2, theCurvature, theCentre);
0464 }
0465 
0466 } // namespace LProp_CurveUtils
0467 
0468 #endif // _LProp_CurveUtils_HeaderFile