Bin
2025-12-17 05a69820e0c402b0b33c063d3b922f0a0571cbbb
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
/**
 * project any angle onto the interval (-180;180]
 */
export function normalizeAngle(angle: number) {
  let a = angle;
 
  while (a > 0) a -= 360;
  return ((a - 180) % 360) + 180;
}
 
type SequenceItem = {
  frame: number;
  [k: string]: any;
};
 
/**
 * interpolate prop between two sequence items
 * @return {any} propValue
 * @example
 * interpolateProp({frame: 0, x: -10}, {frame: 100, x: 10}, 25, 'x'); // will return -5
 * @example
 * interpolateProp(
 *   {frame: 0, rotation: -170},
 *   {frame: 20, rotation: 170},
 *   5,
 *   'rotation'
 * ); // will return -175
 */
export const interpolateProp = (start: SequenceItem, end: SequenceItem, frame: number, prop: string): any => {
  // @todo edge cases
  const r = (frame - start.frame) / (end.frame - start.frame);
 
  // Interpolation of angles is more tricky due to the cyclical nature of the angle value.
  if (prop === "rotation") {
    // In order to perform interpolation over the shortest distance,
    // we must normalize the difference in the values of the angles to the interval of [180;180) degrees,
    // because this is analogous to [0;360) degrees,
    // but at the same time the maximum absolute value remains the minimum possible 180 degrees.
    const dAngle = normalizeAngle(end[prop] - start[prop]);
 
    return normalizeAngle(start[prop] + dAngle * r);
  }
  return start[prop] + (end[prop] - start[prop]) * r;
};