Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple, ugly function to produce an orientation from an angle.

Tags:

python

I wrote a function that takes a degree and returns the orientation as 'N', 'NE', ...etc. Very simple, but it's ugly - is there any way to rewrite this to make it...prettier?

def orientation(tn):
    if 23 <= tn <= 67:
        o = 'NE'
    elif 68 <= tn <= 113:
        o = 'E'    
    elif 114 <= tn <= 158:
        o = 'SE'
    elif 159 <= tn <= 203:
        o = 'S'
    elif 204 <= tn <= 248:
        o = 'SW'
    elif 249 <= tn <= 293:
        o = 'W'
    elif 294 <= tn <= 338:
        o = 'NW'
    else:
        o = 'N'
    return o
like image 529
mk8efz Avatar asked Aug 16 '16 19:08

mk8efz


1 Answers

Use bisection:

from bisect import bisect_left

directions = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'N']
boundaries = [22,  67,   113, 158,  203, 248,  293, 338,  360]

def orientation(tn):
    return directions[bisect_left(boundaries, tn)]

bisect_left() (very efficiently) finds the index into which you'd insert tn into the boundaries list; that index is then mapped into the directions list to translate to a string.

Bisection only takes up to 4 steps to find the right boundary (log2(len(boundaries))).

You could also add 22 and divide the value modulo 360 by 45:

directions = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'N']

def orientation(tn):
    index = ((tn + 22) % 360) // 45
    return directions[index]

However, your original boundaries were not evenly distributed at 45 degrees each, so this gives a slightly different result (your N boundaries span 44 degrees, while E is allotted 46 degrees). Bisection doesn't care about such exceptions; you can shift the boundaries all you like.

like image 70
Martijn Pieters Avatar answered Oct 01 '22 01:10

Martijn Pieters