CubicSpline.cpp 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. #include "CubicSpline.h"
  2. USING_NS_BF;
  3. /* calculates the natural cubic spline that interpolates
  4. y[0], y[1], ... y[n]
  5. The first segment is returned as
  6. C[0].a + C[0].b*u + C[0].c*u^2 + C[0].d*u^3 0<=u <1
  7. the other segments are in C[1], C[2], ... C[n-1] */
  8. CubicVal* CubicSpline2D::SolveCubic(std::vector<float> vals)
  9. {
  10. int n = (int) vals.size() - 1;
  11. const float* x = &vals[0];
  12. float* gamma = new float[n+1];
  13. float* delta = new float[n+1];
  14. float* D = new float[n+1];
  15. int i;
  16. /* We solve the equation
  17. [2 1 ] [D[0]] [3(x[1] - x[0]) ]
  18. |1 4 1 | |D[1]| |3(x[2] - x[0]) |
  19. | 1 4 1 | | . | = | . |
  20. | ..... | | . | | . |
  21. | 1 4 1| | . | |3(x[n] - x[n-2])|
  22. [ 1 2] [D[n]] [3(x[n] - x[n-1])]
  23. by using row operations to convert the matrix to upper triangular
  24. and then back sustitution. The D[i] are the derivatives at the knots.
  25. */
  26. gamma[0] = 1.0f/2.0f;
  27. for ( i = 1; i < n; i++)
  28. gamma[i] = 1/(4-gamma[i-1]);
  29. gamma[n] = 1/(2-gamma[n-1]);
  30. delta[0] = 3*(x[1]-x[0])*gamma[0];
  31. for ( i = 1; i < n; i++)
  32. delta[i] = (3*(x[i+1]-x[i-1])-delta[i-1])*gamma[i];
  33. delta[n] = (3*(x[n]-x[n-1])-delta[n-1])*gamma[n];
  34. D[n] = delta[n];
  35. for ( i = n-1; i >= 0; i--)
  36. D[i] = delta[i] - gamma[i]*D[i+1];
  37. /* now compute the coefficients of the cubics */
  38. CubicVal* C = new CubicVal[n];
  39. for ( i = 0; i < n; i++)
  40. {
  41. C[i].Set((float)x[i], D[i], 3*(x[i+1] - x[i]) - 2*D[i] - D[i+1],
  42. 2*(x[i] - x[i+1]) + D[i] + D[i+1]);
  43. }
  44. return C;
  45. }
  46. CubicSpline2D::CubicSpline2D()
  47. {
  48. mXCubicArray = NULL;
  49. mYCubicArray = NULL;
  50. }
  51. CubicSpline2D::~CubicSpline2D()
  52. {
  53. delete mXCubicArray;
  54. delete mYCubicArray;
  55. }
  56. void CubicSpline2D::AddPt(float x, float y)
  57. {
  58. delete mXCubicArray;
  59. mXCubicArray = NULL;
  60. delete mYCubicArray;
  61. mYCubicArray = NULL;
  62. mInputPoints.push_back(PointF(x, y));
  63. }
  64. int CubicSpline2D::GetLength()
  65. {
  66. return (int) mInputPoints.size();
  67. }
  68. void CubicSpline2D::Calculate()
  69. {
  70. std::vector<float> xVals;
  71. std::vector<float> yVals;
  72. for (int i = 0; i < (int) mInputPoints.size(); i++)
  73. {
  74. xVals.push_back(mInputPoints[i].x);
  75. yVals.push_back(mInputPoints[i].y);
  76. }
  77. mXCubicArray = SolveCubic(xVals);
  78. mYCubicArray = SolveCubic(yVals);
  79. }
  80. PointF CubicSpline2D::Evaluate(float t)
  81. {
  82. if (mXCubicArray == NULL)
  83. Calculate();
  84. int idx = (int) t;
  85. float frac = t - idx;
  86. if (idx >= (int) mInputPoints.size() - 1)
  87. return mInputPoints[mInputPoints.size() - 1];
  88. return PointF(mXCubicArray[idx].Evaluate(frac), mYCubicArray[idx].Evaluate(frac));
  89. }