#!/usr/bin/env python3 """ Reichert lg-railnet.json mit OSRM-Polylines an. Nutzt das Auto-Profil als Approximation fuer Bahnstrecken — die echten Bahnkorridore folgen oft den Autobahnen (Wien-Muenchen via Salzburg, Hamburg-Rotterdam via Bremen- Osnabrueck etc.), das ist auf Europa-Zoom visuell sauberer als Luftlinie. Aufruf: python App/sims/logistik/scripts/enrich-railnet-osrm.py """ import json import math import ssl import time import urllib.request from pathlib import Path RAILNET = Path(__file__).resolve().parents[3] / "assets" / "data" / "lg-railnet.json" LOCATIONS = Path(__file__).resolve().parents[3] / "assets" / "data" / "lg-locations.json" TOLERANCE_DEG = 0.001 SSL_CTX = ssl.create_default_context() SSL_CTX.check_hostname = False SSL_CTX.verify_mode = ssl.CERT_NONE OSRM = "https://router.project-osrm.org/route/v1/driving/{coords}?overview=full&geometries=geojson" def perp(pt, a, b): dx, dy = b[0]-a[0], b[1]-a[1] if dx == 0 and dy == 0: return math.hypot(pt[0]-a[0], pt[1]-a[1]) t = max(0.0, min(1.0, ((pt[0]-a[0])*dx + (pt[1]-a[1])*dy)/(dx*dx+dy*dy))) return math.hypot(pt[0]-(a[0]+t*dx), pt[1]-(a[1]+t*dy)) def rdp(points, eps): if len(points) < 3: return list(points) md, idx = 0.0, 0 for i in range(1, len(points)-1): d = perp(points[i], points[0], points[-1]) if d > md: md, idx = d, i if md <= eps: return [points[0], points[-1]] return rdp(points[:idx+1], eps)[:-1] + rdp(points[idx:], eps) def fetch(waypoints): coords = ";".join(f"{w[1]},{w[0]}" for w in waypoints) with urllib.request.urlopen(OSRM.format(coords=coords), timeout=30, context=SSL_CTX) as r: data = json.load(r) route = data["routes"][0] poly = [[round(c[1], 5), round(c[0], 5)] for c in route["geometry"]["coordinates"]] return poly, route["distance"]/1000.0 def main(): net = json.loads(RAILNET.read_text(encoding="utf-8")) locs = {l["id"]: l for l in json.loads(LOCATIONS.read_text(encoding="utf-8"))} nodes = {n["id"]: n for n in net["nodes"]} for i, edge in enumerate(net["edges"], 1): fl = locs[nodes[edge["from"]]["locationId"]] tl = locs[nodes[edge["to"]]["locationId"]] start = [fl["lat"], fl["lon"]] end = [tl["lat"], tl["lon"]] print(f"[{i}/{len(net['edges'])}] {edge['id']}: ", end="", flush=True) try: poly, km = fetch([start, end]) poly = rdp(poly, TOLERANCE_DEG) edge["polyline"] = poly edge["distanceKmOsrm"] = round(km, 1) print(f"{km:.0f} km, {len(poly)} Punkte") except Exception as e: print(f"FEHLER: {e}") time.sleep(1.1) RAILNET.write_text( json.dumps(net, ensure_ascii=False, separators=(",", ":")), encoding="utf-8", ) sz = RAILNET.stat().st_size / 1024 print(f"\nFertig: {sz:.1f} KB") if __name__ == "__main__": main()