# Prayer to math gods: finding the angle of two vectors

Darren Brooks

Ranch Hand

Posts: 32

posted 10 years ago

If a star fighter is located at Point(0,0) and the player clicks on the screen at Point(100,100), how can I determine the angle between two lines: the line (0,0)(100,100) and a line segment constant, such as the horizon (i.e. an imaginary horizontal line the width of the screen...)?

I would like to determine this angle so I know which image of the star fighter would be most appropriate to display.

I have found numerous online tutorials on dot products and such, but perhaps some "java-ized" code would assist my slow learning curve.

I humbly beg a reply from the math gods!

I would like to determine this angle so I know which image of the star fighter would be most appropriate to display.

I have found numerous online tutorials on dot products and such, but perhaps some "java-ized" code would assist my slow learning curve.

I humbly beg a reply from the math gods!

posted 10 years ago

You already know from your research, I guess, that the dot product of two normalized vectors is the cosine of the angle between them. There are a whole bunch of little pieces here:

1) How you represent a vector -- an array, a class?

2) Routines to add and subtract points and vectors, because to compute the dot product between two line segments, you have to turn them into two vectors (i.e., segments with one end at the origin)

3) A dot product routine

4) A way to get the angle from the cosine (Math.acos() will work for this)

It's nice if all this stuff works together. You can either write your own, or do yourself a favor and use a preexisting one. There are many, but one in common use is the javax.vecmath package, originally part of Java3D, now being developed by the java.net folks here. With vecmath, this would look something like

Vector2d horizon = new Vector2f(1, 0);

Vector2d click = new Vector2f(clickx, clicky);

click.normalize();

double angle = horizon.angle(click);

And that's it!

1) How you represent a vector -- an array, a class?

2) Routines to add and subtract points and vectors, because to compute the dot product between two line segments, you have to turn them into two vectors (i.e., segments with one end at the origin)

3) A dot product routine

4) A way to get the angle from the cosine (Math.acos() will work for this)

It's nice if all this stuff works together. You can either write your own, or do yourself a favor and use a preexisting one. There are many, but one in common use is the javax.vecmath package, originally part of Java3D, now being developed by the java.net folks here. With vecmath, this would look something like

Vector2d horizon = new Vector2f(1, 0);

Vector2d click = new Vector2f(clickx, clicky);

click.normalize();

double angle = horizon.angle(click);

And that's it!

Darren Brooks

Ranch Hand

Posts: 32

posted 10 years ago

Thank you for your assistance. I'm having some difficulty at the java.net site finding a way to download the javax.vecmath package. I'm not a newbie at such things, but seems I have beginner's mind with this one. For example, it seems quite involved to use SSH tunneling just to download a java package...!

From your reply, it seems finding the angle of two vectors is more involved than I thought. It appears on the surface like a simple "line, angle/radian thing". Hmmm....

The x,y graph is given - x is the line from one end of the screen width to the other, and y is the screen height as a vertical line. With these constants, we can form a triangle with any two Points. I'm sure this will head me down the road to my own doom, but at least it will make me review my basic geometry.

Any thoughts?

From your reply, it seems finding the angle of two vectors is more involved than I thought. It appears on the surface like a simple "line, angle/radian thing". Hmmm....

The x,y graph is given - x is the line from one end of the screen width to the other, and y is the screen height as a vertical line. With these constants, we can form a triangle with any two Points. I'm sure this will head me down the road to my own doom, but at least it will make me review my basic geometry.

Any thoughts?

posted 10 years ago

To calculate the angle, you take two normalized vectors, compute the dot product, then compute the arccosine of that.

Let's say a vector (i.e., a point, with the other end implicitly at 0, 0) is a double[2]. So normalize() looks like (untested, just off the top of my head)

and the dot product is just

So if your click is at x, y, and your horizon is horizontal, then your angle is something like

double[] click = {x, y};

double[] horizon = {1, 0};

normalize(click);

double cos = dot(click, horizon);

double angleInRadians = Math.acos(cos);

Note that because I just typed this all out in two seconds, I left out some subtleties: what do you do if the click is at 0, 0, for example? normalize() as written will return {NaN, NaN}. Also you may need to deal with the fact that there are four quadrants the click might come in, but the acos routine won't distinguish them for you.

Let's say a vector (i.e., a point, with the other end implicitly at 0, 0) is a double[2]. So normalize() looks like (untested, just off the top of my head)

and the dot product is just

So if your click is at x, y, and your horizon is horizontal, then your angle is something like

double[] click = {x, y};

double[] horizon = {1, 0};

normalize(click);

double cos = dot(click, horizon);

double angleInRadians = Math.acos(cos);

Note that because I just typed this all out in two seconds, I left out some subtleties: what do you do if the click is at 0, 0, for example? normalize() as written will return {NaN, NaN}. Also you may need to deal with the fact that there are four quadrants the click might come in, but the acos routine won't distinguish them for you.

posted 10 years ago

Finally, note that our normal practice here at the Ranch is not to give out code like this, but I made a special exception here because I know that the very first time a programmer is confronted with reducing equations to practice -- especially geometric ones -- it can be very scary and seem much harder than it really is. Now that you've seen that it's actually really very simple, hopefully you will be more relaxed the next time!

Darren Brooks

Ranch Hand

Posts: 32

posted 10 years ago

thanks so much for taking the time to offer a bit more direction for me. Though your post my seem to you like you just "gave me the code," believe me I will be some time in figuring our how to apply it. Some of it makes sense, and the other parts will lead me down the road of a deeper understanding of just what a vector is and, like in your last reply, what it is made up of.

I definitely understand that just handing out code is silly, however, if the main reason for this is that we think our students will then not take the time to think for themselves, I would suggest we teachers (and I have been a teacher for many years) must examine our beliefs and respect for our students.

For example, I had an instructor who really knew his subject, yet would constantly frustrate us students by overwhelming us with too much detail and then think we were just trying to slack off by asking he make things more simple for us. In your last post, you outlined the key points of what I should look for in working out this code, as well as offering a pre-made site where I could just download all this stuff already worked out in java.

In response to your post, I realized how much I didn't know about vectors, and yet I had the feeling there was some simpler way to approach this (there almost always is!). So I spent all last night working out angles, circles, minor arcs, triangles and looking up sine and cosine functions.

And just so you don't think I'm sitting around waiting for a Deus ex Machina in the form of the exact code to use to descend from programmer heaven:

protected double getHeadingAngle(int x, int y) {

double a = 0.0;

double newY = (double)y;

double newX = (double)x;

double currX = currentLoc.getX();

double currY = currentLoc.getY();

a = Math.toDegrees(Math.atan2(newY, newX));

//here, I'm still working out how to compare the new and current location of the object I wish to move along this angle...

return a;

}// close getHeadingAngle()

I definitely understand that just handing out code is silly, however, if the main reason for this is that we think our students will then not take the time to think for themselves, I would suggest we teachers (and I have been a teacher for many years) must examine our beliefs and respect for our students.

For example, I had an instructor who really knew his subject, yet would constantly frustrate us students by overwhelming us with too much detail and then think we were just trying to slack off by asking he make things more simple for us. In your last post, you outlined the key points of what I should look for in working out this code, as well as offering a pre-made site where I could just download all this stuff already worked out in java.

In response to your post, I realized how much I didn't know about vectors, and yet I had the feeling there was some simpler way to approach this (there almost always is!). So I spent all last night working out angles, circles, minor arcs, triangles and looking up sine and cosine functions.

And just so you don't think I'm sitting around waiting for a Deus ex Machina in the form of the exact code to use to descend from programmer heaven:

protected double getHeadingAngle(int x, int y) {

double a = 0.0;

double newY = (double)y;

double newX = (double)x;

double currX = currentLoc.getX();

double currY = currentLoc.getY();

a = Math.toDegrees(Math.atan2(newY, newX));

//here, I'm still working out how to compare the new and current location of the object I wish to move along this angle...

return a;

}// close getHeadingAngle()

Darren Brooks

Ranch Hand

Posts: 32

Darren Brooks

Ranch Hand

Posts: 32

posted 10 years ago

Ok - who could have known my czech girlfriend was a math wiz! She explained one way of doing this to me. What about using the following:

double angle = Math.toDegrees(Math.atan((newX - currentX) / (newY - currentY)));

She explained about having the origin be 0,0 and then translating (my word) the location of the triangle to its location on the screen; the triangle would be formed by the line between the two Point coords, and the x,y axes. So now I understand why we subtract b from a, and B from A.

tgTHETA = b-a/B-A; (a,A) = currentX,currentY; (b,B) = newX,newY

About 20 years ago, I got an A in trig - just shows you knowledge has little to do with schooling (and if only everyone had a smart girlfriend, we'd all enjoy math much, much more!!).

Now I just have to understand the results I'm getting!! Still more to learn, but with the drawings she made for me and the explanations she gave, I didn't feel stupid.

double angle = Math.toDegrees(Math.atan((newX - currentX) / (newY - currentY)));

She explained about having the origin be 0,0 and then translating (my word) the location of the triangle to its location on the screen; the triangle would be formed by the line between the two Point coords, and the x,y axes. So now I understand why we subtract b from a, and B from A.

tgTHETA = b-a/B-A; (a,A) = currentX,currentY; (b,B) = newX,newY

About 20 years ago, I got an A in trig - just shows you knowledge has little to do with schooling (and if only everyone had a smart girlfriend, we'd all enjoy math much, much more!!).

Now I just have to understand the results I'm getting!! Still more to learn, but with the drawings she made for me and the explanations she gave, I didn't feel stupid.

Jeff Albertson

Ranch Hand

Posts: 1780

Darren Brooks

Ranch Hand

Posts: 32

posted 10 years ago

thanks to you math guys for helping guide my research!!

My purpose in examing at first, vectors, and then returning to trig (the highest level of math I obtained!), was to be able to choose the right star fighter image based upon where the player right clicks on the screen. I would either set a new image or simply rotate the current one if the angle isn't too large (I've drawn my images in some kind of perspective).

I'm very happy to show how I used your suggestions to determine the polar angle (theta, I believe) of where the player clicks on the screen (and the fact I can even say, "polar angle," and know what i'm talking about is quite cool):

code:

_____________________________________

double newY = (double)y;// x and y are arguments

double newX = (double)x;

// make current x,y the center of the image in order to get

// a more accurate angle reference

double currX = currentLoc.getX() + (currentImage.getWidth()/2);

double currY = currentLoc.getY() + (currentImage.getHeight()/2);

newTheta = Math.atan2((newY - currY), (newX - currX));

// return polar coord values of 0-359 (360 is 0 again)

newHeading = Math.toDegrees(newTheta);

if (newHeading > 0.0) {

newHeading = 180 + (180 - newHeading);

} else {

// no negative nums

newHeading = 180 - (180 - Math.abs(newHeading));

}

return newHeading;

-----------------------------------------------

Ain't that nifty! Thank you both (and my gal). You both get a free copy of my space game when it comes out in stores!!

My purpose in examing at first, vectors, and then returning to trig (the highest level of math I obtained!), was to be able to choose the right star fighter image based upon where the player right clicks on the screen. I would either set a new image or simply rotate the current one if the angle isn't too large (I've drawn my images in some kind of perspective).

I'm very happy to show how I used your suggestions to determine the polar angle (theta, I believe) of where the player clicks on the screen (and the fact I can even say, "polar angle," and know what i'm talking about is quite cool):

code:

_____________________________________

double newY = (double)y;// x and y are arguments

double newX = (double)x;

// make current x,y the center of the image in order to get

// a more accurate angle reference

double currX = currentLoc.getX() + (currentImage.getWidth()/2);

double currY = currentLoc.getY() + (currentImage.getHeight()/2);

newTheta = Math.atan2((newY - currY), (newX - currX));

// return polar coord values of 0-359 (360 is 0 again)

newHeading = Math.toDegrees(newTheta);

if (newHeading > 0.0) {

newHeading = 180 + (180 - newHeading);

} else {

// no negative nums

newHeading = 180 - (180 - Math.abs(newHeading));

}

return newHeading;

-----------------------------------------------

Ain't that nifty! Thank you both (and my gal). You both get a free copy of my space game when it comes out in stores!!