2
2
"""
3
3
Copyright (C) 2009 Hiroaki Kawai <[email protected] >
4
4
"""
5
+ try :
6
+ import _geohash
7
+ except ImportError ,e :
8
+ _geohash = None
9
+
5
10
__all__ = ['encode' ,'decode' ,'decode_exactly' ,'bbox' , 'neighbors' , 'expand' ]
6
11
7
12
_base32 = '0123456789bcdefghjkmnpqrstuvwxyz'
@@ -32,36 +37,49 @@ def _encode_i2c(lat,lon,lat_length,lon_length):
32
37
a = lat
33
38
b = lon
34
39
40
+ boost = (0 ,1 ,4 ,5 ,16 ,17 ,20 ,21 )
35
41
ret = ''
36
- while precision > 0 :
37
- c = ((a & 4 )<< 2 ) + ((b & 2 )<< 2 ) + ((a & 2 )<< 1 ) + ((b & 1 )<< 1 ) + (a & 1 )
38
- ret += _base32 [c ]
42
+ for i in range (precision ):
43
+ ret += _base32 [(boost [a & 7 ]+ (boost [b & 3 ]<< 1 ))& 0x1F ]
39
44
t = a >> 3
40
45
a = b >> 2
41
46
b = t
42
- precision -= 1
43
47
44
48
return ret [::- 1 ]
45
49
46
50
def encode (latitude , longitude , precision = 12 ):
47
- if latitude > 90.0 or latitude < - 90.0 :
51
+ if latitude >= 90.0 or latitude < - 90.0 :
48
52
raise Exception ("invalid latitude." )
49
53
while longitude < - 180.0 :
50
54
longitude += 360.0
51
55
while longitude >= 180.0 :
52
56
longitude -= 360.0
53
57
54
- lat = (latitude + 90.0 )/ 180.0
55
- lon = (longitude + 180.0 )/ 360.0
58
+ if _geohash :
59
+ basecode = _geohash .encode (latitude ,longitude )
60
+ if len (basecode )> precision :
61
+ return basecode [0 :precision ]
62
+ return basecode + '0' * (precision - len (basecode ))
63
+
64
+ lat = latitude / 180.0
65
+ lon = longitude / 360.0
56
66
57
- lat_length = lon_length = precision * 5 / 2
58
- if precision % 2 == 1 :
67
+ xprecision = precision + 1
68
+ lat_length = lon_length = xprecision * 5 / 2
69
+ if xprecision % 2 == 1 :
59
70
lon_length += 1
60
71
61
- lat = int ((1 << lat_length )* lat )
62
- lon = int ((1 << lon_length )* lon )
72
+ if lat > 0 :
73
+ lat = int ((1 << lat_length )* lat )+ (1 << (lat_length - 1 ))
74
+ else :
75
+ lat = (1 << lat_length - 1 )- int ((1 << lat_length )* (- lat ))
76
+
77
+ if lon > 0 :
78
+ lon = int ((1 << lon_length )* lon )+ (1 << (lon_length - 1 ))
79
+ else :
80
+ lon = (1 << lon_length - 1 )- int ((1 << lon_length )* (- lon ))
63
81
64
- return _encode_i2c (lat ,lon ,lat_length ,lon_length )
82
+ return _encode_i2c (lat ,lon ,lat_length ,lon_length )[: precision ]
65
83
66
84
def _decode_c2i (hashcode ):
67
85
lon = 0
@@ -97,15 +115,28 @@ def _decode_c2i(hashcode):
97
115
return (lat ,lon ,lat_length ,lon_length )
98
116
99
117
def decode (hashcode , delta = False ):
118
+ '''
119
+ decode a hashcode and get center coordinate, and distance between center and outer border
120
+ '''
121
+ if _geohash :
122
+ (lat ,lon ,lat_bits ,lon_bits ) = _geohash .decode (hashcode )
123
+ latitude_delta = 180.0 / (2 << lat_bits )
124
+ longitude_delta = 360.0 / (2 << lon_bits )
125
+ latitude = lat + latitude_delta
126
+ longitude = lon + longitude_delta
127
+ if delta :
128
+ return latitude ,longitude ,latitude_delta ,longitude_delta
129
+ return latitude ,longitude
130
+
100
131
(lat ,lon ,lat_length ,lon_length ) = _decode_c2i (hashcode )
101
132
102
133
lat = (lat << 1 ) + 1
103
134
lon = (lon << 1 ) + 1
104
135
lat_length += 1
105
136
lon_length += 1
106
137
107
- latitude = 180.0 * lat / (1 << lat_length ) - 90.0
108
- longitude = 360.0 * lon / (1 << lon_length ) - 180.0
138
+ latitude = 180.0 * ( lat - ( 1 << ( lat_length - 1 ))) / (1 << lat_length )
139
+ longitude = 360.0 * ( lon - ( 1 << ( lon_length - 1 ))) / (1 << lon_length )
109
140
if delta :
110
141
latitude_delta = 180.0 / (1 << lat_length )
111
142
longitude_delta = 360.0 / (1 << lon_length )
@@ -119,16 +150,36 @@ def decode_exactly(hashcode):
119
150
## hashcode operations below
120
151
121
152
def bbox (hashcode ):
122
- (lat ,lon ,lat_length ,lon_length ) = _decode_c2i (hashcode )
153
+ '''
154
+ decode a hashcode and get north, south, east and west border.
155
+ '''
156
+ if _geohash :
157
+ (lat ,lon ,lat_bits ,lon_bits ) = _geohash .decode (hashcode )
158
+ latitude_delta = 180.0 / (1 << lat_bits )
159
+ longitude_delta = 360.0 / (1 << lon_bits )
160
+ return {'s' :lat ,'w' :lon ,'n' :lat + latitude_delta ,'e' :lon + longitude_delta }
123
161
162
+ (lat ,lon ,lat_length ,lon_length ) = _decode_c2i (hashcode )
124
163
ret = {}
125
- ret ['n' ] = 180.0 * (lat + 1 )/ (1 << lat_length ) - 90.0
126
- ret ['s' ] = 180.0 * lat / (1 << lat_length ) - 90.0
127
- ret ['e' ] = 360.0 * (lon + 1 )/ (1 << lon_length ) - 180.0
128
- ret ['w' ] = 360.0 * lon / (1 << lon_length ) - 180.0
164
+ if lat_length :
165
+ ret ['n' ] = 180.0 * (lat + 1 - (1 << (lat_length - 1 )))/ (1 << lat_length )
166
+ ret ['s' ] = 180.0 * (lat - (1 << (lat_length - 1 )))/ (1 << lat_length )
167
+ else : # can't calculate the half with bit shifts (negative shift)
168
+ ret ['n' ] = 90.0
169
+ ret ['s' ] = - 90.0
170
+
171
+ if lon_length :
172
+ ret ['e' ] = 360.0 * (lon + 1 - (1 << (lon_length - 1 )))/ (1 << lon_length )
173
+ ret ['w' ] = 360.0 * (lon - (1 << (lon_length - 1 )))/ (1 << lon_length )
174
+ else : # can't calculate the half with bit shifts (negative shift)
175
+ ret ['e' ] = 180.0
176
+ ret ['w' ] = - 180.0
177
+
129
178
return ret
130
179
131
180
def neighbors (hashcode ):
181
+ if _geohash and len (hashcode )< 25 :
182
+ return _geohash .neighbors (hashcode )
132
183
(lat ,lon ,lat_length ,lon_length ) = _decode_c2i (hashcode )
133
184
ret = []
134
185
tlat = lat
0 commit comments