-
Notifications
You must be signed in to change notification settings - Fork 23
/
KFStepCurve.ts
158 lines (126 loc) · 4.98 KB
/
KFStepCurve.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import { Vector2, Vector3, Vector4 } from "../GeoMath";
import Curve from "./Curve";
import Type from "./Type";
import Time from "./Time";
import Interval from "./Interval";
import Invariance from "./Invariance";
import AnimUtil from "./AnimUtil";
/**
* キーフレームによる階段関数
*
* あるキーフレームから次のキーフレームの直前まで一定の値を返す階段関数である。
*
* 構築子により任意の関数値の型を指定することができる。
*/
class KFStepCurve extends Curve
{
/** number | vector2 | vector3 | vector4 */
private _value_type: Type;
/** >= 1 */
private _num_keyframes!: number;
private _key_times!: Time[];
private _key_values!: object[];
/**
* type 型の階段関数を keyframes により生成する。
*
* type は任意の型を指定することができる。
*
* keyframes を省略したときは type 型の既定値を返す定数関数と同等になる。keyframes の形式に関しては
* [[KFStepCurve.setKeyFrames setKeyFrames()]] を参照のこと。
*
* @param {mapray.animation.Type} type 関数値の型
* @param {object[]} [keyframes] 初期キーフレーム
*/
constructor( type: Type, keyframes?: (Time | number | Vector2 | Vector3 | Vector4)[] )
{
super();
this._value_type = type;
if ( keyframes !== undefined ) {
// 初期のキーフレームを設定
this.setKeyFrames( keyframes );
}
else {
// 既定のキーフレームを設定
const t0 = Time.fromNumber( 0 );
const dv = type.getDefaultValue();
this.setKeyFrames( [t0, dv] );
}
}
/**
* キーフレーム設定
*
* keyframes により、すべてのキーフレームを指定する。
*
* 条件
* - keyframes.length >= 2 (キーフレーム数 >= 1)<br>
* - すべての i, j において、i < j ⇔ 時刻i < 時刻j<br>
* - すべての i において、値i は構築子の type 引数で指定した型のインスタンス
*
* @param keyframes [時刻0, 値0, 時刻1, 値1, ...]
*/
setKeyFrames( keyframes: (Time | any)[] )
{
this._num_keyframes = keyframes.length / 2;
this._key_times = new Array( this._num_keyframes );
this._key_values = new Array( this._num_keyframes );
// キーフレームを設定
for ( let i = 0; i < this._num_keyframes; ++i ) {
const time = keyframes[2*i ];
const value = keyframes[2*i + 1];
this._key_times[i] = time;
this._key_values[i] = this._value_type.getCloneValue( value );
}
// 全時刻の値が変化
this.notifyValueChange( Interval.UNIVERSAL );
}
override isTypeSupported( type: Type )
{
const from_type = this._value_type;
return type.isConvertible( from_type );
}
override getValue( time: Time, type: Type )
{
const from_type = this._value_type;
const from_value = this._getInterpolatedValue( time );
return type.convertValue( from_type, from_value );
}
override getInvariance( interval: Interval ): Invariance
{
if ( this._num_keyframes == 1 ) {
// キーフレームが 1 個のときは ConstantCurve と同じく、全時間で一定値
// (UNIVERSAL と非空区間は必ず交差するので interval の参照は不要)
return new Invariance().write( Interval.UNIVERSAL );
}
else {
// assert: this._num_keyframes >= 2
const invr = new Invariance();
// 最初から2番目のキー時刻より前は一定値
const first = this._key_times[1];
invr.write( new Interval( first, first ).getPrecedings() );
// 最後のキー時刻とその後は一定値
const lastL = this._key_times[this._num_keyframes - 2];
const lastU = this._key_times[this._num_keyframes - 1];
invr.write( new Interval( lastL, lastU, false, true ).getFollowings() );
// interval 範囲に絞って返す
return invr.getNarrowed( interval );
}
}
/**
* time での補間値を取得
*
* @param time
*
* @return 補間値 (this._value_type に適応した型)
*/
private _getInterpolatedValue( time: Time ): any
{
// this._key_times に time より後の時刻が存在すれば、その中で最小のインデックス
// そのような時刻が存在しなければ this._num_keyframes
const found = AnimUtil.findKeyFrameIndex( time, this._key_times, 0, this._num_keyframes );
// キー値のインデックス
const index = (found > 0) ? found - 1 : 0;
// 補間値を生成
return this._value_type.getCloneValue( this._key_values[index] );
}
}
export default KFStepCurve;