RosettaCodeData/Task/Angle-difference-between-tw.../Python/angle-difference-between-tw...

90 lines
2.2 KiB
Python

'''Difference between two bearings'''
from math import (acos, cos, pi, sin)
# bearingDelta :: Radians -> Radians -> Radians
def bearingDelta(ar):
'''Difference between two bearings,
expressed in radians.'''
def go(br):
[(ax, ay), (bx, by)] = [
(sin(x), cos(x)) for x in [ar, br]
]
# cross-product > 0 ?
sign = +1 if 0 < ((ay * bx) - (by * ax)) else -1
# sign * dot-product
return sign * acos((ax * bx) + (ay * by))
return lambda br: go(br)
# TEST ----------------------------------------------------
# main :: IO ()
def main():
'''Test and display'''
# showMap :: Degrees -> Degrees -> String
def showMap(da, db):
return unwords(
str(x).rjust(n) for n, x in
[
(22, str(da) + ' +'),
(24, str(db) + ' -> '),
(7, round(
degrees(
bearingDelta
(radians(da))
(radians(db))
), 2)
)
]
)
print(__doc__ + ':')
print(
unlines(showMap(a, b) for a, b in [
(20, 45),
(-45, 45),
(-85, 90),
(-95, 90),
(-45, 125),
(-45, 145),
(-70099.74233810938, 29840.67437876723),
(-165313.6666297357, 33693.9894517456),
(1174.8380510598456, -154146.66490124757),
(60175.77306795546, 42213.07192354373)
]))
# GENERIC ----------------------------------------------
# radians :: Float x => Degrees x -> Radians x
def radians(x):
'''Radians derived from degrees.'''
return pi * x / 180
# degrees :: Float x => Radians x -> Degrees x
def degrees(x):
'''Degrees derived from radians.'''
return 180 * x / pi
# unlines :: [String] -> String
def unlines(xs):
'''A single newline-delimited string derived
from a list of strings.'''
return '\n'.join(xs)
# unwords :: [String] -> String
def unwords(xs):
'''A space-separated string derived from
a list of words.'''
return ' '.join(xs)
if __name__ == '__main__':
main()