#!/usr/bin/env python3 """ Process and simplify Dutch municipality GeoJSON for web use. Takes the raw PDOK data and creates a simplified version suitable for web display. Uses Shapely for proper Douglas-Peucker geometry simplification. Input: frontend/public/data/netherlands_municipalities.geojson (raw from PDOK) Output: frontend/public/data/netherlands_municipalities_simplified.geojson """ import json from pathlib import Path from shapely.geometry import shape, mapping from shapely.validation import make_valid # Paths DATA_DIR = Path(__file__).parent.parent / "frontend" / "public" / "data" INPUT_FILE = DATA_DIR / "netherlands_municipalities.geojson" OUTPUT_FILE = DATA_DIR / "netherlands_municipalities_simplified.geojson" # Simplification tolerance in degrees # 0.001 degrees ≈ 111 meters (good for web display at typical zoom levels) SIMPLIFY_TOLERANCE = 0.001 def simplify_feature(feature, tolerance=SIMPLIFY_TOLERANCE): """Simplify a GeoJSON feature using Shapely.""" try: geom = shape(feature["geometry"]) # Make geometry valid if needed if not geom.is_valid: geom = make_valid(geom) # Simplify using Douglas-Peucker algorithm simplified = geom.simplify(tolerance, preserve_topology=True) # Ensure the result is valid if not simplified.is_valid: simplified = make_valid(simplified) # Skip if geometry becomes too small/empty if simplified.is_empty: return None return { "type": "Feature", "properties": feature["properties"], "geometry": mapping(simplified) } except Exception as e: print(f" Warning: Error simplifying {feature['properties'].get('naam', 'unknown')}: {e}") return feature # Return original if simplification fails def main(): print(f"Loading {INPUT_FILE}...") with open(INPUT_FILE, "r", encoding="utf-8") as f: data = json.load(f) print(f"Loaded {len(data['features'])} municipalities") # Simplify each feature print(f"Simplifying geometries (tolerance: {SIMPLIFY_TOLERANCE} degrees ≈ {SIMPLIFY_TOLERANCE * 111000:.0f}m)...") simplified_features = [] for i, feature in enumerate(data["features"]): if (i + 1) % 50 == 0: print(f" Processed {i + 1}/{len(data['features'])}...") simplified = simplify_feature(feature) if simplified: simplified_features.append(simplified) print(f"Simplified to {len(simplified_features)} features") # Create output GeoJSON output = { "type": "FeatureCollection", "name": "netherlands_municipalities_simplified", "features": simplified_features } # Write with minimal whitespace for smaller file print(f"Writing to {OUTPUT_FILE}...") with open(OUTPUT_FILE, "w", encoding="utf-8") as f: json.dump(output, f, ensure_ascii=False, separators=(",", ":")) # Compare sizes input_size = INPUT_FILE.stat().st_size / (1024 * 1024) output_size = OUTPUT_FILE.stat().st_size / (1024 * 1024) reduction = (1 - output_size / input_size) * 100 print(f"\nDone!") print(f" Input: {input_size:.2f} MB") print(f" Output: {output_size:.2f} MB") print(f" Reduction: {reduction:.1f}%") if __name__ == "__main__": main()