1 //-----------------------------------------------------------------------------
2 // Copyright (c) 2012 GarageGames, LLC
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:
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
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
21 //-----------------------------------------------------------------------------
23 #ifndef _CATMULLROM_H_
24 #define _CATMULLROM_H_
27 /// The shared base class used by the catmull rom
28 /// interpolation template class.
35 virtual ~CatmullRomBase() {}
39 /// Clean out all the data.
42 /// Find length of curve between parameters t1 and t2.
43 F32
arcLength( F32 t1
, F32 t2
);
45 /// Get the total length of the curve.
46 inline F32
getLength() { return mTotalLength
; }
48 /// Get the closest previous control point to time t.
49 U32
getPrevNode( F32 t
);
51 /// Returns the time at idx (rather than at a F32 time)
52 F32
getTime( U32 idx
);
54 /// Find length of curve segment between parameters u1 and u2.
55 virtual F32
segmentArcLength( U32 i
, F32 u1
, F32 u2
) = 0;
59 static const F32 smX
[];
60 static const F32 smC
[];
62 void _initialize( U32 count
, const F32
*times
= NULL
);
64 /// The time to arrive at each point.
67 /// the length of each curve segment.
70 /// The total length of curve.
73 /// The number of points and times.
78 /// The catmull-rom template class for performing interpolation
79 /// over an arbitraty type.
80 template<typename TYPE
>
81 class CatmullRom
: public CatmullRomBase
86 virtual ~CatmullRom();
89 void initialize( U32 count
, const TYPE
*positions
, const F32
*times
= NULL
);
92 TYPE
evaluate( F32 t
);
94 /// Evaluate derivative at parameter t.
95 TYPE
velocity( F32 t
);
97 // Evaluate second derivative at parameter t.
98 TYPE
acceleration( F32 t
);
100 // Returns the position at idx (rather than at a F32 time)
101 TYPE
getPosition( U32 idx
);
105 F32
segmentArcLength( U32 i
, F32 u1
, F32 u2
);
109 /// The sample points.
114 /// The copy constructors are disabled.
115 CatmullRom( const CatmullRom
&other
);
116 CatmullRom
& operator=( const CatmullRom
&other
);
120 template<typename TYPE
>
121 inline CatmullRom
<TYPE
>::CatmullRom()
127 template<typename TYPE
>
128 inline CatmullRom
<TYPE
>::~CatmullRom()
133 template<typename TYPE
>
134 inline void CatmullRom
<TYPE
>::clear()
136 delete [] mPositions
;
139 CatmullRomBase::clear();
142 template<typename TYPE
>
143 inline void CatmullRom
<TYPE
>::initialize( U32 count
, const TYPE
*positions
, const F32
*times
)
145 AssertFatal( positions
, "CatmullRom::initialize - Got null position!" );
146 AssertFatal( count
> 1, "CatmullRom::initialize - Must have more than 2 points!" );
148 // Clean up any previous state.
152 mPositions
= new TYPE
[count
];
153 for ( U32 i
= 0; i
< count
; ++i
)
154 mPositions
[i
] = positions
[i
];
156 _initialize( count
, times
);
159 template<typename TYPE
>
160 inline TYPE CatmullRom
<TYPE
>::evaluate( F32 t
)
162 AssertFatal( mCount
>= 2, "CatmullRom::evaluate - Not initialized!" );
164 // handle boundary conditions
165 if ( t
<= mTimes
[0] )
166 return mPositions
[0];
167 else if ( t
>= mTimes
[mCount
-1] )
168 return mPositions
[mCount
-1];
170 // find segment and parameter
172 for ( i
= 0; i
< mCount
-1; ++i
)
174 if ( t
<= mTimes
[i
+1] )
180 AssertFatal( i
>= 0 && i
< mCount
, "CatmullRom::evaluate - Got bad index!" );
183 F32 t1
= mTimes
[i
+1];
184 F32 u
= (t
- t0
)/(t1
- t0
);
186 S32 idx0
, idx1
, idx2
, idx3
;
194 if ( idx3
>= mCount
)
197 TYPE A
= 3.0f
*mPositions
[idx1
]
199 - 3.0f
*mPositions
[idx2
]
202 TYPE B
= 2.0f
*mPositions
[idx0
]
203 - 5.0f
*mPositions
[idx1
]
204 + 4.0f
*mPositions
[idx2
]
207 TYPE C
= mPositions
[idx2
] - mPositions
[idx0
];
209 return mPositions
[i
] + (0.5f
*u
)*(C
+ u
*(B
+ u
*A
));
212 template<typename TYPE
>
213 inline TYPE CatmullRom
<TYPE
>::velocity( F32 t
)
215 AssertFatal( mCount
>= 2, "CatmullRom::velocity - Not initialized!" );
217 // handle boundary conditions
218 if ( t
<= mTimes
[0] )
220 else if ( t
> mTimes
[mCount
-1] )
221 t
= mTimes
[mCount
-1];
223 // find segment and parameter
225 for ( i
= 0; i
< mCount
-1; ++i
)
227 if ( t
<= mTimes
[i
+1] )
233 F32 t1
= mTimes
[i
+1];
234 F32 u
= (t
- t0
)/(t1
- t0
);
236 S32 idx0
, idx1
, idx2
, idx3
;
244 if ( idx3
>= mCount
)
247 TYPE A
= 3.0f
*mPositions
[idx1
]
249 - 3.0f
*mPositions
[idx2
]
252 TYPE B
= 2.0f
*mPositions
[idx0
]
253 - 5.0f
*mPositions
[idx1
]
254 + 4.0f
*mPositions
[idx2
]
257 TYPE C
= mPositions
[idx2
] - mPositions
[idx0
];
259 return 0.5f
*C
+ u
*(B
+ 1.5f
*u
*A
);
262 template<typename TYPE
>
263 inline TYPE CatmullRom
<TYPE
>::acceleration( F32 t
)
265 AssertFatal( mCount
>= 2, "CatmullRom::acceleration - Not initialized!" );
267 // handle boundary conditions
268 if ( t
<= mTimes
[0] )
270 else if ( t
> mTimes
[mCount
-1] )
271 t
= mTimes
[mCount
-1];
273 // find segment and parameter
275 for ( i
= 0; i
< mCount
-1; ++i
)
277 if ( t
<= mTimes
[i
+1] )
283 F32 t1
= mTimes
[i
+1];
284 F32 u
= (t
- t0
)/(t1
- t0
);
286 S32 idx0
, idx1
, idx2
, idx3
;
294 if ( idx3
>= mCount
)
297 TYPE A
= 3.0f
*mPositions
[idx1
]
299 - 3.0f
*mPositions
[idx2
]
302 TYPE B
= 2.0f
*mPositions
[idx0
]
303 - 5.0f
*mPositions
[idx1
]
304 + 4.0f
*mPositions
[idx2
]
307 TYPE C
= mPositions
[idx2
] - mPositions
[idx0
];
309 return B
+ (3.0f
*u
)*A
;
312 template<typename TYPE
>
313 inline TYPE CatmullRom
<TYPE
>::getPosition( U32 idx
)
315 AssertFatal( idx
>= 0 && idx
< mCount
-1, "CatmullRom<>::getPosition - Got bad index!" );
316 return mPositions
[idx
];
319 template<typename TYPE
>
320 inline F32 CatmullRom
<TYPE
>::segmentArcLength( U32 i
, F32 u1
, F32 u2
)
322 AssertFatal( i
>= 0 && i
< mCount
-1, "CatmullRom<>::getPosition - Got bad index!" );
333 S32 idx0
, idx1
, idx2
, idx3
;
341 if ( idx3
>= mCount
)
344 TYPE A
= 3.0f
*mPositions
[idx1
]
346 - 3.0f
*mPositions
[idx2
]
348 TYPE B
= 2.0f
*mPositions
[idx0
]
349 - 5.0f
*mPositions
[idx1
]
350 + 4.0f
*mPositions
[idx2
]
352 TYPE C
= mPositions
[idx2
] - mPositions
[idx0
];
356 for ( U32 j
= 0; j
< 5; ++j
)
358 F32 u
= 0.5f
*((u2
- u1
)*smX
[j
] + u2
+ u1
);
360 if ( i
== 0 || i
>= mCount
-2)
361 derivative
= 0.5f
*B
+ u
*A
;
363 derivative
= 0.5f
*C
+ u
*(B
+ 1.5f
*u
*A
);
364 sum
+= smC
[j
]*derivative
.len();
371 #endif // _CATMULLROM_H_