TCBSplineCurve.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2019.08.13
  7. #pragma once
  8. #include <Mathematics/Logger.h>
  9. #include <Mathematics/ParametricCurve.h>
  10. namespace WwiseGTE
  11. {
  12. template <int N, typename Real>
  13. class TCBSplineCurve : public ParametricCurve<N, Real>
  14. {
  15. public:
  16. // Construction and destruction. The object copies the input arrays.
  17. // The number of points must be at least 2. To validate construction,
  18. // create an object as shown:
  19. // TCBSplineCurve<N, Real> curve(parameters);
  20. // if (!curve) { <constructor failed, handle accordingly>; }
  21. TCBSplineCurve(int numPoints, Vector<N, Real> const* points,
  22. Real const* times, Real const* tension, Real const* continuity,
  23. Real const* bias)
  24. :
  25. ParametricCurve<N, Real>(numPoints - 1, times)
  26. {
  27. LogAssert(numPoints >= 2 && points != nullptr, "Invalid input.");
  28. mPoints.resize(numPoints);
  29. mTension.resize(numPoints);
  30. mContinuity.resize(numPoints);
  31. mBias.resize(numPoints);
  32. std::copy(points, points + numPoints, mPoints.begin());
  33. std::copy(tension, tension + numPoints, mTension.begin());
  34. std::copy(continuity, continuity + numPoints, mContinuity.begin());
  35. std::copy(bias, bias + numPoints, mBias.begin());
  36. int numSegments = numPoints - 1;
  37. mA.resize(numSegments);
  38. mB.resize(numSegments);
  39. mC.resize(numSegments);
  40. mD.resize(numSegments);
  41. // For now, treat the first point as if it occurred twice.
  42. ComputePoly(0, 0, 1, 2);
  43. for (int i = 1; i < numSegments - 1; ++i)
  44. {
  45. ComputePoly(i - 1, i, i + 1, i + 2);
  46. }
  47. // For now, treat the last point as if it occurred twice.
  48. ComputePoly(numSegments - 2, numSegments - 1, numSegments, numSegments);
  49. this->mConstructed = true;
  50. }
  51. virtual ~TCBSplineCurve()
  52. {
  53. }
  54. // Member access.
  55. inline int GetNumPoints() const
  56. {
  57. return static_cast<int>(mPoints.size());
  58. }
  59. inline Vector<N, Real> const* GetPoints() const
  60. {
  61. return &mPoints[0];
  62. }
  63. inline Real const* GetTensions() const
  64. {
  65. return &mTension[0];
  66. }
  67. inline Real const* GetContinuities() const
  68. {
  69. return &mContinuity[0];
  70. }
  71. inline Real const* GetBiases() const
  72. {
  73. return &mBias[0];
  74. }
  75. // Evaluation of the curve. The function supports derivative
  76. // calculation through order 3; that is, order <= 3 is required. If
  77. // you want/ only the position, pass in order of 0. If you want the
  78. // position and first derivative, pass in order of 1, and so on. The
  79. // output array 'jet' must have enough storage to support the maximum
  80. // order. The values are ordered as: position, first derivative,
  81. // second derivative, third derivative.
  82. virtual void Evaluate(Real t, unsigned int order, Vector<N, Real>* jet) const override
  83. {
  84. unsigned int const supOrder = ParametricCurve<N, Real>::SUP_ORDER;
  85. if (!this->mConstructed || order >= supOrder)
  86. {
  87. // Return a zero-valued jet for invalid state.
  88. for (unsigned int i = 0; i < supOrder; ++i)
  89. {
  90. jet[i].MakeZero();
  91. }
  92. return;
  93. }
  94. int key;
  95. Real dt;
  96. GetKeyInfo(t, key, dt);
  97. dt /= (this->mTime[key + 1] - this->mTime[key]);
  98. // Compute position.
  99. jet[0] = mA[key] + dt * (mB[key] + dt * (mC[key] + dt * mD[key]));
  100. if (order >= 1)
  101. {
  102. // Compute first derivative.
  103. jet[1] = mB[key] + dt * ((Real)2 * mC[key] + ((Real)3 * dt) * mD[key]);
  104. if (order >= 2)
  105. {
  106. // Compute second derivative.
  107. jet[2] = (Real)2 * mC[key] + ((Real)6 * dt) * mD[key];
  108. if (order == 3)
  109. {
  110. jet[3] = (Real)6 * mD[key];
  111. }
  112. }
  113. }
  114. }
  115. protected:
  116. // Support for construction.
  117. void ComputePoly(int i0, int i1, int i2, int i3)
  118. {
  119. Vector<N, Real> diff = mPoints[i2] - mPoints[i1];
  120. Real dt = this->mTime[i2] - this->mTime[i1];
  121. // Build multipliers at P1.
  122. Real oneMinusT0 = (Real)1 - mTension[i1];
  123. Real oneMinusC0 = (Real)1 - mContinuity[i1];
  124. Real onePlusC0 = (Real)1 + mContinuity[i1];
  125. Real oneMinusB0 = (Real)1 - mBias[i1];
  126. Real onePlusB0 = (Real)1 + mBias[i1];
  127. Real adj0 = (Real)2 * dt / (this->mTime[i2] - this->mTime[i0]);
  128. Real out0 = (Real)0.5 * adj0 * oneMinusT0 * onePlusC0 * onePlusB0;
  129. Real out1 = (Real)0.5 * adj0 * oneMinusT0 * oneMinusC0 * oneMinusB0;
  130. // Build outgoing tangent at P1.
  131. Vector<N, Real> tOut = out1 * diff + out0 * (mPoints[i1] - mPoints[i0]);
  132. // Build multipliers at point P2.
  133. Real oneMinusT1 = (Real)1 - mTension[i2];
  134. Real oneMinusC1 = (Real)1 - mContinuity[i2];
  135. Real onePlusC1 = (Real)1 + mContinuity[i2];
  136. Real oneMinusB1 = (Real)1 - mBias[i2];
  137. Real onePlusB1 = (Real)1 + mBias[i2];
  138. Real adj1 = (Real)2 * dt / (this->mTime[i3] - this->mTime[i1]);
  139. Real in0 = (Real)0.5 * adj1 * oneMinusT1 * oneMinusC1 * onePlusB1;
  140. Real in1 = (Real)0.5 * adj1 * oneMinusT1 * onePlusC1 * oneMinusB1;
  141. // Build incoming tangent at P2.
  142. Vector<N, Real> tIn = in1 * (mPoints[i3] - mPoints[i2]) + in0 * diff;
  143. mA[i1] = mPoints[i1];
  144. mB[i1] = tOut;
  145. mC[i1] = (Real)3 * diff - (Real)2 * tOut - tIn;
  146. mD[i1] = (Real)-2 * diff + tOut + tIn;
  147. }
  148. // Determine the index i for which times[i] <= t < times[i+1].
  149. void GetKeyInfo(Real t, int& key, Real& dt) const
  150. {
  151. int numSegments = static_cast<int>(mA.size());
  152. if (t <= this->mTime[0])
  153. {
  154. key = 0;
  155. dt = (Real)0;
  156. return;
  157. }
  158. if (t < this->mTime[numSegments])
  159. {
  160. for (int i = 0; i < numSegments; ++i)
  161. {
  162. if (t < this->mTime[i + 1])
  163. {
  164. key = i;
  165. dt = t - this->mTime[i];
  166. return;
  167. }
  168. }
  169. }
  170. key = numSegments - 1;
  171. dt = this->mTime[numSegments] - this->mTime[numSegments - 1];
  172. }
  173. std::vector<Vector<N, Real>> mPoints;
  174. std::vector<Real> mTension, mContinuity, mBias;
  175. // Polynomial coefficients. mA are the degree 0 coefficients, mB are
  176. // the degree 1 coefficients, mC are the degree 2 coefficients, and mD
  177. // are the degree 3 coefficients.
  178. std::vector<Vector<N, Real>> mA, mB, mC, mD;
  179. };
  180. }