import { invlerp } from "../systems/math" ; /**
 * Represents a key on a spline.
 */ export interface SplineKey < T > { /**
     * The value of the key.
     */ value : T ; /**
     * The position of the key.
     */ time : number ; } /**
 * Represents a spline that can be used to continueously evaluate a function
 * between keys. The base implementation is kept generic, so the functionality
 * can easily be implemented for similar constructs, such as gradients.
 */ export abstract class Spline < T > { /**
     * The keys in the gradient. Note that these are not sorted.
     */ protected keys : SplineKey < T > [ ] ; /**
     * Creates a new spline instance, using the specified keys.
     * Note that you have to pass at least one key.
     */ constructor ( ... keys ) { if ( keys . length === 0 ) { throw new Error ( "Splines require at least one key." ) ; } if ( Array . isArray ( keys [ 0 ] ) ) { throw new Error ( "You are trying to pass an array to the spline constructor, which is not supported. " + "Try to spread the array into the constructor instead." ) ; } this . keys = keys ; } /**
     * Evaluates the spline at the given time.
     */ public evaluate ( time ) { if ( this . keys . length === 0 ) { throw new Error ( "Attempt to evaluate a spline with no keys." ) ; } if ( this . keys . length === 1 ) { return this . keys [ 0 ] . value ; } const ascendingKeys = this . keys . sort ( ( a , b ) => a . time - b . time ) ; const upperKeyIndex = ascendingKeys . findIndex ( ( g ) => g . time > time ) ; if ( upperKeyIndex === 0 ) { return ascendingKeys [ 0 ] . value ; } if ( upperKeyIndex === - 1 ) { return ascendingKeys [ ascendingKeys . length - 1 ] . value ; } const lowerKey = ascendingKeys [ upperKeyIndex - 1 ] ; const upperKey = ascendingKeys [ upperKeyIndex ] ; const containedTime = invlerp ( lowerKey . time , upperKey . time , time ) ; return this . interpolate ( lowerKey . value , upperKey . value , containedTime ) ; } /**
     * Interpolates using the values of two keys.
     */ protected abstract interpolate ( a , b , t ) ; }