fourdgsPoseAt function
The pose at scene time t, or null when the record has no samples.
Outside the sample range the pose is clamped, never extrapolated: before the first sample it is the first sample, at or after the last it is the last. Extrapolating produces a platform that accelerates away from the scene at the ends of the clip, which is never what the capture did.
Implementation
FourdgsPose? fourdgsPoseAt(FourdgsPoseSampled track, double t) {
checkSceneTime(t);
final n = track.sampleCount;
if (n == 0) return null;
if (t <= track.timeAt(0)) return _sample(track, 0);
if (t >= track.timeAt(n - 1)) return _sample(track, n - 1);
// Times are strictly increasing (enforced at parse), so a bisection is exact.
var lo = 0;
var hi = n - 1;
while (hi - lo > 1) {
final mid = (lo + hi) >> 1;
if (track.timeAt(mid) <= t) {
lo = mid;
} else {
hi = mid;
}
}
if (track.interpolation == trajectoryStep) {
return _sample(track, lo);
}
if (track.interpolation != trajectoryLinear) {
// Unknown-but-legal, not malformed — but there is no defensible way to
// invent the rule, and picking linear would silently answer a question the
// file asked differently. Naming it is the whole obligation.
throw FourdgsMalformedFile(
"trajectory '${track.name}' uses interpolation ${track.interpolation}, "
'which this build does not implement',
);
}
final u = interpolationFraction(t, track.timeAt(lo), track.timeAt(lo + 1));
final a = _sample(track, lo);
final b = _sample(track, lo + 1);
return FourdgsPose(
rotation: fourdgsSlerp(a.rotation, b.rotation, u),
translation: <double>[
finiteLerp(a.translation[0], b.translation[0], u),
finiteLerp(a.translation[1], b.translation[1], u),
finiteLerp(a.translation[2], b.translation[2], u),
],
);
}