catmullRom.h 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #ifndef _CATMULLROM_H_
  23. #define _CATMULLROM_H_
  24. /// The shared base class used by the catmull rom
  25. /// interpolation template class.
  26. /// @see CatmullRom
  27. class CatmullRomBase
  28. {
  29. protected:
  30. CatmullRomBase();
  31. virtual ~CatmullRomBase() {}
  32. public:
  33. /// Clean out all the data.
  34. virtual void clear();
  35. /// Find length of curve between parameters t1 and t2.
  36. F32 arcLength( F32 t1, F32 t2 );
  37. /// Get the total length of the curve.
  38. inline F32 getLength() { return mTotalLength; }
  39. /// Get the closest previous control point to time t.
  40. U32 getPrevNode( F32 t );
  41. /// Returns the time at idx (rather than at a F32 time)
  42. F32 getTime( U32 idx );
  43. /// Find length of curve segment between parameters u1 and u2.
  44. virtual F32 segmentArcLength( U32 i, F32 u1, F32 u2 ) = 0;
  45. protected:
  46. static const F32 smX[];
  47. static const F32 smC[];
  48. void _initialize( U32 count, const F32 *times = NULL );
  49. /// The time to arrive at each point.
  50. F32 *mTimes;
  51. /// the length of each curve segment.
  52. F32* mLengths;
  53. /// The total length of curve.
  54. F32 mTotalLength;
  55. /// The number of points and times.
  56. U32 mCount;
  57. };
  58. /// The catmull-rom template class for performing interpolation
  59. /// over an arbitraty type.
  60. template<typename TYPE>
  61. class CatmullRom : public CatmullRomBase
  62. {
  63. public:
  64. CatmullRom();
  65. virtual ~CatmullRom();
  66. /// Initialization.
  67. void initialize( U32 count, const TYPE *positions, const F32 *times = NULL );
  68. // evaluate position
  69. TYPE evaluate( F32 t );
  70. /// Evaluate derivative at parameter t.
  71. TYPE velocity( F32 t );
  72. // Evaluate second derivative at parameter t.
  73. TYPE acceleration( F32 t );
  74. // Returns the position at idx (rather than at a F32 time)
  75. TYPE getPosition( U32 idx );
  76. // CatmullRomBase
  77. void clear();
  78. F32 segmentArcLength( U32 i, F32 u1, F32 u2 );
  79. protected:
  80. /// The sample points.
  81. TYPE* mPositions;
  82. private:
  83. /// The copy constructors are disabled.
  84. CatmullRom( const CatmullRom &other );
  85. CatmullRom& operator=( const CatmullRom &other );
  86. };
  87. template<typename TYPE>
  88. inline CatmullRom<TYPE>::CatmullRom()
  89. : CatmullRomBase(),
  90. mPositions( NULL )
  91. {
  92. }
  93. template<typename TYPE>
  94. inline CatmullRom<TYPE>::~CatmullRom()
  95. {
  96. clear();
  97. }
  98. template<typename TYPE>
  99. inline void CatmullRom<TYPE>::clear()
  100. {
  101. delete [] mPositions;
  102. mPositions = NULL;
  103. CatmullRomBase::clear();
  104. }
  105. template<typename TYPE>
  106. inline void CatmullRom<TYPE>::initialize( U32 count, const TYPE *positions, const F32 *times )
  107. {
  108. AssertFatal( positions, "CatmullRom::initialize - Got null position!" );
  109. AssertFatal( count > 1, "CatmullRom::initialize - Must have more than 2 points!" );
  110. // Clean up any previous state.
  111. clear();
  112. // copy the points.
  113. mPositions = new TYPE[count];
  114. for ( U32 i = 0; i < count; ++i )
  115. mPositions[i] = positions[i];
  116. _initialize( count, times );
  117. }
  118. template<typename TYPE>
  119. inline TYPE CatmullRom<TYPE>::evaluate( F32 t )
  120. {
  121. AssertFatal( mCount >= 2, "CatmullRom::evaluate - Not initialized!" );
  122. // handle boundary conditions
  123. if ( t <= mTimes[0] )
  124. return mPositions[0];
  125. else if ( t >= mTimes[mCount-1] )
  126. return mPositions[mCount-1];
  127. // find segment and parameter
  128. U32 i; // segment #
  129. for ( i = 0; i < mCount-1; ++i )
  130. {
  131. if ( t <= mTimes[i+1] )
  132. {
  133. break;
  134. }
  135. }
  136. AssertFatal( i >= 0 && i < mCount, "CatmullRom::evaluate - Got bad index!" );
  137. F32 t0 = mTimes[i];
  138. F32 t1 = mTimes[i+1];
  139. F32 u = (t - t0)/(t1 - t0);
  140. S32 idx0, idx1, idx2, idx3;
  141. idx0 = i - 1;
  142. idx1 = i;
  143. idx2 = i + 1;
  144. idx3 = i + 2;
  145. if ( idx0 < 0 )
  146. idx0 = 0;
  147. if ( idx3 >= mCount )
  148. idx3 = mCount - 1;
  149. TYPE A = 3.0f*mPositions[idx1]
  150. - mPositions[idx0]
  151. - 3.0f*mPositions[idx2]
  152. + mPositions[idx3];
  153. TYPE B = 2.0f*mPositions[idx0]
  154. - 5.0f*mPositions[idx1]
  155. + 4.0f*mPositions[idx2]
  156. - mPositions[idx3];
  157. TYPE C = mPositions[idx2] - mPositions[idx0];
  158. return mPositions[i] + (0.5f*u)*(C + u*(B + u*A));
  159. }
  160. template<typename TYPE>
  161. inline TYPE CatmullRom<TYPE>::velocity( F32 t )
  162. {
  163. AssertFatal( mCount >= 2, "CatmullRom::velocity - Not initialized!" );
  164. // handle boundary conditions
  165. if ( t <= mTimes[0] )
  166. t = 0.0f;
  167. else if ( t > mTimes[mCount-1] )
  168. t = mTimes[mCount-1];
  169. // find segment and parameter
  170. U32 i;
  171. for ( i = 0; i < mCount-1; ++i )
  172. {
  173. if ( t <= mTimes[i+1] )
  174. {
  175. break;
  176. }
  177. }
  178. F32 t0 = mTimes[i];
  179. F32 t1 = mTimes[i+1];
  180. F32 u = (t - t0)/(t1 - t0);
  181. S32 idx0, idx1, idx2, idx3;
  182. idx0 = i - 1;
  183. idx1 = i;
  184. idx2 = i + 1;
  185. idx3 = i + 2;
  186. if ( idx0 < 0 )
  187. idx0 = 0;
  188. if ( idx3 >= mCount )
  189. idx3 = mCount - 1;
  190. TYPE A = 3.0f*mPositions[idx1]
  191. - mPositions[idx0]
  192. - 3.0f*mPositions[idx2]
  193. + mPositions[idx3];
  194. TYPE B = 2.0f*mPositions[idx0]
  195. - 5.0f*mPositions[idx1]
  196. + 4.0f*mPositions[idx2]
  197. - mPositions[idx3];
  198. TYPE C = mPositions[idx2] - mPositions[idx0];
  199. return 0.5f*C + u*(B + 1.5f*u*A);
  200. }
  201. template<typename TYPE>
  202. inline TYPE CatmullRom<TYPE>::acceleration( F32 t )
  203. {
  204. AssertFatal( mCount >= 2, "CatmullRom::acceleration - Not initialized!" );
  205. // handle boundary conditions
  206. if ( t <= mTimes[0] )
  207. t = 0.0f;
  208. else if ( t > mTimes[mCount-1] )
  209. t = mTimes[mCount-1];
  210. // find segment and parameter
  211. U32 i;
  212. for ( i = 0; i < mCount-1; ++i )
  213. {
  214. if ( t <= mTimes[i+1] )
  215. {
  216. break;
  217. }
  218. }
  219. F32 t0 = mTimes[i];
  220. F32 t1 = mTimes[i+1];
  221. F32 u = (t - t0)/(t1 - t0);
  222. S32 idx0, idx1, idx2, idx3;
  223. idx0 = i - 1;
  224. idx1 = i;
  225. idx2 = i + 1;
  226. idx3 = i + 2;
  227. if ( idx0 < 0 )
  228. idx0 = 0;
  229. if ( idx3 >= mCount )
  230. idx3 = mCount - 1;
  231. TYPE A = 3.0f*mPositions[idx1]
  232. - mPositions[idx0]
  233. - 3.0f*mPositions[idx2]
  234. + mPositions[idx3];
  235. TYPE B = 2.0f*mPositions[idx0]
  236. - 5.0f*mPositions[idx1]
  237. + 4.0f*mPositions[idx2]
  238. - mPositions[idx3];
  239. TYPE C = mPositions[idx2] - mPositions[idx0];
  240. return B + (3.0f*u)*A;
  241. }
  242. template<typename TYPE>
  243. inline TYPE CatmullRom<TYPE>::getPosition( U32 idx )
  244. {
  245. AssertFatal( idx >= 0 && idx < mCount-1, "CatmullRom<>::getPosition - Got bad index!" );
  246. return mPositions[idx];
  247. }
  248. template<typename TYPE>
  249. inline F32 CatmullRom<TYPE>::segmentArcLength( U32 i, F32 u1, F32 u2 )
  250. {
  251. AssertFatal( i >= 0 && i < mCount-1, "CatmullRom<>::getPosition - Got bad index!" );
  252. if ( u2 <= u1 )
  253. return 0.0f;
  254. if ( u1 < 0.0f )
  255. u1 = 0.0f;
  256. if ( u2 > 1.0f )
  257. u2 = 1.0f;
  258. S32 idx0, idx1, idx2, idx3;
  259. idx0 = i - 1;
  260. idx1 = i;
  261. idx2 = i + 1;
  262. idx3 = i + 2;
  263. if ( idx0 < 0 )
  264. idx0 = 0;
  265. if ( idx3 >= mCount )
  266. idx3 = mCount - 1;
  267. TYPE A = 3.0f*mPositions[idx1]
  268. - mPositions[idx0]
  269. - 3.0f*mPositions[idx2]
  270. + mPositions[idx3];
  271. TYPE B = 2.0f*mPositions[idx0]
  272. - 5.0f*mPositions[idx1]
  273. + 4.0f*mPositions[idx2]
  274. - mPositions[idx3];
  275. TYPE C = mPositions[idx2] - mPositions[idx0];
  276. F32 sum = 0.0f;
  277. for ( U32 j = 0; j < 5; ++j )
  278. {
  279. F32 u = 0.5f*((u2 - u1)*smX[j] + u2 + u1);
  280. TYPE derivative;
  281. if ( i == 0 || i >= mCount-2)
  282. derivative = 0.5f*B + u*A;
  283. else
  284. derivative = 0.5f*C + u*(B + 1.5f*u*A);
  285. sum += smC[j]*derivative.len();
  286. }
  287. sum *= 0.5f*(u2-u1);
  288. return sum;
  289. }
  290. #endif // _CATMULLROM_H_