-
Notifications
You must be signed in to change notification settings - Fork 2
/
geohash.go
84 lines (73 loc) · 1.39 KB
/
geohash.go
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
// Copyright 2012 Chris Broadfoot (chris@chrisbroadfoot.id.au). All rights reserved.
// Licensed under Apache 2.
// An implementation of the geohash algorithm: http://en.wikipedia.org/wiki/Geohash
package geohash
import (
"strings"
)
const (
precision = 12
base32 = "0123456789bcdefghjkmnpqrstuvwxyz"
)
func Encode(lat, lng float64) string {
geohash := ""
lats := [2]float64{-90, 90}
lngs := [2]float64{-180, 180}
even := true
bit := 0
n := 0
for len(geohash) < precision {
n <<= 1
// interleave bits
if even {
n ^= constrict(&lngs, lng)
} else {
n ^= constrict(&lats, lat)
}
if bit == 4 {
geohash += string(base32[n])
bit = 0
n = 0
} else {
bit++
}
even = !even
}
return geohash
}
func Decode(geohash string) ([2]float64, [2]float64) {
lats := [2]float64{-90, 90}
lngs := [2]float64{-180, 180}
even := true
for _, r := range geohash {
i := strings.Index(base32, string(r))
for j := 16; j != 0; j >>= 1 {
if even {
refine(&lngs, i&j)
} else {
refine(&lats, i&j)
}
even = !even
}
}
return lats, lngs
}
func constrict(pair *[2]float64, coord float64) int {
m := mid(pair)
if coord > m {
pair[0] = m
return 1
}
pair[1] = m
return 0
}
func refine(pair *[2]float64, bit int) {
if bit != 0 {
pair[0] = mid(pair)
} else {
pair[1] = mid(pair)
}
}
func mid(pair *[2]float64) float64 {
return (pair[0] + pair[1]) / 2
}