Spaces:
Running
Running
import { ZeroCurvatureEnding } from '../../constants.js'; | |
import { Interpolant } from '../Interpolant.js'; | |
import { WrapAroundEnding, ZeroSlopeEnding } from '../../constants.js'; | |
/** | |
* Fast and simple cubic spline interpolant. | |
* | |
* It was derived from a Hermitian construction setting the first derivative | |
* at each sample position to the linear slope between neighboring positions | |
* over their parameter interval. | |
* | |
* @author tschw | |
*/ | |
function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { | |
Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); | |
this._weightPrev = - 0; | |
this._offsetPrev = - 0; | |
this._weightNext = - 0; | |
this._offsetNext = - 0; | |
} | |
CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { | |
constructor: CubicInterpolant, | |
DefaultSettings_: { | |
endingStart: ZeroCurvatureEnding, | |
endingEnd: ZeroCurvatureEnding | |
}, | |
intervalChanged_: function ( i1, t0, t1 ) { | |
var pp = this.parameterPositions, | |
iPrev = i1 - 2, | |
iNext = i1 + 1, | |
tPrev = pp[ iPrev ], | |
tNext = pp[ iNext ]; | |
if ( tPrev === undefined ) { | |
switch ( this.getSettings_().endingStart ) { | |
case ZeroSlopeEnding: | |
// f'(t0) = 0 | |
iPrev = i1; | |
tPrev = 2 * t0 - t1; | |
break; | |
case WrapAroundEnding: | |
// use the other end of the curve | |
iPrev = pp.length - 2; | |
tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; | |
break; | |
default: // ZeroCurvatureEnding | |
// f''(t0) = 0 a.k.a. Natural Spline | |
iPrev = i1; | |
tPrev = t1; | |
} | |
} | |
if ( tNext === undefined ) { | |
switch ( this.getSettings_().endingEnd ) { | |
case ZeroSlopeEnding: | |
// f'(tN) = 0 | |
iNext = i1; | |
tNext = 2 * t1 - t0; | |
break; | |
case WrapAroundEnding: | |
// use the other end of the curve | |
iNext = 1; | |
tNext = t1 + pp[ 1 ] - pp[ 0 ]; | |
break; | |
default: // ZeroCurvatureEnding | |
// f''(tN) = 0, a.k.a. Natural Spline | |
iNext = i1 - 1; | |
tNext = t0; | |
} | |
} | |
var halfDt = ( t1 - t0 ) * 0.5, | |
stride = this.valueSize; | |
this._weightPrev = halfDt / ( t0 - tPrev ); | |
this._weightNext = halfDt / ( tNext - t1 ); | |
this._offsetPrev = iPrev * stride; | |
this._offsetNext = iNext * stride; | |
}, | |
interpolate_: function ( i1, t0, t, t1 ) { | |
var result = this.resultBuffer, | |
values = this.sampleValues, | |
stride = this.valueSize, | |
o1 = i1 * stride, o0 = o1 - stride, | |
oP = this._offsetPrev, oN = this._offsetNext, | |
wP = this._weightPrev, wN = this._weightNext, | |
p = ( t - t0 ) / ( t1 - t0 ), | |
pp = p * p, | |
ppp = pp * p; | |
// evaluate polynomials | |
var sP = - wP * ppp + 2 * wP * pp - wP * p; | |
var s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1; | |
var s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; | |
var sN = wN * ppp - wN * pp; | |
// combine data linearly | |
for ( var i = 0; i !== stride; ++ i ) { | |
result[ i ] = | |
sP * values[ oP + i ] + | |
s0 * values[ o0 + i ] + | |
s1 * values[ o1 + i ] + | |
sN * values[ oN + i ]; | |
} | |
return result; | |
} | |
} ); | |
export { CubicInterpolant }; | |