0031381: Foundation Classes -wrong evaluations for rational BSpline curves using...
[occt.git] / src / BSplCLib / BSplCLib_Cache.cxx
index 275a7b9..2075211 100644 (file)
@@ -31,159 +31,71 @@ static Standard_Real* ConvertArray(const Handle(TColStd_HArray2OfReal)& theHArra
   return (Standard_Real*) &(anArray(anArray.LowerRow(), anArray.LowerCol()));
 }
 
-
-BSplCLib_Cache::BSplCLib_Cache()
-{
-  myPolesWeights.Nullify();
-  myIsRational = Standard_False;
-  mySpanStart = 0.0;
-  mySpanLength = 0.0;
-  mySpanIndex = 0;
-  myDegree = 0;
-  myFlatKnots.Nullify();
-}
-
 BSplCLib_Cache::BSplCLib_Cache(const Standard_Integer&        theDegree,
                                const Standard_Boolean&        thePeriodic,
                                const TColStd_Array1OfReal&    theFlatKnots,
-                               const TColgp_Array1OfPnt2d&    thePoles2d,
+                               const TColgp_Array1OfPnt2d&    /* only used to distinguish from 3d variant */,
                                const TColStd_Array1OfReal*    theWeights)
+: myIsRational(theWeights != NULL),
+  myParams (theDegree, thePeriodic, theFlatKnots)
 {
-  Standard_Real aCacheParam = theFlatKnots.Value(theFlatKnots.Lower() + theDegree);
-  BuildCache(aCacheParam, theDegree, thePeriodic, 
-             theFlatKnots, thePoles2d, theWeights);
+  Standard_Integer aPWColNumber = (myIsRational ? 3 : 2);
+  myPolesWeights = new TColStd_HArray2OfReal (1, theDegree + 1, 1, aPWColNumber);
 }
 
 BSplCLib_Cache::BSplCLib_Cache(const Standard_Integer&        theDegree,
                                const Standard_Boolean&        thePeriodic,
                                const TColStd_Array1OfReal&    theFlatKnots,
-                               const TColgp_Array1OfPnt&      thePoles,
+                               const TColgp_Array1OfPnt&      /* only used to distinguish from 2d variant */,
                                const TColStd_Array1OfReal*    theWeights)
+: myIsRational(theWeights != NULL),
+  myParams (theDegree, thePeriodic, theFlatKnots)
 {
-  Standard_Real aCacheParam = theFlatKnots.Value(theFlatKnots.Lower() + theDegree);
-  BuildCache(aCacheParam, theDegree, thePeriodic, 
-             theFlatKnots, thePoles, theWeights);
+  Standard_Integer aPWColNumber = (myIsRational ? 4 : 3);
+  myPolesWeights = new TColStd_HArray2OfReal (1, theDegree + 1, 1, aPWColNumber);
 }
 
-
 Standard_Boolean BSplCLib_Cache::IsCacheValid(Standard_Real theParameter) const
 {
-  Standard_Real aNewParam = theParameter;
-  if (!myFlatKnots.IsNull())
-    PeriodicNormalization(myFlatKnots->Array1(), aNewParam);
-
-  Standard_Real aDelta = aNewParam - mySpanStart;
-  return ((aDelta >= 0.0 || mySpanIndex == mySpanIndexMin) &&
-          (aDelta < mySpanLength || mySpanIndex == mySpanIndexMax));
+  return myParams.IsCacheValid (theParameter);
 }
 
-void BSplCLib_Cache::PeriodicNormalization(const TColStd_Array1OfReal& theFlatKnots, 
-                                           Standard_Real& theParameter) const
-{
-  Standard_Real aPeriod = theFlatKnots.Value(theFlatKnots.Upper() - myDegree) - 
-                          theFlatKnots.Value(myDegree + 1) ;
-  if (theParameter < theFlatKnots.Value(myDegree + 1))
-  {
-    Standard_Real aScale = IntegerPart(
-        (theFlatKnots.Value(myDegree + 1) - theParameter) / aPeriod);
-    theParameter += aPeriod * (aScale + 1.0);
-  }
-  if (theParameter > theFlatKnots.Value(theFlatKnots.Upper() - myDegree))
-  {
-    Standard_Real aScale = IntegerPart(
-        (theParameter - theFlatKnots.Value(theFlatKnots.Upper() - myDegree)) / aPeriod);
-    theParameter -= aPeriod * (aScale + 1.0);
-  }
-}
-
-
 void BSplCLib_Cache::BuildCache(const Standard_Real&           theParameter,
-                                const Standard_Integer&        theDegree,
-                                const Standard_Boolean&        thePeriodic,
                                 const TColStd_Array1OfReal&    theFlatKnots,
                                 const TColgp_Array1OfPnt2d&    thePoles2d,
                                 const TColStd_Array1OfReal*    theWeights)
 {
   // Normalize theParameter for periodical B-splines
-  Standard_Real aNewParam = theParameter;
-  if (thePeriodic)
-  {
-    PeriodicNormalization(theFlatKnots, aNewParam);
-    myFlatKnots = new TColStd_HArray1OfReal(1, theFlatKnots.Length());
-    myFlatKnots->ChangeArray1() = theFlatKnots;
-  }
-  else if (!myFlatKnots.IsNull()) // Periodical curve became non-periodical
-    myFlatKnots.Nullify();
-
-  // Change the size of cached data if needed
-  myIsRational = (theWeights != NULL);
-  Standard_Integer aPWColNumber = myIsRational ? 3 : 2;
-  if (theDegree > myDegree)
-    myPolesWeights = new TColStd_HArray2OfReal(1, theDegree + 1, 1, aPWColNumber);
-
-  myDegree = theDegree;
-  mySpanIndex = 0;
-  BSplCLib::LocateParameter(theDegree, theFlatKnots, BSplCLib::NoMults(), 
-                            aNewParam, thePeriodic, mySpanIndex, aNewParam);
-  mySpanStart  = theFlatKnots.Value(mySpanIndex);
-  mySpanLength = theFlatKnots.Value(mySpanIndex + 1) - mySpanStart;
-  mySpanIndexMin = thePeriodic ? 0 : myDegree + 1;
-  mySpanIndexMax = theFlatKnots.Length() - 1 - theDegree;
+  Standard_Real aNewParam = myParams.PeriodicNormalization (theParameter);
+  myParams.LocateParameter (aNewParam, theFlatKnots);
 
   // Calculate new cache data
-  BSplCLib::BuildCache(mySpanStart, mySpanLength, thePeriodic, theDegree, 
-                       theFlatKnots, thePoles2d, theWeights, 
-                       myPolesWeights->ChangeArray2());
+  BSplCLib::BuildCache (myParams.SpanStart, myParams.SpanLength, myParams.IsPeriodic,
+                        myParams.Degree, myParams.SpanIndex, theFlatKnots, thePoles2d,
+                        theWeights, myPolesWeights->ChangeArray2());
 }
 
 void BSplCLib_Cache::BuildCache(const Standard_Real&           theParameter,
-                                const Standard_Integer&        theDegree,
-                                const Standard_Boolean&        thePeriodic,
                                 const TColStd_Array1OfReal&    theFlatKnots,
                                 const TColgp_Array1OfPnt&      thePoles,
                                 const TColStd_Array1OfReal*    theWeights)
 {
   // Create list of knots with repetitions and normalize theParameter for periodical B-splines
-  Standard_Real aNewParam = theParameter;
-  if (thePeriodic)
-  {
-    PeriodicNormalization(theFlatKnots, aNewParam);
-    myFlatKnots = new TColStd_HArray1OfReal(1, theFlatKnots.Length());
-    myFlatKnots->ChangeArray1() = theFlatKnots;
-  }
-  else if (!myFlatKnots.IsNull()) // Periodical curve became non-periodical
-    myFlatKnots.Nullify();
-
-  // Change the size of cached data if needed
-  myIsRational = (theWeights != NULL);
-  Standard_Integer aPWColNumber = myIsRational ? 4 : 3;
-  if (theDegree > myDegree)
-    myPolesWeights = new TColStd_HArray2OfReal(1, theDegree + 1, 1, aPWColNumber);
-
-  myDegree = theDegree;
-  mySpanIndex = 0;
-  BSplCLib::LocateParameter(theDegree, theFlatKnots, BSplCLib::NoMults(), 
-                            aNewParam, thePeriodic, mySpanIndex, aNewParam);
-  mySpanStart  = theFlatKnots.Value(mySpanIndex);
-  mySpanLength = theFlatKnots.Value(mySpanIndex + 1) - mySpanStart;
-  mySpanIndexMin = thePeriodic ? 0 : myDegree + 1;
-  mySpanIndexMax = theFlatKnots.Length() - 1 - theDegree;
+  Standard_Real aNewParam = myParams.PeriodicNormalization (theParameter);
+  myParams.LocateParameter (aNewParam, theFlatKnots);
 
   // Calculate new cache data
-  BSplCLib::BuildCache(mySpanStart, mySpanLength, thePeriodic, theDegree
-                       theFlatKnots, thePoles, theWeights, 
-                       myPolesWeights->ChangeArray2());
+  BSplCLib::BuildCache (myParams.SpanStart, myParams.SpanLength, myParams.IsPeriodic
+                        myParams.Degree, myParams.SpanIndex, theFlatKnots, thePoles,
+                        theWeights, myPolesWeights->ChangeArray2());
 }
 
-
 void BSplCLib_Cache::CalculateDerivative(const Standard_Real&    theParameter, 
                                          const Standard_Integer& theDerivative, 
                                                Standard_Real&    theDerivArray) const
 {
-  Standard_Real aNewParameter = theParameter;
-  if (!myFlatKnots.IsNull()) // B-spline is periodical
-    PeriodicNormalization(myFlatKnots->Array1(), aNewParameter);
-  aNewParameter = (aNewParameter - mySpanStart) / mySpanLength;
+  Standard_Real aNewParameter = myParams.PeriodicNormalization (theParameter);
+  aNewParameter = (aNewParameter - myParams.SpanStart) / myParams.SpanLength;
 
   Standard_Real* aPolesArray = ConvertArray(myPolesWeights);
   Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns
@@ -199,23 +111,23 @@ void BSplCLib_Cache::CalculateDerivative(const Standard_Real&    theParameter,
   // When the degree of curve is lesser than the requested derivative,
   // nullify array cells corresponding to greater derivatives
   Standard_Integer aDerivative = theDerivative;
-  if (myDegree < theDerivative)
+  if (!myIsRational && myParams.Degree < theDerivative)
   {
-    aDerivative = myDegree;
-    for (Standard_Integer ind = myDegree * aDimension; ind < (theDerivative + 1) * aDimension; ind++)
+    aDerivative = myParams.Degree;
+    for (Standard_Integer ind = myParams.Degree * aDimension; ind < (theDerivative + 1) * aDimension; ind++)
     {
       aPntDeriv[ind] = 0.0;
       (&theDerivArray)[ind] = 0.0; // should be cleared separately, because aPntDeriv may look to another memory area
     }
   }
 
-  PLib::EvalPolynomial(aNewParameter, aDerivative, myDegree, aDimension, 
+  PLib::EvalPolynomial(aNewParameter, aDerivative, myParams.Degree, aDimension, 
                        aPolesArray[0], aPntDeriv[0]);
   // Unnormalize derivatives since those are computed normalized
   Standard_Real aFactor = 1.0;
   for (Standard_Integer deriv = 1; deriv <= aDerivative; deriv++)
   {
-    aFactor /= mySpanLength;
+    aFactor /= myParams.SpanLength;
     for (Standard_Integer ind = 0; ind < aDimension; ind++)
       aPntDeriv[aDimension * deriv + ind] *= aFactor;
   }
@@ -227,17 +139,15 @@ void BSplCLib_Cache::CalculateDerivative(const Standard_Real&    theParameter,
 
 void BSplCLib_Cache::D0(const Standard_Real& theParameter, gp_Pnt2d& thePoint) const
 {
-  Standard_Real aNewParameter = theParameter;
-  if (!myFlatKnots.IsNull()) // B-spline is periodical
-    PeriodicNormalization(myFlatKnots->Array1(), aNewParameter);
-  aNewParameter = (aNewParameter - mySpanStart) / mySpanLength;
+  Standard_Real aNewParameter = myParams.PeriodicNormalization (theParameter);
+  aNewParameter = (aNewParameter - myParams.SpanStart) / myParams.SpanLength;
 
   Standard_Real* aPolesArray = ConvertArray(myPolesWeights);
   Standard_Real aPoint[4];
   Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns
 
-  PLib::NoDerivativeEvalPolynomial(aNewParameter, myDegree,
-                                   aDimension, myDegree * aDimension,
+  PLib::NoDerivativeEvalPolynomial(aNewParameter, myParams.Degree,
+                                   aDimension, myParams.Degree * aDimension,
                                    aPolesArray[0], aPoint[0]);
 
   thePoint.SetCoord(aPoint[0], aPoint[1]);
@@ -247,17 +157,15 @@ void BSplCLib_Cache::D0(const Standard_Real& theParameter, gp_Pnt2d& thePoint) c
 
 void BSplCLib_Cache::D0(const Standard_Real& theParameter, gp_Pnt& thePoint) const
 {
-  Standard_Real aNewParameter = theParameter;
-  if (!myFlatKnots.IsNull()) // B-spline is periodical
-    PeriodicNormalization(myFlatKnots->Array1(), aNewParameter);
-  aNewParameter = (aNewParameter - mySpanStart) / mySpanLength;
+  Standard_Real aNewParameter = myParams.PeriodicNormalization (theParameter);
+  aNewParameter = (aNewParameter - myParams.SpanStart) / myParams.SpanLength;
 
   Standard_Real* aPolesArray = ConvertArray(myPolesWeights);
   Standard_Real aPoint[4];
   Standard_Integer aDimension = myPolesWeights->RowLength(); // number of columns
 
-  PLib::NoDerivativeEvalPolynomial(aNewParameter, myDegree,
-                                   aDimension, myDegree * aDimension,
+  PLib::NoDerivativeEvalPolynomial(aNewParameter, myParams.Degree,
+                                   aDimension, myParams.Degree * aDimension,
                                    aPolesArray[0], aPoint[0]);
 
   thePoint.SetCoord(aPoint[0], aPoint[1], aPoint[2]);