gadm-ts/scripts/boundaries.ts
2026-03-21 17:06:05 +01:00

93 lines
3.2 KiB
TypeScript

import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import { getBoundaryFromGpkg } from '../src/gpkg-reader.js';
import { readFileSync, existsSync } from 'fs';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const continentData = JSON.parse(
readFileSync(join(__dirname, '../data/gadm_continent.json'), 'utf-8')
);
async function processCountry(country: string, level: number | undefined) {
if (level !== undefined) {
console.log(`Processing ${country} at level ${level}...`);
await doProcess(country, level);
} else {
console.log(`Processing ${country} for all levels (0-5)...`);
for (let l = 0; l <= 5; l++) {
await doProcess(country, l);
}
}
}
async function doProcess(country: string, level: number | undefined) {
const levelStr = level !== undefined ? level.toString() : 'auto';
const safeCountry = country.replace(/[^a-zA-Z0-9\.\-_]/g, '_').substring(0, 50);
const expectedFile = join(__dirname, '../cache/gadm', `boundary_${safeCountry}_${levelStr}.json`);
if (existsSync(expectedFile)) {
console.log(`⏭️ ${country} (L${level ?? 0}): Skipped, already cached.`);
return;
}
try {
const start = Date.now();
const res = await getBoundaryFromGpkg(country, level);
const duration = Date.now() - start;
if (res && res.features && res.features.length > 0) {
console.log(`${country} (L${level ?? 0}): Successfully cached in ${duration}ms (${res.features.length} features).`);
} else {
console.log(`${country} (L${level ?? 0}): No boundary found.`);
}
} catch (e: any) {
console.error(`${country} (L${level ?? 0}): Failed - ${e.message}`);
}
}
async function main() {
const argv = await yargs(hideBin(process.argv))
.option('country', {
type: 'string',
description: 'ISO 3 code of the country (e.g. DEU, ESP), or "all" for all countries',
demandOption: true,
alias: 'c'
})
.option('level', {
type: 'number',
description: 'The administrative level to calculate. Omit for the outer boundary.',
alias: 'l'
})
.help()
.argv;
const country = argv.country as string;
const level = argv.level as number | undefined;
if (country.toLowerCase() === 'all') {
// Collect all countries
const allCountries = new Set<string>();
for (const codes of Object.values(continentData)) {
for (const code of codes as string[]) {
allCountries.add(code);
}
}
console.log(`Starting precalculation for ${allCountries.size} countries at level ${level ?? 'outer'}...`);
let current = 1;
for (const code of allCountries) {
console.log(`\n[${current}/${allCountries.size}]`);
await processCountry(code, level);
current++;
}
console.log('\n🎉 Finished precalculating all countries.');
} else {
await processCountry(country.toUpperCase(), level);
}
}
main().catch(console.error);