79 lines
2.3 KiB
JavaScript
79 lines
2.3 KiB
JavaScript
import Geohash from 'latlon-geohash';
|
|
|
|
/**
|
|
* Calculates 4-character geohash prefixes that cover the given bounding box.
|
|
*
|
|
* @param {Object} bbox
|
|
* @param {number} bbox.minLat
|
|
* @param {number} bbox.minLon
|
|
* @param {number} bbox.maxLat
|
|
* @param {number} bbox.maxLon
|
|
* @returns {string[]} Array of unique 4-character geohash prefixes
|
|
*/
|
|
export function getGeohashPrefixesInBbox(bbox) {
|
|
const { minLat, minLon, maxLat, maxLon } = bbox;
|
|
const prefixes = new Set();
|
|
|
|
// 4-char geohash precision is approx 20km x 39km at equator.
|
|
// We can step through the bbox in increments smaller than that to ensure coverage.
|
|
// Latitude: 1 deg ~= 111km. 20km ~= 0.18 deg.
|
|
// Longitude: 1 deg ~= 111km (at equator). 39km ~= 0.35 deg.
|
|
// Let's use conservative steps to hit every cell.
|
|
// 0.1 degree steps should be safe enough for 4-char hashes.
|
|
|
|
// Safety check to avoid infinite loops or massive arrays if bbox is weird
|
|
if (Math.abs(maxLat - minLat) > 20 || Math.abs(maxLon - minLon) > 20) {
|
|
console.warn(
|
|
'BBox too large for 4-char geohash scanning, aborting fine scan.'
|
|
);
|
|
return [];
|
|
}
|
|
|
|
const latStep = 0.1;
|
|
const lonStep = 0.1;
|
|
|
|
for (let lat = minLat; lat <= maxLat + latStep; lat += latStep) {
|
|
for (let lon = minLon; lon <= maxLon + lonStep; lon += lonStep) {
|
|
// Clamp to bbox for the edge cases
|
|
const cLat = Math.min(lat, maxLat);
|
|
const cLon = Math.min(lon, maxLon);
|
|
|
|
try {
|
|
const hash = Geohash.encode(cLat, cLon, 4);
|
|
prefixes.add(hash);
|
|
// eslint-disable-next-line no-unused-vars
|
|
} catch (e) {
|
|
// Ignore invalid coords if any
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ensure corners are definitely included (floating point steps might miss slightly)
|
|
try {
|
|
prefixes.add(Geohash.encode(minLat, minLon, 4));
|
|
// eslint-disable-next-line no-unused-vars
|
|
} catch (e) {
|
|
/* ignore */
|
|
}
|
|
try {
|
|
prefixes.add(Geohash.encode(maxLat, maxLon, 4));
|
|
// eslint-disable-next-line no-unused-vars
|
|
} catch (e) {
|
|
/* ignore */
|
|
}
|
|
try {
|
|
prefixes.add(Geohash.encode(minLat, maxLon, 4));
|
|
// eslint-disable-next-line no-unused-vars
|
|
} catch (e) {
|
|
/* ignore */
|
|
}
|
|
try {
|
|
prefixes.add(Geohash.encode(maxLat, minLon, 4));
|
|
// eslint-disable-next-line no-unused-vars
|
|
} catch (e) {
|
|
/* ignore */
|
|
}
|
|
|
|
return Array.from(prefixes);
|
|
}
|