I have a spring that is applied to a rotating element:
This thing needs to rotate left and right. If I attach the angle to a spring, sometimes the rotating circle takes the long way around. What is the correct way to implement a modular spring in this setting?
My current solution uses the following function:
export function useNearestModulo(pp: number, m: number): number {
const q = React.useRef<number | null>(null);
// If the function hasn't been called yet, just return P' which satisfies
// P' % M = P', but record it as Q for the next call.
if (q.current == null) {
q.current = pp;
return pp;
}
// Calculate Q' that gets as close to Q as possible while satisfying
// Q' % M = P'.
const qq = Math.round((q.current - pp) / m) * m + pp;
q.current = qq;
return qq;
}
useNearestModulo
returns a value minimizing the distance traveled around a
circle. It always satisfies useNearestModulo(P, M) % M = P
.
useNearestModulo(P', M) = Q'
such that Q' % M = P'
but minimizing |Q' - Q|
,
where Q
is the return value from the previous call. The returned value Q'
is
then used as the Q
for the next call, and so forth.
In the code below, P' is pp and Q' is qq.
Example (sequence of calls):
useNearestModulo( 0, 12) = 0
useNearestModulo(10, 12) = -2
useNearestModulo( 3, 12) = 3
useNearestModulo( 7, 12) = 7
useNearestModulo(10, 12) = 10
I use the function as follows:
const { spring } = useSpring({
angle: useNearestModulo(angle, 12)
});
This causes things to rotate in the correct direction, but because the spring target is constantly changing, the resulting movement is sort of jerky.