How do I convert an Angle to the range [-pi,pi]?

Started by
16 comments, last by navderm 11 years, 5 months ago
An arbitrary positive or negative Angle. I am using C++.
Advertisement
From what? What's wrong with angle = 1.23456?
pi being 3.14, 1.23456 is a valid angle.
I have an exponential Model f(x) that for a Speed x gives f(x) the Maximum absolute Value of the Angle you can turn at that Speed. f(x) is in the range[0,pi].
I also use the inverse function i(y). That given an Angle y gives you the Maximum Speed at which you can turn y radians.
If y is not in the range [0,pi], i(y) will make no sense.
If you just want to convert radians into a range, you can either wrap or clamp. Presumably you want to wrap (So that 2*pi == 0), in which case use fmod

[Edited by - Evil Steve on March 31, 2010 9:34:19 AM]
Quote:Original post by Evil Steve
If you just want to convert radians into a range, you can either wrap or clamp. Presumably you want to clamp wrap (So that 2*pi == 0), in which case use fmod


corrected?
Quote:Original post by phresnel
Quote:Original post by Evil Steve
If you just want to convert radians into a range, you can either wrap or clamp. Presumably you want to clamp wrap (So that 2*pi == 0), in which case use fmod


corrected?
Whoops, fixed [smile]
Yes I want to wrap. So when an Angle becomes 3.15 I want it to be -3.13 .
I found a good Solution:
If x is any Angle positive or Negative then
x = ::atan2 ( ::sin ( x ), ::cos ( x ) ) ;

will be between -pi and pi. Not as efficient as fmod() but more compact.
I'll note that fmod is pretty slow, and so is atan2(sin, cos). I find that most of the time I need to rewrap angles, it occurs in situations where I know that I will only need to either add of subtract 2*pi once from my angle to get one in the range I want -- and I find that this code is noticeably faster. It's basically a specialization of fmod for when you know something additional about its input:

const inline double rewrapAngleRestricted(const double angle)// This function takes an angle in the range [-3*pi, 3*pi] and// wraps it to the range [-pi, pi].{  if(angle > pi)    return angle - TWO_PI;  else if(angle < -pi)    return angle + TWO_PI;}


You'd need to be careful to package this up in a way that makes sure that external code doesn't see these restrictions though; otherwise your code could get pretty brittle. One way to do this is to have an "angle" class that does this stuff automatically.
I use the same for warping as Emergent suggests (in other situations too).
In most cases, it's enough, since you cannot increment/decrement with a value that's comparable to the interval.
If there's a little chance for a bigger increment to occur, then you could use a loop (a clever loop, which I can't think of now...).

Or use the slower method:
angle += increment;if( increment > interval || increment < -interval )   angle = slow_wrap(angle);else   angle = fast_wrap(angle);
Sorry, I came up with this at the moment, can be totally stupid...

EDIT: wrap or warp? My English is *sigh*
As has been mentioned in this forum many times, you can probably do whatever you are doing without using angles. Representing a 2D heading as a unit vector often results in code that is much cleaner (fewer corner cases to consider) and faster to execute.

If you are familiar with complex numbers, you can also think of that 2D unit vector as a complex number, since multiplying by it results in the correct rotation.

This topic is closed to new replies.

Advertisement