123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #ifndef _CATMULLROM_H_
- #define _CATMULLROM_H_
- /// The shared base class used by the catmull rom
- /// interpolation template class.
- /// @see CatmullRom
- class CatmullRomBase
- {
- protected:
- CatmullRomBase();
- virtual ~CatmullRomBase() {}
- public:
-
- /// Clean out all the data.
- virtual void clear();
- /// Find length of curve between parameters t1 and t2.
- F32 arcLength( F32 t1, F32 t2 );
- /// Get the total length of the curve.
- inline F32 getLength() { return mTotalLength; }
- /// Get the closest previous control point to time t.
- U32 getPrevNode( F32 t );
- /// Returns the time at idx (rather than at a F32 time)
- F32 getTime( U32 idx );
- /// Find length of curve segment between parameters u1 and u2.
- virtual F32 segmentArcLength( U32 i, F32 u1, F32 u2 ) = 0;
- protected:
- static const F32 smX[];
- static const F32 smC[];
- void _initialize( U32 count, const F32 *times = NULL );
- /// The time to arrive at each point.
- F32 *mTimes;
- /// the length of each curve segment.
- F32* mLengths;
- /// The total length of curve.
- F32 mTotalLength;
- /// The number of points and times.
- U32 mCount;
- };
- /// The catmull-rom template class for performing interpolation
- /// over an arbitraty type.
- template<typename TYPE>
- class CatmullRom : public CatmullRomBase
- {
- public:
- CatmullRom();
- virtual ~CatmullRom();
- /// Initialization.
- void initialize( U32 count, const TYPE *positions, const F32 *times = NULL );
- // evaluate position
- TYPE evaluate( F32 t );
- /// Evaluate derivative at parameter t.
- TYPE velocity( F32 t );
- // Evaluate second derivative at parameter t.
- TYPE acceleration( F32 t );
- // Returns the position at idx (rather than at a F32 time)
- TYPE getPosition( U32 idx );
- // CatmullRomBase
- void clear();
- F32 segmentArcLength( U32 i, F32 u1, F32 u2 );
- protected:
- /// The sample points.
- TYPE* mPositions;
- private:
- /// The copy constructors are disabled.
- CatmullRom( const CatmullRom &other );
- CatmullRom& operator=( const CatmullRom &other );
- };
- template<typename TYPE>
- inline CatmullRom<TYPE>::CatmullRom()
- : CatmullRomBase(),
- mPositions( NULL )
- {
- }
- template<typename TYPE>
- inline CatmullRom<TYPE>::~CatmullRom()
- {
- clear();
- }
- template<typename TYPE>
- inline void CatmullRom<TYPE>::clear()
- {
- delete [] mPositions;
- mPositions = NULL;
- CatmullRomBase::clear();
- }
- template<typename TYPE>
- inline void CatmullRom<TYPE>::initialize( U32 count, const TYPE *positions, const F32 *times )
- {
- AssertFatal( positions, "CatmullRom::initialize - Got null position!" );
- AssertFatal( count > 1, "CatmullRom::initialize - Must have more than 2 points!" );
- // Clean up any previous state.
- clear();
- // copy the points.
- mPositions = new TYPE[count];
- for ( U32 i = 0; i < count; ++i )
- mPositions[i] = positions[i];
- _initialize( count, times );
- }
- template<typename TYPE>
- inline TYPE CatmullRom<TYPE>::evaluate( F32 t )
- {
- AssertFatal( mCount >= 2, "CatmullRom::evaluate - Not initialized!" );
- // handle boundary conditions
- if ( t <= mTimes[0] )
- return mPositions[0];
- else if ( t >= mTimes[mCount-1] )
- return mPositions[mCount-1];
- // find segment and parameter
- U32 i; // segment #
- for ( i = 0; i < mCount-1; ++i )
- {
- if ( t <= mTimes[i+1] )
- {
- break;
- }
- }
- AssertFatal( i >= 0 && i < mCount, "CatmullRom::evaluate - Got bad index!" );
- F32 t0 = mTimes[i];
- F32 t1 = mTimes[i+1];
- F32 u = (t - t0)/(t1 - t0);
-
- S32 idx0, idx1, idx2, idx3;
- idx0 = i - 1;
- idx1 = i;
- idx2 = i + 1;
- idx3 = i + 2;
- if ( idx0 < 0 )
- idx0 = 0;
- if ( idx3 >= mCount )
- idx3 = mCount - 1;
-
- TYPE A = 3.0f*mPositions[idx1]
- - mPositions[idx0]
- - 3.0f*mPositions[idx2]
- + mPositions[idx3];
- TYPE B = 2.0f*mPositions[idx0]
- - 5.0f*mPositions[idx1]
- + 4.0f*mPositions[idx2]
- - mPositions[idx3];
- TYPE C = mPositions[idx2] - mPositions[idx0];
- return mPositions[i] + (0.5f*u)*(C + u*(B + u*A));
- }
- template<typename TYPE>
- inline TYPE CatmullRom<TYPE>::velocity( F32 t )
- {
- AssertFatal( mCount >= 2, "CatmullRom::velocity - Not initialized!" );
- // handle boundary conditions
- if ( t <= mTimes[0] )
- t = 0.0f;
- else if ( t > mTimes[mCount-1] )
- t = mTimes[mCount-1];
- // find segment and parameter
- U32 i;
- for ( i = 0; i < mCount-1; ++i )
- {
- if ( t <= mTimes[i+1] )
- {
- break;
- }
- }
- F32 t0 = mTimes[i];
- F32 t1 = mTimes[i+1];
- F32 u = (t - t0)/(t1 - t0);
- S32 idx0, idx1, idx2, idx3;
- idx0 = i - 1;
- idx1 = i;
- idx2 = i + 1;
- idx3 = i + 2;
- if ( idx0 < 0 )
- idx0 = 0;
- if ( idx3 >= mCount )
- idx3 = mCount - 1;
- TYPE A = 3.0f*mPositions[idx1]
- - mPositions[idx0]
- - 3.0f*mPositions[idx2]
- + mPositions[idx3];
- TYPE B = 2.0f*mPositions[idx0]
- - 5.0f*mPositions[idx1]
- + 4.0f*mPositions[idx2]
- - mPositions[idx3];
- TYPE C = mPositions[idx2] - mPositions[idx0];
- return 0.5f*C + u*(B + 1.5f*u*A);
- }
- template<typename TYPE>
- inline TYPE CatmullRom<TYPE>::acceleration( F32 t )
- {
- AssertFatal( mCount >= 2, "CatmullRom::acceleration - Not initialized!" );
- // handle boundary conditions
- if ( t <= mTimes[0] )
- t = 0.0f;
- else if ( t > mTimes[mCount-1] )
- t = mTimes[mCount-1];
- // find segment and parameter
- U32 i;
- for ( i = 0; i < mCount-1; ++i )
- {
- if ( t <= mTimes[i+1] )
- {
- break;
- }
- }
- F32 t0 = mTimes[i];
- F32 t1 = mTimes[i+1];
- F32 u = (t - t0)/(t1 - t0);
- S32 idx0, idx1, idx2, idx3;
- idx0 = i - 1;
- idx1 = i;
- idx2 = i + 1;
- idx3 = i + 2;
- if ( idx0 < 0 )
- idx0 = 0;
- if ( idx3 >= mCount )
- idx3 = mCount - 1;
- TYPE A = 3.0f*mPositions[idx1]
- - mPositions[idx0]
- - 3.0f*mPositions[idx2]
- + mPositions[idx3];
-
- TYPE B = 2.0f*mPositions[idx0]
- - 5.0f*mPositions[idx1]
- + 4.0f*mPositions[idx2]
- - mPositions[idx3];
- TYPE C = mPositions[idx2] - mPositions[idx0];
- return B + (3.0f*u)*A;
- }
- template<typename TYPE>
- inline TYPE CatmullRom<TYPE>::getPosition( U32 idx )
- {
- AssertFatal( idx >= 0 && idx < mCount-1, "CatmullRom<>::getPosition - Got bad index!" );
- return mPositions[idx];
- }
- template<typename TYPE>
- inline F32 CatmullRom<TYPE>::segmentArcLength( U32 i, F32 u1, F32 u2 )
- {
- AssertFatal( i >= 0 && i < mCount-1, "CatmullRom<>::getPosition - Got bad index!" );
- if ( u2 <= u1 )
- return 0.0f;
- if ( u1 < 0.0f )
- u1 = 0.0f;
- if ( u2 > 1.0f )
- u2 = 1.0f;
- S32 idx0, idx1, idx2, idx3;
- idx0 = i - 1;
- idx1 = i;
- idx2 = i + 1;
- idx3 = i + 2;
- if ( idx0 < 0 )
- idx0 = 0;
- if ( idx3 >= mCount )
- idx3 = mCount - 1;
- TYPE A = 3.0f*mPositions[idx1]
- - mPositions[idx0]
- - 3.0f*mPositions[idx2]
- + mPositions[idx3];
- TYPE B = 2.0f*mPositions[idx0]
- - 5.0f*mPositions[idx1]
- + 4.0f*mPositions[idx2]
- - mPositions[idx3];
- TYPE C = mPositions[idx2] - mPositions[idx0];
- F32 sum = 0.0f;
- for ( U32 j = 0; j < 5; ++j )
- {
- F32 u = 0.5f*((u2 - u1)*smX[j] + u2 + u1);
- TYPE derivative;
- if ( i == 0 || i >= mCount-2)
- derivative = 0.5f*B + u*A;
- else
- derivative = 0.5f*C + u*(B + 1.5f*u*A);
- sum += smC[j]*derivative.len();
- }
- sum *= 0.5f*(u2-u1);
- return sum;
- }
- #endif // _CATMULLROM_H_
|