gadm-ts/dist/gpkg-reader.js

622 lines
52 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* gpkg-reader.ts — Read geometry from a local GeoPackage file.
*
* Parses GeoPackage Binary (GPKG header + WKB) into GeoJSON.
* Uses better-sqlite3 for SQLite access.
*
* GeoPackage Binary format:
* [2 bytes magic "GP"] [1 byte version] [1 byte flags]
* [4 bytes SRS ID] [envelope (064 bytes)] [WKB geometry]
*
* Flags byte: bit 0 = byte order, bits 1-3 = envelope type, bit 5 = empty
* Envelope sizes: 0=none, 1=xy(32B), 2=xyz(48B), 3=xym(48B), 4=xyzm(64B)
*/
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
import { resolve, join, dirname } from 'path';
import { fileURLToPath } from 'url';
import { enrichFeatureWithGHS } from './enrich-ghs.js';
const _filename = fileURLToPath(import.meta.url);
const _dirname = dirname(_filename);
// ────────── GeoPackage paths ──────────
const DEFAULT_GPKG_PATHS = [
// 1. Explicit environment-defined path
process.env.GADM_GPKG_PATH,
// 2. Production CWD data mount
resolve(process.cwd(), 'data/gadm_410.gpkg'),
resolve(process.cwd(), 'cache/gadm/gadm_410.gpkg'),
];
let _gpkgPath = null;
/** Set or override the GeoPackage file path */
export function setGpkgPath(p) {
_gpkgPath = p;
}
function findGpkg() {
if (_gpkgPath && existsSync(_gpkgPath))
return _gpkgPath;
for (const p of DEFAULT_GPKG_PATHS) {
if (p && existsSync(p)) {
_gpkgPath = p;
return p;
}
}
return null;
}
// ────────── WKB Parser ──────────
class WKBReader {
buf;
pos;
le; // little-endian
constructor(buf, offset) {
this.buf = buf;
this.pos = offset;
// First byte of WKB = endianness indicator
this.le = this.buf[this.pos] === 1;
this.pos++;
}
readUInt32() {
const v = this.le
? this.buf.readUInt32LE(this.pos)
: this.buf.readUInt32BE(this.pos);
this.pos += 4;
return v;
}
readDouble() {
const v = this.le
? this.buf.readDoubleLE(this.pos)
: this.buf.readDoubleBE(this.pos);
this.pos += 8;
return v;
}
readCoord() {
const x = this.readDouble(); // longitude
const y = this.readDouble(); // latitude
return [x, y];
}
readRing() {
const count = this.readUInt32();
const ring = [];
for (let i = 0; i < count; i++) {
ring.push(this.readCoord());
}
return ring;
}
readPolygon() {
const ringCount = this.readUInt32();
const rings = [];
for (let i = 0; i < ringCount; i++) {
rings.push(this.readRing());
}
return rings;
}
readGeometry() {
const wkbType = this.readUInt32();
switch (wkbType) {
case 1: // Point
return { type: 'Point', coordinates: this.readCoord() };
case 2: { // LineString
const count = this.readUInt32();
const coords = [];
for (let i = 0; i < count; i++)
coords.push(this.readCoord());
return { type: 'LineString', coordinates: coords };
}
case 3: // Polygon
return { type: 'Polygon', coordinates: this.readPolygon() };
case 4: { // MultiPoint
const count = this.readUInt32();
const points = [];
for (let i = 0; i < count; i++) {
this.le = this.buf[this.pos] === 1;
this.pos++;
this.readUInt32(); // skip type
points.push(this.readCoord());
}
return { type: 'MultiPoint', coordinates: points };
}
case 5: { // MultiLineString
const count = this.readUInt32();
const lines = [];
for (let i = 0; i < count; i++) {
this.le = this.buf[this.pos] === 1;
this.pos++;
this.readUInt32(); // skip type
const ptCount = this.readUInt32();
const coords = [];
for (let j = 0; j < ptCount; j++)
coords.push(this.readCoord());
lines.push(coords);
}
return { type: 'MultiLineString', coordinates: lines };
}
case 6: { // MultiPolygon
const count = this.readUInt32();
const polys = [];
for (let i = 0; i < count; i++) {
this.le = this.buf[this.pos] === 1;
this.pos++;
this.readUInt32(); // skip type (3 = Polygon)
polys.push(this.readPolygon());
}
return { type: 'MultiPolygon', coordinates: polys };
}
default:
throw new Error(`Unsupported WKB type: ${wkbType}`);
}
}
}
/** Parse GeoPackage Binary blob → GeoJSON geometry */
export function parseGpkgGeometry(blob) {
// Validate magic
if (blob[0] !== 0x47 || blob[1] !== 0x50) {
throw new Error('Not a GeoPackage geometry (missing GP magic)');
}
const flags = blob[3];
const isEmpty = (flags >> 5) & 1;
if (isEmpty) {
return { type: 'MultiPolygon', coordinates: [] };
}
const envelopeType = (flags >> 1) & 7;
const envSizes = [0, 32, 48, 48, 64];
const envSize = envSizes[envelopeType] || 0;
const wkbStart = 8 + envSize;
const reader = new WKBReader(blob, wkbStart);
return reader.readGeometry();
}
import { feature } from '@turf/helpers';
import polygonClipping from 'polygon-clipping';
import simplifyJs from 'simplify-js';
// ────────── Query ──────────
/**
* Merge polygon coordinates by dissolving them.
*/
async function mergeGeometries(geometries) {
const polys = [];
for (const g of geometries) {
if (g.type === 'MultiPolygon') {
for (const coords of g.coordinates) {
polys.push(feature({ type: 'Polygon', coordinates: coords }));
}
}
else if (g.type === 'Polygon') {
polys.push(feature(g));
}
}
// Chunked Dissolve
let currentPolys = polys;
const CHUNK_SIZE = 100;
while (currentPolys.length > 1) {
const nextPolys = [];
for (let i = 0; i < currentPolys.length; i += CHUNK_SIZE) {
const chunk = currentPolys.slice(i, i + CHUNK_SIZE);
if (chunk.length === 1) {
nextPolys.push(chunk[0]);
continue;
}
try {
const startTime = Date.now();
// Use polygon-clipping instead of Turf.js as turf.dissolve is prone to infinite loops
const polyCoords = chunk.map(f => {
const g = f.geometry;
return g.type === 'Polygon' ? [g.coordinates] : g.coordinates;
});
const unionedCoords = polygonClipping.union(polyCoords[0], ...polyCoords.slice(1));
if (unionedCoords.length > 0) {
nextPolys.push(feature({ type: 'MultiPolygon', coordinates: unionedCoords }));
}
}
catch (e) {
console.warn('[mergeGeometries] polygon-clipping failed on chunk, falling back to basic merge:', e);
nextPolys.push(...chunk);
}
// microtask yield barrier
await new Promise(r => setTimeout(r, 0));
}
// If length did not decrease, we can't dissolve further
if (nextPolys.length >= currentPolys.length) {
currentPolys = nextPolys;
break;
}
currentPolys = nextPolys;
}
if (currentPolys.length === 1) {
return currentPolys[0].geometry;
}
// fallback if dissolve fails or returns multiple disjoint polygons
const allPolygons = [];
for (const p of currentPolys) {
const g = p.geometry;
if (g.type === 'MultiPolygon') {
allPolygons.push(...g.coordinates);
}
else if (g.type === 'Polygon') {
allPolygons.push(g.coordinates);
}
}
return { type: 'MultiPolygon', coordinates: allPolygons };
}
// ────────── Geometry Optimization ──────────
function optimizeCoordinates(coords, tolerance) {
if (coords.length > 0 && typeof coords[0] === 'number') {
const x = Number(coords[0].toFixed(5));
const y = Number(coords[1].toFixed(5));
return [x, y];
}
// If it's a ring of points (array of arrays of numbers)
if (coords.length > 0 && Array.isArray(coords[0]) && typeof coords[0][0] === 'number') {
// Map to {x, y} for simplify-js
let points = coords.map((c) => ({ x: c[0], y: c[1] }));
if (tolerance > 0 && points.length > 2) {
points = simplifyJs(points, tolerance, false);
}
// Map back to [x, y] and round
return points.map(p => [Number(p.x.toFixed(5)), Number(p.y.toFixed(5))]);
}
// Deeper arrays (Polygon / MultiPolygon)
return coords.map(c => optimizeCoordinates(c, tolerance));
}
/**
* Get boundary features for a specific GID.
*
* The flat GADM table has one row per leaf-level area (all levels filled).
* This function:
* 1. Queries all rows where `GID_{gidLevel} = gadmId`
* 2. Groups them by `GID_{contentLevel}`
* 3. Merges leaf geometries into one MultiPolygon per group
*
* Examples:
* - getBoundaryFromGpkg('DEU', 0) → 1 feature (Germany outline, merged from all leaves)
* - getBoundaryFromGpkg('DEU.14_1', 2) → 13 features (one per L2 district in Sachsen)
* - getBoundaryFromGpkg('DEU.14_1') → 1 feature (Sachsen outline)
*
* Returns null if GeoPackage is not available.
*/
import { createRequire } from 'module';
let sharedDb = null;
let sharedTableName = '';
function ensureDb() {
if (sharedDb)
return true;
const gpkgPath = findGpkg();
if (!gpkgPath)
return false;
let Database;
try {
if (typeof require !== 'undefined') {
Database = require('better-sqlite3');
}
else {
const req = createRequire(import.meta.url);
Database = req('better-sqlite3');
}
}
catch (e) {
console.warn('Failed to load better-sqlite3 (GeoPackage bounds will be skipped):', e.message);
return false;
}
sharedDb = new Database(gpkgPath, { readonly: true });
try {
const tables = sharedDb.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'gpkg_%' AND name NOT LIKE 'rtree_%' AND name NOT LIKE 'sqlite_%'").all();
sharedTableName = tables.find((t) => t.name === 'gadm_410' || t.name === 'gadm41_raw')?.name;
if (!sharedTableName) {
sharedDb.close();
sharedDb = null;
return false;
}
return true;
}
catch (e) {
sharedDb.close();
sharedDb = null;
return false;
}
}
export async function getBoundaryFromGpkg(gadmId, contentLevel, externalCache, resolution = 3) {
const levelStr = contentLevel != null ? contentLevel.toString() : 'auto';
const safeId = gadmId.replace(/[^a-zA-Z0-9\.\-_]/g, '_').substring(0, 50);
const cacheKey = `boundary_${safeId}_${levelStr}`;
// Resolve cache locations for cross-environment compatibility (Dev Workspace vs Prod Server)
const possibleCacheDirs = [];
if (process.env.GADM_CACHE)
possibleCacheDirs.push(process.env.GADM_CACHE);
possibleCacheDirs.push(resolve(process.cwd(), 'cache/gadm'));
possibleCacheDirs.push(resolve(_dirname, '../cache/gadm'));
const uniqueCacheDirs = [...new Set(possibleCacheDirs)];
if (externalCache) {
try {
const cached = await externalCache.get(cacheKey);
if (cached)
return cached;
}
catch (e) { /* ignore */ }
}
else {
for (const dir of uniqueCacheDirs) {
const cacheFile = join(dir, `${cacheKey}.json`);
if (existsSync(cacheFile)) {
try {
return JSON.parse(readFileSync(cacheFile, 'utf-8'));
}
catch (e) {
console.warn(`[gpkg-reader] Failed to read cache from ${cacheFile}:`, e);
}
}
}
// Fallback: check for C++ pre-built cache (boundary_{COUNTRY}_{LEVEL}.json)
// The C++ pipeline outputs one file per country per level, containing ALL features.
// For sub-region queries (e.g. 'DEU.2_1' at level 3), we read the full country file
// and filter by GID prefix — since GADM GIDs are hierarchical (DEU.2.91.1_1 ⊂ DEU.2_1).
const dotCount = (gadmId.match(/\./g) || []).length;
const gidLevel = dotCount;
const resolvedLevel = contentLevel != null ? contentLevel : gidLevel;
const countryCode = gadmId.split('.')[0];
// C++ outputs sub-region precise files too if batched with `--split-levels`.
// We look for exact gadmId match first, then fall back to full country.
const fallbackNames = [
`boundary_${gadmId}_${resolvedLevel}.json`,
`boundary_${countryCode}_${resolvedLevel}.json`
];
// Remove duplicates if gadmId == countryCode
const uniqueFallbackNames = [...new Set(fallbackNames)];
// Build a prefix for sub-region filtering (used mostly for the full-country fallback)
const isSubRegion = gadmId.includes('.');
const gidPrefix = isSubRegion
? gadmId.replace(/_\d+$/, '') + '.' // strip version suffix, add dot
: null;
for (const cppFileName of uniqueFallbackNames) {
for (const dir of uniqueCacheDirs) {
const cppFile = join(dir, cppFileName);
if (existsSync(cppFile)) {
try {
const raw = JSON.parse(readFileSync(cppFile, 'utf-8'));
if (raw.features && Array.isArray(raw.features)) {
console.log(`[gpkg-reader] Loading from CPP Cache File ${cppFile} : ${gidPrefix || 'country-wide'}`);
let rawFeatures = raw.features;
// Filter by GID prefix if we had to read the fallback country-wide file
// (If we loaded the exact sub-region file, it's already perfectly chunked)
if (gidPrefix && cppFileName.includes(countryCode) && !cppFileName.includes(gadmId)) {
rawFeatures = rawFeatures.filter((f) => f.code && f.code.startsWith(gidPrefix));
}
if (rawFeatures.length === 0)
continue; // no matches, try next dir
const features = rawFeatures.map((f) => {
const { geometry, code, name, ...enrichment } = f;
return {
type: 'Feature',
properties: { name, code, ...enrichment },
geometry,
};
});
const result = { type: 'FeatureCollection', features };
const outCacheFile = join(uniqueCacheDirs[1] || uniqueCacheDirs[0], `${cacheKey}.json`);
try {
writeFileSync(outCacheFile, JSON.stringify(result));
}
catch (e) { /* ignore */ }
return result;
}
}
catch (e) {
console.warn(`[gpkg-reader] Failed to read C++ cache from ${cppFile}:`, e);
}
}
}
}
}
if (!ensureDb())
return null;
const db = sharedDb;
const tableName = sharedTableName;
// Determine the GID's own level from dot count: "ESP" = L0, "ESP.6_1" = L1
const dotCount = (gadmId.match(/\./g) || []).length;
const gidLevel = dotCount;
const level = contentLevel != null ? contentLevel : gidLevel;
// Columns to select
const propCols = [];
for (let l = 0; l <= Math.min(level, 5); l++) {
propCols.push(`NAME_${l}`, `GID_${l}`);
}
const allCols = ['geom', ...propCols].filter((c, i, a) => a.indexOf(c) === i);
const colList = allCols.map(c => `"${c}"`).join(', ');
try {
// Query all leaf rows for this GID
const gidCol = `GID_${gidLevel}`;
const rows = db.prepare(`SELECT ${colList} FROM "${tableName}" WHERE "${gidCol}" = ?`).all(gadmId);
if (rows.length === 0)
return null;
// Group by content-level GID, merge geometries
const groupCol = `GID_${level}`;
const groups = new Map();
for (const row of rows) {
if (!row.geom)
continue;
const groupKey = row[groupCol] || gadmId;
if (!groups.has(groupKey)) {
const props = {};
for (const col of propCols) {
if (row[col] != null)
props[col] = String(row[col]);
}
groups.set(groupKey, { props, geoms: [] });
}
try {
const geometry = parseGpkgGeometry(Buffer.from(row.geom));
groups.get(groupKey).geoms.push(geometry);
}
catch (e) {
console.warn(`[gpkg-reader] Failed to parse geometry for ${groupKey}:`, e);
}
}
// Build features
const features = [];
for (const [, { props, geoms }] of groups) {
if (geoms.length === 0)
continue;
const geometry = geoms.length === 1 ? geoms[0] : await mergeGeometries(geoms);
if (level === gidLevel) {
props.isOuter = true;
}
features.push({ type: 'Feature', properties: props, geometry });
}
// Removed includeOuter unshift logic entirely
let result = { type: 'FeatureCollection', features };
// Determine tolerance for simplification based on resolution
let tolerance = 0.0;
switch (resolution) {
case 1:
tolerance = 0.0;
break;
case 2:
tolerance = 0.001;
break;
case 3:
tolerance = 0.002;
break;
case 4:
tolerance = 0.005;
break;
case 5:
tolerance = 0.01;
break;
case 6:
tolerance = 0.05;
break;
default:
tolerance = 0.0;
break;
}
// Simplify and truncate geometries to reduce payload size safely
const simplifiedFeatures = [];
for (const feat of result.features) {
try {
// recursively simplify and truncate to 5 decimal places matching C++ processing
feat.geometry.coordinates = optimizeCoordinates(feat.geometry.coordinates, tolerance);
}
catch (e) {
console.warn(`[gpkg-reader] geometry optimization failed for ${gadmId}:`, e);
}
simplifiedFeatures.push(feat);
}
result = { type: 'FeatureCollection', features: simplifiedFeatures };
// Enrich features with population and built density data
for (const feat of result.features) {
try {
const enriched = await enrichFeatureWithGHS(feat, { pop: true, built: true });
Object.assign(feat.properties, enriched);
}
catch (err) {
console.warn(`[gpkg-reader] GHS enrichment failed for ${gadmId}:`, err);
}
}
if (externalCache) {
try {
await externalCache.set(cacheKey, result);
}
catch (e) { /* ignore */ }
}
else {
const targetDir = uniqueCacheDirs[0];
const targetFile = join(targetDir, `${cacheKey}.json`);
try {
if (!existsSync(targetDir)) {
mkdirSync(targetDir, { recursive: true });
}
console.log('GADM Writing External cache:', targetFile);
writeFileSync(targetFile, JSON.stringify(result));
}
catch (e) {
console.warn(`[gpkg-reader] Failed to write cache for ${gadmId}:`, e);
}
}
return result;
}
catch (err) {
console.error("Error reading from GeoPackage:", err);
return null;
}
}
// ────────── Point in Polygon ──────────
function pointInRing(pt, ring) {
let isInside = false;
const [x, y] = pt;
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
const xi = ring[i][0], yi = ring[i][1];
const xj = ring[j][0], yj = ring[j][1];
const intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect)
isInside = !isInside;
}
return isInside;
}
function pointInPolygon(pt, polygon) {
if (polygon.length === 0)
return false;
if (!pointInRing(pt, polygon[0]))
return false;
for (let i = 1; i < polygon.length; i++) {
if (pointInRing(pt, polygon[i]))
return false;
}
return true;
}
function pointInMultiPolygon(pt, multiPolygon) {
for (const poly of multiPolygon) {
if (pointInPolygon(pt, poly))
return true;
}
return false;
}
export function containsPoint(geom, pt) {
if (geom.type === 'Polygon') {
return pointInPolygon(pt, geom.coordinates);
}
else if (geom.type === 'MultiPolygon') {
return pointInMultiPolygon(pt, geom.coordinates);
}
return false;
}
/**
* Perform a spatial query to find the exact GADM hierarchy containing a point.
*/
export function getHierarchyByPoint(lat, lon) {
if (!ensureDb())
return null;
const db = sharedDb;
const tableName = sharedTableName;
try {
const rows = db.prepare(`SELECT a.* FROM "${tableName}" a
JOIN "rtree_${tableName}_geom" b ON a.fid = b.id
WHERE b.minx <= ? AND b.maxx >= ? AND b.miny <= ? AND b.maxy >= ?`).all(lon, lon, lat, lat);
for (const row of rows) {
if (!row.geom)
continue;
try {
const geometry = parseGpkgGeometry(Buffer.from(row.geom));
if (containsPoint(geometry, [lon, lat])) {
// Exact match found among candidate bounding boxes!
const results = [];
for (let i = 0; i <= 5; i++) {
const gid = row[`GID_${i}`];
const name = row[`NAME_${i}`];
if (gid || name) {
results.push({
level: i,
gadmName: name || null,
gid: gid || null
});
}
}
return results;
}
}
catch (e) {
// Ignore parsing errors for individual geometries
}
}
return null;
}
catch (err) {
console.error("Error performing spatial point query against GeoPackage:", err);
return null;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3BrZy1yZWFkZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZ3BrZy1yZWFkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsT0FBTyxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsYUFBYSxFQUFFLFNBQVMsRUFBRSxNQUFNLElBQUksQ0FBQztBQUN4RSxPQUFPLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDOUMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLEtBQUssQ0FBQztBQUNwQyxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUV2RCxNQUFNLFNBQVMsR0FBRyxhQUFhLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUNqRCxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7QUFvQnBDLHlDQUF5QztBQUV6QyxNQUFNLGtCQUFrQixHQUFHO0lBQ3ZCLHVDQUF1QztJQUN2QyxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWM7SUFDMUIsK0JBQStCO0lBQy9CLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEVBQUUsb0JBQW9CLENBQUM7SUFDNUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSwwQkFBMEIsQ0FBQztDQUNyRCxDQUFDO0FBRUYsSUFBSSxTQUFTLEdBQWtCLElBQUksQ0FBQztBQUVwQywrQ0FBK0M7QUFDL0MsTUFBTSxVQUFVLFdBQVcsQ0FBQyxDQUFTO0lBQ2pDLFNBQVMsR0FBRyxDQUFDLENBQUM7QUFDbEIsQ0FBQztBQUVELFNBQVMsUUFBUTtJQUNiLElBQUksU0FBUyxJQUFJLFVBQVUsQ0FBQyxTQUFTLENBQUM7UUFBRSxPQUFPLFNBQVMsQ0FBQztJQUN6RCxLQUFLLE1BQU0sQ0FBQyxJQUFJLGtCQUFrQixFQUFFLENB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