#!/usr/bin/env python3 """ Erweitert lg-roadnet.json um innsbruck und graz als Knoten. Neue Kanten: - muenchen-innsbruck (A8/A93, ~170 km) - innsbruck-salzburg (A12/A10 ueber Loferer Hochtal, ~190 km) - innsbruck-mailand (A13+A22 Brenner, ~390 km) - wien-graz (A2 Sued, ~200 km) - salzburg-graz (A10+A9 via Tauerntunnel+Liezen, ~280 km) Polylines per OSRM holen + Douglas-Peucker mit ~110 m Toleranz. """ import json import math import ssl import time import urllib.request from pathlib import Path ROADNET = Path(__file__).resolve().parents[3] / "assets" / "data" / "lg-roadnet.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_dist(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) max_d, idx = 0.0, 0 for i in range(1, len(points) - 1): d = perp_dist(points[i], points[0], points[-1]) if d > max_d: max_d, idx = d, i if max_d <= 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(ROADNET.read_text(encoding="utf-8")) locs = {l["id"]: l for l in json.loads(LOCATIONS.read_text(encoding="utf-8"))} # Neue Knoten existing_ids = {n["id"] for n in net["nodes"]} for nid in ("innsbruck", "graz"): if nid in existing_ids: continue loc = locs[nid] net["nodes"].append({"id": nid, "locationId": nid, "name": loc["name"]}) # Neue Kanten NEW_EDGES = [ ("muenchen-innsbruck", "muenchen", "innsbruck", 170, "A8/A93"), ("innsbruck-salzburg", "innsbruck", "salzburg", 190, "A12/A93/A10"), ("innsbruck-mailand", "innsbruck", "mailand", 390, "A13/A22 Brenner"), ("wien-graz", "wien", "graz", 200, "A2 Sued"), ("salzburg-graz", "salzburg", "graz", 280, "A10/A9 Tauern+Liezen"), ] existing_edge_ids = {e["id"] for e in net["edges"]} for eid, fnode, tnode, dist, code in NEW_EDGES: if eid in existing_edge_ids: print(f"skip {eid} (schon da)") continue fl = locs[net["nodes"][[n["id"] for n in net["nodes"]].index(fnode)]["locationId"]] tl = locs[net["nodes"][[n["id"] for n in net["nodes"]].index(tnode)]["locationId"]] start = [fl["lat"], fl["lon"]] end = [tl["lat"], tl["lon"]] print(f"-> {eid}: OSRM [{start}] -> [{end}] ...", flush=True) try: poly, osrm_km = fetch([start, end]) poly = rdp(poly, TOLERANCE_DEG) net["edges"].append({ "id": eid, "from": fnode, "to": tnode, "distanceKm": dist, "routeCode": code, "polyline": poly, "distanceKmOsrm": round(osrm_km, 1), }) print(f" {osrm_km:.0f} km real, {len(poly)} Punkte") except Exception as e: print(f" FEHLER: {e}") time.sleep(1.1) ROADNET.write_text( json.dumps(net, ensure_ascii=False, separators=(",", ":")), encoding="utf-8", ) sz = ROADNET.stat().st_size / 1024 print(f"\nFertig: {len(net['edges'])} Kanten, {sz:.1f} KB") if __name__ == "__main__": main()