1

I have a spring that is applied to a rotating element: enter image description here

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.

ethanabrooks
  • 747
  • 8
  • 19

1 Answers1

0

I am still trying to debug the jerkiness, but it doesn't have to do with the "spring target constantly changing." That was just a misunderstanding on my part regarding React. So the solution that I posted (basically using a modulus as the spring target) is a working solution to this. There are certainly simpler implementations that do not use useRef, but this is just how I happened to have implemented this.

ethanabrooks
  • 747
  • 8
  • 19