Files
geograsim/App/sims/logistik/scripts/rebuild-roadnet-clean.py
T
Adminator 79ac9dad84 Atlas: Deploy-Buendel vor Staustufen-Sprint
- Logistik: Musik-Player Playlist-Modus (5 Gruppen, 20 Tracks)
- Heli: End-Screen auf .ggs-endscreen, Mission-Bilder, Voice-Lines, Briefing-Audio
- Logistik: Layout-Tausch Auftraege+Fahrzeuge links, Karte rechts
- Logistik: Tier-1-Staedte ausgebaut, Auto-Timescale-Badge
- Logistik: Roadnet/Railnet Dijkstra-Routing, Balance-Updates
- Atlas: 5 Atlas-Inbox-Nachrichten (Cards-Pattern, DALL-E-Key, Musik-Playlists)
- Status-Updates Heli + Logistik

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 01:05:13 +02:00

124 lines
4.4 KiB
Python

#!/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()