Browse Source

added class Location

Fabian Peter Hammerle 6 years ago
parent
commit
ad550e31b5
2 changed files with 74 additions and 0 deletions
  1. 37 0
      termux_log_location/__init__.py
  2. 37 0
      tests/test_location.py

+ 37 - 0
termux_log_location/__init__.py

@@ -0,0 +1,37 @@
+import math
+
+
+class Location:
+
+    EARTH_RADIUS_METRES = 6.371e6
+
+    def __init__(self, latitude, longitude, altitude):
+        self.latitude = latitude
+        self.longitude = longitude
+        self.altitude = altitude
+
+    @property
+    def latitude_radian(self):
+        return math.radians(self.latitude)
+
+    @property
+    def longitude_radian(self):
+        return math.radians(self.longitude)
+
+    @staticmethod
+    def haversine(angle_rad):
+        # http://mathworld.wolfram.com/Haversine.html
+        return math.sin(angle_rad / 2) ** 2
+
+    @staticmethod
+    def haversine_inv(hav):
+        # return math.atan2(math.sqrt(hav), math.sqrt(1-hav)) * 2
+        return math.asin(math.sqrt(hav)) * 2
+
+    @staticmethod
+    def haversine_distance_metres(a, b):
+        # https://en.wikipedia.org/wiki/Haversine_formula
+        hav = Location.haversine(b.latitude_radian - a.latitude_radian) \
+            + math.cos(a.latitude_radian) * math.cos(b.latitude_radian) \
+                * Location.haversine(b.longitude_radian - a.longitude_radian)
+        return Location.haversine_inv(hav) * Location.EARTH_RADIUS_METRES

+ 37 - 0
tests/test_location.py

@@ -0,0 +1,37 @@
+import pytest
+
+from termux_log_location import *
+
+
+@pytest.mark.parametrize(('a', 'hav'), [
+    [math.pi*0,    0  ],
+    [math.pi/2,    1/2],
+    [math.pi*1,    1  ],
+    [math.pi*3/2,  1/2],
+    [math.pi*2,    0  ],
+    [math.pi/-2,   1/2],
+    [math.pi*-1,   1  ],
+    [math.pi*-3/2, 1/2],
+    [math.pi*-2,   0  ],
+])
+def test_haversine(a, hav):
+    assert Location.haversine(a) == pytest.approx(hav)
+
+
+@pytest.mark.parametrize(('a'), [0, 1, 2, math.pi])
+def test_haversine_inv(a):
+    assert Location.haversine_inv(Location.haversine(a)) == pytest.approx(a)
+
+LINZ = Location(latitude=48.3069, longitude=14.2858, altitude=266)
+INNSBRUCK = Location(latitude=47.2692, longitude=11.4041, altitude=574)
+STEPHENS_CATHEDRAL = Location(latitude=48.2084, longitude=16.3735, altitude=178)
+VIENNA_STATE_OPERA = Location(latitude=48.2033, longitude=16.3692, altitude=173)
+
+@pytest.mark.parametrize(('a', 'b', 'd'), [
+    [INNSBRUCK, LINZ, 244238],
+    [LINZ, INNSBRUCK, 244238],
+    [STEPHENS_CATHEDRAL, LINZ, 154938],
+    [STEPHENS_CATHEDRAL, VIENNA_STATE_OPERA, 650],
+])
+def test_haversine_distance_metres(a, b, d):
+    assert Location.haversine_distance_metres(a, b) == pytest.approx(d, abs=1)