python-geohash-0.8.3/0000775000076400007640000000000011544653021014400 5ustar hawkhawk00000000000000python-geohash-0.8.3/src/0000775000076400007640000000000011544653021015167 5ustar hawkhawk00000000000000python-geohash-0.8.3/src/geohash.cpp0000664000076400007640000006301011544653011017310 0ustar hawkhawk00000000000000extern "C" { #include #include #include // on Windows, __STDC_IEC_559__ not defined #if defined(_MSC_VER) && (_MSC_VER <= 1500) typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int64 uint64_t; #define UINT64_C(C) ((uint64_t) C ## ULL) #else #define __STDC_CONSTANT_MACROS 1 #include #endif } #include "geohash.h" static inline uint16_t interleave(uint8_t upper, uint8_t lower){ static const uint16_t map[256] = { 0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115, 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, 0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, 0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, 0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555, 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055, 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, 0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, 0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, 0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515, 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, 0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015, 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, 0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, 0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455, 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555, 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, 0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, 0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155, 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415, 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, 0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515, 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555 }; return (map[upper]<<1)+map[lower]; } static inline void deinterleave(uint16_t interleaved, uint8_t *upper, uint8_t *lower){ *upper = *lower = 0; for(int i=7; i>=0; i--){ *upper = (*upper<<1) + ((interleaved>>(i*2+1))&0x01); *lower = (*lower<<1) + ((interleaved>>(i*2))&0x01); } } /** * map double[-1.0, 1.0) into uint64_t */ static inline int double_to_i64(double in, uint64_t *out){ if(in<-1.0 || 1.0<=in){ return 0; } union { double d; // assuming IEEE 754-1985 binary64. This might not be true on some CPU (I don't know which). // formally, we should use unsigned char for type-punning (see C99 ISO/IEC 9899:201x spec 6.2.6) uint64_t i64; } x; x.d = in; int sign = x.i64 >> 63; int exp = (x.i64 >> 52) & 0x7FF; if(exp==0){ *out = UINT64_C(0x8000000000000000); return !0; }else if(exp==0x7FF){ return 0; } x.i64 &= UINT64_C(0x000FFFFFFFFFFFFF); x.i64 |= UINT64_C(0x0010000000000000); int shift = exp - 0x3FF + 11; if(shift > 0){ x.i64 <<= shift; }else{ x.i64 >>= shift; } if(sign){ x.i64 = UINT64_C(0x8000000000000000) - x.i64; }else{ x.i64 += UINT64_C(0x8000000000000000); } *out = x.i64; return !0; } /** * map uint64_t into double[-1.0, 1.0) */ static inline void i64_to_double(uint64_t in, double *out){ union { double d; // assuming IEEE 754-1985 binary64. This might not be true on some CPU (I don't know which). // formally, we should use unsigned char for type-punning (see C99 ISO/IEC 9899:201x spec 6.2.6) uint64_t i64; } x; if(in==UINT64_C(0x8000000000000000)){ *out = 0.0; return; } int sign = 0; if(in < UINT64_C(0x8000000000000000)){ sign = 1; // negative. -1.0 -- 0.0 in = UINT64_C(0x8000000000000000) - in; }else{ in -= UINT64_C(0x8000000000000000); } int i; for(i=0;i<64;i++){ if(in>>(63-i)){ break; } } if(i>11){ x.i64 = in<<(i-11); }else{ x.i64 = in>>(11-i); } x.i64 = ((UINT64_C(0x3FF) - i)<<52) + (x.i64 & UINT64_C(0x000FFFFFFFFFFFFF)); if(sign){ x.i64 |= UINT64_C(0x8000000000000000); } *out = x.d; } static int interleaved_to_geohashstr(uint16_t *interleaved, size_t length, char* dst, size_t dst_length){ static const char* map="0123456789bcdefghjkmnpqrstuvwxyz"; if(dst_length*5 < length*16){ return GEOHASH_INTERNALERROR; } unsigned char *w = (unsigned char*)dst; uint16_t *i = interleaved; for(unsigned int j=0; j>11); w[ 1] = (unsigned char)( i[0]>>6); w[ 2] = (unsigned char)( i[0]>>1); w[ 3] = (unsigned char)((i[1]>>12) + (i[0]<<4)); w[ 4] = (unsigned char)( i[1]>>7); w[ 5] = (unsigned char)( i[1]>>2); w[ 6] = (unsigned char)((i[2]>>13) + (i[1]<<3)); w[ 7] = (unsigned char)( i[2]>>8); w[ 8] = (unsigned char)( i[2]>>3); w[ 9] = (unsigned char)((i[3]>>14) + (i[2]<<2)); w[10] = (unsigned char)( i[3]>>9); w[11] = (unsigned char)( i[3]>>4); w[12] = (unsigned char)((i[4]>>15) + (i[3]<<1)); w[13] = (unsigned char)( i[4]>>10); w[14] = (unsigned char)( i[4]>>5); w[15] = (unsigned char)( i[4]); i+=5; w+=16; } for(unsigned int j=0; j>11); if(j== 1) w[ 1] = (unsigned char)( i[0]>>6); if(j== 2) w[ 2] = (unsigned char)( i[0]>>1); if(j== 3) w[ 3] = (unsigned char)((i[1]>>12) + (i[0]<<4)); if(j== 4) w[ 4] = (unsigned char)( i[1]>>7); if(j== 5) w[ 5] = (unsigned char)( i[1]>>2); if(j== 6) w[ 6] = (unsigned char)((i[2]>>13) + (i[1]<<3)); if(j== 7) w[ 7] = (unsigned char)( i[2]>>8); if(j== 8) w[ 8] = (unsigned char)( i[2]>>3); if(j== 9) w[ 9] = (unsigned char)((i[3]>>14) + (i[2]<<2)); if(j==10) w[10] = (unsigned char)( i[3]>>9); if(j==11) w[11] = (unsigned char)( i[3]>>4); if(j==12) w[12] = (unsigned char)((i[4]>>15) + (i[3]<<1)); if(j==13) w[13] = (unsigned char)( i[4]>>10); if(j==14) w[14] = (unsigned char)( i[4]>>5); if(j==15) w[15] = (unsigned char)( i[4]); } for(unsigned int j=0; j>(i*8)), (uint8_t)(lat64>>(i*8))); } int ret = GEOHASH_OK; if((ret=interleaved_to_geohashstr(interleaved, 8, lr, 26)) != GEOHASH_OK){ return ret; } lr[26] = '\0'; if(0>4); i[1] = (map[c[ 3]]<<12) + (map[c[ 4]]<< 7) + (map[c[ 5]]<<2) + (map[c[ 6]]>>3); i[2] = (map[c[ 6]]<<13) + (map[c[ 7]]<< 8) + (map[c[ 8]]<<3) + (map[c[ 9]]>>2); i[3] = (map[c[ 9]]<<14) + (map[c[10]]<< 9) + (map[c[11]]<<4) + (map[c[12]]>>1); i[4] = (map[c[12]]<<15) + (map[c[13]]<<10) + (map[c[14]]<<5) + (map[c[15]]>>0); i+=5; c+=16; } for(unsigned int j=0; j> 4; if(j== 3) i[1] = map[c[ 3]]<<12; if(j== 4) i[1] += map[c[ 4]]<< 7; if(j== 5) i[1] += map[c[ 5]]<< 2; if(j== 6) i[1] += map[c[ 6]]>> 3; if(j== 6) i[2] = map[c[ 6]]<<13; if(j== 7) i[2] += map[c[ 7]]<< 8; if(j== 8) i[2] += map[c[ 8]]<< 3; if(j== 9) i[2] += map[c[ 9]]>> 2; if(j== 9) i[3] = map[c[ 9]]<<14; if(j==10) i[3] += map[c[10]]<< 9; if(j==11) i[3] += map[c[11]]<< 4; if(j==12) i[3] += map[c[12]]>> 1; if(j==12) i[4] = map[c[12]]<<15; if(j==13) i[4] += map[c[13]]<<10; if(j==14) i[4] += map[c[14]]<< 5; if(j==15) i[4] += map[c[15]]>> 0; } return GEOHASH_OK; } /* (latitude, longitude) will be that of south west point. */ static int geohash_decode_impl(char* r, size_t length, double *latitude, double *longitude){ uint16_t intr_auto[8]; uint16_t *interleaved = intr_auto; size_t intr_length = length*5/16+1; int intr_free = 0; if(intr_length > 8){ interleaved = (uint16_t*)malloc(sizeof(uint16_t)*intr_length); if(!interleaved){ return GEOHASH_NOMEMORY; } intr_free = 1; }else{ intr_length = 8; } int ret = GEOHASH_OK; if((ret=geohashstr_to_interleaved(r, length, interleaved, intr_length)) != GEOHASH_OK){ return ret; } uint64_t lat64=0; uint64_t lon64=0; for(int i=0; i<8; i++){ uint8_t upper, lower; deinterleave(interleaved[i], &upper, &lower); lon64 = (lon64<<8)+upper; lat64 = (lat64<<8)+lower; } if(intr_free){ free(interleaved); } double t; i64_to_double(lat64, &t); *latitude = t*90.0; i64_to_double(lon64, &t); *longitude = t*180.0; return GEOHASH_OK; } int geohash_decode(char* r, size_t length, double *latitude, double *longitude){ return geohash_decode_impl(r, length, latitude, longitude); } /** * compare two uint8_t array of variable sized integers. */ static int uint8s_cmp(uint8_t *src, uint8_t *dst, size_t length){ if(length==0){ return 0; } unsigned int i=0; for(i=0; i<(length-1)/8; i++){ if(src[i] != dst[i]){ return (int)(src[i] - dst[i]); } } uint8_t cell_offset = (8-length%8)%8; return (int)((src[i]>>cell_offset) - (dst[i]>>cell_offset)); } /** * plus minus operations for uint8_t array of variable sized integer. */ static int uint8s_plus_minus(uint8_t *src, uint8_t *dst, size_t length, int plus){ if(length==0){ return 0; } unsigned int cell = (length-1)/8; for(unsigned int i=0; i0 && uint8s_cmp(lats[i-1], lats[i], lat_len)==0){ continue; } for(int j=0;j<3;j++){ if(j>0 && uint8s_cmp(lons[j-1], lons[j], lon_len)==0){ continue; } if(i==0 && j==0){ continue; } for(unsigned int k=0; k static void set_error(int status){ if(status==GEOHASH_NOTSUPPORTED) PyErr_SetString(PyExc_EnvironmentError, "Unknown endian"); if(status==GEOHASH_INVALIDCODE) PyErr_SetString(PyExc_ValueError, "geohash code is [0123456789bcdefghjkmnpqrstuvwxyz]+"); if(status==GEOHASH_INVALIDARGUMENT) PyErr_SetString(PyExc_ValueError, "Invalid argument"); if(status==GEOHASH_INTERNALERROR) PyErr_SetString(PyExc_EnvironmentError, "Internal error"); if(status==GEOHASH_NOMEMORY) PyErr_NoMemory(); } static PyObject *py_geohash_encode(PyObject *self, PyObject *args) { double latitude; double longitude; char hashcode[28]; int ret = GEOHASH_OK; if(!PyArg_ParseTuple(args, "dd", &latitude, &longitude)) return NULL; if((ret=geohash_encode_impl(latitude,longitude,hashcode,28))!=GEOHASH_OK){ set_error(ret); return NULL; } return Py_BuildValue("s",hashcode); } static PyObject *py_geohash_decode(PyObject *self, PyObject *args) { double latitude; double longitude; char *hashcode; int codelen=0; int ret = GEOHASH_OK; if(!PyArg_ParseTuple(args, "s", &hashcode)) return NULL; codelen = strlen(hashcode); if((ret=geohash_decode_impl(hashcode,codelen,&latitude,&longitude))!=GEOHASH_OK){ set_error(ret); return NULL; } return Py_BuildValue("(ddii)",latitude,longitude, codelen/2*5+codelen%2*2, codelen/2*5+codelen%2*3); } static PyObject *py_geohash_neighbors(PyObject *self, PyObject *args) { PyObject *obj = NULL; char *hashcode; if(!PyArg_ParseTuple(args, "s", &hashcode)) return NULL; size_t blen = strlen(hashcode)+1; size_t buffer_sz = blen*8; char *buffer = (char*)malloc(sizeof(char)*buffer_sz); if(buffer==NULL){ set_error(GEOHASH_NOMEMORY); return NULL; } int ret; int string_count = 0; if((ret = geo_neighbors_impl(hashcode, buffer, buffer_sz, &string_count)) != GEOHASH_OK){ set_error(ret); } if(string_count==0){ obj= Py_BuildValue("[]"); }else if(string_count==1){ obj= Py_BuildValue("[s]", buffer); }else if(string_count==3){ obj= Py_BuildValue("[sss]", buffer, buffer+blen, buffer+blen*2); }else if(string_count==5){ obj= Py_BuildValue("[sssss]", buffer, buffer+blen, buffer+blen*2, buffer+blen*3, buffer+blen*4); }else if(string_count==8){ obj= Py_BuildValue("[ssssssss]", buffer, buffer+blen, buffer+blen*2, buffer+blen*3, buffer+blen*4, buffer+blen*5, buffer+blen*6, buffer+blen*7); }else{ set_error(GEOHASH_INTERNALERROR); } free(buffer); return obj; } static PyObject *py_geoint_encode(PyObject *self, PyObject *args){ double latitude; double longitude; if(!PyArg_ParseTuple(args, "dd", &latitude, &longitude)) return NULL; uint64_t lat64, lon64; if(!double_to_i64(latitude/90.0, &lat64) || !double_to_i64(longitude/180.0, &lon64)){ return NULL; } uint16_t interleaved[8]; for(int i=0; i<8; i++){ interleaved[7-i] = interleave((uint8_t)(lon64>>(i*8)), (uint8_t)(lat64>>(i*8))); } PyObject *ret = NULL; #if UINT64_MAX <= ULLONG_MAX ret = PyTuple_New(2); unsigned PY_LONG_LONG li; li = ((unsigned PY_LONG_LONG)interleaved[0]<<48) + ((unsigned PY_LONG_LONG)interleaved[1]<<32) + ((unsigned PY_LONG_LONG)interleaved[2]<<16) + (unsigned PY_LONG_LONG)interleaved[3]; PyTuple_SET_ITEM(ret, 0, PyLong_FromUnsignedLongLong(li)); li = ((unsigned PY_LONG_LONG)interleaved[4]<<48) + ((unsigned PY_LONG_LONG)interleaved[5]<<32) + ((unsigned PY_LONG_LONG)interleaved[6]<<16) + (unsigned PY_LONG_LONG)interleaved[7]; PyTuple_SET_ITEM(ret, 1, PyLong_FromUnsignedLongLong(li)); #elif UINT32_MAX <= ULLONG_MAX ret = PyTuple_New(4); unsigned PY_LONG_LONG li; li = ((unsigned PY_LONG_LONG)interleaved[0]<<16) + (unsigned PY_LONG_LONG)interleaved[1]; PyTuple_SET_ITEM(ret, 0, PyLong_FromUnsignedLongLong(li)); li = ((unsigned PY_LONG_LONG)interleaved[1]<<16) + (unsigned PY_LONG_LONG)interleaved[3]; PyTuple_SET_ITEM(ret, 1, PyLong_FromUnsignedLongLong(li)); li = ((unsigned PY_LONG_LONG)interleaved[2]<<16) + (unsigned PY_LONG_LONG)interleaved[5]; PyTuple_SET_ITEM(ret, 2, PyLong_FromUnsignedLongLong(li)); li = ((unsigned PY_LONG_LONG)interleaved[3]<<16) + (unsigned PY_LONG_LONG)interleaved[7]; PyTuple_SET_ITEM(ret, 3, PyLong_FromUnsignedLongLong(li)); #elif UINT16_MAX <= ULLONG_MAX ret = PyTuple_New(8); PyTuple_SET_ITEM(ret, 0, PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)interleaved[0])); PyTuple_SET_ITEM(ret, 1, PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)interleaved[1])); PyTuple_SET_ITEM(ret, 2, PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)interleaved[2])); PyTuple_SET_ITEM(ret, 3, PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)interleaved[3])); PyTuple_SET_ITEM(ret, 4, PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)interleaved[4])); PyTuple_SET_ITEM(ret, 5, PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)interleaved[5])); PyTuple_SET_ITEM(ret, 6, PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)interleaved[6])); PyTuple_SET_ITEM(ret, 7, PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)interleaved[7])); #else #error "This platform not supported" #endif // UINT64_MAX <= ULLONG_MAX return ret; } static PyObject *py_geoint_decode(PyObject *self, PyObject *args){ uint16_t interleaved[8]; #if PY_MAJOR_VERSION >= 3 || (PY_MAJOR_VERSION >=2 && PY_MINOR_VERSION >= 5) Py_ssize_t sz = PyTuple_GET_SIZE(args); #else int sz = PyTuple_GET_SIZE(args); #endif if(sz==2){ unsigned PY_LONG_LONG lo; lo = PyLong_AsUnsignedLongLong(PyTuple_GET_ITEM(args,0)); interleaved[0] = (uint16_t)(lo>>48); interleaved[1] = (uint16_t)(lo>>32); interleaved[2] = (uint16_t)(lo>>16); interleaved[3] = (uint16_t)lo; lo = PyLong_AsUnsignedLongLong(PyTuple_GET_ITEM(args,1)); interleaved[4] = (uint16_t)(lo>>48); interleaved[5] = (uint16_t)(lo>>32); interleaved[6] = (uint16_t)(lo>>16); interleaved[7] = (uint16_t)lo; }else if(sz==4){ unsigned PY_LONG_LONG lo; lo = PyLong_AsUnsignedLongLong(PyTuple_GET_ITEM(args,0)); interleaved[0] = (uint16_t)(lo>>16); interleaved[1] = (uint16_t)lo; lo = PyLong_AsUnsignedLongLong(PyTuple_GET_ITEM(args,1)); interleaved[2] = (uint16_t)(lo>>16); interleaved[3] = (uint16_t)lo; lo = PyLong_AsUnsignedLongLong(PyTuple_GET_ITEM(args,2)); interleaved[4] = (uint16_t)(lo>>16); interleaved[5] = (uint16_t)lo; lo = PyLong_AsUnsignedLongLong(PyTuple_GET_ITEM(args,3)); interleaved[6] = (uint16_t)(lo>>16); interleaved[7] = (uint16_t)lo; }else if(sz==8){ interleaved[0] = (uint16_t)PyLong_AsUnsignedLongLong(PyTuple_GET_ITEM(args,0)); interleaved[1] = (uint16_t)PyLong_AsUnsignedLongLong(PyTuple_GET_ITEM(args,1)); interleaved[2] = (uint16_t)PyLong_AsUnsignedLongLong(PyTuple_GET_ITEM(args,2)); interleaved[3] = (uint16_t)PyLong_AsUnsignedLongLong(PyTuple_GET_ITEM(args,3)); interleaved[4] = (uint16_t)PyLong_AsUnsignedLongLong(PyTuple_GET_ITEM(args,4)); interleaved[5] = (uint16_t)PyLong_AsUnsignedLongLong(PyTuple_GET_ITEM(args,5)); interleaved[6] = (uint16_t)PyLong_AsUnsignedLongLong(PyTuple_GET_ITEM(args,6)); interleaved[7] = (uint16_t)PyLong_AsUnsignedLongLong(PyTuple_GET_ITEM(args,7)); }else{ PyErr_SetString(PyExc_ValueError, "Argument must be 2, 4 or 8 integers."); return NULL; } uint64_t lat64=0; uint64_t lon64=0; for(int i=0; i<8; i++){ uint8_t upper, lower; deinterleave(interleaved[i], &upper, &lower); lon64 = (lon64<<8)+upper; lat64 = (lat64<<8)+lower; } double tlat, tlon; i64_to_double(lat64, &tlat); i64_to_double(lon64, &tlon); return Py_BuildValue("(dd)", tlat*90.0, tlon*180.0); } static PyMethodDef GeohashMethods[] = { {"encode", py_geohash_encode, METH_VARARGS, "geohash encoding."}, {"decode", py_geohash_decode, METH_VARARGS, "geohash decoding."}, {"neighbors", py_geohash_neighbors, METH_VARARGS, "geohash neighbor codes",}, {"encode_int", py_geoint_encode, METH_VARARGS, "encode geometric coordinates into 128bit interleaved integer(divided into some integers)"}, {"decode_int", py_geoint_decode, METH_VARARGS, "decode 128bit interleaved integer(divided into some integers) into geometric coordinates"}, {NULL, NULL, 0, NULL} }; #ifdef Py_InitModule PyMODINIT_FUNC init_geohash(void){ PyObject *mod = Py_InitModule("_geohash", GeohashMethods); #if UINT64_MAX <= ULLONG_MAX PyModule_AddIntConstant(mod, "intunit", 64); #elif UINT32_MAX <= ULLONG_MAX PyModule_AddIntConstant(mod, "intunit", 32); #elif UINT16_MAX <= ULLONG_MAX PyModule_AddIntConstant(mod, "intunit", 16); #else #error "This platform not supported" #endif // UINT64_MAX <= ULLONG_MAX return (void)mod; } #else PyDoc_STRVAR(module_doc, "geohash speedups"); static struct PyModuleDef geohash_moduledef = { PyModuleDef_HEAD_INIT, "_geohash", module_doc, -1, GeohashMethods, NULL, NULL, NULL, NULL }; PyMODINIT_FUNC PyInit__geohash(void){ PyObject *mod = PyModule_Create(&geohash_moduledef); #if UINT64_MAX <= ULLONG_MAX PyModule_AddIntConstant(mod, "intunit", 64); #elif UINT32_MAX <= ULLONG_MAX PyModule_AddIntConstant(mod, "intunit", 32); #elif UINT16_MAX <= ULLONG_MAX PyModule_AddIntConstant(mod, "intunit", 16); #else #error "This platform not supported" #endif // UINT64_MAX <= ULLONG_MAX return mod; }; #endif /* Py_InitModule */ #endif /* PYTHON_MODULE */ python-geohash-0.8.3/src/geohash_sample.c0000664000076400007640000000060111544653011020306 0ustar hawkhawk00000000000000#include #include "geohash.h" int main(int argc,char* argv[]){ char r[20]; double lat,lon; int res; if((res=geohash_encode(35.0, 135.0, r, 20))==GEOHASH_OK){ printf("%s\n",r); }else{ printf("error with %d\n",res); } if((res=geohash_decode(r,23,&lat,&lon))==GEOHASH_OK){ printf("%f %f\n",lat,lon); }else{ printf("error with %d\n",res); } } python-geohash-0.8.3/src/Makefile0000664000076400007640000000040611544653011016626 0ustar hawkhawk00000000000000CC = gcc CXX = g++ CFLAGS = -O3 CXXFLAGS = TARGET = sample OBJS = geohash_sample.o geohash.o all: $(TARGET) $(TARGET): $(OBJS) $(CXX) -o $@ $(OBJS) clean: -rm -f $(TARGET) $(OBJS) .c.o: $(CC) $(CFLAGS) -c $< .cpp.o: $(CXX) $(CXXFLAGS) -c $< python-geohash-0.8.3/src/geohash.h0000664000076400007640000000131411544653011016754 0ustar hawkhawk00000000000000#ifdef __cplusplus extern "C" { #endif enum { GEOHASH_OK, GEOHASH_NOTSUPPORTED, GEOHASH_INVALIDCODE, GEOHASH_INVALIDARGUMENT, GEOHASH_INTERNALERROR, GEOHASH_NOMEMORY }; int geohash_encode(double latitude, double longitude, char* r, size_t capacity); int geohash_decode(char* r, size_t length, double *latitude, double *longitude); int geo_neighbors(char *hashcode, char* dst, size_t dst_length, int *string_count); #ifdef __cplusplus } #endif /* int main(int argc,char* argv[]){ char r[23]; double lat,lon; if(geohash_encode(35.0, 135.0, r, 23)==GEOHASH_OK){ printf("%s\n",r); } if(geohash_decode(r,23,&lat,&lon)==GEOHASH_OK){ printf("%f %f\n",lat,lon); } } */ python-geohash-0.8.3/quadtree.py0000664000076400007640000000521011544653011016561 0ustar hawkhawk00000000000000# coding: UTF-8 """ Copyright (C) 2009 Hiroaki Kawai """ try: import _geohash except ImportError: _geohash = None def _encode_i2c(lat,lon,bitlength): digits='0123' r = '' while bitlength>0: r += digits[((lat&1)<<1)+(lon&1)] lat = lat>>1 lon = lon>>1 bitlength -= 1 return r[::-1] def _decode_c2i(treecode): lat = 0 lon = 0 for i in treecode: b = ord(i)-48 lat = (lat<<1)+int(b/2) lon = (lon<<1)+b%2 return (lat,lon,len(treecode)) def encode(lat,lon,precision=12): if _geohash and precision<=64: ints = _geohash.encode_int(lat, lon) ret = "" for intu in ints: for i in range(int(_geohash.intunit/2)): if len(ret) > precision: break ret += "0213"[(intu>>(_geohash.intunit-2-i*2))&0x03] return ret[:precision] b = 1<>bitlength: for tlon in (lon-1, lon, lon+1): r.append(_encode_i2c(tlat, tlon, bitlength)) tlat = lat-1 if tlat>=0: for tlon in (lon-1, lon, lon+1): r.append(_encode_i2c(tlat, tlon, bitlength)) return r def expand(treecode): r = neighbors(treecode) r.append(treecode) return r python-geohash-0.8.3/setup.py0000664000076400007640000000063411544653011016114 0ustar hawkhawk00000000000000from distutils.core import setup, Extension c1=Extension('_geohash', sources=['src/geohash.cpp',], define_macros = [('PYTHON_MODULE',1),]) setup(name='python-geohash', version='0.8.3', description='Fast, accurate python geohashing library', author='Hiroaki Kawai', url='http://code.google.com/p/python-geohash/', py_modules=['geohash','quadtree','jpgrid','jpiarea'], ext_modules = [c1] ) python-geohash-0.8.3/README0000664000076400007640000000727611544653011015273 0ustar hawkhawk00000000000000* python-geohash python-geohash is a fast, accurate python geohashing library. ** History python-geohash 0.8 introduced uint64 representation. python-geohash 0.7.1 starts supporting python3k. python-geohash 0.3 can create C extension. If you want to use python-geohash without C extension, simply copy geohash.py into your system. geohash.py will work fine without C extension. ** LICENSE Code is licensed under Apache License 2.0, MIT Licence and NEW BSD License. You can choose one of these licences. Declarations follow: *** Apache License 2.0 Copyright 2011 Hiroaki Kawai Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *** MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *** New BSD License Copyright (c) 2011, Hiroaki Kawai All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. python-geohash-0.8.3/test/0000775000076400007640000000000011544653021015357 5ustar hawkhawk00000000000000python-geohash-0.8.3/test/test_jpgrid.py0000664000076400007640000001123111544653011020244 0ustar hawkhawk00000000000000# coding: UTF-8 import unittest import jpgrid class TestReference(unittest.TestCase): def test_lv1(self): self.assertEqual("5438", jpgrid.encodeLv1(36,138)) def test_prefectures(self): # http://www.stat.go.jp/data/mesh/pdf/gaiyo1.pdf # page. 15 def dms(d,m,s): return float(d) + (float(m) + float(s)/60)/60.0 dataset = [ ("北海道", "札幌市", "6441-42-77", ("43","03","30"), ("141","20","15")), ("青森県", "青森市", "6140-15-89", ("40","49","00"), ("140","44","15")), ("岩手県", "盛岡市", "5941-41-42", ("39","42","00"), ("141","09","00")), ("宮城県", "仙台市", "5740-36-29", ("38","16","00"), ("140","51","45")), ("秋田県", "秋田市", "5940-40-68", ("39","43","00"), ("140","06","00")), ("山形県", "山形市", "5740-22-89", ("38","14","00"), ("140","21","45")), ("福島県", "福島市", "5640-53-07", ("37","45","00"), ("140","27","45")), ("茨城県", "水戸市", "5440-43-15", ("36","20","30"), ("140","26","15")), ("栃木県", "宇都宮市", "5439-67-70", ("36","33","30"), ("139","52","30")), ("群馬県", "前橋市", "5439-40-64", ("36","23","00"), ("139","03","00")), ("埼玉県", "さいたま市", "5339-65-21", ("35","51","00"), ("139","38","15")), ("千葉県", "千葉市", "5340-30-29", ("35","36","00"), ("140","06","45")), ("東京都", "新宿区", "5339-45-25", ("35","41","00"), ("139","41","15")), ("神奈川県", "横浜市", "5339-15-31", ("35","26","30"), ("139","38","15")), ("新潟県", "新潟市", "5639-60-81", ("37","54","00"), ("139","00","45")), ("富山県", "富山市", "5537-01-36", ("36","41","30"), ("137","12","00")), ("石川県", "金沢市", "5436-75-10", ("36","35","30"), ("136","37","30")), ("福井県", "福井市", "5436-01-77", ("36","03","30"), ("136","12","45")), ("山梨県", "甲府市", "5338-34-95", ("35","39","30"), ("138","33","45")), ("長野県", "長野市", "5438-71-84", ("36","39","00"), ("138","10","30")), ("岐阜県", "岐阜市", "5336-05-67", ("35","23","00"), ("136","42","45")), ("静岡県", "静岡市", "5238-33-70", ("34","58","30"), ("138","22","30")), ("愛知県", "名古屋市", "5236-67-12", ("35","10","30"), ("136","54","00")), ("三重県", "津市", "5236-04-70", ("34","43","30"), ("136","30","00")), ("滋賀県", "大津市", "5235-46-09", ("35","00","00"), ("135","51","45")), ("京都府", "京都市", "5235-46-20", ("35","01","00"), ("135","45","00")), ("大阪府", "大阪市", "5235-04-21", ("34","41","00"), ("135","30","45")), ("兵庫県", "神戸市", "5235-01-24", ("34","41","00"), ("135","10","30")), ("奈良県", "奈良市", "5235-06-26", ("34","41","00"), ("135","49","30")), ("和歌山県", "和歌山市", "5135-21-73", ("34","13","30"), ("135","09","45")), ("鳥取県", "鳥取市", "5334-21-09", ("35","30","00"), ("134","14","15")), ("島根県", "松江市", "5333-10-64", ("35","28","00"), ("133","03","00")), ("岡山県", "岡山市", "5133-77-94", ("34","39","30"), ("133","55","30")), ("広島県", "広島市", "5132-43-76", ("34","23","30"), ("132","27","00")), ("山口県", "山口市", "5131-23-27", ("34","11","00"), ("131","27","45")), ("徳島県", "徳島市", "5134-04-74", ("34","03","30"), ("134","33","00")), ("香川県", "高松市", "5134-40-03", ("34","20","00"), ("134","02","15")), ("愛媛県", "松山市", "5032-66-01", ("33","50","00"), ("132","45","45")), ("高知県", "高知市", "5033-24-72", ("33","33","30"), ("133","31","30")), ("福岡県", "福岡市", "5030-33-23", ("33","36","00"), ("130","24","45")), ("佐賀県", "佐賀市", "4930-62-93", ("33","14","30"), ("130","17","15")), ("長崎県", "長崎市", "4929-06-99", ("32","44","30"), ("129","51","45")), ("熊本県", "熊本市", "4930-15-49", ("32","47","00"), ("130","44","15")), ("大分県", "大分市", "4931-64-89", ("33","14","00"), ("131","36","45")), ("宮崎県", "宮崎市", "4731-63-93", ("31","54","30"), ("131","24","45")), ("鹿児島県", "鹿児島市", "4730-24-74", ("31","33","30"), ("130","33","00")), ("沖縄県", "那覇市", "3927-25-54", ("26","12","30"), ("127","40","30")) ] for data in dataset: # encode self.assertEqual(data[2].replace("-",""), jpgrid.encode(dms(*data[3]), dms(*data[4]))) t = jpgrid.decode(data[2].replace("-","")) # decode self.assertTrue(t[0] > dms(*data[3])) self.assertTrue(t[0] < dms(*data[3]) + 1.5/80.0) self.assertTrue(t[1] > dms(*data[4])) self.assertTrue(t[1] < dms(*data[4]) + 1.0/80.0) if __name__=='__main__': unittest.main() python-geohash-0.8.3/test/test_uint64.py0000664000076400007640000000313611544653011020123 0ustar hawkhawk00000000000000import unittest import geohash class TestUint64(unittest.TestCase): def test_one(self): dataset = [ (0x0000000000000000, -90.0, -180.0), (0x0800000000000000, -90.0, -135.0), (0x1000000000000000, -45.0, -180.0), (0x1800000000000000, -45.0, -135.0), (0x2000000000000000, -90.0, -90.0), (0x2800000000000000, -90.0, -45.0), (0x3000000000000000, -45.0, -90.0), (0x3800000000000000, -45.0, -45.0), (0x4000000000000000, 0.0, -180.0), (0x4800000000000000, 0.0, -135.0), (0x5000000000000000, 45.0, -180.0), (0x5800000000000000, 45.0, -135.0), (0x6000000000000000, 0.0, -90.0), (0x6800000000000000, 0.0, -45.0), (0x7000000000000000, 45.0, -90.0), (0x7800000000000000, 45.0, -45.0), (0x8000000000000000, -90.0, 0.0), (0x8800000000000000, -90.0, 45.0), (0x9000000000000000, -45.0, 0.0), (0x9800000000000000, -45.0, 45.0), (0xA000000000000000, -90.0, 90.0), (0xA800000000000000, -90.0, 135.0), (0xB000000000000000, -45.0, 90.0), (0xB800000000000000, -45.0, 135.0), (0xC000000000000000, 0.0, 0.0), (0xC800000000000000, 0.0, 45.0), (0xD000000000000000, 45.0, 0.0), (0xD800000000000000, 45.0, 45.0), (0xE000000000000000, 0.0, 90.0), (0xE800000000000000, 0.0, 135.0), (0xF000000000000000, 45.0, 90.0), (0xF800000000000000, 45.0, 135.0) ] for data in dataset: self.assertEqual(data[0], geohash.encode_uint64(data[1], data[2])) latlon = geohash.decode_uint64(data[0]) self.assertEqual(latlon[0], data[1]) self.assertEqual(latlon[1], data[2]) if __name__=='__main__': unittest.main() python-geohash-0.8.3/test/test_jpiarea.py0000664000076400007640000000217211544653011020404 0ustar hawkhawk00000000000000# coding: UTF-8 import unittest import jpiarea def dms(d,m,s): return float(d) + (float(m) + float(s)/60)/60.0 class TestReference(unittest.TestCase): # hash code examples from open iarea document # http://www.nttdocomo.co.jp/service/imode/make/content/iarea/domestic/index.html def test_lv1(self): self.assertEqual("5438", jpiarea.encode(36,138)[0:4]) self.assertEqual("5637", jpiarea.encode(dms(37,20,0),137)[0:4]) def test_lv2(self): p = jpiarea.bbox("533946") self.assertAlmostEqual(503100000, p["s"]*3600*1000) self.assertAlmostEqual(503550000, p["n"]*3600*1000) self.assertAlmostEqual(128400000, p["w"]*3600*1000) self.assertAlmostEqual(128700000, p["e"]*3600*1000) def test_lv3(self): p = jpiarea.bbox("5339463") self.assertAlmostEqual(503325000, p["s"]*3600*1000) self.assertAlmostEqual(503550000, p["n"]*3600*1000) self.assertAlmostEqual(128550000, p["w"]*3600*1000) self.assertAlmostEqual(128700000, p["e"]*3600*1000) def test_lvN(self): self.assertEqual("53394600300",jpiarea.encode(dms(35,40,41), dms(139,46,9.527))) if __name__=='__main__': unittest.main() python-geohash-0.8.3/test/test_geohash.py0000664000076400007640000000346311544653011020413 0ustar hawkhawk00000000000000import unittest import geohash class TestEncode(unittest.TestCase): def test_cycle(self): for code in ["000000000000","zzzzzzzzzzzz","bgr96qxvpd46",]: self.assertEqual(code, geohash.encode(*geohash.decode(code))) class TestDecode(unittest.TestCase): def test_empty(self): self.assertEqual( geohash.bbox(''), {'s':-90.0, 'n':90.0, 'w':-180.0, 'e':180.0}) def test_one(self): seq = '0123456789bcdefghjkmnpqrstuvwxyz' sws = [ (-90.0, -180.0), (-90.0, -135.0), (-45.0, -180.0), (-45.0, -135.0), (-90.0, -90.0), (-90.0, -45.0), (-45.0, -90.0), (-45.0, -45.0), (0.0, -180.0), (0.0, -135.0), (45.0, -180.0), (45.0, -135.0), (0.0, -90.0), (0.0, -45.0), (45.0, -90.0), (45.0, -45.0), (-90.0, 0.0), (-90.0, 45.0), (-45.0, 0.0), (-45.0, 45.0), (-90.0, 90.0), (-90.0, 135.0), (-45.0, 90.0), (-45.0, 135.0), (0.0, 0.0), (0.0, 45.0), (45.0, 0.0), (45.0, 45.0), (0.0, 90.0), (0.0, 135.0), (45.0, 90.0), (45.0, 135.0) ] for i in zip(seq, sws): x = geohash.bbox(i[0]) self.assertEqual((x['s'], x['w']), i[1]) self.assertEqual(x['n']-x['s'], 45) self.assertEqual(x['e']-x['w'], 45) def test_ezs42(self): x=geohash.bbox('ezs42') self.assertEqual(round(x['s'],3), 42.583) self.assertEqual(round(x['n'],3), 42.627) class TestNeighbors(unittest.TestCase): def test_empty(self): self.assertEqual([], geohash.neighbors("")) def test_one(self): self.assertEqual(set(['1', '2', '3', 'p', 'r']), set(geohash.neighbors("0"))) self.assertEqual(set(['w', 'x', 'y', '8', 'b']), set(geohash.neighbors("z"))) self.assertEqual(set(['2', '6', '1', '0', '4', '9', '8', 'd']), set(geohash.neighbors("3"))) if __name__=='__main__': unittest.main() python-geohash-0.8.3/jpiarea.py0000664000076400007640000000420011544653011016360 0ustar hawkhawk00000000000000# coding: UTF-8 # Coder for Japanese iarea grid code. # NTT DoCoMo's Open iArea in Japan use a gridcode which is very similar to # JIS X 0410, but absolutely different in detail. def _encode_i2c(lat,lon,basebits): t=[] for i in range(basebits-3): t.append((lat&1)*2 + (lon&1)) lat = lat>>1 lon = lon>>1 if basebits>=3: t.append(lon&7) t.append(lat&7) lat = lat>>3 lon = lon>>3 t.append(lon) t.append(lat) t.reverse() return ''.join([str(i) for i in t]) def encode(lat, lon): if lat<7 or lon<100: raise Exception('Unsupported location') basebits = 8 return _encode_i2c(int(lat * (1<6: for i in gridcode[6:]: lat = (lat<<1) + int(int(i)/2) lon = (lon<<1) + int(i)%2 base = base<<1 basebits += 1 if len(gridcode)>4: lat = int(gridcode[4:5])*base + lat lon = int(gridcode[5:6])*base + lon base = base<<3 basebits += 3 lat = int(gridcode[0:2])*base + lat lon = int(gridcode[2:4])*base + lon return (lat, lon, basebits) def decode_sw(gridcode, delta=False): lat, lon, basebits = _decode_c2i(gridcode) if delta: return (float(lat)/(1.5*(1<(90<(100< """ try: import _geohash except ImportError: _geohash = None __all__ = ['encode','decode','decode_exactly','bbox', 'neighbors', 'expand'] _base32 = '0123456789bcdefghjkmnpqrstuvwxyz' _base32_map = {} for i in range(len(_base32)): _base32_map[_base32[i]] = i del i LONG_ZERO = 0 import sys if sys.version_info[0] < 3: LONG_ZERO = long(0) def _float_hex_to_int(f): if f<-1.0 or f>=1.0: return None if f==0.0: return 1,1 h = f.hex() x = h.find("0x1.") assert(x>=0) p = h.find("p") assert(p>0) half_len = len(h[x+4:p])*4-int(h[p+1:]) if x==0: r = (1<= half: i = i-half return float.fromhex(("0x0.%0"+str(s)+"xp1") % (i<<(s*4-l),)) else: i = half-i return float.fromhex(("-0x0.%0"+str(s)+"xp1") % (i<<(s*4-l),)) def _encode_i2c(lat,lon,lat_length,lon_length): precision = int((lat_length+lon_length)/5) if lat_length < lon_length: a = lon b = lat else: a = lat b = lon boost = (0,1,4,5,16,17,20,21) ret = '' for i in range(precision): ret+=_base32[(boost[a&7]+(boost[b&3]<<1))&0x1F] t = a>>3 a = b>>2 b = t return ret[::-1] def encode(latitude, longitude, precision=12): if latitude >= 90.0 or latitude < -90.0: raise Exception("invalid latitude.") while longitude < -180.0: longitude += 360.0 while longitude >= 180.0: longitude -= 360.0 if _geohash: basecode=_geohash.encode(latitude,longitude) if len(basecode)>precision: return basecode[0:precision] return basecode+'0'*(precision-len(basecode)) xprecision=precision+1 lat_length = lon_length = int(xprecision*5/2) if xprecision%2==1: lon_length+=1 if hasattr(float, "fromhex"): a = _float_hex_to_int(latitude/90.0) o = _float_hex_to_int(longitude/180.0) if a[1] > lat_length: ai = a[0]>>(a[1]-lat_length) else: ai = a[0]<<(lat_length-a[1]) if o[1] > lon_length: oi = o[0]>>(o[1]-lon_length) else: oi = o[0]<<(lon_length-o[1]) return _encode_i2c(ai, oi, lat_length, lon_length)[:precision] lat = latitude/180.0 lon = longitude/360.0 if lat>0: lat = int((1<0: lon = int((1<>2)&4 lat += (t>>2)&2 lon += (t>>1)&2 lat += (t>>1)&1 lon += t&1 lon_length+=3 lat_length+=2 else: lon = lon<<2 lat = lat<<3 lat += (t>>2)&4 lon += (t>>2)&2 lat += (t>>1)&2 lon += (t>>1)&1 lat += t&1 lon_length+=2 lat_length+=3 bit_length+=5 return (lat,lon,lat_length,lon_length) def decode(hashcode, delta=False): ''' decode a hashcode and get center coordinate, and distance between center and outer border ''' if _geohash: (lat,lon,lat_bits,lon_bits) = _geohash.decode(hashcode) latitude_delta = 90.0/(1<> lat_length: for tlon in (lon-1, lon, lon+1): ret.append(_encode_i2c(tlat,tlon,lat_length,lon_length)) tlat = lat-1 if tlat >= 0: for tlon in (lon-1, lon, lon+1): ret.append(_encode_i2c(tlat,tlon,lat_length,lon_length)) return ret def expand(hashcode): ret = neighbors(hashcode) ret.append(hashcode) return ret def _uint64_interleave(lat32, lon32): intr = 0 boost = (0,1,4,5,16,17,20,21,64,65,68,69,80,81,84,85) for i in range(8): intr = (intr<<8) + (boost[(lon32>>(28-i*4))%16]<<1) + boost[(lat32>>(28-i*4))%16] return intr def _uint64_deinterleave(ui64): lat = lon = 0 boost = ((0,0),(0,1),(1,0),(1,1),(0,2),(0,3),(1,2),(1,3), (2,0),(2,1),(3,0),(3,1),(2,2),(2,3),(3,2),(3,3)) for i in range(16): p = boost[(ui64>>(60-i*4))%16] lon = (lon<<2) + p[0] lat = (lat<<2) + p[1] return (lat, lon) def encode_uint64(latitude, longitude): if latitude >= 90.0 or latitude < -90.0: raise ValueError("Latitude must be in the range of (-90.0, 90.0)") while longitude < -180.0: longitude += 360.0 while longitude >= 180.0: longitude -= 360.0 if _geohash: ui128 = _geohash.encode_int(latitude,longitude) if _geohash.intunit == 64: return ui128[0] elif _geohash.intunit == 32: return (ui128[0]<<32) + ui128[1] elif _geohash.intunit == 16: return (ui128[0]<<48) + (ui128[1]<<32) + (ui128[2]<<16) + ui128[3] lat = int(((latitude + 90.0)/180.0)*(1<<32)) lon = int(((longitude+180.0)/360.0)*(1<<32)) return _uint64_interleave(lat, lon) def decode_uint64(ui64): if _geohash: latlon = _geohash.decode_int(ui64 % 0xFFFFFFFFFFFFFFFF, LONG_ZERO) if latlon: return latlon lat,lon = _uint64_deinterleave(ui64) return (180.0*lat/(1<<32) - 90.0, 360.0*lon/(1<<32) - 180.0) def expand_uint64(ui64, precision=50): ui64 = ui64 & (0xFFFFFFFFFFFFFFFF << (64-precision)) lat,lon = _uint64_deinterleave(ui64) lat_grid = 1<<(32-int(precision/2)) lon_grid = lat_grid>>(precision%2) if precision<=2: # expand becomes to the whole range return [] ranges = [] if lat & lat_grid: if lon & lon_grid: ui64 = _uint64_interleave(lat-lat_grid, lon-lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision+2)))) if precision%2==0: # lat,lon = (1, 1) and even precision ui64 = _uint64_interleave(lat-lat_grid, lon+lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision+1)))) if lat + lat_grid < 0xFFFFFFFF: ui64 = _uint64_interleave(lat+lat_grid, lon-lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) ui64 = _uint64_interleave(lat+lat_grid, lon) ranges.append((ui64, ui64 + (1<<(64-precision)))) ui64 = _uint64_interleave(lat+lat_grid, lon+lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) else: # lat,lon = (1, 1) and odd precision if lat + lat_grid < 0xFFFFFFFF: ui64 = _uint64_interleave(lat+lat_grid, lon-lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision+1)))) ui64 = _uint64_interleave(lat+lat_grid, lon+lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) ui64 = _uint64_interleave(lat, lon+lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) ui64 = _uint64_interleave(lat-lat_grid, lon+lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) else: ui64 = _uint64_interleave(lat-lat_grid, lon) ranges.append((ui64, ui64 + (1<<(64-precision+2)))) if precision%2==0: # lat,lon = (1, 0) and odd precision ui64 = _uint64_interleave(lat-lat_grid, lon-lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision+1)))) if lat + lat_grid < 0xFFFFFFFF: ui64 = _uint64_interleave(lat+lat_grid, lon-lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) ui64 = _uint64_interleave(lat+lat_grid, lon) ranges.append((ui64, ui64 + (1<<(64-precision)))) ui64 = _uint64_interleave(lat+lat_grid, lon+lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) else: # lat,lon = (1, 0) and odd precision if lat + lat_grid < 0xFFFFFFFF: ui64 = _uint64_interleave(lat+lat_grid, lon) ranges.append((ui64, ui64 + (1<<(64-precision+1)))) ui64 = _uint64_interleave(lat+lat_grid, lon-lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) ui64 = _uint64_interleave(lat, lon-lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) ui64 = _uint64_interleave(lat-lat_grid, lon-lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) else: if lon & lon_grid: ui64 = _uint64_interleave(lat, lon-lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision+2)))) if precision%2==0: # lat,lon = (0, 1) and even precision ui64 = _uint64_interleave(lat, lon+lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision+1)))) if lat > 0: ui64 = _uint64_interleave(lat-lat_grid, lon-lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) ui64 = _uint64_interleave(lat-lat_grid, lon) ranges.append((ui64, ui64 + (1<<(64-precision)))) ui64 = _uint64_interleave(lat-lat_grid, lon+lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) else: # lat,lon = (0, 1) and odd precision if lat > 0: ui64 = _uint64_interleave(lat-lat_grid, lon-lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision+1)))) ui64 = _uint64_interleave(lat-lat_grid, lon+lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) ui64 = _uint64_interleave(lat, lon+lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) ui64 = _uint64_interleave(lat+lat_grid, lon+lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) else: ui64 = _uint64_interleave(lat, lon) ranges.append((ui64, ui64 + (1<<(64-precision+2)))) if precision%2==0: # lat,lon = (0, 0) and even precision ui64 = _uint64_interleave(lat, lon-lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision+1)))) if lat > 0: ui64 = _uint64_interleave(lat-lat_grid, lon-lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) ui64 = _uint64_interleave(lat-lat_grid, lon) ranges.append((ui64, ui64 + (1<<(64-precision)))) ui64 = _uint64_interleave(lat-lat_grid, lon+lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) else: # lat,lon = (0, 0) and odd precision if lat > 0: ui64 = _uint64_interleave(lat-lat_grid, lon) ranges.append((ui64, ui64 + (1<<(64-precision+1)))) ui64 = _uint64_interleave(lat-lat_grid, lon-lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) ui64 = _uint64_interleave(lat, lon-lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) ui64 = _uint64_interleave(lat+lat_grid, lon-lon_grid) ranges.append((ui64, ui64 + (1<<(64-precision)))) ranges.sort() # merge the conditions shrink = [] prev = None for i in ranges: if prev: if prev[1] != i[0]: shrink.append(prev) prev = i else: prev = (prev[0], i[1]) else: prev = i shrink.append(prev) ranges = [] for i in shrink: a,b=i if a == 0: a = None # we can remove the condition because it is the lowest value if b == 0x10000000000000000: b = None # we can remove the condition because it is the highest value ranges.append((a,b)) return ranges python-geohash-0.8.3/jpgrid.py0000664000076400007640000000653611544653011016242 0ustar hawkhawk00000000000000# coding: UTF-8 # Coder for Japanese grid square code. (JIS C 6304 / JIS X 0410) # 行政管理庁告示第143号 http://www.stat.go.jp/data/mesh/ def _encode_i2c(lat, lon, base1): t=[] while base1>80: t.append(1 + (lat&1)*2 + (lon&1)) lat = lat>>1 lon = lon>>1 base1 = base1>>1 if base1==80: t.append(lon%10) t.append(lat%10) lat = int(lat/10) lon = int(lon/10) base1 = int(base1/10) elif base1==16: # Uni5 t.append(1 + (lat&1)*2 + (lon&1)) lat = lat>>1 lon = lon>>1 base1 = base1>>1 elif base1==40: # Uni2 t.append(5) t.append(lon%5*2) t.append(lat%5*2) lat = int(lat/5) lon = int(lon/5) base1 = int(base1/5) if base1==8: t.append(lon%8) t.append(lat%8) lat = lat>>3 lon = lon>>3 base1 = base1>>3 t.append(lon) t.append(lat) t.reverse() return ''.join([str(i) for i in t]) def encode(latitude, longitude, base1=80): return _encode_i2c(int(latitude*base1*1.5), int(longitude*base1-100.0*base1), base1) #def _encode_i2c(lat, lon, base1): def _decode_c2i(gridcode): base1 = 1 lat = lon = 0 codelen = len(gridcode) if codelen>0: lat = int(gridcode[0:2]) lon = int(gridcode[2:4]) if codelen>4: lat = (lat<<3) + int(gridcode[4:5]) lon = (lon<<3) + int(gridcode[5:6]) base1 = base1<<3 if codelen>6: if codelen==7: i = int(gridcode[6:7])-1 lat = (lat<<1) + int(i/2) lon = (lon<<1) + i%2 base1 = base1<<1 else: lat = lat*10 + int(gridcode[6:7]) lon = lon*10 + int(gridcode[7:8]) base1 = base1*10 if codelen>8: if gridcode[8:]=='5': lat = lat>>1 lon = lon>>1 base1 = base1>>1 else: for i in gridcode[8:]: i = int(i)-1 lat = (lat<<1) + int(i/2) lon = (lon<<1) + i%2 base1 = base1<<1 return (lat, lon, base1) def decode_sw(gridcode, delta=False): (lat, lon, base1) = _decode_c2i(gridcode) lat = lat/(base1*1.5) lon = lon/float(base1) + 100.0 if delta: return (lat, lon, 1.0/(base1*1.5), 1.0/base1) else: return (lat, lon) def decode(gridcode): (lat, lon, base1) = _decode_c2i(gridcode) # center position of the meshcode. lat = (lat<<1) + 1 lon = (lon<<1) + 1 base1 = base1<<1 return (lat/(base1*1.5), lon/float(base1) + 100.0) def bbox(gridcode): (a,b,c,d) = decode_sw(gridcode, True) return {'w':a, 's':b, 'n':b+d, 'e':a+c} ## short-cut methods def encodeLv1(lat, lon): return encode(lat,lon,1) def encodeLv2(lat, lon): return encode(lat,lon,8) def encodeLv3(lat, lon): return encode(lat,lon,80) def encodeBase(lat,lon): return encodeLv3(lat,lon) def encodeHalf(lat,lon): return encode(lat,lon,160) def encodeQuarter(lat,lon): return encode(lat,lon,320) def encodeEighth(lat,lon): return encode(lat,lon,640) def encodeUni10(lat,lon): return encodeLv2(lat,lon) def encodeUni5(lat, lon): return encode(lat,lon,16) def encodeUni2(lat, lon): return encode(lat,lon,40) def neighbors(gridcode): (lat,lon,base1)=_decode_c2i(gridcode) ret = [] for i in ((0,-1),(0,1),(1,-1),(1,0),(1,1),(-1,-1),(-1,0),(-1,1)): tlat=lat+i[0] tlon=lon+i[1] if tlat<0 or tlat>(90*base1): continue if tlon<0 or tlon>(100*base1): continue ret.append(_encode_i2c(tlat,tlon,base1)) return ret def expand(gridcode): ret = neighbors(gridcode) ret.append(gridcode) return ret python-geohash-0.8.3/PKG-INFO0000664000076400007640000000040411544653021015473 0ustar hawkhawk00000000000000Metadata-Version: 1.0 Name: python-geohash Version: 0.8.3 Summary: Fast, accurate python geohashing library Home-page: http://code.google.com/p/python-geohash/ Author: Hiroaki Kawai Author-email: UNKNOWN License: UNKNOWN Description: UNKNOWN Platform: UNKNOWN