BSplineVolume.h 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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/Vector.h>
  10. namespace WwiseGTE
  11. {
  12. template <int N, typename Real>
  13. class BSplineVolume
  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, pass a null
  18. // pointer and later access the control points via GetControls() or
  19. // SetControl() member functions. The input 'controls' must be stored
  20. // in lexicographical order,
  21. // control[i0+numControls0*(i1+numControls1*i2)]. As a 3D array, this
  22. // corresponds to control3D[i2][i1][i0].
  23. BSplineVolume(BasisFunctionInput<Real> const input[3], Vector<N, Real> const* controls)
  24. :
  25. mConstructed(false)
  26. {
  27. for (int i = 0; i < 3; ++i)
  28. {
  29. mNumControls[i] = input[i].numControls;
  30. mBasisFunction[i].Create(input[i]);
  31. }
  32. // The replication of control points for periodic splines is
  33. // avoided by wrapping the i-loop index in Evaluate.
  34. int numControls = mNumControls[0] * mNumControls[1] * mNumControls[2];
  35. mControls.resize(numControls);
  36. if (controls)
  37. {
  38. std::copy(controls, controls + numControls, mControls.begin());
  39. }
  40. else
  41. {
  42. Vector<N, Real> zero{ (Real)0 };
  43. std::fill(mControls.begin(), mControls.end(), zero);
  44. }
  45. mConstructed = true;
  46. }
  47. // To validate construction, create an object as shown:
  48. // BSplineVolume<N, Real> volume(parameters);
  49. // if (!volume) { <constructor failed, handle accordingly>; }
  50. inline operator bool() const
  51. {
  52. return mConstructed;
  53. }
  54. // Member access. The index 'dim' must be in {0,1,2}.
  55. inline BasisFunction<Real> const& GetBasisFunction(int dim) const
  56. {
  57. return mBasisFunction[dim];
  58. }
  59. inline Real GetMinDomain(int dim) const
  60. {
  61. return mBasisFunction[dim].GetMinDomain();
  62. }
  63. inline Real GetMaxDomain(int dim) const
  64. {
  65. return mBasisFunction[dim].GetMaxDomain();
  66. }
  67. inline int GetNumControls(int dim) const
  68. {
  69. return mNumControls[dim];
  70. }
  71. inline Vector<N, Real> const* GetControls() const
  72. {
  73. return mControls.data();
  74. }
  75. inline Vector<N, Real>* GetControls()
  76. {
  77. return mControls.data();
  78. }
  79. void SetControl(int i0, int i1, int i2, Vector<N, Real> const& control)
  80. {
  81. if (0 <= i0 && i0 < GetNumControls(0)
  82. && 0 <= i1 && i1 < GetNumControls(1)
  83. && 0 <= i2 && i2 < GetNumControls(2))
  84. {
  85. mControls[i0 + mNumControls[0] * (i1 + mNumControls[1] * i2)] = control;
  86. }
  87. }
  88. Vector<N, Real> const& GetControl(int i0, int i1, int i2) const
  89. {
  90. if (0 <= i0 && i0 < GetNumControls(0)
  91. && 0 <= i1 && i1 < GetNumControls(1)
  92. && 0 <= i2 && i2 < GetNumControls(2))
  93. {
  94. return mControls[i0 + mNumControls[0] * (i1 + mNumControls[1] * i2)];
  95. }
  96. else
  97. {
  98. return mControls[0];
  99. }
  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. // Return a zero-valued jet for invalid state.
  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. jet[0] = Compute(0, 0, 0, iumin, iumax, ivmin, ivmax, iwmin, iwmax);
  128. if (order >= 1)
  129. {
  130. // Compute first-order derivatives.
  131. jet[1] = Compute(1, 0, 0, iumin, iumax, ivmin, ivmax, iwmin, iwmax);
  132. jet[2] = Compute(0, 1, 0, iumin, iumax, ivmin, ivmax, iwmin, iwmax);
  133. jet[3] = Compute(0, 0, 1, iumin, iumax, ivmin, ivmax, iwmin, iwmax);
  134. if (order >= 2)
  135. {
  136. // Compute second-order derivatives.
  137. jet[4] = Compute(2, 0, 0, iumin, iumax, ivmin, ivmax, iwmin, iwmax);
  138. jet[5] = Compute(0, 2, 0, iumin, iumax, ivmin, ivmax, iwmin, iwmax);
  139. jet[6] = Compute(0, 0, 2, iumin, iumax, ivmin, ivmax, iwmin, iwmax);
  140. jet[7] = Compute(1, 1, 0, iumin, iumax, ivmin, ivmax, iwmin, iwmax);
  141. jet[8] = Compute(1, 0, 1, iumin, iumax, ivmin, ivmax, iwmin, iwmax);
  142. jet[9] = Compute(0, 1, 1, iumin, iumax, ivmin, ivmax, iwmin, iwmax);
  143. }
  144. }
  145. }
  146. private:
  147. // Support for Evaluate(...).
  148. Vector<N, Real> Compute(unsigned int uOrder, unsigned int vOrder,
  149. unsigned int wOrder, int iumin, int iumax, int ivmin, int ivmax,
  150. int iwmin, int iwmax) const
  151. {
  152. // The j*-indices introduce a tiny amount of overhead in order to
  153. // handle both aperiodic and periodic splines. For aperiodic
  154. // splines, j* = i* always.
  155. int const numControls0 = mNumControls[0];
  156. int const numControls1 = mNumControls[1];
  157. int const numControls2 = mNumControls[2];
  158. Vector<N, Real> result;
  159. result.MakeZero();
  160. for (int iw = iwmin; iw <= iwmax; ++iw)
  161. {
  162. Real tmpw = mBasisFunction[2].GetValue(wOrder, iw);
  163. int jw = (iw >= numControls2 ? iw - numControls2 : iw);
  164. for (int iv = ivmin; iv <= ivmax; ++iv)
  165. {
  166. Real tmpv = mBasisFunction[1].GetValue(vOrder, iv);
  167. Real tmpvw = tmpv * tmpw;
  168. int jv = (iv >= numControls1 ? iv - numControls1 : iv);
  169. for (int iu = iumin; iu <= iumax; ++iu)
  170. {
  171. Real tmpu = mBasisFunction[0].GetValue(uOrder, iu);
  172. int ju = (iu >= numControls0 ? iu - numControls0 : iu);
  173. result += (tmpu * tmpvw) *
  174. mControls[ju + numControls0 * (jv + numControls1 * jw)];
  175. }
  176. }
  177. }
  178. return result;
  179. }
  180. std::array<BasisFunction<Real>, 3> mBasisFunction;
  181. std::array<int, 3> mNumControls;
  182. std::vector<Vector<N, Real>> mControls;
  183. bool mConstructed;
  184. };
  185. }