diff --git a/lib/tro_flow.py b/lib/tro_flow.py index 3b592e3..617e2e1 100644 --- a/lib/tro_flow.py +++ b/lib/tro_flow.py @@ -32,28 +32,42 @@ doc/500573_Mubea/TRO_Identifikation_500573.md: Kreisel-Bahn -> 1Sep Zwei Ausnahmen stufen einen Separator auf einer "Strecke" trotzdem als 1Sep -statt Vario ein (Review 2026-09-23, HundM05): +statt Vario ein (Review 2026-09-23/25, HundM05): -1. Letzter Separator vor dem Wiedereinschleusen auf die Kreisel-Bahn (in - TrackIds-Reihenfolge) - reiner Vereinzeler ohne eigene VarioDrive-Strecke, - die Kreisel-Bahn treibt ab dort selbst an. Gilt fuer jede Separatoranzahl - >= 2 (z. B. VF_3: erster Separator 0041 = Vario, letzter 0040 = 1Sep); bei - genau einem Separator bleibt dieser Vario (einziger Antriebspunkt). +1. Alternierendes Muster vom Wiedereinschleusen auf die Kreisel-Bahn + rueckwaerts (in TrackIds-Reihenfolge, nur echte Kettenmitglieder - siehe + "eigenstaendige Vereinzeler" unten): der letzte Separator vor dem + Wiedereinschleusen ist ein reiner Vereinzeler ohne eigene VarioDrive- + Strecke (die Kreisel-Bahn treibt ab dort selbst an), der vorletzte wieder + ein eigener Vario-Antriebspunkt, der drittletzte wieder 1Sep usw. - eine + Streckengruppe ist baulich meist eine alternierende VF/GF-Kette + (angetriebener Abschnitt, Vereinzeler, unbetriebener Abschnitt, + Vereinzeler, ...), nicht nur am Ende. Gilt fuer jede Separatoranzahl >= 2 + (z. B. VF_3: erster Separator 0041 = Vario, letzter 0040 = 1Sep); bei + genau einem Separator bleibt dieser Vario (einziger Antriebspunkt der + Strecke). 2. Eine "Strecke" (Streckengruppe) ist selbst oft eine gemischte VF/GF-Kette: sie enthaelt sowohl angetriebene (VF, jede Antriebfahrtrichtung - horizontal, Auf oder Ab zaehlt gleichermassen als VF) als auch unbetriebene Gefaelle-Teilstuecke (GF) - siehe Merkmal "Antriebfahrtrichtung"/"VF_Winkel" - je TrackIds-Segment. Ein (nicht letzter) Separator, dessen unmittelbar - vorangehendes Segment als "horizontal" (=keine aktive Antriebsrichtung) - gefuehrt wird, dabei aber tatsaechlich an Hoehe verliert (Merkmal "Hoehe" - der Anbauteile, > 30mm Gefaelle), sitzt auf einem GF-Teilstueck und wird - ebenfalls 1Sep (siehe _incoming_drop). Achtung: diese Hoehen-/ + je TrackIds-Segment. Ein laut Regel 1 als Vario erwarteter Separator, + dessen unmittelbar vorangehendes Segment als "horizontal" (=keine aktive + Antriebsrichtung) gefuehrt wird, dabei aber tatsaechlich an Hoehe verliert + (Merkmal "Hoehe" der Anbauteile, > 30mm Gefaelle), sitzt auf einem + GF-Teilstueck und wird ebenfalls 1Sep (siehe _incoming_drop) - eine + unabhaengige Zusatzpruefung neben der Positions-Regel, kein Ersatz dafuer; + ein laut Regel 1 bereits 1Sep bleibt 1Sep. Achtung: diese Hoehen-/ Antriebsangaben sind bei mehreren Streckengruppen desselben Typs (z. B. VF_2/VF_3/VF_4 bei HundM05) identisch und damit vermutlich unkorrigierte CAD-Blockvorgaben, nicht echte Einzelmessungen - Regel 1 (Position in der Kette) ist deshalb der robustere Nachweis, Regel 2 nur ein Zusatzfund fuer Faelle mit echten, individuellen Messwerten (wie VF_1). +Separatoren, deren Zuordnung zwar auf eine Streckengruppe zeigt, die aber +nicht Teil von deren eigener TrackIds-Kette sind, zaehlen bei beiden Regeln +nicht mit - sie sind eigenstaendige Vereinzeler (plain 1Sep, siehe +derive_tros Schritt 2) und treiben das alternierende Muster nicht mit. + Ein Scanner am Separator aendert den Typ NICHT: in connect.ini der Referenzanlage sind Separatoren mit Scanner ueberwiegend 1Sep (z. B. "TRO104 = 1Sep | TRO 104 (1Sep)+Scanner"). 1Sep_SSCC ist dem Sonderfall mit @@ -678,20 +692,32 @@ def derive_tros( drive = element.drive_dir or "unbekannt" reason = f"angetriebenes Streckensegment (Antriebfahrtrichtung: {drive})" - # Letzter Separator vor dem Wiedereinschleusen auf die Kreisel-Bahn - # (in echter TrackIds-Reihenfolge, nicht sortierte Teile-Id) ist ein - # reiner Vereinzeler ohne eigene VarioDrive-Strecke: die Kreisel-Bahn - # uebernimmt den Antrieb ab dort selbst - bestaetigt am Beispiel VF_3 - # (Review 2026-09-23): TRO11 (erster Separator 0041, direkt nach dem - # Ausschleusen) ist Vario, TRO10 (zweiter/letzter Separator 0040, vor - # dem Wiedereinschleusen) ist 1Sep. Gilt unabhaengig von der - # Separatoranzahl - siehe auch VF_1 (0034, letzter von vieren). Nur - # bei genau einem Separator gibt es kein "erster vs. letzter", der - # bleibt Vario (er ist der einzige Antriebspunkt der Strecke). + # Alternierendes Muster vom Wiedereinschleusen auf die Kreisel-Bahn + # rueckwaerts (in echter TrackIds-Reihenfolge, nicht sortierte + # Teile-Id): eine Streckengruppe ist baulich meist eine alternierende + # VF/GF-Kette, deshalb wechselt auch der TRO-Typ ab dem letzten + # Separator (naechster Nachbar der Kreisel-Bahn, reiner Vereinzeler + # ohne eigene VarioDrive-Strecke - die Kreisel-Bahn treibt ab dort + # selbst an) rueckwaerts durch: letzter = 1Sep, davor Vario, davor + # wieder 1Sep usw. Bestaetigt am Beispiel VF_3 (Review 2026-09-23): + # TRO11 (erster Separator 0041, direkt nach dem Ausschleusen) ist + # Vario, TRO10 (zweiter/letzter Separator 0040, vor dem + # Wiedereinschleusen) ist 1Sep; siehe auch VF_1 (0034, letzter von + # vieren). Fuer genau 2 Separatoren identisch zur frueheren "nur der + # letzte wird umgestuft"-Regel; ab 3 weicht es ab (Review 2026-09-25) + # - vorher blieben alle bis auf den letzten pauschal Vario, obwohl die + # Kette baulich mehrfach zwischen VF und GF wechselt. Bei genau einem + # Separator gibt es kein "erster vs. letzter", der bleibt Vario + # (einziger Antriebspunkt der Strecke). seps_set = set(seps) track_seps = [tid for tid in element.track_ids if tid in seps_set] track_seps_set = set(track_seps) - last_sep_id = track_seps[-1] if len(track_seps) > 1 else None + alt_type: dict[str, str] = {} + alt_offset: dict[str, int] = {} + if len(track_seps) > 1: + for offset, tid in enumerate(reversed(track_seps)): + alt_offset[tid] = offset + alt_type[tid] = "1Sep" if offset % 2 == 0 else "Vario" for sep_id in seps: if sep_id not in track_seps_set: @@ -723,22 +749,29 @@ def derive_tros( ) continue - type_name = "Vario" + type_name = alt_type.get(sep_id, "Vario") sep_reason = reason confidence = "hoch" - if sep_id == last_sep_id: - type_name = "1Sep" + if type_name == "1Sep": confidence = "mittel" sep_reason = ( - f"letzter Separator vor dem Wiedereinschleusen von " - f"{element.name} auf die Kreisel-Bahn - reiner Vereinzeler, " - f"kein eigenes VarioDrive mehr noetig (Review 2026-09-23)" + f"alternierendes VF/GF-Muster vom Wiedereinschleusen von " + f"{element.name} rueckwaerts ({alt_offset[sep_id] + 1}. " + f"Separator von hinten) - unbetriebener Abschnitt ohne " + f"eigenes VarioDrive (Review 2026-09-23/25)" ) findings.append( - f"{element.name} Separator {sep_id}: letzter Separator vor dem " - f"Wiedereinschleusen - als 1Sep statt Vario eingestuft" + f"{element.name} Separator {sep_id}: alternierendes Muster " + f"({alt_offset[sep_id] + 1}. von hinten) - als 1Sep statt " + f"Vario eingestuft" ) - else: + # Hoehen-/Antriebsdaten des vorangehenden Segments (Strecke/ + # Gefaellestrecke) bleiben eine unabhaengige Zusatzpruefung (siehe + # Docstring oben, Regel 2): sie kann eine laut Muster als Vario + # erwartete Position auf 1Sep umstufen, wenn dort tatsaechlich ein + # unbetriebenes Gefaelle gemessen wurde - nicht umgekehrt, ein + # bereits per Muster bestimmtes 1Sep bleibt 1Sep. + if type_name == "Vario": seg_drive, seg_drop = _incoming_drop(element, sep_id, elements_by_id) if seg_drive == "horizontal" and seg_drop is not None and seg_drop <= -GEFAELLE_DROP_MM: type_name = "1Sep" @@ -747,12 +780,13 @@ def derive_tros( f"Separator {sep_id} liegt auf einem unbetriebenen " f"Gefaelle-Teilstueck der Streckengruppe {element.name} " f"(Hoehe faellt um {-seg_drop:.0f}mm, keine aktive " - f"Antriebfahrtrichtung) - kein Vario trotz Host 'Strecke'" + f"Antriebfahrtrichtung) - kein Vario trotz Host 'Strecke' " + f"und trotz alternierendem Muster" ) findings.append( f"{element.name} Separator {sep_id}: {-seg_drop:.0f}mm Gefaelle " f"ohne Antrieb auf dem vorangehenden Segment - als 1Sep statt " - f"Vario eingestuft" + f"Vario eingestuft (widerspricht alternierendem Muster)" ) tros.append( Tro(