mirror of
https://github.com/dhewm/dhewm3-sdk.git
synced 2024-11-25 14:01:10 +00:00
afebd7e1e5
Don't include the lazy precompiled.h everywhere, only what's required for the compilation unit. platform.h needs to be included instead to provide all essential defines and types. All includes use the relative path to the neo or the game specific root. Move all idlib related includes from idlib/Lib.h to precompiled.h. precompiled.h still exists for the MFC stuff in tools/. Add some missing header guards.
2545 lines
71 KiB
C++
2545 lines
71 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
Doom 3 GPL Source Code
|
|
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
|
|
|
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
|
|
|
|
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Doom 3 Source Code is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
|
|
|
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#ifndef __MATH_CURVE_H__
|
|
#define __MATH_CURVE_H__
|
|
|
|
#include "idlib/containers/List.h"
|
|
#include "idlib/math/Math.h"
|
|
#include "idlib/math/Matrix.h"
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Curve base template.
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
template< class type >
|
|
class idCurve {
|
|
public:
|
|
idCurve( void );
|
|
virtual ~idCurve( void );
|
|
|
|
virtual int AddValue( const float time, const type &value );
|
|
virtual void RemoveIndex( const int index ) { values.RemoveIndex(index); times.RemoveIndex(index); changed = true; }
|
|
virtual void Clear( void ) { values.Clear(); times.Clear(); currentIndex = -1; changed = true; }
|
|
|
|
virtual type GetCurrentValue( const float time ) const;
|
|
virtual type GetCurrentFirstDerivative( const float time ) const;
|
|
virtual type GetCurrentSecondDerivative( const float time ) const;
|
|
|
|
virtual bool IsDone( const float time ) const;
|
|
|
|
int GetNumValues( void ) const { return values.Num(); }
|
|
void SetValue( const int index, const type &value ) { values[index] = value; changed = true; }
|
|
type GetValue( const int index ) const { return values[index]; }
|
|
type * GetValueAddress( const int index ) { return &values[index]; }
|
|
float GetTime( const int index ) const { return times[index]; }
|
|
|
|
float GetLengthForTime( const float time ) const;
|
|
float GetTimeForLength( const float length, const float epsilon = 0.1f ) const;
|
|
float GetLengthBetweenKnots( const int i0, const int i1 ) const;
|
|
|
|
void MakeUniform( const float totalTime );
|
|
void SetConstantSpeed( const float totalTime );
|
|
void ShiftTime( const float deltaTime );
|
|
void Translate( const type &translation );
|
|
|
|
protected:
|
|
|
|
idList<float> times; // knots
|
|
idList<type> values; // knot values
|
|
|
|
mutable int currentIndex; // cached index for fast lookup
|
|
mutable bool changed; // set whenever the curve changes
|
|
|
|
int IndexForTime( const float time ) const;
|
|
float TimeForIndex( const int index ) const;
|
|
type ValueForIndex( const int index ) const;
|
|
|
|
float GetSpeed( const float time ) const;
|
|
float RombergIntegral( const float t0, const float t1, const int order ) const;
|
|
};
|
|
|
|
/*
|
|
====================
|
|
idCurve::idCurve
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE idCurve<type>::idCurve( void ) {
|
|
currentIndex = -1;
|
|
changed = false;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve::~idCurve
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE idCurve<type>::~idCurve( void ) {
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve::AddValue
|
|
|
|
add a timed/value pair to the spline
|
|
returns the index to the inserted pair
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE int idCurve<type>::AddValue( const float time, const type &value ) {
|
|
int i;
|
|
|
|
i = IndexForTime( time );
|
|
times.Insert( time, i );
|
|
values.Insert( value, i );
|
|
changed = true;
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve::GetCurrentValue
|
|
|
|
get the value for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve<type>::GetCurrentValue( const float time ) const {
|
|
int i;
|
|
|
|
i = IndexForTime( time );
|
|
if ( i >= values.Num() ) {
|
|
return values[values.Num() - 1];
|
|
} else {
|
|
return values[i];
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve::GetCurrentFirstDerivative
|
|
|
|
get the first derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve<type>::GetCurrentFirstDerivative( const float time ) const {
|
|
return ( values[0] - values[0] );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve::GetCurrentSecondDerivative
|
|
|
|
get the second derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve<type>::GetCurrentSecondDerivative( const float time ) const {
|
|
return ( values[0] - values[0] );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve::IsDone
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE bool idCurve<type>::IsDone( const float time ) const {
|
|
return ( time >= times[ times.Num() - 1 ] );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve::GetSpeed
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE float idCurve<type>::GetSpeed( const float time ) const {
|
|
int i;
|
|
float speed;
|
|
type value;
|
|
|
|
value = GetCurrentFirstDerivative( time );
|
|
for ( speed = 0.0f, i = 0; i < value.GetDimension(); i++ ) {
|
|
speed += value[i] * value[i];
|
|
}
|
|
return idMath::Sqrt( speed );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve::RombergIntegral
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE float idCurve<type>::RombergIntegral( const float t0, const float t1, const int order ) const {
|
|
int i, j, k, m, n;
|
|
float sum, delta;
|
|
float *temp[2];
|
|
|
|
temp[0] = (float *) _alloca16( order * sizeof( float ) );
|
|
temp[1] = (float *) _alloca16( order * sizeof( float ) );
|
|
|
|
delta = t1 - t0;
|
|
temp[0][0] = 0.5f * delta * ( GetSpeed( t0 ) + GetSpeed( t1 ) );
|
|
|
|
for ( i = 2, m = 1; i <= order; i++, m *= 2, delta *= 0.5f ) {
|
|
|
|
// approximate using the trapezoid rule
|
|
sum = 0.0f;
|
|
for ( j = 1; j <= m; j++ ) {
|
|
sum += GetSpeed( t0 + delta * ( j - 0.5f ) );
|
|
}
|
|
|
|
// Richardson extrapolation
|
|
temp[1][0] = 0.5f * ( temp[0][0] + delta * sum );
|
|
for ( k = 1, n = 4; k < i; k++, n *= 4 ) {
|
|
temp[1][k] = ( n * temp[1][k-1] - temp[0][k-1] ) / ( n - 1 );
|
|
}
|
|
|
|
for ( j = 0; j < i; j++ ) {
|
|
temp[0][j] = temp[1][j];
|
|
}
|
|
}
|
|
return temp[0][order-1];
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve::GetLengthBetweenKnots
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE float idCurve<type>::GetLengthBetweenKnots( const int i0, const int i1 ) const {
|
|
float length = 0.0f;
|
|
for ( int i = i0; i < i1; i++ ) {
|
|
length += RombergIntegral( times[i], times[i+1], 5 );
|
|
}
|
|
return length;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve::GetLengthForTime
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE float idCurve<type>::GetLengthForTime( const float time ) const {
|
|
float length = 0.0f;
|
|
int index = IndexForTime( time );
|
|
for ( int i = 0; i < index; i++ ) {
|
|
length += RombergIntegral( times[i], times[i+1], 5 );
|
|
}
|
|
length += RombergIntegral( times[index], time, 5 );
|
|
return length;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve::GetTimeForLength
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE float idCurve<type>::GetTimeForLength( const float length, const float epsilon ) const {
|
|
int i, index;
|
|
float *accumLength, totalLength, len0, len1, t, diff;
|
|
|
|
if ( length <= 0.0f ) {
|
|
return times[0];
|
|
}
|
|
|
|
accumLength = (float *) _alloca16( values.Num() * sizeof( float ) );
|
|
totalLength = 0.0f;
|
|
for ( index = 0; index < values.Num() - 1; index++ ) {
|
|
totalLength += GetLengthBetweenKnots( index, index + 1 );
|
|
accumLength[index] = totalLength;
|
|
if ( length < accumLength[index] ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( index >= values.Num() - 1 ) {
|
|
return times[times.Num() - 1];
|
|
}
|
|
|
|
if ( index == 0 ) {
|
|
len0 = length;
|
|
len1 = accumLength[0];
|
|
} else {
|
|
len0 = length - accumLength[index-1];
|
|
len1 = accumLength[index] - accumLength[index-1];
|
|
}
|
|
|
|
// invert the arc length integral using Newton's method
|
|
t = ( times[index+1] - times[index] ) * len0 / len1;
|
|
for ( i = 0; i < 32; i++ ) {
|
|
diff = RombergIntegral( times[index], times[index] + t, 5 ) - len0;
|
|
if ( idMath::Fabs( diff ) <= epsilon ) {
|
|
return times[index] + t;
|
|
}
|
|
t -= diff / GetSpeed( times[index] + t );
|
|
}
|
|
return times[index] + t;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve::MakeUniform
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve<type>::MakeUniform( const float totalTime ) {
|
|
int i, n;
|
|
|
|
n = times.Num() - 1;
|
|
for ( i = 0; i <= n; i++ ) {
|
|
times[i] = i * totalTime / n;
|
|
}
|
|
changed = true;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve::SetConstantSpeed
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve<type>::SetConstantSpeed( const float totalTime ) {
|
|
int i;
|
|
float *length, totalLength, scale, t;
|
|
|
|
length = (float *) _alloca16( values.Num() * sizeof( float ) );
|
|
totalLength = 0.0f;
|
|
for ( i = 0; i < values.Num() - 1; i++ ) {
|
|
length[i] = GetLengthBetweenKnots( i, i + 1 );
|
|
totalLength += length[i];
|
|
}
|
|
scale = totalTime / totalLength;
|
|
for ( t = 0.0f, i = 0; i < times.Num() - 1; i++ ) {
|
|
times[i] = t;
|
|
t += scale * length[i];
|
|
}
|
|
times[times.Num() - 1] = totalTime;
|
|
changed = true;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve::ShiftTime
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve<type>::ShiftTime( const float deltaTime ) {
|
|
for ( int i = 0; i < times.Num(); i++ ) {
|
|
times[i] += deltaTime;
|
|
}
|
|
changed = true;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve::Translate
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve<type>::Translate( const type &translation ) {
|
|
for ( int i = 0; i < values.Num(); i++ ) {
|
|
values[i] += translation;
|
|
}
|
|
changed = true;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve::IndexForTime
|
|
|
|
find the index for the first time greater than or equal to the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE int idCurve<type>::IndexForTime( const float time ) const {
|
|
int len, mid, offset, res;
|
|
|
|
if ( currentIndex >= 0 && currentIndex <= times.Num() ) {
|
|
// use the cached index if it is still valid
|
|
if ( currentIndex == 0 ) {
|
|
if ( time <= times[currentIndex] ) {
|
|
return currentIndex;
|
|
}
|
|
} else if ( currentIndex == times.Num() ) {
|
|
if ( time > times[currentIndex-1] ) {
|
|
return currentIndex;
|
|
}
|
|
} else if ( time > times[currentIndex-1] && time <= times[currentIndex] ) {
|
|
return currentIndex;
|
|
} else if ( time > times[currentIndex] && ( currentIndex+1 == times.Num() || time <= times[currentIndex+1] ) ) {
|
|
// use the next index
|
|
currentIndex++;
|
|
return currentIndex;
|
|
}
|
|
}
|
|
|
|
// use binary search to find the index for the given time
|
|
len = times.Num();
|
|
mid = len;
|
|
offset = 0;
|
|
res = 0;
|
|
while( mid > 0 ) {
|
|
mid = len >> 1;
|
|
if ( time == times[offset+mid] ) {
|
|
return offset+mid;
|
|
} else if ( time > times[offset+mid] ) {
|
|
offset += mid;
|
|
len -= mid;
|
|
res = 1;
|
|
} else {
|
|
len -= mid;
|
|
res = 0;
|
|
}
|
|
}
|
|
currentIndex = offset+res;
|
|
return currentIndex;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve::ValueForIndex
|
|
|
|
get the value for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve<type>::ValueForIndex( const int index ) const {
|
|
int n = values.Num()-1;
|
|
|
|
if ( index < 0 ) {
|
|
return values[0] + index * ( values[1] - values[0] );
|
|
} else if ( index > n ) {
|
|
return values[n] + ( index - n ) * ( values[n] - values[n-1] );
|
|
}
|
|
return values[index];
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve::TimeForIndex
|
|
|
|
get the value for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE float idCurve<type>::TimeForIndex( const int index ) const {
|
|
int n = times.Num()-1;
|
|
|
|
if ( index < 0 ) {
|
|
return times[0] + index * ( times[1] - times[0] );
|
|
} else if ( index > n ) {
|
|
return times[n] + ( index - n ) * ( times[n] - times[n-1] );
|
|
}
|
|
return times[index];
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Bezier Curve template.
|
|
The degree of the polynomial equals the number of knots minus one.
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
template< class type >
|
|
class idCurve_Bezier : public idCurve<type> {
|
|
public:
|
|
idCurve_Bezier( void );
|
|
|
|
virtual type GetCurrentValue( const float time ) const;
|
|
virtual type GetCurrentFirstDerivative( const float time ) const;
|
|
virtual type GetCurrentSecondDerivative( const float time ) const;
|
|
|
|
protected:
|
|
void Basis( const int order, const float t, float *bvals ) const;
|
|
void BasisFirstDerivative( const int order, const float t, float *bvals ) const;
|
|
void BasisSecondDerivative( const int order, const float t, float *bvals ) const;
|
|
};
|
|
|
|
/*
|
|
====================
|
|
idCurve_Bezier::idCurve_Bezier
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE idCurve_Bezier<type>::idCurve_Bezier( void ) {
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_Bezier::GetCurrentValue
|
|
|
|
get the value for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_Bezier<type>::GetCurrentValue( const float time ) const {
|
|
int i;
|
|
float *bvals;
|
|
type v;
|
|
|
|
bvals = (float *) _alloca16( this->values.Num() * sizeof( float ) );
|
|
|
|
Basis( this->values.Num(), time, bvals );
|
|
v = bvals[0] * this->values[0];
|
|
for ( i = 1; i < this->values.Num(); i++ ) {
|
|
v += bvals[i] * this->values[i];
|
|
}
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_Bezier::GetCurrentFirstDerivative
|
|
|
|
get the first derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_Bezier<type>::GetCurrentFirstDerivative( const float time ) const {
|
|
int i;
|
|
float *bvals, d;
|
|
type v;
|
|
|
|
bvals = (float *) _alloca16( this->values.Num() * sizeof( float ) );
|
|
|
|
BasisFirstDerivative( this->values.Num(), time, bvals );
|
|
v = bvals[0] * this->values[0];
|
|
for ( i = 1; i < this->values.Num(); i++ ) {
|
|
v += bvals[i] * this->values[i];
|
|
}
|
|
d = ( this->times[this->times.Num()-1] - this->times[0] );
|
|
return ( (float) (this->values.Num()-1) / d ) * v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_Bezier::GetCurrentSecondDerivative
|
|
|
|
get the second derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_Bezier<type>::GetCurrentSecondDerivative( const float time ) const {
|
|
int i;
|
|
float *bvals, d;
|
|
type v;
|
|
|
|
bvals = (float *) _alloca16( this->values.Num() * sizeof( float ) );
|
|
|
|
BasisSecondDerivative( this->values.Num(), time, bvals );
|
|
v = bvals[0] * this->values[0];
|
|
for ( i = 1; i < this->values.Num(); i++ ) {
|
|
v += bvals[i] * this->values[i];
|
|
}
|
|
d = ( this->times[this->times.Num()-1] - this->times[0] );
|
|
return ( (float) (this->values.Num()-2) * (this->values.Num()-1) / ( d * d ) ) * v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_Bezier::Basis
|
|
|
|
bezier basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_Bezier<type>::Basis( const int order, const float t, float *bvals ) const {
|
|
int i, j, d;
|
|
float *c, c1, c2, s, o, ps, po;
|
|
|
|
bvals[0] = 1.0f;
|
|
d = order - 1;
|
|
if ( d <= 0 ) {
|
|
return;
|
|
}
|
|
|
|
c = (float *) _alloca16( (d+1) * sizeof( float ) );
|
|
s = (float) ( t - this->times[0] ) / ( this->times[this->times.Num()-1] - this->times[0] );
|
|
o = 1.0f - s;
|
|
ps = s;
|
|
po = o;
|
|
|
|
for ( i = 1; i < d; i++ ) {
|
|
c[i] = 1.0f;
|
|
}
|
|
for ( i = 1; i < d; i++ ) {
|
|
c[i-1] = 0.0f;
|
|
c1 = c[i];
|
|
c[i] = 1.0f;
|
|
for ( j = i+1; j <= d; j++ ) {
|
|
c2 = c[j];
|
|
c[j] = c1 + c[j-1];
|
|
c1 = c2;
|
|
}
|
|
bvals[i] = c[d] * ps;
|
|
ps *= s;
|
|
}
|
|
for ( i = d-1; i >= 0; i-- ) {
|
|
bvals[i] *= po;
|
|
po *= o;
|
|
}
|
|
bvals[d] = ps;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_Bezier::BasisFirstDerivative
|
|
|
|
first derivative of bezier basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_Bezier<type>::BasisFirstDerivative( const int order, const float t, float *bvals ) const {
|
|
int i;
|
|
|
|
Basis( order-1, t, bvals+1 );
|
|
bvals[0] = 0.0f;
|
|
for ( i = 0; i < order-1; i++ ) {
|
|
bvals[i] -= bvals[i+1];
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_Bezier::BasisSecondDerivative
|
|
|
|
second derivative of bezier basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_Bezier<type>::BasisSecondDerivative( const int order, const float t, float *bvals ) const {
|
|
int i;
|
|
|
|
BasisFirstDerivative( order-1, t, bvals+1 );
|
|
bvals[0] = 0.0f;
|
|
for ( i = 0; i < order-1; i++ ) {
|
|
bvals[i] -= bvals[i+1];
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Quadratic Bezier Curve template.
|
|
Should always have exactly three knots.
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
template< class type >
|
|
class idCurve_QuadraticBezier : public idCurve<type> {
|
|
|
|
public:
|
|
idCurve_QuadraticBezier( void );
|
|
|
|
virtual type GetCurrentValue( const float time ) const;
|
|
virtual type GetCurrentFirstDerivative( const float time ) const;
|
|
virtual type GetCurrentSecondDerivative( const float time ) const;
|
|
|
|
protected:
|
|
void Basis( const float t, float *bvals ) const;
|
|
void BasisFirstDerivative( const float t, float *bvals ) const;
|
|
void BasisSecondDerivative( const float t, float *bvals ) const;
|
|
};
|
|
|
|
/*
|
|
====================
|
|
idCurve_QuadraticBezier::idCurve_QuadraticBezier
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE idCurve_QuadraticBezier<type>::idCurve_QuadraticBezier( void ) {
|
|
}
|
|
|
|
|
|
/*
|
|
====================
|
|
idCurve_QuadraticBezier::GetCurrentValue
|
|
|
|
get the value for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_QuadraticBezier<type>::GetCurrentValue( const float time ) const {
|
|
float bvals[3];
|
|
assert( this->values.Num() == 3 );
|
|
Basis( time, bvals );
|
|
return ( bvals[0] * this->values[0] + bvals[1] * this->values[1] + bvals[2] * this->values[2] );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_QuadraticBezier::GetCurrentFirstDerivative
|
|
|
|
get the first derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_QuadraticBezier<type>::GetCurrentFirstDerivative( const float time ) const {
|
|
float bvals[3], d;
|
|
assert( this->values.Num() == 3 );
|
|
BasisFirstDerivative( time, bvals );
|
|
d = ( this->times[2] - this->times[0] );
|
|
return ( bvals[0] * this->values[0] + bvals[1] * this->values[1] + bvals[2] * this->values[2] ) / d;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_QuadraticBezier::GetCurrentSecondDerivative
|
|
|
|
get the second derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_QuadraticBezier<type>::GetCurrentSecondDerivative( const float time ) const {
|
|
float bvals[3], d;
|
|
assert( this->values.Num() == 3 );
|
|
BasisSecondDerivative( time, bvals );
|
|
d = ( this->times[2] - this->times[0] );
|
|
return ( bvals[0] * this->values[0] + bvals[1] * this->values[1] + bvals[2] * this->values[2] ) / ( d * d );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_QuadraticBezier::Basis
|
|
|
|
quadratic bezier basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_QuadraticBezier<type>::Basis( const float t, float *bvals ) const {
|
|
float s1 = (float) ( t - this->times[0] ) / ( this->times[2] - this->times[0] );
|
|
float s2 = s1 * s1;
|
|
bvals[0] = s2 - 2.0f * s1 + 1.0f;
|
|
bvals[1] = -2.0f * s2 + 2.0f * s1;
|
|
bvals[2] = s2;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_QuadraticBezier::BasisFirstDerivative
|
|
|
|
first derivative of quadratic bezier basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_QuadraticBezier<type>::BasisFirstDerivative( const float t, float *bvals ) const {
|
|
float s1 = (float) ( t - this->times[0] ) / ( this->times[2] - this->times[0] );
|
|
bvals[0] = 2.0f * s1 - 2.0f;
|
|
bvals[1] = -4.0f * s1 + 2.0f;
|
|
bvals[2] = 2.0f * s1;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_QuadraticBezier::BasisSecondDerivative
|
|
|
|
second derivative of quadratic bezier basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_QuadraticBezier<type>::BasisSecondDerivative( const float t, float *bvals ) const {
|
|
bvals[0] = 2.0f;
|
|
bvals[1] = -4.0f;
|
|
bvals[2] = 2.0f;
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Cubic Bezier Curve template.
|
|
Should always have exactly four knots.
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
template< class type >
|
|
class idCurve_CubicBezier : public idCurve<type> {
|
|
|
|
public:
|
|
idCurve_CubicBezier( void );
|
|
|
|
virtual type GetCurrentValue( const float time ) const;
|
|
virtual type GetCurrentFirstDerivative( const float time ) const;
|
|
virtual type GetCurrentSecondDerivative( const float time ) const;
|
|
|
|
protected:
|
|
void Basis( const float t, float *bvals ) const;
|
|
void BasisFirstDerivative( const float t, float *bvals ) const;
|
|
void BasisSecondDerivative( const float t, float *bvals ) const;
|
|
};
|
|
|
|
/*
|
|
====================
|
|
idCurve_CubicBezier::idCurve_CubicBezier
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE idCurve_CubicBezier<type>::idCurve_CubicBezier( void ) {
|
|
}
|
|
|
|
|
|
/*
|
|
====================
|
|
idCurve_CubicBezier::GetCurrentValue
|
|
|
|
get the value for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_CubicBezier<type>::GetCurrentValue( const float time ) const {
|
|
float bvals[4];
|
|
assert( this->values.Num() == 4 );
|
|
Basis( time, bvals );
|
|
return ( bvals[0] * this->values[0] + bvals[1] * this->values[1] + bvals[2] * this->values[2] + bvals[3] * this->values[3] );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_CubicBezier::GetCurrentFirstDerivative
|
|
|
|
get the first derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_CubicBezier<type>::GetCurrentFirstDerivative( const float time ) const {
|
|
float bvals[4], d;
|
|
assert( this->values.Num() == 4 );
|
|
BasisFirstDerivative( time, bvals );
|
|
d = ( this->times[3] - this->times[0] );
|
|
return ( bvals[0] * this->values[0] + bvals[1] * this->values[1] + bvals[2] * this->values[2] + bvals[3] * this->values[3] ) / d;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_CubicBezier::GetCurrentSecondDerivative
|
|
|
|
get the second derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_CubicBezier<type>::GetCurrentSecondDerivative( const float time ) const {
|
|
float bvals[4], d;
|
|
assert( this->values.Num() == 4 );
|
|
BasisSecondDerivative( time, bvals );
|
|
d = ( this->times[3] - this->times[0] );
|
|
return ( bvals[0] * this->values[0] + bvals[1] * this->values[1] + bvals[2] * this->values[2] + bvals[3] * this->values[3] ) / ( d * d );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_CubicBezier::Basis
|
|
|
|
cubic bezier basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_CubicBezier<type>::Basis( const float t, float *bvals ) const {
|
|
float s1 = (float) ( t - this->times[0] ) / ( this->times[3] - this->times[0] );
|
|
float s2 = s1 * s1;
|
|
float s3 = s2 * s1;
|
|
bvals[0] = -s3 + 3.0f * s2 - 3.0f * s1 + 1.0f;
|
|
bvals[1] = 3.0f * s3 - 6.0f * s2 + 3.0f * s1;
|
|
bvals[2] = -3.0f * s3 + 3.0f * s2;
|
|
bvals[3] = s3;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_CubicBezier::BasisFirstDerivative
|
|
|
|
first derivative of cubic bezier basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_CubicBezier<type>::BasisFirstDerivative( const float t, float *bvals ) const {
|
|
float s1 = (float) ( t - this->times[0] ) / ( this->times[3] - this->times[0] );
|
|
float s2 = s1 * s1;
|
|
bvals[0] = -3.0f * s2 + 6.0f * s1 - 3.0f;
|
|
bvals[1] = 9.0f * s2 - 12.0f * s1 + 3.0f;
|
|
bvals[2] = -9.0f * s2 + 6.0f * s1;
|
|
bvals[3] = 3.0f * s2;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_CubicBezier::BasisSecondDerivative
|
|
|
|
second derivative of cubic bezier basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_CubicBezier<type>::BasisSecondDerivative( const float t, float *bvals ) const {
|
|
float s1 = (float) ( t - this->times[0] ) / ( this->times[3] - this->times[0] );
|
|
bvals[0] = -6.0f * s1 + 6.0f;
|
|
bvals[1] = 18.0f * s1 - 12.0f;
|
|
bvals[2] = -18.0f * s1 + 6.0f;
|
|
bvals[3] = 6.0f * s1;
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Spline base template.
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
template< class type >
|
|
class idCurve_Spline : public idCurve<type> {
|
|
|
|
public:
|
|
enum boundary_t { BT_FREE, BT_CLAMPED, BT_CLOSED };
|
|
|
|
idCurve_Spline( void );
|
|
|
|
virtual bool IsDone( const float time ) const;
|
|
|
|
virtual void SetBoundaryType( const boundary_t bt ) { boundaryType = bt; this->changed = true; }
|
|
virtual boundary_t GetBoundaryType( void ) const { return boundaryType; }
|
|
|
|
virtual void SetCloseTime( const float t ) { closeTime = t; this->changed = true; }
|
|
virtual float GetCloseTime( void ) { return boundaryType == BT_CLOSED ? closeTime : 0.0f; }
|
|
|
|
protected:
|
|
boundary_t boundaryType;
|
|
float closeTime;
|
|
|
|
type ValueForIndex( const int index ) const;
|
|
float TimeForIndex( const int index ) const;
|
|
float ClampedTime( const float t ) const;
|
|
};
|
|
|
|
/*
|
|
====================
|
|
idCurve_Spline::idCurve_Spline
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE idCurve_Spline<type>::idCurve_Spline( void ) {
|
|
boundaryType = BT_FREE;
|
|
closeTime = 0.0f;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_Spline::ValueForIndex
|
|
|
|
get the value for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_Spline<type>::ValueForIndex( const int index ) const {
|
|
int n = this->values.Num()-1;
|
|
|
|
if ( index < 0 ) {
|
|
if ( boundaryType == BT_CLOSED ) {
|
|
return this->values[ this->values.Num() + index % this->values.Num() ];
|
|
}
|
|
else {
|
|
return this->values[0] + index * ( this->values[1] - this->values[0] );
|
|
}
|
|
}
|
|
else if ( index > n ) {
|
|
if ( boundaryType == BT_CLOSED ) {
|
|
return this->values[ index % this->values.Num() ];
|
|
}
|
|
else {
|
|
return this->values[n] + ( index - n ) * ( this->values[n] - this->values[n-1] );
|
|
}
|
|
}
|
|
return this->values[index];
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_Spline::TimeForIndex
|
|
|
|
get the value for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE float idCurve_Spline<type>::TimeForIndex( const int index ) const {
|
|
int n = this->times.Num()-1;
|
|
|
|
if ( index < 0 ) {
|
|
if ( boundaryType == BT_CLOSED ) {
|
|
return ( index / this->times.Num() ) * ( this->times[n] + closeTime ) - ( this->times[n] + closeTime - this->times[this->times.Num() + index % this->times.Num()] );
|
|
}
|
|
else {
|
|
return this->times[0] + index * ( this->times[1] - this->times[0] );
|
|
}
|
|
}
|
|
else if ( index > n ) {
|
|
if ( boundaryType == BT_CLOSED ) {
|
|
return ( index / this->times.Num() ) * ( this->times[n] + closeTime ) + this->times[index % this->times.Num()];
|
|
}
|
|
else {
|
|
return this->times[n] + ( index - n ) * ( this->times[n] - this->times[n-1] );
|
|
}
|
|
}
|
|
return this->times[index];
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_Spline::ClampedTime
|
|
|
|
return the clamped time based on the boundary type
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE float idCurve_Spline<type>::ClampedTime( const float t ) const {
|
|
if ( boundaryType == BT_CLAMPED ) {
|
|
if ( t < this->times[0] ) {
|
|
return this->times[0];
|
|
}
|
|
else if ( t >= this->times[this->times.Num()-1] ) {
|
|
return this->times[this->times.Num()-1];
|
|
}
|
|
}
|
|
return t;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_Spline::IsDone
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE bool idCurve_Spline<type>::IsDone( const float time ) const {
|
|
return ( boundaryType != BT_CLOSED && time >= this->times[ this->times.Num() - 1 ] );
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Cubic Interpolating Spline template.
|
|
The curve goes through all the knots.
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
template< class type >
|
|
class idCurve_NaturalCubicSpline : public idCurve_Spline<type> {
|
|
public:
|
|
idCurve_NaturalCubicSpline( void );
|
|
|
|
virtual void Clear( void ) { idCurve_Spline<type>::Clear(); this->values.Clear(); b.Clear(); c.Clear(); d.Clear(); }
|
|
|
|
virtual type GetCurrentValue( const float time ) const;
|
|
virtual type GetCurrentFirstDerivative( const float time ) const;
|
|
virtual type GetCurrentSecondDerivative( const float time ) const;
|
|
|
|
protected:
|
|
mutable idList<type>b;
|
|
mutable idList<type>c;
|
|
mutable idList<type>d;
|
|
|
|
void Setup( void ) const;
|
|
void SetupFree( void ) const;
|
|
void SetupClamped( void ) const;
|
|
void SetupClosed( void ) const;
|
|
};
|
|
|
|
/*
|
|
====================
|
|
idCurve_NaturalCubicSpline::idCurve_NaturalCubicSpline
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE idCurve_NaturalCubicSpline<type>::idCurve_NaturalCubicSpline( void ) {
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_NaturalCubicSpline::GetCurrentValue
|
|
|
|
get the value for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_NaturalCubicSpline<type>::GetCurrentValue( const float time ) const {
|
|
float clampedTime = this->ClampedTime( time );
|
|
int i = this->IndexForTime( clampedTime );
|
|
float s = time - this->TimeForIndex( i );
|
|
Setup();
|
|
return ( this->values[i] + s * ( b[i] + s * ( c[i] + s * d[i] ) ) );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_NaturalCubicSpline::GetCurrentFirstDerivative
|
|
|
|
get the first derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_NaturalCubicSpline<type>::GetCurrentFirstDerivative( const float time ) const {
|
|
float clampedTime = this->ClampedTime( time );
|
|
int i = this->IndexForTime( clampedTime );
|
|
float s = time - this->TimeForIndex( i );
|
|
Setup();
|
|
return ( b[i] + s * ( 2.0f * c[i] + 3.0f * s * d[i] ) );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_NaturalCubicSpline::GetCurrentSecondDerivative
|
|
|
|
get the second derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_NaturalCubicSpline<type>::GetCurrentSecondDerivative( const float time ) const {
|
|
float clampedTime = this->ClampedTime( time );
|
|
int i = this->IndexForTime( clampedTime );
|
|
float s = time - this->TimeForIndex( i );
|
|
Setup();
|
|
return ( 2.0f * c[i] + 6.0f * s * d[i] );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_NaturalCubicSpline::Setup
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_NaturalCubicSpline<type>::Setup( void ) const {
|
|
if ( this->changed ) {
|
|
switch( this->boundaryType ) {
|
|
case idCurve_Spline<type>::BT_FREE: SetupFree(); break;
|
|
case idCurve_Spline<type>::BT_CLAMPED: SetupClamped(); break;
|
|
case idCurve_Spline<type>::BT_CLOSED: SetupClosed(); break;
|
|
}
|
|
this->changed = false;
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_NaturalCubicSpline::SetupFree
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_NaturalCubicSpline<type>::SetupFree( void ) const {
|
|
int i;
|
|
float inv;
|
|
float *d0, *d1, *beta, *gamma;
|
|
type *alpha, *delta;
|
|
|
|
d0 = (float *) _alloca16( ( this->values.Num() - 1 ) * sizeof( float ) );
|
|
d1 = (float *) _alloca16( ( this->values.Num() - 1 ) * sizeof( float ) );
|
|
alpha = (type *) _alloca16( ( this->values.Num() - 1 ) * sizeof( type ) );
|
|
beta = (float *) _alloca16( this->values.Num() * sizeof( float ) );
|
|
gamma = (float *) _alloca16( ( this->values.Num() - 1 ) * sizeof( float ) );
|
|
delta = (type *) _alloca16( this->values.Num() * sizeof( type ) );
|
|
|
|
for ( i = 0; i < this->values.Num() - 1; i++ ) {
|
|
d0[i] = this->times[i+1] - this->times[i];
|
|
}
|
|
|
|
for ( i = 1; i < this->values.Num() - 1; i++ ) {
|
|
d1[i] = this->times[i+1] - this->times[i-1];
|
|
}
|
|
|
|
for ( i = 1; i < this->values.Num() - 1; i++ ) {
|
|
type sum = 3.0f * ( d0[i-1] * this->values[i+1] - d1[i] * this->values[i] + d0[i] * this->values[i-1] );
|
|
inv = 1.0f / ( d0[i-1] * d0[i] );
|
|
alpha[i] = inv * sum;
|
|
}
|
|
|
|
beta[0] = 1.0f;
|
|
gamma[0] = 0.0f;
|
|
delta[0] = this->values[0] - this->values[0];
|
|
|
|
for ( i = 1; i < this->values.Num() - 1; i++ ) {
|
|
beta[i] = 2.0f * d1[i] - d0[i-1] * gamma[i-1];
|
|
inv = 1.0f / beta[i];
|
|
gamma[i] = inv * d0[i];
|
|
delta[i] = inv * ( alpha[i] - d0[i-1] * delta[i-1] );
|
|
}
|
|
beta[this->values.Num() - 1] = 1.0f;
|
|
delta[this->values.Num() - 1] = this->values[0] - this->values[0];
|
|
|
|
b.AssureSize( this->values.Num() );
|
|
c.AssureSize( this->values.Num() );
|
|
d.AssureSize( this->values.Num() );
|
|
|
|
c[this->values.Num() - 1] = this->values[0] - this->values[0];
|
|
|
|
for ( i = this->values.Num() - 2; i >= 0; i-- ) {
|
|
c[i] = delta[i] - gamma[i] * c[i+1];
|
|
inv = 1.0f / d0[i];
|
|
b[i] = inv * ( this->values[i+1] - this->values[i] ) - ( 1.0f / 3.0f ) * d0[i] * ( c[i+1] + 2.0f * c[i] );
|
|
d[i] = ( 1.0f / 3.0f ) * inv * ( c[i+1] - c[i] );
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_NaturalCubicSpline::SetupClamped
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_NaturalCubicSpline<type>::SetupClamped( void ) const {
|
|
int i;
|
|
float inv;
|
|
float *d0, *d1, *beta, *gamma;
|
|
type *alpha, *delta;
|
|
|
|
d0 = (float *) _alloca16( ( this->values.Num() - 1 ) * sizeof( float ) );
|
|
d1 = (float *) _alloca16( ( this->values.Num() - 1 ) * sizeof( float ) );
|
|
alpha = (type *) _alloca16( ( this->values.Num() - 1 ) * sizeof( type ) );
|
|
beta = (float *) _alloca16( this->values.Num() * sizeof( float ) );
|
|
gamma = (float *) _alloca16( ( this->values.Num() - 1 ) * sizeof( float ) );
|
|
delta = (type *) _alloca16( this->values.Num() * sizeof( type ) );
|
|
|
|
for ( i = 0; i < this->values.Num() - 1; i++ ) {
|
|
d0[i] = this->times[i+1] - this->times[i];
|
|
}
|
|
|
|
for ( i = 1; i < this->values.Num() - 1; i++ ) {
|
|
d1[i] = this->times[i+1] - this->times[i-1];
|
|
}
|
|
|
|
inv = 1.0f / d0[0];
|
|
alpha[0] = 3.0f * ( inv - 1.0f ) * ( this->values[1] - this->values[0] );
|
|
inv = 1.0f / d0[this->values.Num() - 2];
|
|
alpha[this->values.Num() - 1] = 3.0f * ( 1.0f - inv ) * ( this->values[this->values.Num() - 1] - this->values[this->values.Num() - 2] );
|
|
|
|
for ( i = 1; i < this->values.Num() - 1; i++ ) {
|
|
type sum = 3.0f * ( d0[i-1] * this->values[i+1] - d1[i] * this->values[i] + d0[i] * this->values[i-1] );
|
|
inv = 1.0f / ( d0[i-1] * d0[i] );
|
|
alpha[i] = inv * sum;
|
|
}
|
|
|
|
beta[0] = 2.0f * d0[0];
|
|
gamma[0] = 0.5f;
|
|
inv = 1.0f / beta[0];
|
|
delta[0] = inv * alpha[0];
|
|
|
|
for ( i = 1; i < this->values.Num() - 1; i++ ) {
|
|
beta[i] = 2.0f * d1[i] - d0[i-1] * gamma[i-1];
|
|
inv = 1.0f / beta[i];
|
|
gamma[i] = inv * d0[i];
|
|
delta[i] = inv * ( alpha[i] - d0[i-1] * delta[i-1] );
|
|
}
|
|
|
|
beta[this->values.Num() - 1] = d0[this->values.Num() - 2] * ( 2.0f - gamma[this->values.Num() - 2] );
|
|
inv = 1.0f / beta[this->values.Num() - 1];
|
|
delta[this->values.Num() - 1] = inv * ( alpha[this->values.Num() - 1] - d0[this->values.Num() - 2] * delta[this->values.Num() - 2] );
|
|
|
|
b.AssureSize( this->values.Num() );
|
|
c.AssureSize( this->values.Num() );
|
|
d.AssureSize( this->values.Num() );
|
|
|
|
c[this->values.Num() - 1] = delta[this->values.Num() - 1];
|
|
|
|
for ( i = this->values.Num() - 2; i >= 0; i-- ) {
|
|
c[i] = delta[i] - gamma[i] * c[i+1];
|
|
inv = 1.0f / d0[i];
|
|
b[i] = inv * ( this->values[i+1] - this->values[i] ) - ( 1.0f / 3.0f ) * d0[i]* ( c[i+1] + 2.0f * c[i] );
|
|
d[i] = ( 1.0f / 3.0f ) * inv * ( c[i+1] - c[i] );
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_NaturalCubicSpline::SetupClosed
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_NaturalCubicSpline<type>::SetupClosed( void ) const {
|
|
int i, j;
|
|
float c0, c1;
|
|
float *d0;
|
|
idMatX mat;
|
|
idVecX x;
|
|
|
|
d0 = (float *) _alloca16( ( this->values.Num() - 1 ) * sizeof( float ) );
|
|
x.SetData( this->values.Num(), VECX_ALLOCA( this->values.Num() ) );
|
|
mat.SetData( this->values.Num(), this->values.Num(), MATX_ALLOCA( this->values.Num() * this->values.Num() ) );
|
|
|
|
b.AssureSize( this->values.Num() );
|
|
c.AssureSize( this->values.Num() );
|
|
d.AssureSize( this->values.Num() );
|
|
|
|
for ( i = 0; i < this->values.Num() - 1; i++ ) {
|
|
d0[i] = this->times[i+1] - this->times[i];
|
|
}
|
|
|
|
// matrix of system
|
|
mat[0][0] = 1.0f;
|
|
mat[0][this->values.Num() - 1] = -1.0f;
|
|
for ( i = 1; i <= this->values.Num() - 2; i++ ) {
|
|
mat[i][i-1] = d0[i-1];
|
|
mat[i][i ] = 2.0f * ( d0[i-1] + d0[i] );
|
|
mat[i][i+1] = d0[i];
|
|
}
|
|
mat[this->values.Num() - 1][this->values.Num() - 2] = d0[this->values.Num() - 2];
|
|
mat[this->values.Num() - 1][0] = 2.0f * ( d0[this->values.Num() - 2] + d0[0] );
|
|
mat[this->values.Num() - 1][1] = d0[0];
|
|
|
|
// right-hand side
|
|
c[0].Zero();
|
|
for ( i = 1; i <= this->values.Num() - 2; i++ ) {
|
|
c0 = 1.0f / d0[i];
|
|
c1 = 1.0f / d0[i-1];
|
|
c[i] = 3.0f * ( c0 * ( this->values[i + 1] - this->values[i] ) - c1 * ( this->values[i] - this->values[i - 1] ) );
|
|
}
|
|
c0 = 1.0f / d0[0];
|
|
c1 = 1.0f / d0[this->values.Num() - 2];
|
|
c[this->values.Num() - 1] = 3.0f * ( c0 * ( this->values[1] - this->values[0] ) - c1 * ( this->values[0] - this->values[this->values.Num() - 2] ) );
|
|
|
|
// solve system for each dimension
|
|
mat.LU_Factor( NULL );
|
|
for ( i = 0; i < this->values[0].GetDimension(); i++ ) {
|
|
for ( j = 0; j < this->values.Num(); j++ ) {
|
|
x[j] = c[j][i];
|
|
}
|
|
mat.LU_Solve( x, x, NULL );
|
|
for ( j = 0; j < this->values.Num(); j++ ) {
|
|
c[j][i] = x[j];
|
|
}
|
|
}
|
|
|
|
for ( i = 0; i < this->values.Num() - 1; i++ ) {
|
|
c0 = 1.0f / d0[i];
|
|
b[i] = c0 * ( this->values[i + 1] - this->values[i] ) - ( 1.0f / 3.0f ) * ( c[i+1] + 2.0f * c[i] ) * d0[i];
|
|
d[i] = ( 1.0f / 3.0f ) * c0 * ( c[i + 1] - c[i] );
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Uniform Cubic Interpolating Spline template.
|
|
The curve goes through all the knots.
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
template< class type >
|
|
class idCurve_CatmullRomSpline : public idCurve_Spline<type> {
|
|
|
|
public:
|
|
idCurve_CatmullRomSpline( void );
|
|
|
|
virtual type GetCurrentValue( const float time ) const;
|
|
virtual type GetCurrentFirstDerivative( const float time ) const;
|
|
virtual type GetCurrentSecondDerivative( const float time ) const;
|
|
|
|
protected:
|
|
void Basis( const int index, const float t, float *bvals ) const;
|
|
void BasisFirstDerivative( const int index, const float t, float *bvals ) const;
|
|
void BasisSecondDerivative( const int index, const float t, float *bvals ) const;
|
|
};
|
|
|
|
/*
|
|
====================
|
|
idCurve_CatmullRomSpline::idCurve_CatmullRomSpline
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE idCurve_CatmullRomSpline<type>::idCurve_CatmullRomSpline( void ) {
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_CatmullRomSpline::GetCurrentValue
|
|
|
|
get the value for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_CatmullRomSpline<type>::GetCurrentValue( const float time ) const {
|
|
int i, j, k;
|
|
float bvals[4], clampedTime;
|
|
type v;
|
|
|
|
if ( this->times.Num() == 1 ) {
|
|
return this->values[0];
|
|
}
|
|
|
|
clampedTime = this->ClampedTime( time );
|
|
i = this->IndexForTime( clampedTime );
|
|
Basis( i-1, clampedTime, bvals );
|
|
v = this->values[0] - this->values[0];
|
|
for ( j = 0; j < 4; j++ ) {
|
|
k = i + j - 2;
|
|
v += bvals[j] * this->ValueForIndex( k );
|
|
}
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_CatmullRomSpline::GetCurrentFirstDerivative
|
|
|
|
get the first derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_CatmullRomSpline<type>::GetCurrentFirstDerivative( const float time ) const {
|
|
int i, j, k;
|
|
float bvals[4], d, clampedTime;
|
|
type v;
|
|
|
|
if ( this->times.Num() == 1 ) {
|
|
return ( this->values[0] - this->values[0] );
|
|
}
|
|
|
|
clampedTime = this->ClampedTime( time );
|
|
i = this->IndexForTime( clampedTime );
|
|
BasisFirstDerivative( i-1, clampedTime, bvals );
|
|
v = this->values[0] - this->values[0];
|
|
for ( j = 0; j < 4; j++ ) {
|
|
k = i + j - 2;
|
|
v += bvals[j] * this->ValueForIndex( k );
|
|
}
|
|
d = ( this->TimeForIndex( i ) - this->TimeForIndex( i-1 ) );
|
|
return v / d;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_CatmullRomSpline::GetCurrentSecondDerivative
|
|
|
|
get the second derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_CatmullRomSpline<type>::GetCurrentSecondDerivative( const float time ) const {
|
|
int i, j, k;
|
|
float bvals[4], d, clampedTime;
|
|
type v;
|
|
|
|
if ( this->times.Num() == 1 ) {
|
|
return ( this->values[0] - this->values[0] );
|
|
}
|
|
|
|
clampedTime = this->ClampedTime( time );
|
|
i = this->IndexForTime( clampedTime );
|
|
BasisSecondDerivative( i-1, clampedTime, bvals );
|
|
v = this->values[0] - this->values[0];
|
|
for ( j = 0; j < 4; j++ ) {
|
|
k = i + j - 2;
|
|
v += bvals[j] * this->ValueForIndex( k );
|
|
}
|
|
d = ( this->TimeForIndex( i ) - this->TimeForIndex( i-1 ) );
|
|
return v / ( d * d );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_CatmullRomSpline::Basis
|
|
|
|
spline basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_CatmullRomSpline<type>::Basis( const int index, const float t, float *bvals ) const {
|
|
float s = (float) ( t - this->TimeForIndex( index ) ) / ( this->TimeForIndex( index+1 ) - this->TimeForIndex( index ) );
|
|
bvals[0] = ( ( -s + 2.0f ) * s - 1.0f ) * s * 0.5f; // -0.5f s * s * s + s * s - 0.5f * s
|
|
bvals[1] = ( ( ( 3.0f * s - 5.0f ) * s ) * s + 2.0f ) * 0.5f; // 1.5f * s * s * s - 2.5f * s * s + 1.0f
|
|
bvals[2] = ( ( -3.0f * s + 4.0f ) * s + 1.0f ) * s * 0.5f; // -1.5f * s * s * s - 2.0f * s * s + 0.5f s
|
|
bvals[3] = ( ( s - 1.0f ) * s * s ) * 0.5f; // 0.5f * s * s * s - 0.5f * s * s
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_CatmullRomSpline::BasisFirstDerivative
|
|
|
|
first derivative of spline basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_CatmullRomSpline<type>::BasisFirstDerivative( const int index, const float t, float *bvals ) const {
|
|
float s = (float) ( t - this->TimeForIndex( index ) ) / ( this->TimeForIndex( index+1 ) - this->TimeForIndex( index ) );
|
|
bvals[0] = ( -1.5f * s + 2.0f ) * s - 0.5f; // -1.5f * s * s + 2.0f * s - 0.5f
|
|
bvals[1] = ( 4.5f * s - 5.0f ) * s; // 4.5f * s * s - 5.0f * s
|
|
bvals[2] = ( -4.5 * s + 4.0f ) * s + 0.5f; // -4.5 * s * s + 4.0f * s + 0.5f
|
|
bvals[3] = 1.5f * s * s - s; // 1.5f * s * s - s
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_CatmullRomSpline::BasisSecondDerivative
|
|
|
|
second derivative of spline basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_CatmullRomSpline<type>::BasisSecondDerivative( const int index, const float t, float *bvals ) const {
|
|
float s = (float) ( t - this->TimeForIndex( index ) ) / ( this->TimeForIndex( index+1 ) - this->TimeForIndex( index ) );
|
|
bvals[0] = -3.0f * s + 2.0f;
|
|
bvals[1] = 9.0f * s - 5.0f;
|
|
bvals[2] = -9.0f * s + 4.0f;
|
|
bvals[3] = 3.0f * s - 1.0f;
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Cubic Interpolating Spline template.
|
|
The curve goes through all the knots.
|
|
The curve becomes the Catmull-Rom spline if the tension,
|
|
continuity and bias are all set to zero.
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
template< class type >
|
|
class idCurve_KochanekBartelsSpline : public idCurve_Spline<type> {
|
|
|
|
public:
|
|
idCurve_KochanekBartelsSpline( void );
|
|
|
|
virtual int AddValue( const float time, const type &value );
|
|
virtual int AddValue( const float time, const type &value, const float tension, const float continuity, const float bias );
|
|
virtual void RemoveIndex( const int index ) { this->values.RemoveIndex(index); this->times.RemoveIndex(index); tension.RemoveIndex(index); continuity.RemoveIndex(index); bias.RemoveIndex(index); }
|
|
virtual void Clear( void ) { this->values.Clear(); this->times.Clear(); tension.Clear(); continuity.Clear(); bias.Clear(); this->currentIndex = -1; }
|
|
|
|
virtual type GetCurrentValue( const float time ) const;
|
|
virtual type GetCurrentFirstDerivative( const float time ) const;
|
|
virtual type GetCurrentSecondDerivative( const float time ) const;
|
|
|
|
protected:
|
|
idList<float> tension;
|
|
idList<float> continuity;
|
|
idList<float> bias;
|
|
|
|
void TangentsForIndex( const int index, type &t0, type &t1 ) const;
|
|
|
|
void Basis( const int index, const float t, float *bvals ) const;
|
|
void BasisFirstDerivative( const int index, const float t, float *bvals ) const;
|
|
void BasisSecondDerivative( const int index, const float t, float *bvals ) const;
|
|
};
|
|
|
|
/*
|
|
====================
|
|
idCurve_KochanekBartelsSpline::idCurve_KochanekBartelsSpline
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE idCurve_KochanekBartelsSpline<type>::idCurve_KochanekBartelsSpline( void ) {
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_KochanekBartelsSpline::AddValue
|
|
|
|
add a timed/value pair to the spline
|
|
returns the index to the inserted pair
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE int idCurve_KochanekBartelsSpline<type>::AddValue( const float time, const type &value ) {
|
|
int i;
|
|
|
|
i = this->IndexForTime( time );
|
|
this->times.Insert( time, i );
|
|
this->values.Insert( value, i );
|
|
tension.Insert( 0.0f, i );
|
|
continuity.Insert( 0.0f, i );
|
|
bias.Insert( 0.0f, i );
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_KochanekBartelsSpline::AddValue
|
|
|
|
add a timed/value pair to the spline
|
|
returns the index to the inserted pair
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE int idCurve_KochanekBartelsSpline<type>::AddValue( const float time, const type &value, const float tension, const float continuity, const float bias ) {
|
|
int i;
|
|
|
|
i = this->IndexForTime( time );
|
|
this->times.Insert( time, i );
|
|
this->values.Insert( value, i );
|
|
this->tension.Insert( tension, i );
|
|
this->continuity.Insert( continuity, i );
|
|
this->bias.Insert( bias, i );
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_KochanekBartelsSpline::GetCurrentValue
|
|
|
|
get the value for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_KochanekBartelsSpline<type>::GetCurrentValue( const float time ) const {
|
|
int i;
|
|
float bvals[4], clampedTime;
|
|
type v, t0, t1;
|
|
|
|
if ( this->times.Num() == 1 ) {
|
|
return this->values[0];
|
|
}
|
|
|
|
clampedTime = this->ClampedTime( time );
|
|
i = this->IndexForTime( clampedTime );
|
|
TangentsForIndex( i - 1, t0, t1 );
|
|
Basis( i - 1, clampedTime, bvals );
|
|
v = bvals[0] * this->ValueForIndex( i - 1 );
|
|
v += bvals[1] * this->ValueForIndex( i );
|
|
v += bvals[2] * t0;
|
|
v += bvals[3] * t1;
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_KochanekBartelsSpline::GetCurrentFirstDerivative
|
|
|
|
get the first derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_KochanekBartelsSpline<type>::GetCurrentFirstDerivative( const float time ) const {
|
|
int i;
|
|
float bvals[4], d, clampedTime;
|
|
type v, t0, t1;
|
|
|
|
if ( this->times.Num() == 1 ) {
|
|
return ( this->values[0] - this->values[0] );
|
|
}
|
|
|
|
clampedTime = this->ClampedTime( time );
|
|
i = this->IndexForTime( clampedTime );
|
|
TangentsForIndex( i - 1, t0, t1 );
|
|
BasisFirstDerivative( i - 1, clampedTime, bvals );
|
|
v = bvals[0] * this->ValueForIndex( i - 1 );
|
|
v += bvals[1] * this->ValueForIndex( i );
|
|
v += bvals[2] * t0;
|
|
v += bvals[3] * t1;
|
|
d = ( this->TimeForIndex( i ) - this->TimeForIndex( i-1 ) );
|
|
return v / d;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_KochanekBartelsSpline::GetCurrentSecondDerivative
|
|
|
|
get the second derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_KochanekBartelsSpline<type>::GetCurrentSecondDerivative( const float time ) const {
|
|
int i;
|
|
float bvals[4], d, clampedTime;
|
|
type v, t0, t1;
|
|
|
|
if ( this->times.Num() == 1 ) {
|
|
return ( this->values[0] - this->values[0] );
|
|
}
|
|
|
|
clampedTime = this->ClampedTime( time );
|
|
i = this->IndexForTime( clampedTime );
|
|
TangentsForIndex( i - 1, t0, t1 );
|
|
BasisSecondDerivative( i - 1, clampedTime, bvals );
|
|
v = bvals[0] * this->ValueForIndex( i - 1 );
|
|
v += bvals[1] * this->ValueForIndex( i );
|
|
v += bvals[2] * t0;
|
|
v += bvals[3] * t1;
|
|
d = ( this->TimeForIndex( i ) - this->TimeForIndex( i-1 ) );
|
|
return v / ( d * d );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_KochanekBartelsSpline::TangentsForIndex
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_KochanekBartelsSpline<type>::TangentsForIndex( const int index, type &t0, type &t1 ) const {
|
|
float dt, omt, omc, opc, omb, opb, adj, s0, s1;
|
|
type delta;
|
|
|
|
delta = this->ValueForIndex( index + 1 ) - this->ValueForIndex( index );
|
|
dt = this->TimeForIndex( index + 1 ) - this->TimeForIndex( index );
|
|
|
|
omt = 1.0f - tension[index];
|
|
omc = 1.0f - continuity[index];
|
|
opc = 1.0f + continuity[index];
|
|
omb = 1.0f - bias[index];
|
|
opb = 1.0f + bias[index];
|
|
adj = 2.0f * dt / ( this->TimeForIndex( index + 1 ) - this->TimeForIndex( index - 1 ) );
|
|
s0 = 0.5f * adj * omt * opc * opb;
|
|
s1 = 0.5f * adj * omt * omc * omb;
|
|
|
|
// outgoing tangent at first point
|
|
t0 = s1 * delta + s0 * ( this->ValueForIndex( index ) - this->ValueForIndex( index - 1 ) );
|
|
|
|
omt = 1.0f - tension[index + 1];
|
|
omc = 1.0f - continuity[index + 1];
|
|
opc = 1.0f + continuity[index + 1];
|
|
omb = 1.0f - bias[index + 1];
|
|
opb = 1.0f + bias[index + 1];
|
|
adj = 2.0f * dt / ( this->TimeForIndex( index + 2 ) - this->TimeForIndex( index ) );
|
|
s0 = 0.5f * adj * omt * omc * opb;
|
|
s1 = 0.5f * adj * omt * opc * omb;
|
|
|
|
// incoming tangent at second point
|
|
t1 = s1 * ( this->ValueForIndex( index + 2 ) - this->ValueForIndex( index + 1 ) ) + s0 * delta;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_KochanekBartelsSpline::Basis
|
|
|
|
spline basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_KochanekBartelsSpline<type>::Basis( const int index, const float t, float *bvals ) const {
|
|
float s = (float) ( t - this->TimeForIndex( index ) ) / ( this->TimeForIndex( index+1 ) - this->TimeForIndex( index ) );
|
|
bvals[0] = ( ( 2.0f * s - 3.0f ) * s ) * s + 1.0f; // 2.0f * s * s * s - 3.0f * s * s + 1.0f
|
|
bvals[1] = ( ( -2.0f * s + 3.0f ) * s ) * s; // -2.0f * s * s * s + 3.0f * s * s
|
|
bvals[2] = ( ( s - 2.0f ) * s ) * s + s; // s * s * s - 2.0f * s * s + s
|
|
bvals[3] = ( ( s - 1.0f ) * s ) * s; // s * s * s - s * s
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_KochanekBartelsSpline::BasisFirstDerivative
|
|
|
|
first derivative of spline basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_KochanekBartelsSpline<type>::BasisFirstDerivative( const int index, const float t, float *bvals ) const {
|
|
float s = (float) ( t - this->TimeForIndex( index ) ) / ( this->TimeForIndex( index+1 ) - this->TimeForIndex( index ) );
|
|
bvals[0] = ( 6.0f * s - 6.0f ) * s; // 6.0f * s * s - 6.0f * s
|
|
bvals[1] = ( -6.0f * s + 6.0f ) * s; // -6.0f * s * s + 6.0f * s
|
|
bvals[2] = ( 3.0f * s - 4.0f ) * s + 1.0f; // 3.0f * s * s - 4.0f * s + 1.0f
|
|
bvals[3] = ( 3.0f * s - 2.0f ) * s; // 3.0f * s * s - 2.0f * s
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_KochanekBartelsSpline::BasisSecondDerivative
|
|
|
|
second derivative of spline basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_KochanekBartelsSpline<type>::BasisSecondDerivative( const int index, const float t, float *bvals ) const {
|
|
float s = (float) ( t - this->TimeForIndex( index ) ) / ( this->TimeForIndex( index+1 ) - this->TimeForIndex( index ) );
|
|
bvals[0] = 12.0f * s - 6.0f;
|
|
bvals[1] = -12.0f * s + 6.0f;
|
|
bvals[2] = 6.0f * s - 4.0f;
|
|
bvals[3] = 6.0f * s - 2.0f;
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
B-Spline base template. Uses recursive definition and is slow.
|
|
Use idCurve_UniformCubicBSpline or idCurve_NonUniformBSpline instead.
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
template< class type >
|
|
class idCurve_BSpline : public idCurve_Spline<type> {
|
|
|
|
public:
|
|
idCurve_BSpline( void );
|
|
|
|
virtual int GetOrder( void ) const { return order; }
|
|
virtual void SetOrder( const int i ) { assert( i > 0 && i < 10 ); order = i; }
|
|
|
|
virtual type GetCurrentValue( const float time ) const;
|
|
virtual type GetCurrentFirstDerivative( const float time ) const;
|
|
virtual type GetCurrentSecondDerivative( const float time ) const;
|
|
|
|
protected:
|
|
int order;
|
|
|
|
float Basis( const int index, const int order, const float t ) const;
|
|
float BasisFirstDerivative( const int index, const int order, const float t ) const;
|
|
float BasisSecondDerivative( const int index, const int order, const float t ) const;
|
|
};
|
|
|
|
/*
|
|
====================
|
|
idCurve_BSpline::idCurve_NaturalCubicSpline
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE idCurve_BSpline<type>::idCurve_BSpline( void ) {
|
|
order = 4; // default to cubic
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_BSpline::GetCurrentValue
|
|
|
|
get the value for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_BSpline<type>::GetCurrentValue( const float time ) const {
|
|
int i, j, k;
|
|
float clampedTime;
|
|
type v;
|
|
|
|
if ( this->times.Num() == 1 ) {
|
|
return this->values[0];
|
|
}
|
|
|
|
clampedTime = this->ClampedTime( time );
|
|
i = this->IndexForTime( clampedTime );
|
|
v = this->values[0] - this->values[0];
|
|
for ( j = 0; j < order; j++ ) {
|
|
k = i + j - ( order >> 1 );
|
|
v += Basis( k-2, order, clampedTime ) * this->ValueForIndex( k );
|
|
}
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_BSpline::GetCurrentFirstDerivative
|
|
|
|
get the first derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_BSpline<type>::GetCurrentFirstDerivative( const float time ) const {
|
|
int i, j, k;
|
|
float clampedTime;
|
|
type v;
|
|
|
|
if ( this->times.Num() == 1 ) {
|
|
return this->values[0];
|
|
}
|
|
|
|
clampedTime = this->ClampedTime( time );
|
|
i = this->IndexForTime( clampedTime );
|
|
v = this->values[0] - this->values[0];
|
|
for ( j = 0; j < order; j++ ) {
|
|
k = i + j - ( order >> 1 );
|
|
v += BasisFirstDerivative( k-2, order, clampedTime ) * this->ValueForIndex( k );
|
|
}
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_BSpline::GetCurrentSecondDerivative
|
|
|
|
get the second derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_BSpline<type>::GetCurrentSecondDerivative( const float time ) const {
|
|
int i, j, k;
|
|
float clampedTime;
|
|
type v;
|
|
|
|
if ( this->times.Num() == 1 ) {
|
|
return this->values[0];
|
|
}
|
|
|
|
clampedTime = this->ClampedTime( time );
|
|
i = this->IndexForTime( clampedTime );
|
|
v = this->values[0] - this->values[0];
|
|
for ( j = 0; j < order; j++ ) {
|
|
k = i + j - ( order >> 1 );
|
|
v += BasisSecondDerivative( k-2, order, clampedTime ) * this->ValueForIndex( k );
|
|
}
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_BSpline::Basis
|
|
|
|
spline basis function
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE float idCurve_BSpline<type>::Basis( const int index, const int order, const float t ) const {
|
|
if ( order <= 1 ) {
|
|
if ( this->TimeForIndex( index ) < t && t <= this->TimeForIndex( index + 1 ) ) {
|
|
return 1.0f;
|
|
} else {
|
|
return 0.0f;
|
|
}
|
|
} else {
|
|
float sum = 0.0f;
|
|
float d1 = this->TimeForIndex( index+order-1 ) - this->TimeForIndex( index );
|
|
if ( d1 != 0.0f ) {
|
|
sum += (float) ( t - this->TimeForIndex( index ) ) * Basis( index, order-1, t ) / d1;
|
|
}
|
|
|
|
float d2 = this->TimeForIndex( index+order ) - this->TimeForIndex( index+1 );
|
|
if ( d2 != 0.0f ) {
|
|
sum += (float) ( this->TimeForIndex( index+order ) - t ) * Basis( index+1, order-1, t ) / d2;
|
|
}
|
|
return sum;
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_BSpline::BasisFirstDerivative
|
|
|
|
first derivative of spline basis function
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE float idCurve_BSpline<type>::BasisFirstDerivative( const int index, const int order, const float t ) const {
|
|
return ( Basis( index, order-1, t ) - Basis( index+1, order-1, t ) ) *
|
|
(float) ( order - 1 ) / ( this->TimeForIndex( index + ( order - 1 ) - 2 ) - this->TimeForIndex( index - 2 ) );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_BSpline::BasisSecondDerivative
|
|
|
|
second derivative of spline basis function
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE float idCurve_BSpline<type>::BasisSecondDerivative( const int index, const int order, const float t ) const {
|
|
return ( BasisFirstDerivative( index, order-1, t ) - BasisFirstDerivative( index+1, order-1, t ) ) *
|
|
(float) ( order - 1 ) / ( this->TimeForIndex( index + ( order - 1 ) - 2 ) - this->TimeForIndex( index - 2 ) );
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Uniform Non-Rational Cubic B-Spline template.
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
template< class type >
|
|
class idCurve_UniformCubicBSpline : public idCurve_BSpline<type> {
|
|
|
|
public:
|
|
idCurve_UniformCubicBSpline( void );
|
|
|
|
virtual type GetCurrentValue( const float time ) const;
|
|
virtual type GetCurrentFirstDerivative( const float time ) const;
|
|
virtual type GetCurrentSecondDerivative( const float time ) const;
|
|
|
|
protected:
|
|
void Basis( const int index, const float t, float *bvals ) const;
|
|
void BasisFirstDerivative( const int index, const float t, float *bvals ) const;
|
|
void BasisSecondDerivative( const int index, const float t, float *bvals ) const;
|
|
};
|
|
|
|
/*
|
|
====================
|
|
idCurve_UniformCubicBSpline::idCurve_UniformCubicBSpline
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE idCurve_UniformCubicBSpline<type>::idCurve_UniformCubicBSpline( void ) {
|
|
this->order = 4; // always cubic
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_UniformCubicBSpline::GetCurrentValue
|
|
|
|
get the value for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_UniformCubicBSpline<type>::GetCurrentValue( const float time ) const {
|
|
int i, j, k;
|
|
float bvals[4], clampedTime;
|
|
type v;
|
|
|
|
if ( this->times.Num() == 1 ) {
|
|
return this->values[0];
|
|
}
|
|
|
|
clampedTime = this->ClampedTime( time );
|
|
i = this->IndexForTime( clampedTime );
|
|
Basis( i-1, clampedTime, bvals );
|
|
v = this->values[0] - this->values[0];
|
|
for ( j = 0; j < 4; j++ ) {
|
|
k = i + j - 2;
|
|
v += bvals[j] * this->ValueForIndex( k );
|
|
}
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_UniformCubicBSpline::GetCurrentFirstDerivative
|
|
|
|
get the first derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_UniformCubicBSpline<type>::GetCurrentFirstDerivative( const float time ) const {
|
|
int i, j, k;
|
|
float bvals[4], d, clampedTime;
|
|
type v;
|
|
|
|
if ( this->times.Num() == 1 ) {
|
|
return ( this->values[0] - this->values[0] );
|
|
}
|
|
|
|
clampedTime = this->ClampedTime( time );
|
|
i = this->IndexForTime( clampedTime );
|
|
BasisFirstDerivative( i-1, clampedTime, bvals );
|
|
v = this->values[0] - this->values[0];
|
|
for ( j = 0; j < 4; j++ ) {
|
|
k = i + j - 2;
|
|
v += bvals[j] * this->ValueForIndex( k );
|
|
}
|
|
d = ( this->TimeForIndex( i ) - this->TimeForIndex( i-1 ) );
|
|
return v / d;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_UniformCubicBSpline::GetCurrentSecondDerivative
|
|
|
|
get the second derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_UniformCubicBSpline<type>::GetCurrentSecondDerivative( const float time ) const {
|
|
int i, j, k;
|
|
float bvals[4], d, clampedTime;
|
|
type v;
|
|
|
|
if ( this->times.Num() == 1 ) {
|
|
return ( this->values[0] - this->values[0] );
|
|
}
|
|
|
|
clampedTime = this->ClampedTime( time );
|
|
i = this->IndexForTime( clampedTime );
|
|
BasisSecondDerivative( i-1, clampedTime, bvals );
|
|
v = this->values[0] - this->values[0];
|
|
for ( j = 0; j < 4; j++ ) {
|
|
k = i + j - 2;
|
|
v += bvals[j] * this->ValueForIndex( k );
|
|
}
|
|
d = ( this->TimeForIndex( i ) - this->TimeForIndex( i-1 ) );
|
|
return v / ( d * d );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_UniformCubicBSpline::Basis
|
|
|
|
spline basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_UniformCubicBSpline<type>::Basis( const int index, const float t, float *bvals ) const {
|
|
float s = (float) ( t - this->TimeForIndex( index ) ) / ( this->TimeForIndex( index+1 ) - this->TimeForIndex( index ) );
|
|
bvals[0] = ( ( ( -s + 3.0f ) * s - 3.0f ) * s + 1.0f ) * ( 1.0f / 6.0f );
|
|
bvals[1] = ( ( ( 3.0f * s - 6.0f ) * s ) * s + 4.0f ) * ( 1.0f / 6.0f );
|
|
bvals[2] = ( ( ( -3.0f * s + 3.0f ) * s + 3.0f ) * s + 1.0f ) * ( 1.0f / 6.0f );
|
|
bvals[3] = ( s * s * s ) * ( 1.0f / 6.0f );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_UniformCubicBSpline::BasisFirstDerivative
|
|
|
|
first derivative of spline basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_UniformCubicBSpline<type>::BasisFirstDerivative( const int index, const float t, float *bvals ) const {
|
|
float s = (float) ( t - this->TimeForIndex( index ) ) / ( this->TimeForIndex( index+1 ) - this->TimeForIndex( index ) );
|
|
bvals[0] = -0.5f * s * s + s - 0.5f;
|
|
bvals[1] = 1.5f * s * s - 2.0f * s;
|
|
bvals[2] = -1.5f * s * s + s + 0.5f;
|
|
bvals[3] = 0.5f * s * s;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_UniformCubicBSpline::BasisSecondDerivative
|
|
|
|
second derivative of spline basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_UniformCubicBSpline<type>::BasisSecondDerivative( const int index, const float t, float *bvals ) const {
|
|
float s = (float) ( t - this->TimeForIndex( index ) ) / ( this->TimeForIndex( index+1 ) - this->TimeForIndex( index ) );
|
|
bvals[0] = -s + 1.0f;
|
|
bvals[1] = 3.0f * s - 2.0f;
|
|
bvals[2] = -3.0f * s + 1.0f;
|
|
bvals[3] = s;
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Non-Uniform Non-Rational B-Spline (NUBS) template.
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
template< class type >
|
|
class idCurve_NonUniformBSpline : public idCurve_BSpline<type> {
|
|
|
|
public:
|
|
idCurve_NonUniformBSpline( void );
|
|
|
|
virtual type GetCurrentValue( const float time ) const;
|
|
virtual type GetCurrentFirstDerivative( const float time ) const;
|
|
virtual type GetCurrentSecondDerivative( const float time ) const;
|
|
|
|
protected:
|
|
void Basis( const int index, const int order, const float t, float *bvals ) const;
|
|
void BasisFirstDerivative( const int index, const int order, const float t, float *bvals ) const;
|
|
void BasisSecondDerivative( const int index, const int order, const float t, float *bvals ) const;
|
|
};
|
|
|
|
/*
|
|
====================
|
|
idCurve_NonUniformBSpline::idCurve_NonUniformBSpline
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE idCurve_NonUniformBSpline<type>::idCurve_NonUniformBSpline( void ) {
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_NonUniformBSpline::GetCurrentValue
|
|
|
|
get the value for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_NonUniformBSpline<type>::GetCurrentValue( const float time ) const {
|
|
int i, j, k;
|
|
float clampedTime;
|
|
type v;
|
|
float *bvals = (float *) _alloca16( this->order * sizeof(float) );
|
|
|
|
if ( this->times.Num() == 1 ) {
|
|
return this->values[0];
|
|
}
|
|
|
|
clampedTime = this->ClampedTime( time );
|
|
i = this->IndexForTime( clampedTime );
|
|
Basis( i-1, this->order, clampedTime, bvals );
|
|
v = this->values[0] - this->values[0];
|
|
for ( j = 0; j < this->order; j++ ) {
|
|
k = i + j - ( this->order >> 1 );
|
|
v += bvals[j] * this->ValueForIndex( k );
|
|
}
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_NonUniformBSpline::GetCurrentFirstDerivative
|
|
|
|
get the first derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_NonUniformBSpline<type>::GetCurrentFirstDerivative( const float time ) const {
|
|
int i, j, k;
|
|
float clampedTime;
|
|
type v;
|
|
float *bvals = (float *) _alloca16( this->order * sizeof(float) );
|
|
|
|
if ( this->times.Num() == 1 ) {
|
|
return ( this->values[0] - this->values[0] );
|
|
}
|
|
|
|
clampedTime = this->ClampedTime( time );
|
|
i = this->IndexForTime( clampedTime );
|
|
BasisFirstDerivative( i-1, this->order, clampedTime, bvals );
|
|
v = this->values[0] - this->values[0];
|
|
for ( j = 0; j < this->order; j++ ) {
|
|
k = i + j - ( this->order >> 1 );
|
|
v += bvals[j] * this->ValueForIndex( k );
|
|
}
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_NonUniformBSpline::GetCurrentSecondDerivative
|
|
|
|
get the second derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_NonUniformBSpline<type>::GetCurrentSecondDerivative( const float time ) const {
|
|
int i, j, k;
|
|
float clampedTime;
|
|
type v;
|
|
float *bvals = (float *) _alloca16( this->order * sizeof(float) );
|
|
|
|
if ( this->times.Num() == 1 ) {
|
|
return ( this->values[0] - this->values[0] );
|
|
}
|
|
|
|
clampedTime = this->ClampedTime( time );
|
|
i = this->IndexForTime( clampedTime );
|
|
BasisSecondDerivative( i-1, this->order, clampedTime, bvals );
|
|
v = this->values[0] - this->values[0];
|
|
for ( j = 0; j < this->order; j++ ) {
|
|
k = i + j - ( this->order >> 1 );
|
|
v += bvals[j] * this->ValueForIndex( k );
|
|
}
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_NonUniformBSpline::Basis
|
|
|
|
spline basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_NonUniformBSpline<type>::Basis( const int index, const int order, const float t, float *bvals ) const {
|
|
int r, s, i;
|
|
float omega;
|
|
|
|
bvals[order-1] = 1.0f;
|
|
for ( r = 2; r <= order; r++ ) {
|
|
i = index - r + 1;
|
|
bvals[order - r] = 0.0f;
|
|
for ( s = order - r + 1; s < order; s++ ) {
|
|
i++;
|
|
omega = (float) ( t - this->TimeForIndex( i ) ) / ( this->TimeForIndex( i + r - 1 ) - this->TimeForIndex( i ) );
|
|
bvals[s - 1] += ( 1.0f - omega ) * bvals[s];
|
|
bvals[s] *= omega;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_NonUniformBSpline::BasisFirstDerivative
|
|
|
|
first derivative of spline basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_NonUniformBSpline<type>::BasisFirstDerivative( const int index, const int order, const float t, float *bvals ) const {
|
|
int i;
|
|
|
|
Basis( index, order-1, t, bvals+1 );
|
|
bvals[0] = 0.0f;
|
|
for ( i = 0; i < order-1; i++ ) {
|
|
bvals[i] -= bvals[i+1];
|
|
bvals[i] *= (float) ( order - 1) / ( this->TimeForIndex( index + i + (order-1) - 2 ) - this->TimeForIndex( index + i - 2 ) );
|
|
}
|
|
bvals[i] *= (float) ( order - 1) / ( this->TimeForIndex( index + i + (order-1) - 2 ) - this->TimeForIndex( index + i - 2 ) );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_NonUniformBSpline::BasisSecondDerivative
|
|
|
|
second derivative of spline basis functions
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE void idCurve_NonUniformBSpline<type>::BasisSecondDerivative( const int index, const int order, const float t, float *bvals ) const {
|
|
int i;
|
|
|
|
BasisFirstDerivative( index, order-1, t, bvals+1 );
|
|
bvals[0] = 0.0f;
|
|
for ( i = 0; i < order-1; i++ ) {
|
|
bvals[i] -= bvals[i+1];
|
|
bvals[i] *= (float) ( order - 1) / ( this->TimeForIndex( index + i + (order-1) - 2 ) - this->TimeForIndex( index + i - 2 ) );
|
|
}
|
|
bvals[i] *= (float) ( order - 1) / ( this->TimeForIndex( index + i + (order-1) - 2 ) - this->TimeForIndex( index + i - 2 ) );
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Non-Uniform Rational B-Spline (NURBS) template.
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
template< class type >
|
|
class idCurve_NURBS : public idCurve_NonUniformBSpline<type> {
|
|
|
|
public:
|
|
idCurve_NURBS( void );
|
|
|
|
virtual int AddValue( const float time, const type &value );
|
|
virtual int AddValue( const float time, const type &value, const float weight );
|
|
virtual void RemoveIndex( const int index ) { this->values.RemoveIndex(index); this->times.RemoveIndex(index); weights.RemoveIndex(index); }
|
|
virtual void Clear( void ) { this->values.Clear(); this->times.Clear(); weights.Clear(); this->currentIndex = -1; }
|
|
|
|
virtual type GetCurrentValue( const float time ) const;
|
|
virtual type GetCurrentFirstDerivative( const float time ) const;
|
|
virtual type GetCurrentSecondDerivative( const float time ) const;
|
|
|
|
protected:
|
|
idList<float> weights;
|
|
|
|
float WeightForIndex( const int index ) const;
|
|
};
|
|
|
|
/*
|
|
====================
|
|
idCurve_NURBS::idCurve_NURBS
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE idCurve_NURBS<type>::idCurve_NURBS( void ) {
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_NURBS::AddValue
|
|
|
|
add a timed/value pair to the spline
|
|
returns the index to the inserted pair
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE int idCurve_NURBS<type>::AddValue( const float time, const type &value ) {
|
|
int i;
|
|
|
|
i = this->IndexForTime( time );
|
|
this->times.Insert( time, i );
|
|
this->values.Insert( value, i );
|
|
weights.Insert( 1.0f, i );
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_NURBS::AddValue
|
|
|
|
add a timed/value pair to the spline
|
|
returns the index to the inserted pair
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE int idCurve_NURBS<type>::AddValue( const float time, const type &value, const float weight ) {
|
|
int i;
|
|
|
|
i = this->IndexForTime( time );
|
|
this->times.Insert( time, i );
|
|
this->values.Insert( value, i );
|
|
weights.Insert( weight, i );
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_NURBS::GetCurrentValue
|
|
|
|
get the value for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_NURBS<type>::GetCurrentValue( const float time ) const {
|
|
int i, j, k;
|
|
float w, b, *bvals, clampedTime;
|
|
type v;
|
|
|
|
if ( this->times.Num() == 1 ) {
|
|
return this->values[0];
|
|
}
|
|
|
|
bvals = (float *) _alloca16( this->order * sizeof(float) );
|
|
|
|
clampedTime = this->ClampedTime( time );
|
|
i = this->IndexForTime( clampedTime );
|
|
this->Basis( i-1, this->order, clampedTime, bvals );
|
|
v = this->values[0] - this->values[0];
|
|
w = 0.0f;
|
|
for ( j = 0; j < this->order; j++ ) {
|
|
k = i + j - ( this->order >> 1 );
|
|
b = bvals[j] * WeightForIndex( k );
|
|
w += b;
|
|
v += b * this->ValueForIndex( k );
|
|
}
|
|
return v / w;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_NURBS::GetCurrentFirstDerivative
|
|
|
|
get the first derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_NURBS<type>::GetCurrentFirstDerivative( const float time ) const {
|
|
int i, j, k;
|
|
float w, wb, wd1, b, d1, *bvals, *d1vals, clampedTime;
|
|
type v, vb, vd1;
|
|
|
|
if ( this->times.Num() == 1 ) {
|
|
return this->values[0];
|
|
}
|
|
|
|
bvals = (float *) _alloca16( this->order * sizeof(float) );
|
|
d1vals = (float *) _alloca16( this->order * sizeof(float) );
|
|
|
|
clampedTime = this->ClampedTime( time );
|
|
i = this->IndexForTime( clampedTime );
|
|
this->Basis( i-1, this->order, clampedTime, bvals );
|
|
this->BasisFirstDerivative( i-1, this->order, clampedTime, d1vals );
|
|
vb = vd1 = this->values[0] - this->values[0];
|
|
wb = wd1 = 0.0f;
|
|
for ( j = 0; j < this->order; j++ ) {
|
|
k = i + j - ( this->order >> 1 );
|
|
w = WeightForIndex( k );
|
|
b = bvals[j] * w;
|
|
d1 = d1vals[j] * w;
|
|
wb += b;
|
|
wd1 += d1;
|
|
v = this->ValueForIndex( k );
|
|
vb += b * v;
|
|
vd1 += d1 * v;
|
|
}
|
|
return ( wb * vd1 - vb * wd1 ) / ( wb * wb );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_NURBS::GetCurrentSecondDerivative
|
|
|
|
get the second derivative for the given time
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE type idCurve_NURBS<type>::GetCurrentSecondDerivative( const float time ) const {
|
|
int i, j, k;
|
|
float w, wb, wd1, wd2, b, d1, d2, *bvals, *d1vals, *d2vals, clampedTime;
|
|
type v, vb, vd1, vd2;
|
|
|
|
if ( this->times.Num() == 1 ) {
|
|
return this->values[0];
|
|
}
|
|
|
|
bvals = (float *) _alloca16( this->order * sizeof(float) );
|
|
d1vals = (float *) _alloca16( this->order * sizeof(float) );
|
|
d2vals = (float *) _alloca16( this->order * sizeof(float) );
|
|
|
|
clampedTime = this->ClampedTime( time );
|
|
i = this->IndexForTime( clampedTime );
|
|
this->Basis( i-1, this->order, clampedTime, bvals );
|
|
this->BasisFirstDerivative( i-1, this->order, clampedTime, d1vals );
|
|
this->BasisSecondDerivative( i-1, this->order, clampedTime, d2vals );
|
|
vb = vd1 = vd2 = this->values[0] - this->values[0];
|
|
wb = wd1 = wd2 = 0.0f;
|
|
for ( j = 0; j < this->order; j++ ) {
|
|
k = i + j - ( this->order >> 1 );
|
|
w = WeightForIndex( k );
|
|
b = bvals[j] * w;
|
|
d1 = d1vals[j] * w;
|
|
d2 = d2vals[j] * w;
|
|
wb += b;
|
|
wd1 += d1;
|
|
wd2 += d2;
|
|
v = this->ValueForIndex( k );
|
|
vb += b * v;
|
|
vd1 += d1 * v;
|
|
vd2 += d2 * v;
|
|
}
|
|
return ( ( wb * wb ) * ( wb * vd2 - vb * wd2 ) - ( wb * vd1 - vb * wd1 ) * 2.0f * wb * wd1 ) / ( wb * wb * wb * wb );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idCurve_NURBS::WeightForIndex
|
|
|
|
get the weight for the given index
|
|
====================
|
|
*/
|
|
template< class type >
|
|
ID_INLINE float idCurve_NURBS<type>::WeightForIndex( const int index ) const {
|
|
int n = weights.Num()-1;
|
|
|
|
if ( index < 0 ) {
|
|
if ( this->boundaryType == idCurve_Spline<type>::BT_CLOSED ) {
|
|
return weights[ weights.Num() + index % weights.Num() ];
|
|
} else {
|
|
return weights[0] + index * ( weights[1] - weights[0] );
|
|
}
|
|
} else if ( index > n ) {
|
|
if ( this->boundaryType == idCurve_Spline<type>::BT_CLOSED ) {
|
|
return weights[ index % weights.Num() ];
|
|
} else {
|
|
return weights[n] + ( index - n ) * ( weights[n] - weights[n-1] );
|
|
}
|
|
}
|
|
return weights[index];
|
|
}
|
|
|
|
#endif /* !__MATH_CURVE_H__ */
|