Sign in to follow this  
hiigara

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

Recommended Posts

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 this post


Link to post
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 this post


Link to post
Share on other sites
phresnel    953
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?

Share this post


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

Share this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
Share on other sites
szecs    2990
Quote:
Original post by Emergent
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.
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 this post


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


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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
Share on other sites
Emergent    982
Quote:
Original post by hiigara
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.


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

Share this post


Link to post
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 this post


Link to post
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);
}

Share this post


Link to post
navderm    97
inline void convertToQuad2(double& theta)
{
if (theta > -PI/2 && theta < PI/2)
return;
if (theta < -PI/2)
{
theta = theta + PI;
convertToQuad2(theta);
}
if (theta > PI/2)
{
theta = theta - PI;
convertToQuad2(theta);
}
}

int main ()
{
convertToQuad(12.423);
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this