@studnicky/geo-data-builder
Builds the binary geohash lookup artifacts (geohash4.bin, overrides.bin, tuples.json) consumed by @studnicky/geo-resolver.
Walks every geohash-4 base cell on Earth, resolves each one's country/timezone (and, where configured, water-body name) via a pluggable oracle and sampling strategy, and interns the results into compact binary/JSON artifacts. Mixed cells — ones straddling a border or coastline — are either resolved with a single fixed-depth sample or recursively subdivided down to maxDescentDepth additional geohash characters, depending on the options passed to the build.
Install
pnpm add @studnicky/geo-data-builderRequires @studnicky:registry=https://npm.pkg.github.com in .npmrc.
Corner-grid sampling
CornerGridSampler samples four inset corners plus an interior grid per cell, with a default and a custom-density configuration:
import { CornerGridSampler } from '../src/index.js';
function demonstrateCornerGridSampling(): { 'allWithinBox': boolean; 'defaultPointCount': number; 'sparsePointCount': number } {
const boundingBox = { 'maxLat': 10, 'maxLon': 20, 'minLat': 0, 'minLon': 0 };
// create() with no options uses the default 4-corner + 3x3 interior grid
const defaultSampler = CornerGridSampler.create();
const defaultPoints = defaultSampler.samplePoints(boundingBox);
console.log('default sampler point count:', defaultPoints.length);
// create() with options trades sample density for build time/accuracy
const sparseSampler = CornerGridSampler.create({ 'interiorGridSize': 1 });
const sparsePoints = sparseSampler.samplePoints(boundingBox);
console.log('sparse sampler point count:', sparsePoints.length);
// every sampled point stays within the requested bounding box
const allWithinBox = defaultPoints.every((point) => {
return point.latitude >= boundingBox.minLat && point.latitude <= boundingBox.maxLat
&& point.longitude >= boundingBox.minLon && point.longitude <= boundingBox.maxLon;
});
console.log('all default points within bounding box:', allWithinBox);
return { 'allWithinBox': allWithinBox, 'defaultPointCount': defaultPoints.length, 'sparsePointCount': sparsePoints.length };
}Fluent sampler builder
CornerGridSamplerBuilder constructs a sampler through a fluent API, trading sample density for build time/accuracy:
import { CornerGridSamplerBuilder } from '../src/index.js';
function demonstrateCornerGridSamplerBuilder(): { 'firstCornerLatitude': number | null; 'pointCount': number } {
const boundingBox = { 'maxLat': 10, 'maxLon': 20, 'minLat': 0, 'minLon': 0 };
// build a sampler with a tighter corner inset and a larger interior grid
const sampler = CornerGridSamplerBuilder.create()
.withCornerInset(0.02)
.withInteriorGridSize(4)
.build();
const points = sampler.samplePoints(boundingBox);
const firstPoint = points[0];
console.log('builder sampler point count:', points.length);
console.log('first corner:', firstPoint);
return { 'firstCornerLatitude': firstPoint?.latitude ?? null, 'pointCount': points.length };
}