NURBSSurface.h 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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.12.28
  7. #pragma once
  8. #include <Mathematics/BasisFunction.h>
  9. #include <Mathematics/ParametricSurface.h>
  10. #include <Mathematics/Vector.h>
  11. namespace WwiseGTE
  12. {
  13. template <int N, typename Real>
  14. class NURBSSurface : public ParametricSurface<N, Real>
  15. {
  16. public:
  17. // Construction. If the input controls is non-null, a copy is made of
  18. // the controls. To defer setting the control points or weights, pass
  19. // null pointers and later access the control points or weights via
  20. // GetControls(), GetWeights(), SetControl(), or SetWeight() member
  21. // functions. The 'controls' and 'weights' must be stored in
  22. // row-major order, attribute[i0 + numControls0*i1]. As a 2D array,
  23. // this corresponds to attribute2D[i1][i0].
  24. NURBSSurface(BasisFunctionInput<Real> const& input0,
  25. BasisFunctionInput<Real> const& input1,
  26. Vector<N, Real> const* controls, Real const* weights)
  27. :
  28. ParametricSurface<N, Real>((Real)0, (Real)1, (Real)0, (Real)1, true)
  29. {
  30. BasisFunctionInput<Real> const* input[2] = { &input0, &input1 };
  31. for (int i = 0; i < 2; ++i)
  32. {
  33. mNumControls[i] = input[i]->numControls;
  34. mBasisFunction[i].Create(*input[i]);
  35. }
  36. // The mBasisFunction stores the domain but so does
  37. // ParametricSurface.
  38. this->mUMin = mBasisFunction[0].GetMinDomain();
  39. this->mUMax = mBasisFunction[0].GetMaxDomain();
  40. this->mVMin = mBasisFunction[1].GetMinDomain();
  41. this->mVMax = mBasisFunction[1].GetMaxDomain();
  42. // The replication of control points for periodic splines is
  43. // avoided by wrapping the i-loop index in Evaluate.
  44. int numControls = mNumControls[0] * mNumControls[1];
  45. mControls.resize(numControls);
  46. mWeights.resize(numControls);
  47. if (controls)
  48. {
  49. std::copy(controls, controls + numControls, mControls.begin());
  50. }
  51. else
  52. {
  53. Vector<N, Real> zero{ (Real)0 };
  54. std::fill(mControls.begin(), mControls.end(), zero);
  55. }
  56. if (weights)
  57. {
  58. std::copy(weights, weights + numControls, mWeights.begin());
  59. }
  60. else
  61. {
  62. std::fill(mWeights.begin(), mWeights.end(), (Real)0);
  63. }
  64. this->mConstructed = true;
  65. }
  66. // Member access. The index 'dim' must be in {0,1}.
  67. inline BasisFunction<Real> const& GetBasisFunction(int dim) const
  68. {
  69. return mBasisFunction[dim];
  70. }
  71. inline int GetNumControls(int dim) const
  72. {
  73. return mNumControls[dim];
  74. }
  75. inline Vector<N, Real> const* GetControls() const
  76. {
  77. return mControls.data();
  78. }
  79. inline Vector<N, Real>* GetControls()
  80. {
  81. return mControls.data();
  82. }
  83. inline Real const* GetWeights() const
  84. {
  85. return mWeights.data();
  86. }
  87. inline Real* GetWeights()
  88. {
  89. return mWeights.data();
  90. }
  91. void SetControl(int i0, int i1, Vector<N, Real> const& control)
  92. {
  93. if (0 <= i0 && i0 < GetNumControls(0) && 0 <= i1 && i1 < GetNumControls(1))
  94. {
  95. mControls[i0 + mNumControls[0] * i1] = control;
  96. }
  97. }
  98. Vector<N, Real> const& GetControl(int i0, int i1) const
  99. {
  100. if (0 <= i0 && i0 < GetNumControls(0) && 0 <= i1 && i1 < GetNumControls(1))
  101. {
  102. return mControls[i0 + mNumControls[0] * i1];
  103. }
  104. else
  105. {
  106. return mControls[0];
  107. }
  108. }
  109. void SetWeight(int i0, int i1, Real weight)
  110. {
  111. if (0 <= i0 && i0 < GetNumControls(0) && 0 <= i1 && i1 < GetNumControls(1))
  112. {
  113. mWeights[i0 + mNumControls[0] * i1] = weight;
  114. }
  115. }
  116. Real const& GetWeight(int i0, int i1) const
  117. {
  118. if (0 <= i0 && i0 < GetNumControls(0) && 0 <= i1 && i1 < GetNumControls(1))
  119. {
  120. return mWeights[i0 + mNumControls[0] * i1];
  121. }
  122. else
  123. {
  124. return mWeights[0];
  125. }
  126. }
  127. // Evaluation of the surface. The function supports derivative
  128. // calculation through order 2; that is, order <= 2 is required. If
  129. // you want only the position, pass in order of 0. If you want the
  130. // position and first-order derivatives, pass in order of 1, and so
  131. // on. The output array 'jet' must have enough storage to support the
  132. // maximum order. The values are ordered as: position X; first-order
  133. // derivatives dX/du, dX/dv; second-order derivatives d2X/du2,
  134. // d2X/dudv, d2X/dv2.
  135. virtual void Evaluate(Real u, Real v, unsigned int order, Vector<N, Real>* jet) const override
  136. {
  137. unsigned int const supOrder = ParametricSurface<N, Real>::SUP_ORDER;
  138. if (!this->mConstructed || order >= supOrder)
  139. {
  140. // Return a zero-valued jet for invalid state.
  141. for (unsigned int i = 0; i < supOrder; ++i)
  142. {
  143. jet[i].MakeZero();
  144. }
  145. return;
  146. }
  147. int iumin, iumax, ivmin, ivmax;
  148. mBasisFunction[0].Evaluate(u, order, iumin, iumax);
  149. mBasisFunction[1].Evaluate(v, order, ivmin, ivmax);
  150. // Compute position.
  151. Vector<N, Real> X;
  152. Real w;
  153. Compute(0, 0, iumin, iumax, ivmin, ivmax, X, w);
  154. Real invW = (Real)1 / w;
  155. jet[0] = invW * X;
  156. if (order >= 1)
  157. {
  158. // Compute first-order derivatives.
  159. Vector<N, Real> XDerU;
  160. Real wDerU;
  161. Compute(1, 0, iumin, iumax, ivmin, ivmax, XDerU, wDerU);
  162. jet[1] = invW * (XDerU - wDerU * jet[0]);
  163. Vector<N, Real> XDerV;
  164. Real wDerV;
  165. Compute(0, 1, iumin, iumax, ivmin, ivmax, XDerV, wDerV);
  166. jet[2] = invW * (XDerV - wDerV * jet[0]);
  167. if (order >= 2)
  168. {
  169. // Compute second-order derivatives.
  170. Vector<N, Real> XDerUU;
  171. Real wDerUU;
  172. Compute(2, 0, iumin, iumax, ivmin, ivmax, XDerUU, wDerUU);
  173. jet[3] = invW * (XDerUU - (Real)2 * wDerU * jet[1] - wDerUU * jet[0]);
  174. Vector<N, Real> XDerUV;
  175. Real wDerUV;
  176. Compute(1, 1, iumin, iumax, ivmin, ivmax, XDerUV, wDerUV);
  177. jet[4] = invW * (XDerUV - wDerU * jet[2] - wDerV * jet[1]
  178. - wDerUV * jet[0]);
  179. Vector<N, Real> XDerVV;
  180. Real wDerVV;
  181. Compute(0, 2, iumin, iumax, ivmin, ivmax, XDerVV, wDerVV);
  182. jet[5] = invW * (XDerVV - (Real)2 * wDerV * jet[2] - wDerVV * jet[0]);
  183. }
  184. }
  185. }
  186. protected:
  187. // Support for Evaluate(...).
  188. void Compute(unsigned int uOrder, unsigned int vOrder, int iumin,
  189. int iumax, int ivmin, int ivmax, Vector<N, Real>& X, Real& w) const
  190. {
  191. // The j*-indices introduce a tiny amount of overhead in order to handle
  192. // both aperiodic and periodic splines. For aperiodic splines, j* = i*
  193. // always.
  194. int const numControls0 = mNumControls[0];
  195. int const numControls1 = mNumControls[1];
  196. X.MakeZero();
  197. w = (Real)0;
  198. for (int iv = ivmin; iv <= ivmax; ++iv)
  199. {
  200. Real tmpv = mBasisFunction[1].GetValue(vOrder, iv);
  201. int jv = (iv >= numControls1 ? iv - numControls1 : iv);
  202. for (int iu = iumin; iu <= iumax; ++iu)
  203. {
  204. Real tmpu = mBasisFunction[0].GetValue(uOrder, iu);
  205. int ju = (iu >= numControls0 ? iu - numControls0 : iu);
  206. int index = ju + numControls0 * jv;
  207. Real tmp = tmpu * tmpv * mWeights[index];
  208. X += tmp * mControls[index];
  209. w += tmp;
  210. }
  211. }
  212. }
  213. std::array<BasisFunction<Real>, 2> mBasisFunction;
  214. std::array<int, 2> mNumControls;
  215. std::vector<Vector<N, Real>> mControls;
  216. std::vector<Real> mWeights;
  217. };
  218. }