@math.gl/geohash
Version:
Math for the GeoHash DGGS (Discrete Global Grid System)
79 lines (68 loc) • 1.92 kB
text/typescript
// math.gl, MIT license
/* eslint-disable max-depth */
const BASE32_CODES = '0123456789bcdefghjkmnpqrstuvwxyz';
const BASE32_CODES_DICT: Record<string, number> = {};
for (let i = 0; i < BASE32_CODES.length; i++) {
BASE32_CODES_DICT[BASE32_CODES.charAt(i)] = i;
}
const MIN_LAT = -90;
const MAX_LAT = 90;
const MIN_LON = -180;
const MAX_LON = 180;
/** Return center lng,lat of geohash cell */
export function getGeohashLngLat(geohash: string): number[] {
const [s, w, n, e] = getGeohashBounds(geohash);
return [(e + w) / 2, (n + s) / 2];
}
/** Return boundary polygon of geohash cell as lng,lat array */
export function getGeohashBoundary(geohash: string): number[][] {
const [s, w, n, e] = getGeohashBounds(geohash);
return [
[e, n],
[e, s],
[w, s],
[w, n],
[e, n]
];
}
/** Return boundary polygon of geohash cell as flat array */
export function getGeohashBoundaryFlat(geohash: string): number[] {
const [s, w, n, e] = getGeohashBounds(geohash);
return [e, n, e, s, w, s, w, n, e, n];
}
/**
* @note Adapted from ngeohash decode_bbox
*/
export function getGeohashBounds(geohash: string): number[] {
let isLon = true;
let maxLat = MAX_LAT;
let minLat = MIN_LAT;
let maxLon = MAX_LON;
let minLon = MIN_LON;
let mid: number;
let hashValue = 0;
for (let i = 0, l = geohash.length; i < l; i++) {
const code = geohash[i].toLowerCase();
hashValue = BASE32_CODES_DICT[code];
for (let bits = 4; bits >= 0; bits--) {
const bit = (hashValue >> bits) & 1;
if (isLon) {
mid = (maxLon + minLon) / 2;
if (bit === 1) {
minLon = mid;
} else {
maxLon = mid;
}
} else {
mid = (maxLat + minLat) / 2;
if (bit === 1) {
minLat = mid;
} else {
maxLat = mid;
}
}
isLon = !isLon;
}
}
return [minLat, minLon, maxLat, maxLon];
}