-
Notifications
You must be signed in to change notification settings - Fork 0
/
geohash
executable file
·113 lines (91 loc) · 3.15 KB
/
geohash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# Inspired by: https://yatmanwong.medium.com/geohash-implementation-explained-2ed9627a61ff
#!/bin/sh
true + /; exec awk --bignum -f "$0" $@; exit; / {}
function _spaceout(a, res)
{
# turn 01101... into 0010100010...
# from https://stackoverflow.com/a/58980803
# see also: https://graphics.stanford.edu/~seander/bithacks.html#InterleaveBMN
res = and(a, 0x00000000ffffffff)
res = and(or(res, lshift(res,16)), 0x0000ffff0000ffff)
res = and(or(res, lshift(res, 8)), 0x00ff00ff00ff00ff)
res = and(or(res, lshift(res, 4)), 0x0f0f0f0f0f0f0f0f)
res = and(or(res, lshift(res, 2)), 0x3333333333333333)
res = and(or(res, lshift(res, 1)), 0x5555555555555555)
return res
}
function _odd_bits(a, res)
{
# take only odd bits
res = and(a, 0x5555555555555555)
res = and(or(res, rshift(res, 1)), 0x3333333333333333)
res = and(or(res, rshift(res, 2)), 0x0f0f0f0f0f0f0f0f)
res = and(or(res, rshift(res, 4)), 0x00ff00ff00ff00ff)
res = and(or(res, rshift(res, 8)), 0x0000ffff0000ffff)
res = and(or(res, rshift(res,16)), 0x00000000ffffffff)
return res
}
function _interleave(a, b)
{
# turn a=110..., b=010... into 011100
return or(lshift(_spaceout(b), 1), _spaceout(a))
}
function _base32encode(x, res)
{
# encode integer with base32 geohash encoding
# iterate 5 bits at a time
for (i=0; i<precision; ++i)
res = sprintf("%s%s",res,_32ENC[and(rshift(x, 57-i*5), 31)])
return res
}
function _base32decode(x, res, chars, M)
{
# decode base32 geohash to an integer
split(x,chars,"")
M = length(chars) > 12 ? 12 : length(chars)
for (i=0; i<M; ++i)
res = or(lshift(_32DEC[chars[i+1]], 57-i*5), res)
return res
}
function geohash_encode(lat, lon)
{
return _base32encode( \
_interleave( \
and(int((lat + 90) / 180.0 * 0x80000000), 0x7fffffff), \
and(int((lon + 180) / 360.0 * 0x80000000), 0x7fffffff)))
}
function geohash_decode(geohash, x)
{
x = _base32decode(geohash)
return sprintf( \
"%.16f%s%.16f", \
(and(_odd_bits(x), 0x7fffffff) / 0x80000000)*180 - 90, \
FS, \
(and(_odd_bits(rshift(x, 1)), 0x7fffffff) / 0x80000000)*360 - 180)
}
BEGIN {
# set up lookup tables for base32
for (i=0; i<32; ++i) {
if (i < 10)
_32ENC[i] = i
else if (i < 17)
_32ENC[i] = sprintf("%c", i + 88)
else if (i < 19)
_32ENC[i] = sprintf("%c", i + 89)
else if (i < 21)
_32ENC[i] = sprintf("%c", i + 90)
else
_32ENC[i] = sprintf("%c", i + 91)
_32DEC[_32ENC[i]] = i
}
if (precision > 12 || precision < 1)
precision = 12
}
{
res=$0
if ("" != lat && "" != lon)
res = res FS geohash_encode($lat, $lon)
if ("" != geohash)
res = res FS geohash_decode($geohash)
print res
}