UNPKG

carthorse

Version:

A geospatial trail data processing pipeline for building 3D trail databases with elevation data

143 lines β€’ 6.95 kB
#!/usr/bin/env ts-node "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const pg_1 = require("pg"); const bbox_subdivision_1 = require("../utils/bbox-subdivision"); const geometry_preprocessing_1 = require("../utils/sql/geometry-preprocessing"); async function main() { const args = process.argv.slice(2); if (args.length < 1) { console.error('Usage: npx ts-node src/cli/subdivide-region.ts <region> [maxTrailsPerChunk] [minChunkSize]'); process.exit(1); } const region = args[0]; const maxTrailsPerChunk = args[1] ? parseInt(args[1]) : 500; // Smaller chunks for testing const minChunkSize = args[2] ? parseInt(args[2]) : 50; console.log(`πŸ”§ Testing subdivision for region: ${region}`); console.log(`πŸ“Š Max trails per chunk: ${maxTrailsPerChunk}`); console.log(`πŸ“Š Min trails per chunk: ${minChunkSize}`); // Connect to database const pool = new pg_1.Pool({ host: process.env.PGHOST || 'localhost', port: parseInt(process.env.PGPORT || '5432'), database: process.env.PGDATABASE || 'trail_master_db', user: process.env.PGUSER || 'postgres', password: process.env.PGPASSWORD, }); try { const subdivider = (0, bbox_subdivision_1.createBboxSubdivider)(pool); const geometryPreprocessor = (0, geometry_preprocessing_1.createGeometryPreprocessor)(pool); // Step 1: Subdivide the region console.log('\nπŸ—ΊοΈ Step 1: Subdividing region...'); const subdivisions = await subdivider.subdivideRegion({ region, maxTrailsPerChunk, minChunkSize, overlapPercentage: 0.1 }); if (subdivisions.length === 0) { console.log('❌ No subdivisions created'); return; } console.log(`\nβœ… Created ${subdivisions.length} subdivisions`); // Step 2: Process each subdivision console.log('\nπŸ”§ Step 2: Processing subdivisions...'); const results = []; for (const subdivision of subdivisions) { const stagingSchema = `staging_${subdivision.id.replace(/[^a-zA-Z0-9]/g, '_')}`; console.log(`\nπŸ“¦ Processing subdivision: ${subdivision.name}`); // Process the subdivision const processResult = await subdivider.processSubdivision(subdivision, stagingSchema, region); if (processResult.success && processResult.trailCount > 0) { console.log(`πŸ”§ Running geometry preprocessing on ${processResult.trailCount} trails...`); try { const preprocessResult = await geometryPreprocessor.preprocessTrailGeometries({ schemaName: stagingSchema, tableName: 'trails', region: subdivision.name, maxPasses: 3, // Fewer passes for testing minLengthMeters: 1.0, tolerance: 0.00001 }); if (preprocessResult.success) { console.log(`βœ… Subdivision ${subdivision.name}: Preprocessing successful`); console.log(` - Initial: ${preprocessResult.initialCount} trails`); console.log(` - Final: ${preprocessResult.finalCount} trails`); console.log(` - Dropped: ${preprocessResult.droppedCount} trails`); console.log(` - Passes: ${preprocessResult.passes}`); } else { console.log(`❌ Subdivision ${subdivision.name}: Preprocessing failed`); console.log(` - Errors: ${preprocessResult.errors.join(', ')}`); } results.push({ subdivision: subdivision.name, success: preprocessResult.success, initialCount: preprocessResult.initialCount, finalCount: preprocessResult.finalCount, droppedCount: preprocessResult.droppedCount, errors: preprocessResult.errors }); } catch (error) { console.error(`❌ Error preprocessing subdivision ${subdivision.name}:`, error); results.push({ subdivision: subdivision.name, success: false, initialCount: processResult.trailCount, finalCount: 0, droppedCount: processResult.trailCount, errors: [error instanceof Error ? error.message : String(error)] }); } } else { console.log(`⚠️ Subdivision ${subdivision.name}: No trails or processing failed`); results.push({ subdivision: subdivision.name, success: false, initialCount: 0, finalCount: 0, droppedCount: 0, errors: processResult.errors }); } } // Step 3: Summary console.log('\nπŸ“Š Step 3: Processing Summary'); console.log('='.repeat(50)); const successful = results.filter(r => r.success); const failed = results.filter(r => !r.success); console.log(`βœ… Successful subdivisions: ${successful.length}/${results.length}`); console.log(`❌ Failed subdivisions: ${failed.length}/${results.length}`); if (successful.length > 0) { const totalInitial = successful.reduce((sum, r) => sum + r.initialCount, 0); const totalFinal = successful.reduce((sum, r) => sum + r.finalCount, 0); const totalDropped = successful.reduce((sum, r) => sum + r.droppedCount, 0); console.log(`πŸ“Š Total trails processed: ${totalInitial}`); console.log(`πŸ“Š Total trails after preprocessing: ${totalFinal}`); console.log(`πŸ“Š Total trails dropped: ${totalDropped}`); console.log(`πŸ“Š Drop rate: ${((totalDropped / totalInitial) * 100).toFixed(1)}%`); } if (failed.length > 0) { console.log('\n❌ Failed subdivisions:'); failed.forEach(r => { console.log(` - ${r.subdivision}: ${r.errors.join(', ')}`); }); } // Step 4: Cleanup console.log('\n🧹 Step 4: Cleaning up...'); await subdivider.cleanupSubdivisions(subdivisions); } catch (error) { console.error('❌ Error:', error); process.exit(1); } finally { await pool.end(); } } if (require.main === module) { main().catch(console.error); } //# sourceMappingURL=subdivide-region.js.map