Pseudoangles: Difference between revisions
(typo) |
(add new code variant) |
||
(5 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
[[File:atan.png|420px|thumb|Field lines for regular atan.]] |
|||
[[File:pseudoangles.png|420px|thumb|Field lines for pseudoangles. Note that the sectors near the cardinal directions are slightly narrower compared to regular atan.]] |
|||
Pseudoangles allow you to compare the angles of two vectors without actually computing the angle itself (which could be costly). By extension, it also allows you to sort a list of vectors by angle without calling <tt>atan()</tt> or <tt>atan2()</tt>. |
Pseudoangles allow you to compare the angles of two vectors without actually computing the angle itself (which could be costly). By extension, it also allows you to sort a list of vectors by angle without calling <tt>atan()</tt> or <tt>atan2()</tt>. |
||
Line 17: | Line 20: | ||
<source lang="Python"> |
<source lang="Python"> |
||
def |
def pseudoangle(y, x): |
||
r = x / (abs(x) + abs(y)) |
r = x / (abs(x) + abs(y)) |
||
if y < 0: |
if y < 0: |
||
Line 27: | Line 30: | ||
<source lang="Python"> |
<source lang="Python"> |
||
def |
def pseudoangle(y, x): |
||
r = x / (abs(x) + abs(y)) |
r = x / (abs(x) + abs(y)) |
||
if y < 0: |
if y < 0: |
||
Line 35: | Line 38: | ||
I personally prefer this last version as there are no performance disadvantages to using it anyway. |
I personally prefer this last version as there are no performance disadvantages to using it anyway. |
||
In languages with a <tt>sign()</tt> (or <tt>copysign()</tt>) function you can use that to further simplify it: |
|||
<source lang="GLSL"> |
|||
float pseudoangle(float y, float x) |
|||
{ |
|||
return sign(y) * (1. - x / (abs(x) + abs(y))); |
|||
} |
|||
</source> |
|||
=== See also === |
|||
* https://stackoverflow.com/questions/16542042/fastest-way-to-sort-vectors-by-angle-without-actually-computing-that-angle |
|||
[[Category:Programming]] |
[[Category:Programming]] |
||
[[Category:Geometry]] |
[[Category:Geometry]] |
||
[[Category:Trigonometry]] |
Latest revision as of 18:19, 25 February 2020
Pseudoangles allow you to compare the angles of two vectors without actually computing the angle itself (which could be costly). By extension, it also allows you to sort a list of vectors by angle without calling atan() or atan2().
The version you'll typically find on Google [1][2] is basically:
def pseudoangle(y, x):
r = y / (abs(x) + abs(y))
if x < 0:
return 2. - r
else:
return 4. + r
This function returns a value between 1 and 5. When used as a sort key, this yields the same behaviour as the key mod(atan2(y, x) + 1.5 * pi, 2. * pi). It is therefore not a direct replacement for atan2() if you care about which angles are considered the smallest/larges, however it does sort in the correct "direction".
If you want to preserve the exact sorting order as if you had used atan2() (with the return value in range 0-4), you can use:
def pseudoangle(y, x):
r = x / (abs(x) + abs(y))
if y < 0:
return 1. + r
return 3. - r
If you also want the sign of the return value to be the same as for atan2(), i.e. return value in range (-2 to 2), you can use:
def pseudoangle(y, x):
r = x / (abs(x) + abs(y))
if y < 0:
return r - 1.
return 1. - r
I personally prefer this last version as there are no performance disadvantages to using it anyway.
In languages with a sign() (or copysign()) function you can use that to further simplify it:
float pseudoangle(float y, float x)
{
return sign(y) * (1. - x / (abs(x) + abs(y)));
}