86 lines
2.0 KiB
TypeScript
86 lines
2.0 KiB
TypeScript
const BASE32 = "0123456789bcdefghjkmnpqrstuvwxyz";
|
|
|
|
export function encodeGeohash(
|
|
coord: { latitude: number; longitude: number },
|
|
precision = 9
|
|
): string {
|
|
let minLat = -90;
|
|
let maxLat = 90;
|
|
let minLon = -180;
|
|
let maxLon = 180;
|
|
let hash = "";
|
|
let bits = 0;
|
|
let ch = 0;
|
|
let evenBit = true;
|
|
|
|
while (hash.length < precision) {
|
|
if (evenBit) {
|
|
const mid = (minLon + maxLon) / 2;
|
|
if (coord.longitude >= mid) {
|
|
ch = (ch << 1) | 1;
|
|
minLon = mid;
|
|
} else {
|
|
ch = ch << 1;
|
|
maxLon = mid;
|
|
}
|
|
} else {
|
|
const mid = (minLat + maxLat) / 2;
|
|
if (coord.latitude >= mid) {
|
|
ch = (ch << 1) | 1;
|
|
minLat = mid;
|
|
} else {
|
|
ch = ch << 1;
|
|
maxLat = mid;
|
|
}
|
|
}
|
|
evenBit = !evenBit;
|
|
bits++;
|
|
if (bits === 5) {
|
|
hash += BASE32[ch];
|
|
bits = 0;
|
|
ch = 0;
|
|
}
|
|
}
|
|
|
|
return hash;
|
|
}
|
|
|
|
export function decodeGeohash(hash: string): {
|
|
latitude: number;
|
|
longitude: number;
|
|
} {
|
|
let minLat = -90;
|
|
let maxLat = 90;
|
|
let minLon = -180;
|
|
let maxLon = 180;
|
|
let evenBit = true;
|
|
|
|
for (const char of hash) {
|
|
const idx = BASE32.indexOf(char);
|
|
for (let i = 4; i >= 0; i--) {
|
|
const bit = (idx >> i) & 1;
|
|
if (evenBit) {
|
|
const mid = (minLon + maxLon) / 2;
|
|
if (bit === 1) {
|
|
minLon = mid;
|
|
} else {
|
|
maxLon = mid;
|
|
}
|
|
} else {
|
|
const mid = (minLat + maxLat) / 2;
|
|
if (bit === 1) {
|
|
minLat = mid;
|
|
} else {
|
|
maxLat = mid;
|
|
}
|
|
}
|
|
evenBit = !evenBit;
|
|
}
|
|
}
|
|
|
|
return {
|
|
latitude: (minLat + maxLat) / 2,
|
|
longitude: (minLon + maxLon) / 2,
|
|
};
|
|
}
|