MassSpringVolume.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  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/ParticleSystem.h>
  9. namespace WwiseGTE
  10. {
  11. template <int N, typename Real>
  12. class MassSpringVolume : public ParticleSystem<N, Real>
  13. {
  14. public:
  15. // Construction and destruction. This class represents an SxRxC array
  16. // of masses lying on in a volume and connected by an array of
  17. // springs. The masses are indexed by mass[s][r][c] for 0 <= s < S,
  18. // 0 <= r < R and 0 <= c < C. The mass at interior position X[s][r][c]
  19. // is connected by springs to the masses at positions X[s][r-1][c],
  20. // X[s][r+1][c], X[s][r][c-1], X[s][r][c+1], X[s-1][r][c] and
  21. // X[s+1][r][c]. Boundary masses have springs connecting them to the
  22. // obvious neighbors ("face" mass has 5 neighbors, "edge" mass has 4
  23. // neighbors, "corner" mass has 3 neighbors). The masses are arranged
  24. // in lexicographical order: position[c+C*(r+R*s)] = X[s][r][c] for
  25. // 0 <= s < S, 0 <= r < R, and 0 <= c < C. The other arrays are
  26. // stored similarly.
  27. virtual ~MassSpringVolume() = default;
  28. MassSpringVolume(int numSlices, int numRows, int numCols, Real step)
  29. :
  30. ParticleSystem<N, Real>(numSlices* numRows* numCols, step),
  31. mNumSlices(numSlices),
  32. mNumRows(numRows),
  33. mNumCols(numCols),
  34. mConstantS(numSlices* numRows* numCols),
  35. mLengthS(numSlices* numRows* numCols),
  36. mConstantR(numSlices* numRows* numCols),
  37. mLengthR(numSlices* numRows* numCols),
  38. mConstantC(numSlices* numRows* numCols),
  39. mLengthC(numSlices* numRows* numCols)
  40. {
  41. std::fill(mConstantS.begin(), mConstantS.end(), (Real)0);
  42. std::fill(mLengthS.begin(), mLengthS.end(), (Real)0);
  43. std::fill(mConstantR.begin(), mConstantR.end(), (Real)0);
  44. std::fill(mLengthR.begin(), mLengthR.end(), (Real)0);
  45. std::fill(mConstantC.begin(), mConstantC.end(), (Real)0);
  46. std::fill(mLengthC.begin(), mLengthC.end(), (Real)0);
  47. }
  48. // Member access.
  49. inline int GetNumSlices() const
  50. {
  51. return mNumSlices;
  52. }
  53. inline int GetNumRows() const
  54. {
  55. return mNumRows;
  56. }
  57. inline int GetNumCols() const
  58. {
  59. return mNumCols;
  60. }
  61. inline void SetMass(int s, int r, int c, Real mass)
  62. {
  63. ParticleSystem<N, Real>::SetMass(GetIndex(s, r, c), mass);
  64. }
  65. inline void SetPosition(int s, int r, int c, Vector<N, Real> const& position)
  66. {
  67. ParticleSystem<N, Real>::SetPosition(GetIndex(s, r, c), position);
  68. }
  69. inline void SetVelocity(int s, int r, int c, Vector<N, Real> const& velocity)
  70. {
  71. ParticleSystem<N, Real>::SetVelocity(GetIndex(s, r, c), velocity);
  72. }
  73. Real const& GetMass(int s, int r, int c) const
  74. {
  75. return ParticleSystem<N, Real>::GetMass(GetIndex(s, r, c));
  76. }
  77. inline Vector<N, Real> const& GetPosition(int s, int r, int c) const
  78. {
  79. return ParticleSystem<N, Real>::GetPosition(GetIndex(s, r, c));
  80. }
  81. inline Vector<N, Real> const& GetVelocity(int s, int r, int c) const
  82. {
  83. return ParticleSystem<N, Real>::GetVelocity(GetIndex(s, r, c));
  84. }
  85. // Each interior mass at (s,r,c) has 6 adjacent springs. Face masses
  86. // have only 5 neighbors, edge masses have only 4 neighbors, and corner
  87. // masses have only 3 neighbors. Each mass provides access to 3 adjacent
  88. // springs at (s,r,c+1), (s,r+1,c), and (s+1,r,c). The face, edge, and
  89. // corner masses provide access to only an appropriate subset of these.
  90. // The caller is responsible for ensuring the validity of the (s,r,c)
  91. // inputs.
  92. // to (s+1,r,c)
  93. inline void SetConstantS(int s, int r, int c, Real constant)
  94. {
  95. mConstantS[GetIndex(s, r, c)] = constant;
  96. }
  97. // to (s+1,r,c)
  98. inline void SetLengthS(int s, int r, int c, Real length)
  99. {
  100. mLengthS[GetIndex(s, r, c)] = length;
  101. }
  102. // to (s,r+1,c)
  103. inline void SetConstantR(int s, int r, int c, Real constant)
  104. {
  105. mConstantR[GetIndex(s, r, c)] = constant;
  106. }
  107. // to (s,r+1,c)
  108. inline void SetLengthR(int s, int r, int c, Real length)
  109. {
  110. mLengthR[GetIndex(s, r, c)] = length;
  111. }
  112. // to (s,r,c+1)
  113. inline void SetConstantC(int s, int r, int c, Real constant)
  114. {
  115. mConstantC[GetIndex(s, r, c)] = constant;
  116. }
  117. // spring to (s,r,c+1)
  118. inline void SetLengthC(int s, int r, int c, Real length)
  119. {
  120. mLengthC[GetIndex(s, r, c)] = length;
  121. }
  122. inline Real const& GetConstantS(int s, int r, int c) const
  123. {
  124. return mConstantS[GetIndex(s, r, c)];
  125. }
  126. inline Real const& GetLengthS(int s, int r, int c) const
  127. {
  128. return mLengthS[GetIndex(s, r, c)];
  129. }
  130. inline Real const& GetConstantR(int s, int r, int c) const
  131. {
  132. return mConstantR[GetIndex(s, r, c)];
  133. }
  134. inline Real const& GetLengthR(int s, int r, int c) const
  135. {
  136. return mLengthR[GetIndex(s, r, c)];
  137. }
  138. inline Real const& GetConstantC(int s, int r, int c) const
  139. {
  140. return mConstantC[GetIndex(s, r, c)];
  141. }
  142. inline Real const& GetLengthC(int s, int r, int c) const
  143. {
  144. return mLengthC[GetIndex(s, r, c)];
  145. }
  146. // The default external force is zero. Derive a class from this one
  147. // to provide nonzero external forces such as gravity, wind,
  148. // friction and so on. This function is called by Acceleration(...)
  149. // to compute the impulse F/m generated by the external force F.
  150. virtual Vector<N, Real> ExternalAcceleration(int, Real,
  151. std::vector<Vector<N, Real>> const&,
  152. std::vector<Vector<N, Real>> const&)
  153. {
  154. return Vector<N, Real>::Zero();
  155. }
  156. protected:
  157. // Callback for acceleration (ODE solver uses x" = F/m) applied to
  158. // particle i. The positions and velocities are not necessarily
  159. // mPosition and mVelocity, because the ODE solver evaluates the
  160. // impulse function at intermediate positions.
  161. virtual Vector<N, Real> Acceleration(int i, Real time,
  162. std::vector<Vector<N, Real>> const& position,
  163. std::vector<Vector<N, Real>> const& velocity)
  164. {
  165. // Compute spring forces on position X[i]. The positions are not
  166. // necessarily mPosition, because the RK4 solver in ParticleSystem
  167. // evaluates the acceleration function at intermediate positions.
  168. // The face, edge, and corner points of the volume of masses must
  169. // be handled separately, because each has fewer than eight
  170. // springs attached to it.
  171. Vector<N, Real> acceleration = ExternalAcceleration(i, time, position, velocity);
  172. Vector<N, Real> diff, force;
  173. Real ratio;
  174. int s, r, c, prev, next;
  175. GetCoordinates(i, s, r, c);
  176. if (s > 0)
  177. {
  178. prev = i - mNumRows * mNumCols; // index to previous s-neighbor
  179. diff = position[prev] - position[i];
  180. ratio = GetLengthS(s - 1, r, c) / Length(diff);
  181. force = GetConstantS(s - 1, r, c) * ((Real)1 - ratio) * diff;
  182. acceleration += this->mInvMass[i] * force;
  183. }
  184. if (s < mNumSlices - 1)
  185. {
  186. next = i + mNumRows * mNumCols; // index to next s-neighbor
  187. diff = position[next] - position[i];
  188. ratio = GetLengthS(s, r, c) / Length(diff);
  189. force = GetConstantS(s, r, c) * ((Real)1 - ratio) * diff;
  190. acceleration += this->mInvMass[i] * force;
  191. }
  192. if (r > 0)
  193. {
  194. prev = i - mNumCols; // index to previous r-neighbor
  195. diff = position[prev] - position[i];
  196. ratio = GetLengthR(s, r - 1, c) / Length(diff);
  197. force = GetConstantR(s, r - 1, c) * ((Real)1 - ratio) * diff;
  198. acceleration += this->mInvMass[i] * force;
  199. }
  200. if (r < mNumRows - 1)
  201. {
  202. next = i + mNumCols; // index to next r-neighbor
  203. diff = position[next] - position[i];
  204. ratio = GetLengthR(s, r, c) / Length(diff);
  205. force = GetConstantR(s, r, c) * ((Real)1 - ratio) * diff;
  206. acceleration += this->mInvMass[i] * force;
  207. }
  208. if (c > 0)
  209. {
  210. prev = i - 1; // index to previous c-neighbor
  211. diff = position[prev] - position[i];
  212. ratio = GetLengthC(s, r, c - 1) / Length(diff);
  213. force = GetConstantC(s, r, c - 1) * ((Real)1 - ratio) * diff;
  214. acceleration += this->mInvMass[i] * force;
  215. }
  216. if (c < mNumCols - 1)
  217. {
  218. next = i + 1; // index to next c-neighbor
  219. diff = position[next] - position[i];
  220. ratio = GetLengthC(s, r, c) / Length(diff);
  221. force = GetConstantC(s, r, c) * ((Real)1 - ratio) * diff;
  222. acceleration += this->mInvMass[i] * force;
  223. }
  224. return acceleration;
  225. }
  226. inline int GetIndex(int s, int r, int c) const
  227. {
  228. return c + mNumCols * (r + mNumRows * s);
  229. }
  230. void GetCoordinates(int i, int& s, int& r, int& c) const
  231. {
  232. c = i % mNumCols;
  233. i = (i - c) / mNumCols;
  234. r = i % mNumRows;
  235. s = i / mNumRows;
  236. }
  237. int mNumSlices, mNumRows, mNumCols;
  238. std::vector<Real> mConstantS, mLengthS;
  239. std::vector<Real> mConstantR, mLengthR;
  240. std::vector<Real> mConstantC, mLengthC;
  241. };
  242. }