diff --git a/doc/csv-export.md b/doc/csv-export.md index e87e729..0cfe90b 100644 --- a/doc/csv-export.md +++ b/doc/csv-export.md @@ -275,12 +275,18 @@ nah beieinander, auch wenn sie nicht exakt uebereinstimmen. Zusaetzlich zur `"Nachbarn"`-Spalte (Vorgaenger/Nachfolger je Zeile) traegt `write_separatorliste_merkmale` (`lib/export_csv.py`) jeder VF_n/GF_n-Zeile die eigene Spalte `"TrackIds"` (`item["trackids"]`, Top-Level-Feld wie -`"nachbarn"` — KEIN Merkmal) ein: die TeileIds ihrer SEP-Eintraege in -Baureihenfolge, kommagetrennt (z.B. `"0052, 0053, 0054"`). Quelle ist die -rohe `sepliste` des Items (nicht `sep_kette`, dessen dict-Reihenfolge nicht -garantiert ist). Muss NACH `map_separator_kette_items` laufen, weil erst -dann jeder sepliste-SEP-Schluessel auf sein reales Separator-Item (TeileId) -aufgeloest ist. +`"nachbarn"` — KEIN Merkmal) ein: die TeileIds von AS-Ende, Separatoren UND +ES-Ende in Baureihenfolge, kommagetrennt (z.B. `"0051, 0052, 0053, 0054, +0055"` fuer AS, zwei SEP, ES). AS/ES zaehlen mit, weil sie beim Kreisel +(siehe unten) ebenfalls Teil von dessen `TrackIds` sind — ohne sie fehlten +hier die Kettenenden. Quelle ist die rohe `sepliste` des Items (nicht +`sep_kette`, dessen dict-Reihenfolge nicht garantiert ist). Muss NACH +`map_separator_kette_items`/`build_strecke_schleus_items` laufen, weil erst +dann jeder sepliste-Schluessel (AS/SEP/ES) auf sein reales Item (TeileId) +aufgeloest ist. Beruehrt ein Streckenende geometrisch KEINEN Kreisel, +entsteht dort keine AS/ES-Zeile (`build_strecke_schleus_items`) und damit +auch keine TeileId — dieses Ende fehlt dann in `TrackIds` (kein Fehler, +sondern Folge der fehlenden Kollision). `write_kreisel_separatorliste_merkmale` ueberträgt dasselbe Prinzip auf echte Kreisel (`"ILS 2.0 Kreisel"`): Quelle ist hier NICHT die sepliste diff --git a/lib/export_csv.py b/lib/export_csv.py index 9ace82b..eb68361 100644 --- a/lib/export_csv.py +++ b/lib/export_csv.py @@ -852,21 +852,27 @@ def resolve_umlauf_und_sepliste_nachbarn(items, kreisel_umlauf, sep_kette, def write_separatorliste_merkmale(items, sep_kette_by_key, dbg=None): """Traegt in jede Strecke (VF_n/GF_n mit "sepliste") die eigene CSV-Spalte - "TrackIds" (item["trackids"]) ein: die TeileIds ihrer Separatoren in - Baureihenfolge, kommagetrennt (analog zur "Nachbarn"-Spalte, ebenfalls - ein Top-Level-Item-Feld statt eines Merkmals), z.B. "0052, 0053, 0054". + "TrackIds" (item["trackids"]) ein: die TeileIds von AS-Ende, Separatoren + und ES-Ende in Baureihenfolge, kommagetrennt (analog zur "Nachbarn"- + Spalte, ebenfalls ein Top-Level-Item-Feld statt eines Merkmals), z.B. + "0051, 0052, 0053, 0054, 0055" (AS ... SEP ... ES). Quelle ist die rohe "sepliste" des Items (AS/SEP/ES mit x/y, bereits in Baureihenfolge - siehe compute_sep_kette) statt sep_kette selbst: dessen dict-Reihenfolge ist nicht garantiert, die sepliste-Liste dagegen schon. - Nur "SEP"-Eintraege zaehlen als Separator, AS/ES sind die Schleus-Enden - der Kette (siehe build_strecke_schleus_items), keine Separatoren. + AS/ES zaehlen HIER mit (anders als beim "Separatorlist"-Merkmal frueher) - + sie sind die Schleus-Enden der Kette (siehe build_strecke_schleus_items) + und bekommen dort eine eigene TeileId ("ILS Ausschleuselement"/"ILS + Einschleuselement"), analog zu den AS/ES-Enden, die beim Kreisel bereits + ueber compute_kreisel_umlauf in dessen TrackIds auftauchen - ohne sie + fehlten hier die Kettenenden, obwohl sie beim Kreisel schon drin sind. Der eigentliche Separator wurde bereits von map_separator_kette_items ueber die sepliste-Koordinate (x/y) auf sein reales Separator-Item (TeileId) - aufgeloest und unter demselben "#"-Schluessel in - sep_kette_by_key eingetragen - hier wird dieser Schluessel nur noch je - Strecke eingesammelt. Muss darum NACH map_separator_kette_items laufen. + aufgeloest, AS/ES von build_strecke_schleus_items - beide unter demselben + "#"-Schluessel in sep_kette_by_key eingetragen; hier + wird dieser Schluessel nur noch je Strecke eingesammelt. Muss darum NACH + map_separator_kette_items/build_strecke_schleus_items laufen. """ for item in items: if item.get("teileart", "") not in GF_VF_TEILEARTEN: @@ -875,20 +881,17 @@ def write_separatorliste_merkmale(items, sep_kette_by_key, dbg=None): if not sepliste: continue sid = item.get("teileid", "") - separator_ids = [] + track_ids = [] for entry in sepliste: - if entry.get("typ") != "SEP": - continue key = f"{sid}#{entry.get('lfdnr')}" sep_item = sep_kette_by_key.get(key) if sep_item is None: if dbg: - dbg(f" TrackIds {key}: kein aufgeloestes Separator-Item " - f"- uebersprungen") + dbg(f" TrackIds {key}: kein aufgeloestes Item - uebersprungen") continue - separator_ids.append(sep_item.get("teileid", "")) - if separator_ids: - item["trackids"] = ", ".join(separator_ids) + track_ids.append(sep_item.get("teileid", "")) + if track_ids: + item["trackids"] = ", ".join(track_ids) def write_kreisel_separatorliste_merkmale(items, kreisel_umlauf, sep_kette_by_key, diff --git a/tests/test_export_kreisel_umlauf.py b/tests/test_export_kreisel_umlauf.py index b8f6d73..fa24352 100644 --- a/tests/test_export_kreisel_umlauf.py +++ b/tests/test_export_kreisel_umlauf.py @@ -26,6 +26,7 @@ from export_csv import ( # noqa: E402 map_separator_kette_items, resolve_umlauf_und_sepliste_nachbarn, write_kreisel_separatorliste_merkmale, + write_separatorliste_merkmale, ) DURCHMESSER_MM = 800.0 @@ -293,6 +294,29 @@ class TestSeplisteNachbarnAufgeloest: f'SEP-Zeile hat Nachbarn {sep_nachbarn!r}, erwartet ' f'{{{as_item["teileid"]!r}, {es_item["teileid"]!r}}}') + def test_trackids_enthaelt_as_sep_und_es(self): + """Die "TrackIds"-Spalte einer Strecke muss AS- UND ES-Ende mit + enthalten, nicht nur die dazwischenliegenden Separatoren - sonst + fehlen genau die Kettenenden, die beim Kreisel (compute_kreisel_ + umlauf) bereits Teil von dessen TrackIds sind.""" + from export_neighbors import compute_sep_kette + items = self._sepliste_kette() + sep_kette = compute_sep_kette(items) + sep_kette_by_key = {} + build_strecke_schleus_items( + items, None, 100, sep_kette=sep_kette, + sep_kette_by_key=sep_kette_by_key) + map_separator_kette_items( + items, sep_kette, sep_kette_by_key=sep_kette_by_key) + write_separatorliste_merkmale(items, sep_kette_by_key) + + strecke = next(it for it in items if it.get("teileid") == "0010") + as_id = sep_kette_by_key["0010#1"]["teileid"] + sep_id = sep_kette_by_key["0010#2"]["teileid"] + es_id = sep_kette_by_key["0010#3"]["teileid"] + assert sep_id == "0055", "sepliste-SEP nicht auf Proxy-Separator gemappt" + assert strecke["trackids"] == f"{as_id}, {sep_id}, {es_id}" + class TestKreiselUmlaufStartetBeiNullGrad: """compute_kreisel_umlauf muss die Umlauf-Liste je Kreisel bei Winkel