Sideband/sbapp/mapview/utils.py

51 lines
1.6 KiB
Python
Raw Permalink Normal View History

2023-10-19 07:01:17 -06:00
# coding=utf-8
__all__ = ["clamp", "haversine", "get_zoom_for_radius"]
from math import asin, cos, pi, radians, sin, sqrt
from kivy.core.window import Window
from kivy.metrics import dp
def clamp(x, minimum, maximum):
return max(minimum, min(x, maximum))
def haversine(lon1, lat1, lon2, lat2):
"""
Calculate the great circle distance between two points
on the earth (specified in decimal degrees)
Taken from: http://stackoverflow.com/questions/4913349/haversine-formula-in-python-bearing-and-distance-between-two-gps-points
"""
# convert decimal degrees to radians
lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
# haversine formula
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(dlon / 2) ** 2
c = 2 * asin(sqrt(a))
km = 6367 * c
return km
def get_zoom_for_radius(radius_km, lat=None, tile_size=256.0):
"""See: https://wiki.openstreetmap.org/wiki/Zoom_levels"""
radius = radius_km * 1000.0
if lat is None:
lat = 0.0 # Do not compensate for the latitude
# Calculate the equatorial circumference based on the WGS-84 radius
earth_circumference = 2.0 * pi * 6378137.0 * cos(lat * pi / 180.0)
# Check how many tiles that are currently in view
nr_tiles_shown = min(Window.size) / dp(tile_size)
# Keep zooming in until we find a zoom level where the circle can fit inside the screen
zoom = 1
while earth_circumference / (2 << (zoom - 1)) * nr_tiles_shown > 2 * radius:
zoom += 1
return zoom - 1 # Go one zoom level back