101 lines
3.4 KiB
Python
101 lines
3.4 KiB
Python
#!/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()
|