59 lines
1.4 KiB
Python
59 lines
1.4 KiB
Python
import math
|
|
from collections import namedtuple
|
|
|
|
from . import geohash
|
|
|
|
Box = namedtuple("Box", ["s", "w", "n", "e"])
|
|
|
|
|
|
def geohash_bbox(gh):
|
|
ret = geohash.bbox(gh)
|
|
return Box(ret["s"], ret["w"], ret["n"], ret["e"])
|
|
|
|
|
|
def bbox(lat, lon, radius):
|
|
lat_delta = radius * 360 / 40000
|
|
lon_delta = lat_delta / math.cos(lat * math.pi / 180.0)
|
|
return Box(lat - lat_delta, lon - lon_delta, lat + lat_delta, lon + lon_delta)
|
|
|
|
|
|
def overlap(a1, a2, b1, b2):
|
|
return a1 < b2 and a2 > b1
|
|
|
|
|
|
def box_overlap(box1: Box, box2: Box):
|
|
return overlap(box1.s, box1.n, box2.s, box2.n) and overlap(
|
|
box1.w, box1.e, box2.w, box2.e
|
|
)
|
|
|
|
|
|
def compute_geohash_tiles(lat, lon, radius, precision):
|
|
bounds = bbox(lat, lon, radius)
|
|
center = geohash.encode(lat, lon, precision)
|
|
|
|
stack = set()
|
|
checked = set()
|
|
|
|
stack.add(center)
|
|
checked.add(center)
|
|
|
|
while stack:
|
|
current = stack.pop()
|
|
for neighbor in geohash.neighbors(current):
|
|
if neighbor not in checked and box_overlap(geohash_bbox(neighbor), bounds):
|
|
stack.add(neighbor)
|
|
checked.add(neighbor)
|
|
return checked
|
|
|
|
|
|
def geohash_overlap(lat, lon, radius, max_tiles=9):
|
|
result = []
|
|
for precision in range(1, 13):
|
|
tiles = compute_geohash_tiles(lat, lon, radius, precision)
|
|
if len(tiles) <= 9:
|
|
result = tiles
|
|
precision += 1
|
|
else:
|
|
break
|
|
return result
|