Anybody and everybody who has worked with 3D has, at one point or the other, run into a situation where an angle between 2 vectors was needed. The solution is rather straight forward; take the dot-product and take an arccosine of it. That’s it, you have the angle between the two. Well yes, but then again I wouldn’t be writing this blog entry if there wasn’t a story behind this. Yes, the above method will definitely give you the angle between vectors; well most of the times anyways. It’s mathematically correct. However, taking the arccosine (acos) can be prone to floating point overflows and can cause simulations and calculations to go out of whack unexpectedly. That’s because the acos function in the standard library operates in the range between [-1, 1]. Values very near to the extreme range values can cause the function to give out strange angle values and\or will give exceptions if the range values are exceeded even slightly. It’s not always you can clamp these values to prevent error, especially in situations where smooth transition of angles is required. Clamping the values will cause a jerk in the simulation and might reduce precision if it were required.
So what do we do in such a case? Don’t worry there is a solution. Instead of using acos use atan2. atan2 takes two arguments (x,y) and finds the counterclockwise angle in radians between the x-axis and the point (x, y) in 2-dimensional Euclidean space. More importantly it is valid for all values of x and y except (0, 0) which is the origin btw. It uses the signs of both arguments to determine the quadrant of the result. The x and y in our equation are simply perp-dot-product and dot-product respectively, or simply put
angle = atan2( magnitude(cross(a,b)), dot(a,b) );
Just remember one thing, atan2 will give you the results in the range -pi to pi radians. So you may (or may not) have to adapt your code to handle that.