| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  | import * as fs from "fs" | 
					
						
							|  |  |  | import TiledFeatureSource from "../Logic/FeatureSource/TiledFeatureSource/TiledFeatureSource" | 
					
						
							|  |  |  | import StaticFeatureSource from "../Logic/FeatureSource/Sources/StaticFeatureSource" | 
					
						
							|  |  |  | import * as readline from "readline" | 
					
						
							|  |  |  | import ScriptUtils from "./ScriptUtils" | 
					
						
							| 
									
										
										
										
											2022-01-16 01:59:06 +01:00
										 |  |  | import { Utils } from "../Utils" | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-09 17:56:37 +01:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |  * This script slices a big newline-delimeted geojson file into tiled geojson | 
					
						
							| 
									
										
										
										
											2021-12-09 17:56:37 +01:00
										 |  |  |  * It was used to convert the CRAB-data into geojson tiles | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  | async function readFeaturesFromLineDelimitedJsonFile(inputFile: string): Promise<any[]> { | 
					
						
							|  |  |  |     const fileStream = fs.createReadStream(inputFile) | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  |     const rl = readline.createInterface({ | 
					
						
							|  |  |  |         input: fileStream, | 
					
						
							|  |  |  |         crlfDelay: Infinity, | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |     // Note: we use the crlfDelay option to recognize all instances of CR LF
 | 
					
						
							|  |  |  |     // ('\r\n') in input.txt as a single line break.
 | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  |     const allFeatures: any[] = [] | 
					
						
							|  |  |  |     // @ts-ignore
 | 
					
						
							|  |  |  |     for await (const line of rl) { | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |             allFeatures.push(JSON.parse(line)) | 
					
						
							|  |  |  |         } catch (e) { | 
					
						
							|  |  |  |             console.error("Could not parse", line) | 
					
						
							|  |  |  |             break | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (allFeatures.length % 10000 === 0) { | 
					
						
							|  |  |  |             ScriptUtils.erasableLog("Loaded ", allFeatures.length, "features up till now") | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  |     return allFeatures | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  | async function readGeojsonLineByLine(inputFile: string): Promise<any[]> { | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  |     const fileStream = fs.createReadStream(inputFile) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const rl = readline.createInterface({ | 
					
						
							|  |  |  |         input: fileStream, | 
					
						
							|  |  |  |         crlfDelay: Infinity, | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |     // Note: we use the crlfDelay option to recognize all instances of CR LF
 | 
					
						
							|  |  |  |     // ('\r\n') in input.txt as a single line break.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  |     const allFeatures: any[] = [] | 
					
						
							|  |  |  |     let featuresSeen = false | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  |     // @ts-ignore
 | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  |     for await (let line: string of rl) { | 
					
						
							|  |  |  |         if (!featuresSeen && line.startsWith('"features":')) { | 
					
						
							|  |  |  |             featuresSeen = true | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!featuresSeen) { | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (line.endsWith(",")) { | 
					
						
							|  |  |  |             line = line.substring(0, line.length - 1) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try { | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  |             allFeatures.push(JSON.parse(line)) | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  |         } catch (e) { | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  |             console.error("Could not parse", line) | 
					
						
							|  |  |  |             break | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  |         if (allFeatures.length % 10000 === 0) { | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  |             ScriptUtils.erasableLog("Loaded ", allFeatures.length, "features up till now") | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  |     return allFeatures | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function readFeaturesFromGeoJson(inputFile: string): Promise<any[]> { | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |         return JSON.parse(fs.readFileSync(inputFile, "UTF-8")).features | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |         // We retry, but with a line-by-line approach
 | 
					
						
							|  |  |  |         return await readGeojsonLineByLine(inputFile) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function main(args: string[]) { | 
					
						
							|  |  |  |     console.log("GeoJSON slicer") | 
					
						
							|  |  |  |     if (args.length < 3) { | 
					
						
							|  |  |  |         console.log("USAGE: <input-file.geojson> <target-zoom-level> <output-directory>") | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const inputFile = args[0] | 
					
						
							|  |  |  |     const zoomlevel = Number(args[1]) | 
					
						
							|  |  |  |     const outputDirectory = args[2] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!fs.existsSync(outputDirectory)) { | 
					
						
							|  |  |  |         fs.mkdirSync(outputDirectory) | 
					
						
							|  |  |  |         console.log("Directory created") | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     console.log("Using directory ", outputDirectory) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     let allFeatures: any[] | 
					
						
							|  |  |  |     if (inputFile.endsWith(".geojson")) { | 
					
						
							| 
									
										
										
										
											2022-01-16 01:59:06 +01:00
										 |  |  |         console.log("Detected geojson") | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  |         allFeatures = await readFeaturesFromGeoJson(inputFile) | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2022-01-16 01:59:06 +01:00
										 |  |  |         console.log("Loading as newline-delimited features") | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  |         allFeatures = await readFeaturesFromLineDelimitedJsonFile(inputFile) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-01-16 01:59:06 +01:00
										 |  |  |     allFeatures = Utils.NoNull(allFeatures) | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  |     console.log("Loaded all", allFeatures.length, "points") | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-27 20:19:45 +02:00
										 |  |  |     const keysToRemove = ["STRAATNMID", "GEMEENTE", "POSTCODE"] | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  |     for (const f of allFeatures) { | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |         if (f.properties === null) { | 
					
						
							| 
									
										
										
										
											2022-01-16 01:59:06 +01:00
										 |  |  |             console.log("Got a feature without properties!", f) | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  |         for (const keyToRm of keysToRemove) { | 
					
						
							|  |  |  |             delete f.properties[keyToRm] | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  |         delete f.bbox | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-06-05 02:24:14 +02:00
										 |  |  |     TiledFeatureSource.createHierarchy(StaticFeatureSource.fromGeojson(allFeatures), { | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  |         minZoomLevel: zoomlevel, | 
					
						
							|  |  |  |         maxZoomLevel: zoomlevel, | 
					
						
							|  |  |  |         maxFeatureCount: Number.MAX_VALUE, | 
					
						
							|  |  |  |         registerTile: (tile) => { | 
					
						
							|  |  |  |             const path = `${outputDirectory}/tile_${tile.z}_${tile.x}_${tile.y}.geojson` | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  |             const features = tile.features.data.map((ff) => ff.feature) | 
					
						
							|  |  |  |             features.forEach((f) => { | 
					
						
							|  |  |  |                 delete f.bbox | 
					
						
							|  |  |  |             }) | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  |             fs.writeFileSync( | 
					
						
							|  |  |  |                 path, | 
					
						
							|  |  |  |                 JSON.stringify( | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         type: "FeatureCollection", | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  |                         features: features, | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  |                     }, | 
					
						
							|  |  |  |                     null, | 
					
						
							|  |  |  |                     "  " | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  |             ) | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  |             ScriptUtils.erasableLog( | 
					
						
							|  |  |  |                 "Written ", | 
					
						
							|  |  |  |                 path, | 
					
						
							|  |  |  |                 "which has ", | 
					
						
							|  |  |  |                 tile.features.data.length, | 
					
						
							|  |  |  |                 "features" | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  |             ) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         }, | 
					
						
							|  |  |  |     }) | 
					
						
							| 
									
										
										
										
											2021-10-27 01:18:05 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | let args = [...process.argv] | 
					
						
							|  |  |  | args.splice(0, 2) | 
					
						
							|  |  |  | main(args).then((_) => { | 
					
						
							|  |  |  |     console.log("All done!") | 
					
						
							|  |  |  | }) |