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

## Recommended Posts

hiigara    108
An arbitrary positive or negative Angle. I am using C++.

##### Share on other sites
Evil Steve    2017
From what? What's wrong with angle = 1.23456?

##### Share on other sites
hiigara    108
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.

##### Share on other sites
Evil Steve    2017
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]

##### Share on other sites
phresnel    953
Quote:
 Original post by Evil SteveIf 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?

##### Share on other sites
Evil Steve    2017
Quote:
Original post by phresnel
Quote:
 Original post by Evil SteveIf 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]

##### Share on other sites
hiigara    108
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.

##### Share on other sites
Emergent    982
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.

##### Share on other sites
szecs    2990
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*

##### Share on other sites
alvaro    21247
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.

##### Share on other sites
hiigara    108
Quote:
 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...).

How can this clever Loop be faster than the fmod() Division loop? If I decrement 2pi in each Iteration that's pretty much what fmod() does.

##### Share on other sites
szecs    2990
Quote:
 Original post by EmergentI'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.
And he has so many rate points! :P

That's why I suggested to to distinguish between small, and big increments (The second half of the post you quoted)

##### Share on other sites
hiigara    108
Quote:
 Original post by alvaroAs 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.

I don't usually follow the Physics Forum, only at the Moment.
Let's say my current Heading is given by the Vector
(cos(pi), sin(pi))
How do I rotate this vector 0.02 Radians using the Unit Vector Method?

Another task I need to perform is to calculate the Angle of a foreign Object in my Local Referencial and I am currently doing it with Angles:
float Localtargetangle = ::atan2 ( Relativetargetposition.Y,Relativetargetposition.X ) - Orientation ;Localtargetangle = ::atan2 ( ::sin ( Localtargetangle ),::cos ( Localtargetangle ) ) ;

If you can teach me how to do these 2 Tasks using the Vector Method I will appreciate it.

##### Share on other sites
alvaro    21247
[indent]Quote: [i]Original post by hiigara[/i]
How do I rotate this vector 0.02 Radians using the Unit Vector Method? [/indent]

You can rotate the vector like this:
Vector2D rotate(Vector2D const &v, double angle) {

double cosine = std::cos(angle), sine = std::sin(angle);

return Vector2D(cosine*v.x - sine*v.y, sine*v.x + cosine*v.y);

}

If you do it using complex numbers, it becomes:
std::complex<double> rotate(std::complex<double> z, double angle) {

return z * std::complex<double>(std::cos(angle), std::sin(angle));

}

Or even:
std::complex<double> rotate(std::complex<double> z, double angle) {

return z * std::exp(std::complex<double>(0,angle));

}

[indent]Quote: Another task I need to perform is to calculate the Angle of a foreign Object in my Local Referencial and I am currently doing it with Angles:
*** Source Snippet Removed *** [/indent]

This kind of operation is very easy with complex numbers:
std::complex<double> rotation_that_turns_A_into_B(std::complex<double> A, std::complex<double> B) {

std::complex<double> result = B/A;

return result/std::abs(result);

}

If I had to do it with 2D vectors, I would simply expand the formula for complex division.

##### Share on other sites
hiigara    108
Thanks everyone.
Alvaro one last Question. Do I have to "renormalize" my Orientation Vector before using it?

Vct = rotate ( Vct, 0.02 ) ;
Vct = Vct / Vct.length () ;
Position = Position + Vct * Speed ;

I think it will deviate from Norm 1 due to Error Propagation.

##### Share on other sites
Emergent    982
Quote:
 Original post by hiigaraThanks everyone.Alvaro one last Question. Do I have to "renormalize" my Orientation Vector before using it?Vct = rotate ( Vct, 0.02 ) ;Vct = Vct / Vct.length () ;Position = Position + Vct * Speed ;I think it will deviate from Norm 1 due to Error Propagation.

Yep, what you wrote is exactly what people do. Error propagation is the reason as you said.

##### Share on other sites
newacct    100
[quote name='alvaro' timestamp='1270051899' post='4627382']
If you do it using complex numbers, it becomes:
std::complex<double> rotate(std::complex<double> z, double angle) {
return z * std::complex<double>(std::cos(angle), std::sin(angle));
}

Or even:
std::complex<double> rotate(std::complex<double> z, double angle) {
return z * std::exp(std::complex<double>(0,angle));
}
[/quote]

Or even:
std::complex<double> rotate(std::complex<double> z, double angle) {
return z * std::polar(1.0,angle);
}

##### Share on other sites
newacct    100
Hidden
[quote name='alvaro' timestamp='1270051899' post='4627382']
If you do it using complex numbers, it becomes:
std::complex<double> rotate(std::complex<double> z, double angle) {
return z * std::complex<double>(std::cos(angle), std::sin(angle));
}

Or even:
std::complex<double> rotate(std::complex<double> z, double angle) {
return z * std::exp(std::complex<double>(0,angle));
}
[/quote]

Or even:
std::complex<double> rotate(std::complex<double> z, double angle) {
return z * std::polar(1.0,angle);
}

navderm    97
{
if (theta > -PI/2 && theta < PI/2)
return;
if (theta < -PI/2)
{
theta = theta + PI;
}
if (theta > PI/2)
{
theta = theta - PI;
}
}

int main ()
{
}