Convert vector to angle?

Oldtimer
Posts: 834
Joined: 2002.09
Post: #16
So why aren't you striving to get better, by doing it the right way? It's a little bit like learning to drive by constantly having someone drive the car to a hilltop, and then sit by the wheel as it rolls down the hill. Wink

Instead of explaining it to you, I'm going to point you to this wonderful Java applet:
http://catcode.com/trig/trig05.html

Play around with it for a while to get a feel for what the sine and cosine actually are. What you're doing in your application (with regards to moving the player at an angle, not the atan2f stuff) is that you take the angle and ask for the X and Y sides of the triangle. Think of it like this: you have your angle, and you want to move in the direction of it. That's the same as moving in the direction of the hypotenuse. (Regardless of which direction you want to move in, you can always stick a right triangle to that vector, where the short sides make up the X and Y directions.)

Now, here comes the trick: you want a hypotenuse with a length of exactly 1. Why? Well, because it's easy to scale. If you want to move by 30pixels/sec, you do in fact want to move 1 * 30 pixels/sec, right? Might seem trivial, but it will come in handy, since that also means that the X and Y speeds you want to move in are the X and Y sides of that triangle, times 30. What you're doing is:
1) constructing a right triangle
2) with a hypotenuse of 1
3) and then scaling that entire triangle up to the speed you want to move with

It's dead simple! To figure out the short sides of the triangle, you use sin(angle) and cos(angle), which gives you the lengths of the two short sides. Now, just scale those sides up.

Therefore, the complete (and very, very standard) code you'll get is the following:

Code:
float angle;
float radians

void move_player()
{
    NSPoint vector;
    vector.x = new_world_dst.x - player.x;
    vector.y = new_world_dst.y - player.y;

    angle = atan2(vector.y, vector.x);    // The ONLY right way to get the angle
    // Also, atan2 returns in radians already
    position.x += cos(radians) * SPRITE_SPEED; // Add the X-side to the X pos, and scale it to SPRITE_SPEED
    position.y += sin(radians) * SPRITE_SPEED; // Add the Y-side to the Y pos, and scale it to SPRITE_SPEED
}

I hope that clears things up for you. And a little morale of the story: whenever you don't understand code, it will bite you bad. If nothing else, you've skipped an opportunity for learning, which is a terrible thing to waste. Wink
Quote this message in a reply
Hog
Member
Posts: 151
Joined: 2002.09
Post: #17
Things you are still doing wrong: converting to an angular coordinate system and back again when it could have been done faster.
And in the special case of new_world_dst == player you would probably want the position to remain the same.
Quote this message in a reply
Member
Posts: 105
Joined: 2007.03
Post: #18
Fenris Wrote:So why aren't you striving to get better, by doing it the right way? It's a little bit like learning to drive by constantly having someone drive the car to a hilltop, and then sit by the wheel as it rolls down the hill. Wink

Instead of explaining it to you, I'm going to point you to this wonderful Java applet:
http://catcode.com/trig/trig05.html

Play around with it for a while to get a feel for what the sine and cosine actually are. What you're doing in your application (with regards to moving the player at an angle, not the atan2f stuff) is that you take the angle and ask for the X and Y sides of the triangle. Think of it like this: you have your angle, and you want to move in the direction of it. That's the same as moving in the direction of the hypotenuse. (Regardless of which direction you want to move in, you can always stick a right triangle to that vector, where the short sides make up the X and Y directions.)

Now, here comes the trick: you want a hypotenuse with a length of exactly 1. Why? Well, because it's easy to scale. If you want to move by 30pixels/sec, you do in fact want to move 1 * 30 pixels/sec, right? Might seem trivial, but it will come in handy, since that also means that the X and Y speeds you want to move in are the X and Y sides of that triangle, times 30. What you're doing is:
1) constructing a right triangle
2) with a hypotenuse of 1
3) and then scaling that entire triangle up to the speed you want to move with

It's dead simple! To figure out the short sides of the triangle, you use sin(angle) and cos(angle), which gives you the lengths of the two short sides. Now, just scale those sides up.

Therefore, the complete (and very, very standard) code you'll get is the following:

Code:
float angle;
float radians

void move_player()
{
    NSPoint vector;
    vector.x = new_world_dst.x - player.x;
    vector.y = new_world_dst.y - player.y;

    angle = atan2(vector.y, vector.x);    // The ONLY right way to get the angle
    // Also, atan2 returns in radians already
    position.x += cos(radians) * SPRITE_SPEED; // Add the X-side to the X pos, and scale it to SPRITE_SPEED
    position.y += sin(radians) * SPRITE_SPEED; // Add the Y-side to the Y pos, and scale it to SPRITE_SPEED
}

I hope that clears things up for you. And a little morale of the story: whenever you don't understand code, it will bite you bad. If nothing else, you've skipped an opportunity for learning, which is a terrible thing to waste. Wink

Actually atan2 returns the angle value in radians so you wouldn't do position.x += cos(radians) * SPRITE_SPEED you'd use position.x += cos(angle) * SPRITE_SPEED instead. And I was only kidding around earlier when about the inversion thingWink
Quote this message in a reply
DoG
Moderator
Posts: 869
Joined: 2003.01
Post: #19
Leroy Wrote:Actually atan2 returns the angle value in radians so you wouldn't do position.x += cos(radians) * SPRITE_SPEED you'd use position.x += cos(angle) * SPRITE_SPEED instead. And I was only kidding around earlier when about the inversion thingWink

Actually using atan2() for this is quite stupid Rasp

You can save yourself the whole ordeal and just use the normalized vector in the first place.
Quote this message in a reply
Member
Posts: 100
Joined: 2006.05
Post: #20
DoG Wrote:Actually using atan2() for this is quite stupid Rasp

You can save yourself the whole ordeal and just use the normalized vector in the first place.

Just divide the components by the length of the vector:

Code:
vector.x = new_world_dst.x - player.x;
    vector.y = new_world_dst.y - player.y;
    
    float scale = SPRITE_SPEED/sqrt(vector.x^2 + vector.y^2)
    position.x += vector.x*scale;
    position.y += vector.y*scale;
Quote this message in a reply
Hog
Member
Posts: 151
Joined: 2002.09
Post: #21
Code:
vector.x = new_world_dst.x - player.x;
    vector.y = new_world_dst.y - player.y;
    
    float sqd = vector.x * vector.x + vector.y * vector.y;
    if(sqd > 0.00001) {
        float scale = SPRITE_SPEED/sqrt(sqd);
        position.x += vector.x*scale;
        position.y += vector.y*scale;
    }
Quote this message in a reply
Moderator
Posts: 771
Joined: 2003.04
Post: #22
Code:
#define SPRITE_SPEED2 SPRITE_SPEED*SPRITE_SPEED
...
    vector.x = new_world_dst.x - player.x;
    vector.y = new_world_dst.y - player.y;
    
    float sqd = vector.x * vector.x + vector.y * vector.y;
    if(sqd > 0.00001f) {
        float scale = SPRITE_SPEED2/sqd;
        position.x += vector.x*scale;
        position.y += vector.y*scale;
    }
Quote this message in a reply
Member
Posts: 105
Joined: 2007.03
Post: #23
DoG Wrote:Actually using atan2() for this is quite stupid Rasp
You can save yourself the whole ordeal and just use the normalized vector in the first place.

What exactly is is that makes the latter mentioned method superior?
Quote this message in a reply
Sage
Posts: 1,403
Joined: 2005.07
Post: #24
Code:
#define SPRITE_SPEED2 SPRITE_SPEED*SPRITE_SPEED
...
    vector.x = new_world_dst.x - player.x;
    vector.y = new_world_dst.y - player.y;
    
    float sqd = vector.x * vector.x + vector.y * vector.y;
    if(sqd > 0.00001f) {
        float scale = SPRITE_SPEED2/sqd;
        position.x += vector.x*vector.x*scale;
        position.y += vector.y*vector.y*scale;
    }

Sir, e^iπ + 1 = 0, hence God exists; reply!
Quote this message in a reply
Member
Posts: 100
Joined: 2006.05
Post: #25
Whoa there. Why are we squaring everything? The square of a ratio is not identical to the ratio itself. I realize we're trying to avoid the overhead of the expensive sqrt call, but if you square the ratio, you'll have to take the square root anyway. Hog had it right...

Oh yeah. Sin, cos, and atan2 are all very expensive (performance-wise) function calls and are very prone to rounding errors. So if we can avoid all that with one call to sqrt, the routine should perform better.
Quote this message in a reply
Moderator
Posts: 771
Joined: 2003.04
Post: #26
edit: nvm - 1:24am Rasp
Quote this message in a reply
Member
Posts: 105
Joined: 2007.03
Post: #27
Nevada Wrote:Oh yeah. Sin, cos, and atan2 are all very expensive (performance-wise) function calls and are very prone to rounding errors. So if we can avoid all that with one call to sqrt, the routine should perform better.

Correct me if I'm wrong but can't you just use sin and cos tables to eliminate the expense?
Quote this message in a reply
Sage
Posts: 1,482
Joined: 2002.09
Post: #28
Leroy Wrote:Correct me if I'm wrong but can't you just use sin and cos tables to eliminate the expense?

Yes, but at the cost of more rounding errors. Making a lookup table entry for every possible 32bit float is not an option.

Scott Lembcke - Howling Moon Software
Author of Chipmunk Physics - A fast and simple rigid body physics library in C.
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #29
Why are you trying to get around using a much easier, faster, and all round better method anyway?
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #30
On a modern processor, a sin/cos lookup table with any accuracy is almost certainly more expensive than just calculating the sin or cosine directly.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Formula for converting angle to vector? komirad 2 10,210 Jul 29, 2011 07:29 AM
Last Post: ThemsAllTook
  Question Regarding the Reflect Angle of a Transition iBaby 3 3,620 Apr 27, 2010 03:15 PM
Last Post: JustinFic
  ending location from angle and speed Kazooless 5 4,608 Apr 3, 2009 02:40 PM
Last Post: Gillissie
  Angle between two points? Graphic Ace 6 5,541 Nov 8, 2008 12:11 PM
Last Post: macnib
  calculating X and Y coordinates w/ an angle and distance ferum 13 15,270 Jun 25, 2008 10:53 PM
Last Post: rosenth