evaluate method
The hold rule: before the first key its value, after the last the
last, and between neighbours a lerp shaped by the ARRIVING key's
curve. Pure in t — backwards seek needs no history.
Implementation
Object evaluate(Duration t) {
// Blocks: the leading clip's time at this moment, as seconds — the
// whole answer is [blendAt]; this is the one number a track reads as.
if (clips.isNotEmpty) return blendAt(t).time;
if (keys.isEmpty) {
throw StateError(
'an empty track has no value — it contributes '
'nothing and should not be evaluated',
);
}
if (t <= keys.first.at) return keys.first.value;
if (t >= keys.last.at) return keys.last.value;
for (var i = 1; i < keys.length; i++) {
if (t <= keys[i].at) {
var a = keys[i - 1], b = keys[i];
var u = (t - a.at).inMicroseconds / (b.at - a.at).inMicroseconds;
var shaped = (b.curve ?? SceneCurves.linear).transform(u);
return switch (kind) {
TrackKind.number =>
(a.value as double) +
((b.value as double) - (a.value as double)) * shaped,
TrackKind.color => SceneColor.lerp(
a.value as SceneColor,
b.value as SceneColor,
shaped,
),
};
}
}
return keys.last.value;
}