#!/usr/bin/env python3 """ Baut die Polylines in lg-roadnet.json neu — diesmal OHNE Zwischen- wegpunkte. Grund: hand-kuratierte Zwischenpunkte lagen oft auf Stadt- Koordinaten (Linz, Wels, Amstetten). OSRM snappt solche Punkte auf die naechste Strasse = meist Innenstadt-Strasse, nicht Autobahn, und routet entsprechend hin und zurueck. Das erzeugt die sichtbaren Zacken. Loesung: nur [start, ende] an OSRM schicken. OSRM waehlt automatisch die zeitkuerzeste Route (= Autobahn zwischen Grossstaedten). Fuer Berlin- Kopenhagen behalten wir Rostock als Via, da OSRM die Faehre nicht kennt und sonst die Ostsee umrundet. Nach dem OSRM-Fetch direkt Douglas-Peucker-Vereinfachung (~110 m). """ 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 perpendicular_distance(pt, a, b): dx = b[0] - a[0] dy = b[1] - a[1] if dx == 0 and dy == 0: return math.hypot(pt[0] - a[0], pt[1] - a[1]) t = ((pt[0] - a[0]) * dx + (pt[1] - a[1]) * dy) / (dx * dx + dy * dy) t = max(0.0, min(1.0, t)) return math.hypot(pt[0] - (a[0] + t * dx), pt[1] - (a[1] + t * dy)) def rdp(points, epsilon): if len(points) < 3: return list(points) max_d = 0.0 idx = 0 for i in range(1, len(points) - 1): d = perpendicular_distance(points[i], points[0], points[-1]) if d > max_d: max_d, idx = d, i if max_d <= epsilon: return [points[0], points[-1]] left = rdp(points[:idx + 1], epsilon) right = rdp(points[idx:], epsilon) return left[:-1] + right def fetch_osrm(waypoints): coords = ";".join(f"{w[1]},{w[0]}" for w in waypoints) url = OSRM.format(coords=coords) with urllib.request.urlopen(url, timeout=30, context=SSL_CTX) as resp: data = json.load(resp) 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"))} nodes = {n["id"]: n for n in net["nodes"]} # Sonderfall Berlin-Kopenhagen (Faehre) — wird separat behandelt FERRY_EDGE = "berlin-kopenhagen" for idx, edge in enumerate(net["edges"], 1): name = edge["id"] from_n = nodes[edge["from"]] to_n = nodes[edge["to"]] from_l = locs[from_n["locationId"]] to_l = locs[to_n["locationId"]] start = [from_l["lat"], from_l["lon"]] end = [to_l["lat"], to_l["lon"]] print(f"[{idx}/{len(net['edges'])}] {name}: ", end="", flush=True) try: if name == FERRY_EDGE: # Berlin -> Rostock (Land), Rostock-Gedser (Faehre direkt), # Gedser -> Kopenhagen (Land). Distanz = Land-Summen + 48 km Faehre. rostock = [54.09, 12.14] gedser = [54.58, 11.93] poly1, d1 = fetch_osrm([start, rostock]) time.sleep(1.1) poly3, d3 = fetch_osrm([gedser, end]) ferry_poly = [rostock, [54.33, 12.03], gedser] full = poly1 + ferry_poly[1:] + poly3[1:] total = d1 + 48 + d3 print(f"Faehre-Route {d1:.0f}+48+{d3:.0f}={total:.0f} km", end="") else: full, total = fetch_osrm([start, end]) print(f"OSRM-Route {total:.0f} km", end="") # Vereinfachen simplified = rdp(full, TOLERANCE_DEG) edge["polyline"] = simplified edge["distanceKmOsrm"] = round(total, 1) print(f" -> {len(simplified)} Punkte") except Exception as e: print(f" FEHLER: {e}") continue time.sleep(1.1) ROADNET.write_text( json.dumps(net, ensure_ascii=False, separators=(",", ":")), encoding="utf-8", ) size = ROADNET.stat().st_size / 1024 print(f"\nFertig: {size:.1f} KB") if __name__ == "__main__": main()