Game Development Community

RC2 t2dAngleBetween error

by Sam M · in Torque Game Builder · 06/12/2006 (5:07 pm) · 9 replies

Hi, today I was making a quick game in RC2, and when I used the t2dAngleBetween function there seems to be an error. For example if you type

echo(t2dAngleBetween("0 0", "0 1"));

the output would be 90 degrees, however if you put in

echo(t2dAngleBetween("0 0", "0 -1"));

It comes out to 0 degrees.

Anybody have any idea what's wrong? Is this an error or am I missing something? Thanks in advance.

Sam M.

#1
06/12/2006 (9:47 pm)
I haven't used the t2dAngleBetween() very much but it seems OK

==>echo(t2dAngleBetween("0 0", "0 1"));
180
==>echo(t2dAngleBetween("0 0", "0 -1"));
0
#2
06/12/2006 (11:47 pm)
The trouble is, "0 0" is not really a vector. You'll get weird values for that.

That said, it does still seem to be incorrect. Doing:
echo(t2dAngleBetween("1 0", "0 1"));
should give 90 (or -90, depending on the handedness), but it gives -135, for a reason I can't figure out.
Other vectors also give unexplainable results.
#3
06/13/2006 (8:03 am)
I am no geometry expert but it still seems OK to me. You can look at t2dVector.cc and mMathFn.h to see the implementation.

If you plot out the return values on graph paper it returns, clockwise from 12 to 6 o'clock: 0, 45, 90, 135, 180. counterclockwise from 12: -45, -90, -135. So apparently this function never returns a value greater than abs(180) degrees.
#4
06/13/2006 (8:46 am)
Wow, the implementation is wrong!

return mRadToDeg( mAtan( v2.mX-v1.mX, v1.mY-v2.mY ) );

mAtan calls atan2, and the arguments are supposed to be atan2(y,x). That's difference in y, then difference in x. This comes from traditional math, where to find an angle using arctan, you do arctan(y/x).
[url = http://www.cplusplus.com/ref/cmath/atan2.html] See here for C code[/url]

Even with this revelation, the results still don't make sense. I don't understand how it seems OK to you, Alex. A vector that is "1 0" is pointing to the right, and a vector that is "0 1" is pointing up. Clearly the angle between these is 90 degrees, so -135 makes absolutely no sense. Sure the values are between -180 and 180, but it's like I asked you which direction is left, and you answered by pointing up. While you pointed in a valid direction, it makes no sense.

In fact, I just realized... mAtan is the completely wrong tool to use here! mAtan gives the orientation of an individual vector, but if you want the angle between two vectors, you need to use mAcos and the dot product.

I went ahead and fixed this... here is the resulting function:
ConsoleFunction( t2dAngleBetween, F32, 3, 3, "(t2dVector v1$, t2dVector v2$) - Returns the angle between v1 and v2.")
{
    // Check Parameters.
    if ( t2dSceneObject::getStringElementCount(argv[1]) < 2 || t2dSceneObject::getStringElementCount(argv[2]) < 2 )
    {
        Con::warnf("t2dAngleBetween() - Invalid number of parameters!");
        return NULL;
    }

    // Input Vectors.
    t2dVector v1(0,0), v2(0,0);
    // Scan-in vectors.
    dSscanf(argv[1],"%f %f", &v1.mX, &v1.mY);
    dSscanf(argv[2],"%f %f", &v2.mX, &v2.mY);

	// Need to normalise(ize for us Americans) 
	// for arccos to work properly
	v1.normalise();
	v2.normalise();

    // Do Vector Operation.  arccos(dot product)
    return mRadToDeg( mAcos( v2.mX*v1.mX + v2.mY*v1.mY ) );
}

Now the output for echo(t2dAngleBetween("0 1", "1 0")); is 90 as expected, and echo(t2dAngleBetween("0.5 0.5", "1 0")); is 45, also as expected.

Get this in before the final release! Or there will be much hair pulling!
#5
06/13/2006 (8:51 am)
Quote:I don't understand how it seems OK to you, Alex.
Uh... gotta run to my day job now ... but like I said I aint no geometry expert. Looks like you are onto something here J.
#6
06/13/2006 (9:41 am)
Ok, on the walk to work I realized something about all this. The help string in the function is misleading. "(t2dVector v1$, t2dVector v2$) - Returns the angle between v1 and v2." My understanding was that these are two vectors, as in the math sense of a vector. The way the function was before, it could be used to find the angle between two points, in which case it does make some sort of sense. (Sorry Alex, I only saw it my way).

My recommendation would be to have two functions: t2dAngleBetweenVectors and t2dAngleBetweenPoints.

At any rate, the mAtan usage is still incorrect. In order to keep the "points" functionality, the change should be:
return mRadToDeg( mAtan( v2.mY-v1.mY, v2.mX-v1.mX ) );

Now that I'm at work, I can't test that, but it ought to work.

If the intent was to return the angle between vectors, then my above post has the correct code.
#7
06/21/2006 (1:59 pm)
Quote:My recommendation would be to have two functions: t2dAngleBetweenVectors and t2dAngleBetweenPoints.

Agreed! We really need two functions.

In the final release, The t2dAngleBetween() now does something completely different from what it's been doing all along. I've been using it to calculate the angle between points, and it fails miserably at that now :)

Additionally, the comment above the function still says "Angle between two 2D Points", but the inline descriptions says "Returns the angle between v1 and v2". **Confusion**

I suggest leaving t2dAngleBetween() as it is now with the current name and calculating the angle between vectors, and reinstate the old function with the name t2dAngleBetweenPoints().

Quote:At any rate, the mAtan usage is still incorrect. In order to keep the "points" functionality, the change should be:

return mRadToDeg( mAtan( v2.mY-v1.mY, v2.mX-v1.mX ) );

Mmmm... mAtan expects (x, y), so it looks like mMathFn.h is actually where the problem is:

inline F32 mAtan(const F32 x, const F32 y)
{
   return (F32) atan2(x, y);   <<--- should be (y, x)
}

It's odd that t2dAngleBetween() has been working fine for me in spite of the atan2 issue (at least up to the current version).
#8
06/21/2006 (2:55 pm)
Here are my thoughts on the mAtan stuff. I realized that using atan2(x,y) gives a valid result, just transformed from conventional mathematics. Doing atan2(x,y) makes 0 degrees pointing up, like a compass, and increasing angles go clockwise. That is how T2D represents rotations. It's weird to anybody who is still in school with 0 degrees pointing right, but it still works just fine.

It would NOT be a good idea to change mAtan to do atan2(y,x). That would confuse people who have actually used atan2 in C, like myself. Sticking with standards like that is important, or people start griping like they do about Microsoft's blatant disregard for standards, in an attempt to make their own standard. You simply need to know that to get an angle from a right triangle's 2 sides you need to do atan( y/x ), so it looks like atan2(y,x).

I personally would prefer to have t2d represent angles as mainstream math does, with 0 pointing right, and increasing angles going counter-clockwise. But I will still use t2d either way. It's not too hard to think about 0 pointing up.
#9
06/24/2006 (2:54 pm)
I would like to see this addressed as well. I've been using t2dAngleBetween to calculate an angle between two points and as of RC2 it no longer works for me. It would be nice to hear a response as to why this was changed. I would love to have two functions as well although I guess I can just do it myself but I'd rather avoid that if possible.

Thanks for calling this out since your level of understanding is obviously much higher than mine. ;)