Angle wrapping

Started by
0 comments, last by DekuTree64 15 years, 10 months ago
[I've implemented a lame version of this already, but i'm hoping to get a better version from you fine folks.] What's the simplest method for finding the difference between any two angles? I've been building a simple euler-angle based 3D camera (i haven't learned about quaternions yet, so i have to use what i know) and i ran into this issue. Obviously, 95 is 5 away from 90 degrees ( 95-90=5 ), but that doesn't apply to numbers that wrap around the 360 or 0 mark. I feel like the code i wrote is too much for what should be a simple operation. Can you do this any simpler than i did it? Thanks!

// checks to see if two angles are within "range" of each other
// assume angles are clamped 0-360;
bool Camera::AngleInRange( float a, float b, float range ) {
	if ( a > b ) {
		float temp = b;
		b = a;
		a = temp;
		}
	a += 360;
	b += 360;
	if ( b - a > 180 ) { a += 360; }
	return ( b > a - range && b < a + range );
	}
Advertisement
I like to use a straight 16 bit integer for my angles, rather than float. It has some very convenient properties for the kind of angle operations needed in most games.

First, treat 65536 as the number of degrees in a full revolution. The 16 bit value only goes up to 65535, so that way if you go over, it naturally wraps back to 0.

Second, if you cast the unsigned short value to a signed short, you magically have the same angle represented as -180 to +180 degrees.

Third, you can subtract 2 angles, and due to the natural wrapping, the signed representation is the shortest angular distance between them. You can take the absolute value of that if needed, too.

There are a few caveats though:

1. Don't do a for loop comparing an angle with 360 degrees as the ending condition, since 360 is actually the same thing as 0. Use a different loop variable instead.

2. The absolute signed difference has one ambiguous value at precisely -180 degreess, where abs(-32768) becomes 32768, which when treated as a signed 16 bit value is still negative. One solution is to check for it and return 32767 instead. Or if you're more disciplined, just be sure to always treat it as unsigned after doing absolute value.

3. It takes a while to wrap your head around and learn to use effectively, so some programmers will get confused and hate you at first.

4. You may feel compelled to write comparison operators for your angle class. Don't do it. It depends on context wether you want to compare the signed or unsigned representation, or even signed against unsigned, so the operators will inevitably be wrong in some cases. Better to always compare the raw values explicitly the way you want to.

This topic is closed to new replies.

Advertisement