Skip to content

Instantly share code, notes, and snippets.

@paveltyavin
Last active August 16, 2017 13:00
Show Gist options
  • Save paveltyavin/73a69457ebc8ff6a08033a7cf71a200f to your computer and use it in GitHub Desktop.
Save paveltyavin/73a69457ebc8ff6a08033a7cf71a200f to your computer and use it in GitHub Desktop.
converts polygon to list of geohashes. You can specify precision and tile policy. Different interpretations of geohashes in output.
"""find geohashes inside polygon"""
from __future__ import division
__base32 = '0123456789bcdefghjkmnpqrstuvwxyz'
precision = 8
geohash_corners_inside_polygon_policy = any # or all
def geohash(lon, lat):
result_str = []
bit, ch, even = 0, 0, True
data = [[[-90.0, 90.0], lat], [[-180.0, 180.0], lon]]
while len(result_str) < precision:
mid = (data[even][0][0] + data[even][0][1]) / 2
if data[even][1] > mid:
ch |= 1 << (4 - bit)
data[even][0][0] = mid
else:
data[even][0][1] = mid
even = not even
if bit < 4:
bit += 1
else:
result_str += __base32[ch]
bit, ch = 0, 0
return ''.join(result_str)
def is_point_in_path(p, poly):
x, y = p
num = len(poly)
i, j, c = 0, num - 1, 0
for i in range(num):
a, b = poly[i], poly[j]
d = (b[0] - a[0]) / (b[1] - a[1])
c += (a[1] > y) != (b[1] > y) and ((x - a[0]) < d * (y - a[1]))
j = i
return c % 2 == 1
def get_geohash_list(poly):
data = [[-90.0, 90.0, 1], [-180.0, 180.0, 1]]
for x in range(precision):
data[0][2] += 2
data[1][2] += 2
data[x % 2][2] += 1
bor = [[90.0, -90.0], [180.0, -180.0]]
for x in poly:
for k in (0, 1):
bor[k][0] = min(bor[k][0], x[k])
bor[k][1] = max(bor[k][1], x[k])
for k in (0, 1):
a, b = bor[k]
while 1:
mid = (data[k][0] + data[k][1]) / 2
if mid < a:
data[k][0] = mid
elif mid > b:
data[k][1] = mid
else:
break
data[k][2] -= 1
result_str = []
a, b = 2 ** data[0][2], 2 ** data[1][2]
dx, dy = (data[0][1] - data[0][0]) / a, (data[1][1] - data[1][0]) / b
for x in range(int(a)):
for y in range(int(b)):
lat, lon = data[0][0] + x * dx, data[1][0] + y * dy
f = geohash_corners_inside_polygon_policy
if f((is_point_in_path((lat + n * dx, lon + m * dy), poly) for n, m in ((0, 1), (1, 1), (0, 0), (1, 0)))):
result_str.append(geohash(lat, lon))
result_str.sort()
return result_str
if __name__ == "__main__":
poly = [
[37.65523240194326, 55.73743063849311],
[37.654240735852696, 55.7387088631641],
[37.65386326181754, 55.73889370228734],
[37.653893527937065, 55.7382825839584],
[37.65454606654813, 55.73734458984159],
]
geohash_list = get_geohash_list(poly)
print(" ".join(geohash_list))
# other interpretations
geohash_bits = [[__base32.index(c) for c in g] for g in geohash_list]
print(" ".join("".join("{:05b}".format(x) for x in y) for y in geohash_bits))
print(" ".join("{:d}".format(int("".join("{:05b}".format(x) for x in y), 2)) for y in geohash_bits))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment