2010-06-29

Unwrapping Values – nearest next angle from a previous angle


So, assuming you have angles previousAngle and nextAngle, and you want to transition from the first to the second smoothly. If it’s like from 358 to 2, a simple linear interpolation will awfully go through almost a full circle down from 358 to 2, when a simple four degree transition forward would have been enough, i.e. you should have been going to 362 degrees instead. So, how to figure out what’s the shortest transition?

I remember hitting against this problem numerous times, always remembering that I have solved it previously but always seem unable to find the previous solution. And I still can’t just write it out by heart.

Once again I had to solve this, so this time I tried to Google for it (“angle wrap delta”), and found out that somebody named Jason S had posted a nice generalization to a related question in Stackoverflow.com.

For your convenience, I’m posting a modified C version of the code here.


// Fancy generalization for wrapping below (e.g. for angles).
// Original code found from:
// http://stackoverflow.com/questions/2500430/calculating-rotation-in-360-deg-situations

// symmetric modulo:
// y = smod(x,m) = x+k*m where k is an integer,
// and y is always in the range [-0.5,0.5)*m
static float smod(float x, float m)
{
  return x - ((floorf(x / m + 0.5f)) * m);
}

// Unwraps a value, used for e.g. angles.
// Caveat: Doesn't handle negative input values correctly.
// Workaround: Wrap original value prev to [0..range) before applying this.
//       e.g.: prev = fmodf(fmodf(prev, range) + range, range);
static float unwrap(float prev, float next, float range)
{
  return prev + smod(next - prev, range);
}

There’s one caveat: it doesn’t seem to work correctly for negative angles. Just now I don’t have the time now to figure that out. But an easy workaround is to wrap the original angle first with angle=fmodf(fmodf(angle,2*pi)+2*pi,2*pi) and then transition from that angle to the destination. If somebody posts a better version I’ll update the post. :)

CodeRSS feed for responses (closed) — Trackbacks disabled.