MassSpringSurface.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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 MassSpringSurface : public ParticleSystem<N, Real>
  13. {
  14. public:
  15. // Construction and destruction. This class represents an RxC array
  16. // of masses lying on a surface and connected by an array of springs.
  17. // The masses are indexed by mass[r][c] for 0 <= r < R and 0 <= c < C.
  18. // The mass at interior position X[r][c] is connected by springs to
  19. // the masses at positions X[r-1][c], X[r+1][c], X[r][c-1], and
  20. // X[r][c+1]. Boundary masses have springs connecting them to the
  21. // obvious neighbors ("edge" mass has 3 neighbors, "corner" mass has
  22. // 2 neighbors). The masses are arranged in row-major order:
  23. // position[c+C*r] = X[r][c] for 0 <= r < R and 0 <= c < C. The
  24. // other arrays are stored similarly.
  25. virtual ~MassSpringSurface() = default;
  26. MassSpringSurface(int numRows, int numCols, Real step)
  27. :
  28. ParticleSystem<N, Real>(numRows* numCols, step),
  29. mNumRows(numRows),
  30. mNumCols(numCols),
  31. mConstantR(numRows* numCols),
  32. mLengthR(numRows* numCols),
  33. mConstantC(numRows* numCols),
  34. mLengthC(numRows* numCols)
  35. {
  36. std::fill(mConstantR.begin(), mConstantR.end(), (Real)0);
  37. std::fill(mLengthR.begin(), mLengthR.end(), (Real)0);
  38. std::fill(mConstantC.begin(), mConstantC.end(), (Real)0);
  39. std::fill(mLengthC.begin(), mLengthC.end(), (Real)0);
  40. }
  41. // Member access.
  42. inline int GetNumRows() const
  43. {
  44. return mNumRows;
  45. }
  46. inline int GetNumCols() const
  47. {
  48. return mNumCols;
  49. }
  50. inline void SetMass(int r, int c, Real mass)
  51. {
  52. ParticleSystem<N, Real>::SetMass(GetIndex(r, c), mass);
  53. }
  54. inline void SetPosition(int r, int c, Vector<N, Real> const& position)
  55. {
  56. ParticleSystem<N, Real>::SetPosition(GetIndex(r, c), position);
  57. }
  58. inline void SetVelocity(int r, int c, Vector<N, Real> const& velocity)
  59. {
  60. ParticleSystem<N, Real>::SetVelocity(GetIndex(r, c), velocity);
  61. }
  62. inline Real const& GetMass(int r, int c) const
  63. {
  64. return ParticleSystem<N, Real>::GetMass(GetIndex(r, c));
  65. }
  66. inline Vector<N, Real> const& GetPosition(int r, int c) const
  67. {
  68. return ParticleSystem<N, Real>::GetPosition(GetIndex(r, c));
  69. }
  70. inline Vector<N, Real> const& GetVelocity(int r, int c) const
  71. {
  72. return ParticleSystem<N, Real>::GetVelocity(GetIndex(r, c));
  73. }
  74. // The interior mass at (r,c) has springs to the left, right, bottom,
  75. // and top. Edge masses have only three neighbors and corner masses
  76. // have only two neighbors. The mass at (r,c) provides access to the
  77. // springs connecting to locations (r,c+1) and (r+1,c). Edge and
  78. // corner masses provide access to only a subset of these. The caller
  79. // is responsible for ensuring the validity of the (r,c) inputs.
  80. // to (r+1,c)
  81. inline void SetConstantR(int r, int c, Real constant)
  82. {
  83. mConstantR[GetIndex(r, c)] = constant;
  84. }
  85. // to (r+1,c)
  86. inline void SetLengthR(int r, int c, Real length)
  87. {
  88. mLengthR[GetIndex(r, c)] = length;
  89. }
  90. // to (r,c+1)
  91. inline void SetConstantC(int r, int c, Real constant)
  92. {
  93. mConstantC[GetIndex(r, c)] = constant;
  94. }
  95. // to (r,c+1)
  96. inline void SetLengthC(int r, int c, Real length)
  97. {
  98. mLengthC[GetIndex(r, c)] = length;
  99. }
  100. inline Real const& GetConstantR(int r, int c) const
  101. {
  102. return mConstantR[GetIndex(r, c)];
  103. }
  104. inline Real const& GetLengthR(int r, int c) const
  105. {
  106. return mLengthR[GetIndex(r, c)];
  107. }
  108. inline Real const& GetConstantC(int r, int c) const
  109. {
  110. return mConstantC[GetIndex(r, c)];
  111. }
  112. inline Real const& GetLengthC(int r, int c) const
  113. {
  114. return mLengthC[GetIndex(r, c)];
  115. }
  116. // The default external force is zero. Derive a class from this one
  117. // to provide nonzero external forces such as gravity, wind, friction,
  118. // and so on. This function is called by Acceleration(...) to compute
  119. // the impulse F/m generated by the external force F.
  120. virtual Vector<N, Real> ExternalAcceleration(int, Real,
  121. std::vector<Vector<N, Real>> const&,
  122. std::vector<Vector<N, Real>> const&)
  123. {
  124. return Vector<N, Real>::Zero();
  125. }
  126. protected:
  127. // Callback for acceleration (ODE solver uses x" = F/m) applied to
  128. // particle i. The positions and velocities are not necessarily
  129. // mPosition and mVelocity, because the ODE solver evaluates the
  130. // impulse function at intermediate positions.
  131. virtual Vector<N, Real> Acceleration(int i, Real time,
  132. std::vector<Vector<N, Real>> const& position,
  133. std::vector<Vector<N, Real>> const& velocity)
  134. {
  135. // Compute spring forces on position X[i]. The positions are not
  136. // necessarily mPosition, because the RK4 solver in ParticleSystem
  137. // evaluates the acceleration function at intermediate positions.
  138. // The edge and corner points of the surface of masses must be
  139. // handled separately, because each has fewer than four springs
  140. // attached to it.
  141. Vector<N, Real> acceleration = ExternalAcceleration(i, time, position, velocity);
  142. Vector<N, Real> diff, force;
  143. Real ratio;
  144. int r, c, prev, next;
  145. GetCoordinates(i, r, c);
  146. if (r > 0)
  147. {
  148. prev = i - mNumCols; // index to previous row-neighbor
  149. diff = position[prev] - position[i];
  150. ratio = GetLengthR(r - 1, c) / Length(diff);
  151. force = GetConstantR(r - 1, c) * ((Real)1 - ratio) * diff;
  152. acceleration += this->mInvMass[i] * force;
  153. }
  154. if (r < mNumRows - 1)
  155. {
  156. next = i + mNumCols; // index to next row-neighbor
  157. diff = position[next] - position[i];
  158. ratio = GetLengthR(r, c) / Length(diff);
  159. force = GetConstantR(r, c) * ((Real)1 - ratio) * diff;
  160. acceleration += this->mInvMass[i] * force;
  161. }
  162. if (c > 0)
  163. {
  164. prev = i - 1; // index to previous col-neighbor
  165. diff = position[prev] - position[i];
  166. ratio = GetLengthC(r, c - 1) / Length(diff);
  167. force = GetConstantC(r, c - 1) * ((Real)1 - ratio) * diff;
  168. acceleration += this->mInvMass[i] * force;
  169. }
  170. if (c < mNumCols - 1)
  171. {
  172. next = i + 1; // index to next col-neighbor
  173. diff = position[next] - position[i];
  174. ratio = GetLengthC(r, c) / Length(diff);
  175. force = GetConstantC(r, c) * ((Real)1 - ratio) * diff;
  176. acceleration += this->mInvMass[i] * force;
  177. }
  178. return acceleration;
  179. }
  180. inline int GetIndex(int r, int c) const
  181. {
  182. return c + mNumCols * r;
  183. }
  184. void GetCoordinates(int i, int& r, int& c) const
  185. {
  186. c = i % mNumCols;
  187. r = i / mNumCols;
  188. }
  189. int mNumRows, mNumCols;
  190. std::vector<Real> mConstantR, mLengthR;
  191. std::vector<Real> mConstantC, mLengthC;
  192. };
  193. }