116 lines
2.9 KiB
JavaScript
116 lines
2.9 KiB
JavaScript
/*!
|
|
* Copyright© 2008 David Troy
|
|
*
|
|
* geohash.js
|
|
* github: https://github.com/davetroy/geohash-js
|
|
* license: MIT License
|
|
*
|
|
*/
|
|
BITS = [16, 8, 4, 2, 1];
|
|
|
|
BASE32 = "0123456789bcdefghjkmnpqrstuvwxyz";
|
|
NEIGHBORS = { right : { even : "bc01fg45238967deuvhjyznpkmstqrwx" },
|
|
left : { even : "238967debc01fg45kmstqrwxuvhjyznp" },
|
|
top : { even : "p0r21436x8zb9dcf5h7kjnmqesgutwvy" },
|
|
bottom : { even : "14365h7k9dcfesgujnmqp0r2twvyx8zb" } };
|
|
BORDERS = { right : { even : "bcfguvyz" },
|
|
left : { even : "0145hjnp" },
|
|
top : { even : "prxz" },
|
|
bottom : { even : "028b" } };
|
|
|
|
NEIGHBORS.bottom.odd = NEIGHBORS.left.even;
|
|
NEIGHBORS.top.odd = NEIGHBORS.right.even;
|
|
NEIGHBORS.left.odd = NEIGHBORS.bottom.even;
|
|
NEIGHBORS.right.odd = NEIGHBORS.top.even;
|
|
|
|
BORDERS.bottom.odd = BORDERS.left.even;
|
|
BORDERS.top.odd = BORDERS.right.even;
|
|
BORDERS.left.odd = BORDERS.bottom.even;
|
|
BORDERS.right.odd = BORDERS.top.even;
|
|
|
|
function refine_interval(interval, cd, mask) {
|
|
if (cd&mask)
|
|
interval[0] = (interval[0] + interval[1])/2;
|
|
else
|
|
interval[1] = (interval[0] + interval[1])/2;
|
|
}
|
|
|
|
function calculateAdjacent(srcHash, dir) {
|
|
srcHash = srcHash.toLowerCase();
|
|
var lastChr = srcHash.charAt(srcHash.length-1);
|
|
var type = (srcHash.length % 2) ? 'odd' : 'even';
|
|
var base = srcHash.substring(0,srcHash.length-1);
|
|
if (BORDERS[dir][type].indexOf(lastChr)!=-1)
|
|
base = calculateAdjacent(base, dir);
|
|
return base + BASE32[NEIGHBORS[dir][type].indexOf(lastChr)];
|
|
}
|
|
|
|
function decodeGeoHash(geohash) {
|
|
var is_even = 1;
|
|
var lat = []; var lon = [];
|
|
lat[0] = -90.0; lat[1] = 90.0;
|
|
lon[0] = -180.0; lon[1] = 180.0;
|
|
lat_err = 90.0; lon_err = 180.0;
|
|
|
|
for (i=0; i<geohash.length; i++) {
|
|
c = geohash[i];
|
|
cd = BASE32.indexOf(c);
|
|
for (j=0; j<5; j++) {
|
|
mask = BITS[j];
|
|
if (is_even) {
|
|
lon_err /= 2;
|
|
refine_interval(lon, cd, mask);
|
|
} else {
|
|
lat_err /= 2;
|
|
refine_interval(lat, cd, mask);
|
|
}
|
|
is_even = !is_even;
|
|
}
|
|
}
|
|
lat[2] = (lat[0] + lat[1])/2;
|
|
lon[2] = (lon[0] + lon[1])/2;
|
|
|
|
return { latitude: lat, longitude: lon};
|
|
}
|
|
|
|
function encodeGeoHash(latitude, longitude) {
|
|
var is_even=1;
|
|
var i=0;
|
|
var lat = []; var lon = [];
|
|
var bit=0;
|
|
var ch=0;
|
|
var precision = 12;
|
|
geohash = "";
|
|
|
|
lat[0] = -90.0; lat[1] = 90.0;
|
|
lon[0] = -180.0; lon[1] = 180.0;
|
|
|
|
while (geohash.length < precision) {
|
|
if (is_even) {
|
|
mid = (lon[0] + lon[1]) / 2;
|
|
if (longitude > mid) {
|
|
ch |= BITS[bit];
|
|
lon[0] = mid;
|
|
} else
|
|
lon[1] = mid;
|
|
} else {
|
|
mid = (lat[0] + lat[1]) / 2;
|
|
if (latitude > mid) {
|
|
ch |= BITS[bit];
|
|
lat[0] = mid;
|
|
} else
|
|
lat[1] = mid;
|
|
}
|
|
|
|
is_even = !is_even;
|
|
if (bit < 4)
|
|
bit++;
|
|
else {
|
|
geohash += BASE32[ch];
|
|
bit = 0;
|
|
ch = 0;
|
|
}
|
|
}
|
|
return geohash;
|
|
}
|