NURBSVolume.h 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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/Vector.h>
  10. namespace WwiseGTE
  11. {
  12. template <int N, typename Real>
  13. class NURBSVolume
  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 'controls' and 'weights' must be stored in
  21. // lexicographical order,
  22. // attribute[i0 + numControls0 * (i1 + numControls1 * i2)]
  23. // As a 3D array, this corresponds to attribute3D[i2][i1][i0].
  24. NURBSVolume(BasisFunctionInput<Real> const& input0,
  25. BasisFunctionInput<Real> const& input1,
  26. BasisFunctionInput<Real> const& input2,
  27. Vector<N, Real> const* controls, Real const* weights)
  28. :
  29. mConstructed(false)
  30. {
  31. BasisFunctionInput<Real> const* input[3] = { &input0, &input1, &input2 };
  32. for (int i = 0; i < 3; ++i)
  33. {
  34. mNumControls[i] = input[i]->numControls;
  35. mBasisFunction[i].Create(*input[i]);
  36. }
  37. // The replication of control points for periodic splines is
  38. // avoided by wrapping the i-loop index in Evaluate.
  39. int numControls = mNumControls[0] * mNumControls[1] * mNumControls[2];
  40. mControls.resize(numControls);
  41. mWeights.resize(numControls);
  42. if (controls)
  43. {
  44. std::copy(controls, controls + numControls, mControls.begin());
  45. }
  46. else
  47. {
  48. Vector<N, Real> zero{ (Real)0 };
  49. std::fill(mControls.begin(), mControls.end(), zero);
  50. }
  51. if (weights)
  52. {
  53. std::copy(weights, weights + numControls, mWeights.begin());
  54. }
  55. else
  56. {
  57. std::fill(mWeights.begin(), mWeights.end(), (Real)0);
  58. }
  59. mConstructed = true;
  60. }
  61. // To validate construction, create an object as shown:
  62. // NURBSVolume<N, Real> volume(parameters);
  63. // if (!volume) { <constructor failed, handle accordingly>; }
  64. inline operator bool() const
  65. {
  66. return mConstructed;
  67. }
  68. // Member access. The index 'dim' must be in {0,1,2}.
  69. inline BasisFunction<Real> const& GetBasisFunction(int dim) const
  70. {
  71. return mBasisFunction[dim];
  72. }
  73. inline Real GetMinDomain(int dim) const
  74. {
  75. return mBasisFunction[dim].GetMinDomain();
  76. }
  77. inline Real GetMaxDomain(int dim) const
  78. {
  79. return mBasisFunction[dim].GetMaxDomain();
  80. }
  81. inline int GetNumControls(int dim) const
  82. {
  83. return mNumControls[dim];
  84. }
  85. inline Vector<N, Real> const* GetControls() const
  86. {
  87. return mControls.data();
  88. }
  89. inline Vector<N, Real>* GetControls()
  90. {
  91. return mControls.data();
  92. }
  93. inline Real const* GetWeights() const
  94. {
  95. return mWeights.data();
  96. }
  97. inline Real* GetWeights()
  98. {
  99. return mWeights.data();
  100. }
  101. // Evaluation of the volume. The function supports derivative
  102. // calculation through order 2; that is, order <= 2 is required. If
  103. // you want only the position, pass in order of 0. If you want the
  104. // position and first-order derivatives, pass in order of 1, and so
  105. // on. The output array 'jet' muist have enough storage to support
  106. // the maximum order. The values are ordered as: position X;
  107. // first-order derivatives dX/du, dX/dv, dX/dw; second-order
  108. // derivatives d2X/du2, d2X/dv2, d2X/dw2, d2X/dudv, d2X/dudw,
  109. // d2X/dvdw.
  110. enum { SUP_ORDER = 10 };
  111. void Evaluate(Real u, Real v, Real w, unsigned int order, Vector<N, Real>* jet) const
  112. {
  113. if (!mConstructed || order >= SUP_ORDER)
  114. {
  115. // Errors were already generated during construction.
  116. for (unsigned int i = 0; i < SUP_ORDER; ++i)
  117. {
  118. jet[i].MakeZero();
  119. }
  120. return;
  121. }
  122. int iumin, iumax, ivmin, ivmax, iwmin, iwmax;
  123. mBasisFunction[0].Evaluate(u, order, iumin, iumax);
  124. mBasisFunction[1].Evaluate(v, order, ivmin, ivmax);
  125. mBasisFunction[2].Evaluate(w, order, iwmin, iwmax);
  126. // Compute position.
  127. Vector<N, Real> X;
  128. Real h;
  129. Compute(0, 0, 0, iumin, iumax, ivmin, ivmax, iwmin, iwmax, X, h);
  130. Real invH = (Real)1 / h;
  131. jet[0] = invH * X;
  132. if (order >= 1)
  133. {
  134. // Compute first-order derivatives.
  135. Vector<N, Real> XDerU;
  136. Real hDerU;
  137. Compute(1, 0, 0, iumin, iumax, ivmin, ivmax, iwmin, iwmax, XDerU, hDerU);
  138. jet[1] = invH * (XDerU - hDerU * jet[0]);
  139. Vector<N, Real> XDerV;
  140. Real hDerV;
  141. Compute(0, 1, 0, iumin, iumax, ivmin, ivmax, iwmin, iwmax, XDerV, hDerV);
  142. jet[2] = invH * (XDerV - hDerV * jet[0]);
  143. Vector<N, Real> XDerW;
  144. Real hDerW;
  145. Compute(0, 0, 1, iumin, iumax, ivmin, ivmax, iwmin, iwmax, XDerW, hDerW);
  146. jet[3] = invH * (XDerW - hDerW * jet[0]);
  147. if (order >= 2)
  148. {
  149. // Compute second-order derivatives.
  150. Vector<N, Real> XDerUU;
  151. Real hDerUU;
  152. Compute(2, 0, 0, iumin, iumax, ivmin, ivmax, iwmin, iwmax, XDerUU, hDerUU);
  153. jet[4] = invH * (XDerUU - (Real)2 * hDerU * jet[1] - hDerUU * jet[0]);
  154. Vector<N, Real> XDerVV;
  155. Real hDerVV;
  156. Compute(0, 2, 0, iumin, iumax, ivmin, ivmax, iwmin, iwmax, XDerVV, hDerVV);
  157. jet[5] = invH * (XDerVV - (Real)2 * hDerV * jet[2] - hDerVV * jet[0]);
  158. Vector<N, Real> XDerWW;
  159. Real hDerWW;
  160. Compute(0, 0, 2, iumin, iumax, ivmin, ivmax, iwmin, iwmax, XDerWW, hDerWW);
  161. jet[6] = invH * (XDerWW - (Real)2 * hDerW * jet[3] - hDerWW * jet[0]);
  162. Vector<N, Real> XDerUV;
  163. Real hDerUV;
  164. Compute(1, 1, 0, iumin, iumax, ivmin, ivmax, iwmin, iwmax, XDerUV, hDerUV);
  165. jet[7] = invH * (XDerUV - hDerU * jet[2] - hDerV * jet[1] - hDerUV * jet[0]);
  166. Vector<N, Real> XDerUW;
  167. Real hDerUW;
  168. Compute(1, 0, 1, iumin, iumax, ivmin, ivmax, iwmin, iwmax, XDerUW, hDerUW);
  169. jet[8] = invH * (XDerUW - hDerU * jet[3] - hDerW * jet[1] - hDerUW * jet[0]);
  170. Vector<N, Real> XDerVW;
  171. Real hDerVW;
  172. Compute(0, 1, 1, iumin, iumax, ivmin, ivmax, iwmin, iwmax, XDerVW, hDerVW);
  173. jet[9] = invH * (XDerVW - hDerV * jet[3] - hDerW * jet[2] - hDerVW * jet[0]);
  174. }
  175. }
  176. }
  177. private:
  178. // Support for Evaluate(...).
  179. void Compute(unsigned int uOrder, unsigned int vOrder,
  180. unsigned int wOrder, int iumin, int iumax, int ivmin, int ivmax,
  181. int iwmin, int iwmax, Vector<N, Real>& X, Real& h) const
  182. {
  183. // The j*-indices introduce a tiny amount of overhead in order to
  184. // handle both aperiodic and periodic splines. For aperiodic
  185. // splines, j* = i* always.
  186. int const numControls0 = mNumControls[0];
  187. int const numControls1 = mNumControls[1];
  188. int const numControls2 = mNumControls[2];
  189. X.MakeZero();
  190. h = (Real)0;
  191. for (int iw = iwmin; iw <= iwmax; ++iw)
  192. {
  193. Real tmpw = mBasisFunction[2].GetValue(wOrder, iw);
  194. int jw = (iw >= numControls2 ? iw - numControls2 : iw);
  195. for (int iv = ivmin; iv <= ivmax; ++iv)
  196. {
  197. Real tmpv = mBasisFunction[1].GetValue(vOrder, iv);
  198. Real tmpvw = tmpv * tmpw;
  199. int jv = (iv >= numControls1 ? iv - numControls1 : iv);
  200. for (int iu = iumin; iu <= iumax; ++iu)
  201. {
  202. Real tmpu = mBasisFunction[0].GetValue(uOrder, iu);
  203. int ju = (iu >= numControls0 ? iu - numControls0 : iu);
  204. int index = ju + numControls0 * (jv + numControls1 * jw);
  205. Real tmp = (tmpu * tmpvw) * mWeights[index];
  206. X += tmp * mControls[index];
  207. h += tmp;
  208. }
  209. }
  210. }
  211. }
  212. std::array<BasisFunction<Real>, 3> mBasisFunction;
  213. std::array<int, 3> mNumControls;
  214. std::vector<Vector<N, Real>> mControls;
  215. std::vector<Real> mWeights;
  216. bool mConstructed;
  217. };
  218. }