ID:1289853
 
(See the best response by Kaiochao.)
How do you find the angle in degrees between two points without using trig functions?

I can't, for the life of me, figure out how to compute this raw without trig functions.
Use a protractor.

More seriously, why? I can't think of any particular tricks that work in general, and I don't see why you'd want to avoid the trig functions.
Do you really need the angle, or do you just need some vector from one object to the other with a magnitude you specify?

If you really do need the angle, atan2's your best bet.
I need a number between 0 and 359 (or 1 and 360) from point a to point b, namely describing the degree of angle pointing towards point b from point a.
In response to Jp
I want to avoid the trig functions because there are none (of common use) in DM and I want to compute this raw without using a poorly defined version of a trig function that operates in the VM and not internally.
If there's a shortcut, what I'm really trying to do is compute a direction from the angle in degrees, because get_dir() returns results that I don't like. I'm splitting the 8 directions in between very specific degree ranges.
Well, there is no built-in get_angle or atan2. There's also no functions that I know of mathematically that convert numbers into angles aside from the inverse trig functions.
In response to FIREking
Best response
There are, however, general direction procs in the Snippets Database that don't use angles at all.

http://www.byond.com/forum/?post=195151
So, why no trig functions?

And what kind of points?
Pixels? or tile?

edit: we do have cos, sin, arccos, and arcsin in DM. Literally every other trig function is based on those. It's not "poorly defined".
In response to Kaiochao
Kaiochao wrote:
There are, however, general direction procs in the Snippets Database that don't use angles at all.

http://www.byond.com/forum/?post=195151

That's much better than what I was trying to do, and works perfectly for my case.
In response to Super Saiyan X
Super Saiyan X wrote:
So, why no trig functions?

And what kind of points?
Pixels? or tile?

edit: we do have cos, sin, arccos, and arcsin in DM. Literally every other trig function is based on those. It's not "poorly defined".

You should see some of the code snippets I've seen... like in Bravo's get_ libraries O_o

I don't claim to know trig or algebra much, so I don't really know or care to know the difference between atan and atan2 (especially when you have to define them yourself)...

That's why I ask here because I know there are people that will read it who know how to do what I want to do much faster and more efficient. My lack of math understanding doesn't inhibit my ability to create what I wish, it just means I have to rely on someone else to help me get to where I'm trying to go.

Searching for the difference between acos and arcos in google for example yields strange results and unclear information. I'm 28 and graduated high school over 10 years ago, so excuse me for forgetting almost all of geometry and trigonometry haha.

That said, I'm glad there's people around like you guys to help me "get to the point" and make my game instead of trying to become the next John Carmack, who doesn't even make games, he writes engines. If I was interested in doing that, I wouldn't be here at BYOND.
For completeness sake, the absolute most efficient way in DM to calculate an angle in degrees between two points is using atan2(), which is

proc/atan2(x, y)
if(!x && !y) return 0
return y >= 0 ? arccos(x / sqrt(x * x + y * y)) : -arccos(x / sqrt(x * x + y * y))


Correct?

To find the angle from a to b, you'd go:

proc/get_angle(atom/a, atom/b)
return atan2(b.y - a.y, b.x - a.x)


Right?
In response to FIREking
Yeah.

Personally, I prefer 0 pointing north and 90 pointing east, so I return something like clamp_angle(90 - that), which makes it a tiny bit less efficient. This proc isn't usually the bottleneck in any of my projects, though.
That's the angle from A to B, to be clear.
In response to Kaiochao
Kaiochao wrote:
Yeah.

Personally, I prefer 0 pointing north and 90 pointing east, so I return something like clamp_angle(90 - that), which makes it a tiny bit less efficient. This proc isn't usually the bottleneck in any of my projects, though.

Me too, I always did +270 but 90 - x might make more sense (or maybe it doesn't matter).
In response to FIREking
Adding 270 doesn't change it from increasing counterclockwise to increasing clockwise.
Thanks everyone.
Wait, hang on, that atan implementation has the x parameter first. Fireking's getangle above - with the y parameter first - calculates angles with 0 north, positive clockwise.

In response to Jp
Thanks, that helps!
proc
// returns an angle, [0, 360), from given offsets
// 0 = north, increases clockwise
atan2(x, y)
if(!(x || y)) return 1.#IND
if(istype(x, /list) && x:len == 2) { y = x[2]; x = x[1] }
return x >= 0 ? arccos(y / sqrt(x * x + y * y)) : 360 - arccos(y / sqrt(x * x + y * y))
I'm testing the two methods right now, the method mentioned by Kaiochao (get_dir_adv) vs the method I've shown (get_dir_angle), which goes on to return a direction based on some if calls

Here's the speed results between the two (three tests, each)

get_dir_angle

cpu: 29
cpu_average: 26.8693
projectiles: 723
projectiles_fired: 100078
bots: 256

cpu: 30
cpu_average: 26.9944
projectiles: 678
projectiles_fired: 100060
bots: 256

cpu: 31
cpu_average: 28.734
projectiles: 698
projectiles_fired: 100066
bots: 256

test average cpu average: 27.52

get_dir_adv

cpu: 31
cpu_average: 27.8636
projectiles: 722
projectiles_fired: 100006
bots: 256

cpu: 32
cpu_average: 27.8526
projectiles: 738
projectiles_fired: 100062
bots: 256

cpu: 29
cpu_average: 28.0639
projectiles: 687
projectiles_fired: 100088
bots: 256

test average cpu average: 27.92


I'm calling the proc at the beginning of projectile's creation, and its direction does not change during its lifespan. I have no idea why the less efficient (at glance) method is actually better on the CPU... perhaps its a matter of variable storage and recall.

I would expect Kao's solution to be much faster but for some reason it really isn't that much faster...

Here are the two methods:
proc/get_dir_adv(atom/ref, atom/target)
//Written by Lummox JR
//Returns the direction between two atoms more accurately than get_dir()

if(target.z > ref.z) return UP
if(target.z < ref.z) return DOWN

. = get_dir(ref, target)
if(. & . - 1) // diagonal
var/ax = abs(ref.x - target.x)
var/ay = abs(ref.y - target.y)
if(ax >= (ay << 1)) return . & (EAST | WEST) // keep east/west (4 and 8)
else if(ay >= (ax << 1)) return . & (NORTH | SOUTH) // keep north/south (1 and 2)
return .


proc/atan2(x, y)
if(!x && !y) return 0
return y >= 0 ? arccos(x / sqrt(x * x + y * y)) : -arccos(x / sqrt(x * x + y * y))

proc/get_angle(atom/a, atom/b)
return atan2(b.y - a.y, b.x - a.x)

proc/get_dir_angle(atom/a, atom/b)
//converts an angle into a direction, for projectile facing
. = get_angle(a, b) + 270
if(. > 360) . = . * 0.0027 + . % 360
if(. >= 337.5 || . <= 22.5) return EAST
if(. >= 22.5 && . <= 67.5) return SOUTHEAST
if(. >= 67.5 && . <= 112.5) return SOUTH
if(. >= 112.5 && . <= 157.5) return SOUTHWEST
if(. >= 157.5 && . <= 202.5) return WEST
if(. >= 202.5 && . <= 247.5) return NORTHWEST
if(. >= 247.5 && . <= 292.5) return NORTH
if(. >= 292.5 && . < 337.5) return NORTHEAST
Page: 1 2