Last active
August 16, 2017 13:00
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""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