NURBSCurve.h 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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/BasisFunction.h>
  9. #include <Mathematics/ParametricCurve.h>
  10. namespace WwiseGTE
  11. {
  12. template <int N, typename Real>
  13. class NURBSCurve : public ParametricCurve<N, Real>
  14. {
  15. public:
  16. // Construction. If the input controls is non-null, a copy is made of
  17. // the controls. To defer setting the control points or weights, pass
  18. // null pointers and later access the control points or weights via
  19. // GetControls(), GetWeights(), SetControl(), or SetWeight() member
  20. // functions. The domain is t in [t[d],t[n]], where t[d] and t[n] are
  21. // knots with d the degree and n the number of control points.
  22. NURBSCurve(BasisFunctionInput<Real> const& input,
  23. Vector<N, Real> const* controls, Real const* weights)
  24. :
  25. ParametricCurve<N, Real>((Real)0, (Real)1),
  26. mBasisFunction(input)
  27. {
  28. // The mBasisFunction stores the domain but so does
  29. // ParametricCurve.
  30. this->mTime.front() = mBasisFunction.GetMinDomain();
  31. this->mTime.back() = mBasisFunction.GetMaxDomain();
  32. // The replication of control points for periodic splines is
  33. // avoided by wrapping the i-loop index in Evaluate.
  34. mControls.resize(input.numControls);
  35. mWeights.resize(input.numControls);
  36. if (controls)
  37. {
  38. std::copy(controls, controls + input.numControls, mControls.begin());
  39. }
  40. else
  41. {
  42. Vector<N, Real> zero{ (Real)0 };
  43. std::fill(mControls.begin(), mControls.end(), zero);
  44. }
  45. if (weights)
  46. {
  47. std::copy(weights, weights + input.numControls, mWeights.begin());
  48. }
  49. else
  50. {
  51. std::fill(mWeights.begin(), mWeights.end(), (Real)0);
  52. }
  53. this->mConstructed = true;
  54. }
  55. // Member access.
  56. inline BasisFunction<Real> const& GetBasisFunction() const
  57. {
  58. return mBasisFunction;
  59. }
  60. inline int GetNumControls() const
  61. {
  62. return static_cast<int>(mControls.size());
  63. }
  64. inline Vector<N, Real> const* GetControls() const
  65. {
  66. return mControls.data();
  67. }
  68. inline Vector<N, Real>* GetControls()
  69. {
  70. return mControls.data();
  71. }
  72. inline Real const* GetWeights() const
  73. {
  74. return mWeights.data();
  75. }
  76. inline Real* GetWeights()
  77. {
  78. return mWeights.data();
  79. }
  80. void SetControl(int i, Vector<N, Real> const& control)
  81. {
  82. if (0 <= i && i < GetNumControls())
  83. {
  84. mControls[i] = control;
  85. }
  86. }
  87. Vector<N, Real> const& GetControl(int i) const
  88. {
  89. if (0 <= i && i < GetNumControls())
  90. {
  91. return mControls[i];
  92. }
  93. else
  94. {
  95. // Invalid index, return something.
  96. return mControls[0];
  97. }
  98. }
  99. void SetWeight(int i, Real weight)
  100. {
  101. if (0 <= i && i < GetNumControls())
  102. {
  103. mWeights[i] = weight;
  104. }
  105. }
  106. Real const& GetWeight(int i) const
  107. {
  108. if (0 <= i && i < GetNumControls())
  109. {
  110. return mWeights[i];
  111. }
  112. else
  113. {
  114. // Invalid index, return something.
  115. return mWeights[0];
  116. }
  117. }
  118. // Evaluation of the curve. The function supports derivative
  119. // calculation through order 3; that is, order <= 3 is required. If
  120. // you want/ only the position, pass in order of 0. If you want the
  121. // position and first derivative, pass in order of 1, and so on. The
  122. // output array 'jet' must have enough storage to support the maximum
  123. // order. The values are ordered as: position, first derivative,
  124. // second derivative, third derivative.
  125. virtual void Evaluate(Real t, unsigned int order, Vector<N, Real>* jet) const override
  126. {
  127. unsigned int const supOrder = ParametricCurve<N, Real>::SUP_ORDER;
  128. if (!this->mConstructed || order >= supOrder)
  129. {
  130. // Return a zero-valued jet for invalid state.
  131. for (unsigned int i = 0; i < supOrder; ++i)
  132. {
  133. jet[i].MakeZero();
  134. }
  135. return;
  136. }
  137. int imin, imax;
  138. mBasisFunction.Evaluate(t, order, imin, imax);
  139. // Compute position.
  140. Vector<N, Real> X;
  141. Real w;
  142. Compute(0, imin, imax, X, w);
  143. Real invW = (Real)1 / w;
  144. jet[0] = invW * X;
  145. if (order >= 1)
  146. {
  147. // Compute first derivative.
  148. Vector<N, Real> XDer1;
  149. Real wDer1;
  150. Compute(1, imin, imax, XDer1, wDer1);
  151. jet[1] = invW * (XDer1 - wDer1 * jet[0]);
  152. if (order >= 2)
  153. {
  154. // Compute second derivative.
  155. Vector<N, Real> XDer2;
  156. Real wDer2;
  157. Compute(2, imin, imax, XDer2, wDer2);
  158. jet[2] = invW * (XDer2 - (Real)2 * wDer1 * jet[1] - wDer2 * jet[0]);
  159. if (order == 3)
  160. {
  161. // Compute third derivative.
  162. Vector<N, Real> XDer3;
  163. Real wDer3;
  164. Compute(3, imin, imax, XDer3, wDer3);
  165. jet[3] = invW * (XDer3 - (Real)3 * wDer1 * jet[2] -
  166. (Real)3 * wDer2 * jet[1] - wDer3 * jet[0]);
  167. }
  168. }
  169. }
  170. }
  171. protected:
  172. // Support for Evaluate(...).
  173. void Compute(unsigned int order, int imin, int imax, Vector<N, Real>& X, Real& w) const
  174. {
  175. // The j-index introduces a tiny amount of overhead in order to
  176. // handle both aperiodic and periodic splines. For aperiodic
  177. // splines, j = i always.
  178. int numControls = GetNumControls();
  179. X.MakeZero();
  180. w = (Real)0;
  181. for (int i = imin; i <= imax; ++i)
  182. {
  183. int j = (i >= numControls ? i - numControls : i);
  184. Real tmp = mBasisFunction.GetValue(order, i) * mWeights[j];
  185. X += tmp * mControls[j];
  186. w += tmp;
  187. }
  188. }
  189. BasisFunction<Real> mBasisFunction;
  190. std::vector<Vector<N, Real>> mControls;
  191. std::vector<Real> mWeights;
  192. };
  193. }