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