import { Rotor4 } from '../math/rotor4.js'; export type RotorInterpolation = 'step' | 'linear' | 'cubic'; /** * A keyframed rotation track on SO(4). * * The bi-invariant metric on SO(4) is (up to the double cover) the * product metric on SU(2) × SU(2), so geodesics — and therefore correct * interpolants — are per-factor quaternion constructions. The one * global subtlety is the cover: (l, r) and (−l, −r) are the same * rotation, but flipping a single factor multiplies by the central * inversion, a *different* element of SO(4). The track therefore makes * the sign choice once per key at construction (neighborhooding) and * all factor arithmetic downstream is flip-free: * * - each key is pair-normalized; * - key i is jointly negated iff that shortens the squared geodesic * length acos²(dL) + acos²(dR) to key i−1. The explicit comparison used * here is exactly equivalent to the pair-level sign of `dL + dR`; it is * never equivalent to choosing a sign independently for each factor; * - any segment still spanning a factor angle ≥ π − margin is * subdivided by pair-slerp midpoints until none does, keeping every * quaternion log downstream away from its q = −1 singularity. * * Interpolation: 'step', 'linear' (per-factor slerp = the SO(4) * geodesic), or 'cubic' — Shoemake squad applied per factor with inner * points aᵢ = qᵢ·exp(−(log(qᵢ⁻¹qᵢ₊₁) + log(qᵢ⁻¹qᵢ₋₁))/4); because the * metric is a product metric this is a C¹ geodesic-respecting spline * on SO(4) with no cross-factor correction term. */ export declare class Rotor4Track { readonly interpolation: RotorInterpolation; /** Key times, strictly increasing (possibly densified by subdivision). */ readonly times: Float64Array; private readonly left; private readonly right; private innerLeft; private innerRight; /** * Builds a keyed rotation track. Keys are neighbourhooded on construction: * a rotor and its negation represent the same rotation, so each key is put * on the cover nearest its predecessor and interpolation takes the short * way round rather than an arbitrary one. * * @param times - Key times, strictly increasing. * @param rotors - One rotor per time. * @param interpolation - `'step'` holds each key, `'linear'` runs the * geodesic between neighbours, `'cubic'` is C¹ across keys. * * @example * ```ts * const target = Rotor4.fromPlanes([{ i: 0, j: 3, angle: Math.PI / 2 }]); * const track = new Rotor4Track([0, 1], [Rotor4.identity(), target], 'cubic'); * * const transform = new TransformN(4, track.sample(0.5)); * ``` */ constructor(times: ArrayLike, rotors: readonly Rotor4[], interpolation?: RotorInterpolation); get keyCount(): number; /** Samples the track at time `t` (clamped to the key range). */ sample(t: number, out?: Rotor4): Rotor4; } //# sourceMappingURL=rotor4-track.d.ts.map