Trigonometric find angle
Hi guys,
anyone knows a formula to calculate an angle between two coordinates, using basic?s function ATN , recent programming tools have ATAN2(dy,dx), but im having trouble using atn.
thanx in advance.
anyone knows a formula to calculate an angle between two coordinates, using basic?s function ATN , recent programming tools have ATAN2(dy,dx), but im having trouble using atn.
thanx in advance.
Post edited by Valz on

Comments
ATN returns values in range -pi to pi I expect EDIT: I mean -pi/2 to pi/2, you need to check which quadrant y and x are in and adjust the angle accordingly.
x > 0: just return ATN(y/x)
x < 0: if(y > 0) return ATN(y/x) + PI
x < 0: if(y < 0) return ATN(y/x) - PI
x = 0 return PI/2 if y > 0, -PI/2 otherwise.
Here is a link to a C implementation:
http://www.raspberryginger.com/jbailey/minix/html/atan2_8c-source.html
EDIT: Most of the time you can avoid trig by using vectors though...
Egghead Website
Arcade Game Designer
My itch.io page
here?s what i have done in zxbasic compiler:
dim dx,dy as integer rem range -32768..32767
dim value as fixed rem range -32767.9999847 to 32767.9999847
cls
print getangle (100,100,100,50) rem 89,expected 0
print getangle (100,100,150,100) rem -88,expected 90
print getangle (100,100,100,150) rem 89,expected 180
print getangle (100,100,50,100) rem -89,expected -90
end
function getangle (x1 as ubyte,y1 as ubyte,x2 as ubyte,y2 as ubyte) as fixed
dx=x2-x1
dy=y2-y1
if dx>0 then value= atn(dy-dx):end if
if dx<0 and dy>0 then value=atn(dy/dx)+pi:end if
if dx<0 and dy<0 then value=atn(dy/dx)-pi:end if
if dx=0 then
if dy>0 then value=pi/2:end if
if dy<0 then value=-pi/2:end if
end if
return int((value/pi)*180) rem to convert rads to degres right?
end function
can you find out what am i doing wrong? :)
you mean
if dx>0 then value= atn(dy/dx):end if
This case: getangle(100, 100, 100, 50) should return -90...
x1 = 100
y1 = 100
x2 = 100
y2 = 50
dx = x2 - x1 = 0
dy = y2 - y1 = 50 - 100 = -50
if dx=0 then
if dy>0 then value=pi/2:end if
if dy<0 then value=-pi/2:end if
end if
so return int((value/pi)*180) should be
((-pi/2)/pi)*180 = -1/2 * 180 = -90
Try printing out intermediate values are you sure it isn't truncating or doing integer division somewhere? why are you using ubyte as arguments?
Remember the angle is measured from the X-axis (not the y-axis) and +ve angles are anticlockwise
but now i don?t have negative numbers, only zero:
print getangle (100,100,80,120) rem 0
print getangle (100,100,120,50) rem 84
print getangle (100,100,110,50) rem 87
print getangle (100,100,150,100) rem 0
print getangle (100,100,100,150) rem 89
print getangle (100,100,50,100) rem 0
im using ubyte for the coordinates (0-255) value
fixed for the decimals,after divisions
and integer for the actual value of the angle,positive or negative
maybe this doesn?t work, like johnathan said :(
dim dx,dy as fixed
dim value as fixed
cls
print getangle (100,100,100,50) rem 0
print getangle (100,100,120,50) rem 22
print getangle (100,100,110,50) rem 12
print getangle (100,100,150,100) rem 90
print getangle (100,100,100,150) rem 180
print getangle (100,100,50,100) rem -90
function getangle (x1 as fixed,y1 as fixed,x2 as fixed,y2 as fixed) as fixed
dx=x2-x1
dy=y2-y1
if dx>0 then value= atn(dy/dx):end if
if dx<0 and dy>0 then value=atn(dy/dx)+pi:end if
if dx<0 and dy<=0 then value=atn(dy/dx)-pi:end if
if dx=0 then
if dy>0 then value=pi/2:end if
if dy<0 then value=-pi/2:end if
end if
return int((value/pi)*180)+90 rem to convert rads to degres right?
end function
it gives this type of result:
.......0
.-90...90
......180
thanks a lot Paradigm :)
0 degrees is due EAST
90 degrees is due NORTH
+/-180 degrees is due WEST
270 degrees/ -90 degrees is due SOUTH
I do realise a lot of people seem to like measuring their angles clockwise from due north though, rather than anticlockwise from due east which is how we do it in maths ;)
EDIT: Except bearings, but those are used for navigating ships ;) I don't use degrees either, I only ever use radians or some fixed point representation e.g. 256 "angs" in a full circle or something like that.
ie, if a enemy fires a bullet to the player like an homing missile or something,
i find this a essencial function for this type of calculation, could use coordinate checking x<x2 etc, but this is much better. ;)
vToPlayer = vPlayerPos - vBulletPos
vToPlayer = normalise(vToPlayer) // make length of vector 1 by dividing by the magnitude
vBulletPos = vBulletPos + vToPlayer * bulletSpeed
(things with a v in front of variable name are vectors)
EDIT: You can replace the normalise step and instead do
vBulletPos = vBulletPos + vToPlayer * bulletSpeed / vectorLength(vToPlayer)
EDIT2: If you find yourself doing an ATAN2 followed by some SIN/COS stuff on the result, chances are you are better off doing it with vectors instead.
But if using vectors proves to be faster especially for real time calculations i will sure give it a try :)
All you need to do is write routines to add and subtract vectors, multiply them by a scalar, dot product, find the length (which is the square root of the vector dot producted with itself), and normalisation (divide a vector by its length).
A lot of the time you can use length squared (which is just the vector dot producted with itself) instead of the length, since if a < b and a, b are >= 0 then a^2 < b^2
e.g. am I within 50 units of the origin (i.e. within a circle of radius 50) -> is the length squared < 50 * 50
This is basically how the towers in Blizzard's Rift work out which direction to fire at the player:
If x is your horizontal distance and y is your vertical distance then:
LET h=SQR (x*x+y*y)
will give you the length of the hypotenuse. Then:
LET a=ACS (x/h) should give you the angle, which you can then add to/subtract from the relevant compass point depending on the quarter you're in.
Obviously, Blizzard's Rift does all of this in machine code but the principle is the same.
Egghead Website
Arcade Game Designer
My itch.io page
EDIT: I've never had a problem using atan2 in C/C++, dunno if it is different on 8-bit platforms though (PC/PS1/PS2/PS3/PSVita/XBox360/Wii are the platforms I have worked on before). EDIT: Actually I would be using atan2f since that takes and returns a float rather than a double which is what atan2 does. PS1 was fixed point 4.12 (4 bits of integral value [20 if using 32 bit integer fixed point] and 12 bits of fractional values (i.e. 1/4096 accuracy)), and I had no problems with atan2 there either...
And that is in any programming language :)
EDIT: Ok again, you'd also use trig to rotate the facing vector of the player ship when you use rotate left and right buttons ;)