Frankreich, Niederlande, Belgien als weitere Quellen (noch im Test)
- Quellen fr (SNCF), nl (OVapi), be (GTFS.be), Kacheln für alle 5 Länder - Landesgrenzen für 5 Länder (borders.json), Gitter-Cache für die Prüfung - Echtzeit-Abgleich auch über Haltestellen-ID (FR, NL), über den Bahnhof bei Gleiswechsel - SNCF: Gattung aus der Trip-ID, Zugnummer aus dem Headsign; NL-Linien gekürzt - calendar.txt optional (SNCF hat nur calendar_dates) - OSM je Land zugeschnitten vor pfaedle; beim Zusammenführen je Objekt nur die neueste Version (time-filter) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X48pE4bzjHej8w9HyZXCjb
This commit is contained in:
+51
-11
@@ -1,12 +1,22 @@
|
||||
"""Landesgrenze der Schweiz (aus OpenStreetMap, auf ~400 m vereinfacht, mit den Exklaven Büsingen
|
||||
und Campione als Löcher). Damit zeigt jeder Fahrplan seine Züge nur im eigenen Land, sonst wären
|
||||
grenzüberschreitende Züge doppelt auf der Karte."""
|
||||
"""Landesgrenzen, damit jeder Fahrplan seine Züge nur im eigenen Land zeigt – sonst wären
|
||||
grenzüberschreitende Züge doppelt auf der Karte (z. B. ICE Basel–Frankfurt in CH- und DE-Daten).
|
||||
|
||||
Schweiz aus OpenStreetMap (~400 m genau, mit Büsingen und Campione als Löcher), die übrigen
|
||||
Länder aus Natural Earth 1:10 Mio. (gemeinfrei), auf ~400 m vereinfacht."""
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
_B = json.loads((Path(__file__).with_name("ch_border.json")).read_text())
|
||||
_BBOX = (min(x for x, _ in _B["outer"]), min(y for _, y in _B["outer"]),
|
||||
max(x for x, _ in _B["outer"]), max(y for _, y in _B["outer"]))
|
||||
_RAW = json.loads((Path(__file__).with_name("borders.json")).read_text())
|
||||
ORDER = ["ch", "de", "fr", "be", "nl"] # Schweiz zuerst: genauere Grenze, gewinnt bei Überlappung
|
||||
CELL = 0.01 # ~1 km; im Grenzbereich wird je Zelle einmal gerechnet und gemerkt
|
||||
|
||||
|
||||
def _bbox(ring):
|
||||
xs, ys = [p[0] for p in ring], [p[1] for p in ring]
|
||||
return min(xs), min(ys), max(xs), max(ys)
|
||||
|
||||
|
||||
_POLYS = {code: [(_bbox(p[0]), p) for p in _RAW[code]] for code in ORDER if code in _RAW}
|
||||
|
||||
|
||||
def _in_ring(x: float, y: float, ring) -> bool:
|
||||
@@ -17,11 +27,41 @@ def _in_ring(x: float, y: float, ring) -> bool:
|
||||
return inside
|
||||
|
||||
|
||||
def _country(x: float, y: float) -> str | None:
|
||||
for code, polys in _POLYS.items():
|
||||
for (x0, y0, x1, y1), (outer, *holes) in polys:
|
||||
if x0 <= x <= x1 and y0 <= y <= y1 and _in_ring(x, y, outer) \
|
||||
and not any(_in_ring(x, y, h) for h in holes):
|
||||
return code
|
||||
return None
|
||||
|
||||
|
||||
_cache: dict = {}
|
||||
|
||||
|
||||
def country(lon: float, lat: float) -> str | None:
|
||||
"""Ländercode (ch, de, fr, be, nl) oder None für alle anderen Länder."""
|
||||
key = (round(lon / CELL), round(lat / CELL))
|
||||
if key not in _cache:
|
||||
if len(_cache) > 500_000:
|
||||
_cache.clear()
|
||||
_cache[key] = _country(key[0] * CELL, key[1] * CELL)
|
||||
return _cache[key]
|
||||
|
||||
|
||||
def bbox(code: str, margin: float = 0.6) -> str:
|
||||
"""Ausschnitt eines Landes (+ ~50 km Rand) als "x0,y0,x1,y1" für osmium."""
|
||||
boxes = [b for b, _ in _POLYS[code]]
|
||||
return ",".join(f"{v:.2f}" for v in (min(b[0] for b in boxes) - margin, min(b[1] for b in boxes) - margin,
|
||||
max(b[2] for b in boxes) + margin, max(b[3] for b in boxes) + margin))
|
||||
|
||||
|
||||
def in_switzerland(lon: float, lat: float) -> bool:
|
||||
if not (_BBOX[0] <= lon <= _BBOX[2] and _BBOX[1] <= lat <= _BBOX[3]):
|
||||
return False
|
||||
return _in_ring(lon, lat, _B["outer"]) and not any(_in_ring(lon, lat, h) for h in _B["holes"])
|
||||
return _country(lon, lat) == "ch"
|
||||
|
||||
|
||||
# Welche Züge ein Fahrplan zeigen darf, wenn mehrere Quellen aktiv sind
|
||||
SHOW = {"ch": in_switzerland, "de": lambda lon, lat: not in_switzerland(lon, lat)}
|
||||
def shows(source: str, enabled, lon: float, lat: float) -> bool:
|
||||
"""Zeigt diese Quelle den Zug an dieser Stelle? Im eigenen Land ja, in einem Land mit eigenem
|
||||
aktivem Fahrplan nein (dort zeigt ihn dieser). Überall sonst ja."""
|
||||
c = country(lon, lat)
|
||||
return c is None or c == source or c not in enabled
|
||||
|
||||
Reference in New Issue
Block a user