Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-19 09:27:35

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 _Convert_CompBezierCurvesToBSplineCurveBase_HeaderFile
0015 #define _Convert_CompBezierCurvesToBSplineCurveBase_HeaderFile
0016 
0017 #include <BSplCLib.hxx>
0018 #include <gp.hxx>
0019 #include <NCollection_Array1.hxx>
0020 #include <NCollection_Sequence.hxx>
0021 #include <type_traits>
0022 
0023 class gp_Pnt;
0024 class gp_Pnt2d;
0025 
0026 //! Template base class for converting a sequence of adjacent
0027 //! non-rational Bezier curves into a BSpline curve.
0028 //! PointType is gp_Pnt or gp_Pnt2d; VecType is gp_Vec or gp_Vec2d.
0029 template <typename PointType, typename VecType>
0030 class Convert_CompBezierCurvesToBSplineCurveBase
0031 {
0032 public:
0033   //! Constructs a framework for converting a sequence of
0034   //! adjacent non-rational Bezier curves into a BSpline curve.
0035   //! @param[in] theAngularTolerance angular tolerance in radians
0036   //!            for checking tangent parallelism at junction points
0037   explicit Convert_CompBezierCurvesToBSplineCurveBase(const double theAngularTolerance = 1.0e-4)
0038       : myDegree(0),
0039         myAngular(theAngularTolerance)
0040   {
0041   }
0042 
0043   //! Adds the Bezier curve defined by the table of poles to
0044   //! the sequence of adjacent Bezier curves to be converted.
0045   //! @param[in] thePoles poles of the Bezier curve to add
0046   void AddCurve(const NCollection_Array1<PointType>& thePoles) { mySequence.Append(thePoles); }
0047 
0048   //! Computes all the data needed to build a BSpline curve
0049   //! equivalent to the adjacent Bezier curve sequence.
0050   void Perform()
0051   {
0052     myCurvePoles.Clear();
0053     myCurveKnots.Clear();
0054     myKnotsMults.Clear();
0055     if (mySequence.IsEmpty())
0056     {
0057       return;
0058     }
0059     const int                  aLowerI  = 1;
0060     const int                  anUpperI = mySequence.Length();
0061     const int                  aNbrCurv = anUpperI - aLowerI + 1;
0062     NCollection_Array1<double> aCurveKnVals(1, aNbrCurv);
0063 
0064     myDegree = 0;
0065     for (int i = 1; i <= mySequence.Length(); i++)
0066     {
0067       myDegree = std::max(myDegree, mySequence(i).Length() - 1);
0068     }
0069 
0070     double                        aDet = 0;
0071     PointType                     aP1, aP2, aP3;
0072     const int                     aMaxDegree = myDegree;
0073     NCollection_Array1<PointType> aPoints(1, myDegree + 1);
0074 
0075     for (int i = aLowerI; i <= anUpperI; i++)
0076     {
0077       // 1- Raise the Bezier curve to the maximum degree.
0078       const int aDeg  = mySequence(i).Length() - 1;
0079       const int anInc = myDegree - aDeg;
0080       if (anInc > 0)
0081       {
0082         BSplCLib::IncreaseDegree(myDegree,
0083                                  mySequence(i),
0084                                  BSplCLib::NoWeights(),
0085                                  aPoints,
0086                                  BSplCLib::NoWeights());
0087       }
0088       else
0089       {
0090         aPoints = mySequence(i);
0091       }
0092 
0093       // 2- Process the node of junction between 2 Bezier curves.
0094       if (i == aLowerI)
0095       {
0096         // Processing of the initial node of the BSpline.
0097         for (int j = 1; j <= aMaxDegree; j++)
0098         {
0099           myCurvePoles.Append(aPoints(j));
0100         }
0101         aCurveKnVals(1) = 1.; // To begin the series.
0102         myKnotsMults.Append(aMaxDegree + 1);
0103         aDet = 1.;
0104       }
0105 
0106       if (i != aLowerI)
0107       {
0108         aP2 = aPoints(1);
0109         aP3 = aPoints(2);
0110         VecType aV1(aP1, aP2), aV2(aP2, aP3);
0111 
0112         // Processing of the tangency between Bezier and the previous.
0113         // This allows to guarantee at least a C1 continuity if the tangents are coherent.
0114         const double aD1 = aV1.SquareMagnitude();
0115         const double aD2 = aV2.SquareMagnitude();
0116         if (aMaxDegree > 1 && aD1 > gp::Resolution() && aD2 > gp::Resolution()
0117             && aV1.IsParallel(aV2, myAngular))
0118         {
0119           const double aLambda = std::sqrt(aD2 / aD1);
0120           if constexpr (std::is_same_v<PointType, gp_Pnt>)
0121           {
0122             // 3D-specific epsilon guard to avoid numerical issues
0123             // when accumulated knot values become too small relative to Det.
0124             if (aCurveKnVals(i - 1) * aLambda > 10. * Epsilon(aDet))
0125             {
0126               myKnotsMults.Append(aMaxDegree - 1);
0127               aCurveKnVals(i) = aCurveKnVals(i - 1) * aLambda;
0128             }
0129             else
0130             {
0131               myCurvePoles.Append(aPoints(1));
0132               myKnotsMults.Append(aMaxDegree);
0133               aCurveKnVals(i) = 1.0;
0134             }
0135           }
0136           else
0137           {
0138             myKnotsMults.Append(aMaxDegree - 1);
0139             aCurveKnVals(i) = aCurveKnVals(i - 1) * aLambda;
0140           }
0141         }
0142         else
0143         {
0144           myCurvePoles.Append(aPoints(1));
0145           myKnotsMults.Append(aMaxDegree);
0146           aCurveKnVals(i) = 1.0;
0147         }
0148         aDet += aCurveKnVals(i);
0149 
0150         // Store the poles.
0151         for (int j = 2; j <= aMaxDegree; j++)
0152         {
0153           myCurvePoles.Append(aPoints(j));
0154         }
0155       }
0156 
0157       if (i == anUpperI)
0158       {
0159         // Processing of the end node of the BSpline.
0160         myCurvePoles.Append(aPoints(aMaxDegree + 1));
0161         myKnotsMults.Append(aMaxDegree + 1);
0162       }
0163       aP1 = aPoints(aMaxDegree);
0164     }
0165 
0166     // Correct nodal values to make them variable within [0.,1.].
0167     myCurveKnots.Append(0.0);
0168     for (int i = 2; i <= aNbrCurv; i++)
0169     {
0170       myCurveKnots.Append(myCurveKnots(i - 1) + (aCurveKnVals(i - 1) / aDet));
0171     }
0172     myCurveKnots.Append(1.0);
0173   }
0174 
0175   //! Returns the degree of the BSpline curve.
0176   [[nodiscard]] int Degree() const { return myDegree; }
0177 
0178   //! Returns the number of poles of the BSpline curve.
0179   [[nodiscard]] int NbPoles() const { return myCurvePoles.Length(); }
0180 
0181   //! Loads the Poles table with the poles of the BSpline curve.
0182   //! @param[out] thePoles array to fill with poles
0183   void Poles(NCollection_Array1<PointType>& thePoles) const
0184   {
0185     int k = 1;
0186     for (int i = thePoles.Lower(); i <= thePoles.Upper(); i++)
0187     {
0188       thePoles(i) = myCurvePoles(k++);
0189     }
0190   }
0191 
0192   //! Returns the number of knots of the BSpline curve.
0193   [[nodiscard]] int NbKnots() const { return myCurveKnots.Length(); }
0194 
0195   //! Loads the Knots and Mults tables with the knots
0196   //! and corresponding multiplicities of the BSpline curve.
0197   //! @param[out] theKnots array to fill with knots
0198   //! @param[out] theMults array to fill with multiplicities
0199   void KnotsAndMults(NCollection_Array1<double>& theKnots, NCollection_Array1<int>& theMults) const
0200   {
0201     int k = 1;
0202     for (int i = theKnots.Lower(); i <= theKnots.Upper(); i++)
0203     {
0204       theKnots(i) = myCurveKnots(k++);
0205     }
0206     k = 1;
0207     for (int i = theMults.Lower(); i <= theMults.Upper(); i++)
0208     {
0209       theMults(i) = myKnotsMults(k++);
0210     }
0211   }
0212 
0213 private:
0214   NCollection_Sequence<NCollection_Array1<PointType>> mySequence;
0215   NCollection_Sequence<PointType>                     myCurvePoles;
0216   NCollection_Sequence<double>                        myCurveKnots;
0217   NCollection_Sequence<int>                           myKnotsMults;
0218   int                                                 myDegree;
0219   double                                              myAngular;
0220 };
0221 
0222 #endif // _Convert_CompBezierCurvesToBSplineCurveBase_HeaderFile