diff --git a/cfg/export_tro_ids.ini b/cfg/export_tro_ids.ini new file mode 100644 index 0000000..8c312ac --- /dev/null +++ b/cfg/export_tro_ids.ini @@ -0,0 +1,67 @@ +; ============================================================ +; TRO-IDs zu export.csv - erzeugt von lib/tro_flow.py am 2026-10-14 +; +; Je TRO: ID = x, y (mm) seines Anker-Separators im CSV-Koordinatensystem. +; Die IDs duerfen umbenannt werden (eindeutig, gueltiger SCL-Bezeichner); +; tro_flow findet jeden TRO ueber die Lage wieder. Neue TROs werden +; unten angehaengt, weggefallene bleiben stehen und werden gemeldet. +; Alles neu nummerieren: tro_flow --renumber (ueberschreibt diese Datei). +; Siehe doc/Konzept_Layout_Hardware_SCL.md, Abschnitt TRO-IDs. +; ============================================================ + +[tro] +TRO01 = 6133.6, 302.6 ; 1Sep | Separator 0017 auf Kreisel4 Bahn L | Sep 0017 +TRO02 = 4540.0, -3169.7 ; 1Sep1Swi | Separator 0014 an ILS Weiche 0029 | Sep 0014 +TRO03 = 5340.0, -6534.2 ; 1Sep1Swi | Separator 0015 an ILS Weiche 0028 | Sep 0015 +TRO04 = 6933.6, -6618.2 ; 1Sep | Separator 0016 auf Kreisel4 Bahn R | Sep 0016 +TRO05 = 7149.2, 1886.0 ; 1Sep | Separator 0018 auf Kreisel6 Bahn R | Sep 0018 +TRO06 = 6933.6, 2908.5 ; 1Sep | Separator 0019 auf Kreisel6 Bahn R | Sep 0019 +TRO07 = 4540.6, -1493.5 ; 1Sep1Swi | Separator 0013 an ILS Weiche 0024 | Sep 0013 +TRO08 = 3699.4, 905.8 ; 1Sep | Separator 0012 auf Kreisel8 Bahn L | Sep 0012 +TRO09 = 1244.4, 105.8 ; 1Sep | Separator 0011 auf Kreisel8 Bahn R | Sep 0011 +TRO10 = -461.8, 1526.1 ; 1Sep | Separator 0010 auf Kreisel9 Bahn L | Sep 0010 +; neu aus export.csv am 2026-10-15 +TRO11 = 10310.0, -440.1 ; 1Sep | Separator 0042 auf Kreisel3 Bahn R | Sep 0042 +TRO12 = 10310.0, 159.9 ; 1Sep | Separator 0043 auf Kreisel3 Bahn R | Sep 0043 +TRO13 = 10310.0, -5013.1 ; 1Sep | Separator 0044 auf Kreisel3 Bahn R | Sep 0044 +TRO14 = 9510.0, 14217.0 ; 1Sep | Separator 0045 auf Kreisel3 Bahn L | Sep 0045 +TRO15 = 958.0, 12300.0 ; PinStore_Auto | Speicher (20 Schwerkraftlinien) | Sep 0066, 0069, 0072, 0075, 0078, 0081, 0084, 0087, 0090, 0093, 0096, 0099, 0102, 0105, 0108, 0111, 0114, 0117, 0120, 0123 +TRO16 = 3299.6, 13509.6 ; Vario | VF_1 | Sep 0054 +TRO17 = 8953.1, 13509.6 ; 1Sep | VF_1 | Sep 0055 +TRO18 = 400.0, -3978.1 ; 1Sep1Swi | Separator 0005 an Ausschleuselement 0053 (Strecke 0013, Anfang) | Sep 0005 +TRO19 = 3299.6, -4743.4 ; Vario | VF_2 | Sep 0058 +TRO20 = 8953.1, -4743.4 ; 1Sep | VF_2 | Sep 0059 +TRO21 = -400.0, -3554.9 ; 2Sep2Swi | Uebergabestelle Kreisel2: Ausschleuselement 0057 + ILS Weiche 0125 | Sep 0012, 0036 +TRO22 = 5355.1, -5878.0 ; 1Sep | Separator 0040 auf Kreisel1 Bahn R | Sep 0040 +TRO23 = -400.0, 13920.0 ; 1Sep | Separator 0003 auf Kreisel2 Bahn L | Sep 0003 +TRO24 = -400.0, -562.0 ; 1Sep | Separator 0011 auf Kreisel2 Bahn L | Sep 0011 +TRO25 = -898.9, 1134.6 ; Vario | VF_3 | Sep 0062 +TRO26 = -703.0, 12307.8 ; 1Sep | VF_3 | Sep 0063 +TRO27 = -1026.0, 10723.0 ; 1Sep | VF_3 | Sep 0037 +TRO28 = -1026.0, 5250.1 ; 1Sep | VF_3 | Sep 0038 +; neu aus export.csv am 2026-10-15 +TRO29 = 34716.5, 3406.7 ; Vario | VF_4 | Sep 0071 +TRO30 = 20161.7, 3406.7 ; 1Sep | VF_4 | Sep 0072 +TRO31 = 42164.0, 4329.5 ; 1Sep2Swi | Separator 0048 an Ausschleuselementen 0070, 0078 (Strecken 0008, 0010) | Sep 0048 +TRO32 = 40437.8, 2448.3 ; Vario | VF_6 | Sep 0079 +TRO33 = 33048.6, 2448.3 ; 1Sep | VF_6 | Sep 0080 +TRO34 = 26860.8, 2448.3 ; Vario | VF_6 | Sep 0081 +TRO35 = 20134.0, 2448.3 ; 1Sep | VF_6 | Sep 0082 +TRO36 = 20161.9, 6635.8 ; Vario | VF_5 | Sep 0075 +TRO37 = 20161.9, 11560.3 ; 1Sep | VF_5 | Sep 0076 +TRO38 = 19604.0, 4982.3 ; 1Sep1Swi | Separator 0043 an Ausschleuselement 0074 (Strecke 0009, Anfang) | Sep 0043 +TRO39 = 3098.7, 12119.7 ; 1Sep | Separator 0038 auf Kreisel2 Bahn L | Sep 0038 +TRO40 = 34990.4, 12919.7 ; 1Sep | Separator 0046 auf Kreisel2 Bahn R | Sep 0046 +TRO41 = 5034.1, 12919.7 ; PinStore_Auto | Speicher (10 Schwerkraftlinien) | Sep 0040, 0085, 0088, 0091, 0094, 0097, 0100, 0103, 0106, 0109, 0112 +TRO42 = 2703.7, 21969.7 ; Vario | VF_1 | Sep 0059 +TRO43 = 2703.7, 13476.7 ; 1Sep | VF_1 | Sep 0060 +TRO44 = 3542.3, 24478.8 ; 1Sep1Swi | Separator 0039 an Ausschleuselement 0058 (Strecke 0005, Anfang) | Sep 0039 +TRO45 = 14674.7, 21969.7 ; Vario | VF_2 | Sep 0063 +TRO46 = 14674.7, 13476.7 ; 1Sep | VF_2 | Sep 0064 +TRO47 = 15472.4, 24478.8 ; 1Sep1Swi | Separator 0041 an Ausschleuselement 0062 (Strecke 0006, Anfang) | Sep 0041 +TRO48 = 23232.7, 21969.7 ; Vario | VF_3 | Sep 0067 +TRO49 = 23232.7, 13476.7 ; 1Sep | VF_3 | Sep 0068 +TRO50 = 24062.0, 24478.8 ; 1Sep1Swi | Separator 0044 an Ausschleuselement 0066 (Strecke 0007, Anfang) | Sep 0044 +TRO51 = 15934.1, 12919.8 ; PinStore_Auto | Speicher (7 Schwerkraftlinien) | Sep 0042, 0115, 0118, 0121, 0124, 0127, 0130, 0133 +TRO52 = 24734.2, 12919.8 ; PinStore_Auto | Speicher (10 Schwerkraftlinien) | Sep 0045, 0136, 0139, 0142, 0145, 0148, 0151, 0154, 0157, 0160, 0163 +TRO53 = 35122.8, 25278.8 ; 1Sep | Separator 0047 auf Kreisel3 Bahn R | Sep 0047 diff --git a/lib/tro_flow.py b/lib/tro_flow.py index c47bd95..a1d1580 100644 --- a/lib/tro_flow.py +++ b/lib/tro_flow.py @@ -1957,6 +1957,44 @@ def link_tros( if nxt is not None and nxt != vario_id: _add_chain_pair(vario_id, nxt) + # 1b. Uebergang durch eine Weiche zwischen zwei Kreiseln: der Weichen- + # knoten-TRO (derive_tros Schritt 3c) leitet ueber jede seiner Weichen auf + # den Partnerkreisel um - dort faehrt der Traeger zum naechsten Halt NACH + # der Weiche (wie beim Einschleuselement oben). Die Ketten der Kreisel + # kennen Weichen nicht als Glied; ohne diese Kante fehlte der Uebergang, + # sobald der TRO auf seinem eigenen Kreisel schon eine praezise Kette hat + # (dxfmakros test_system: TRO09 auf Kreisel 0008 -> Weiche 0023 -> + # Kreisel 0009 -> TRO10 fehlte, der Ausgang war unerreichbar). Nur in + # Richtung eines Kreisels, auf dem der TRO NICHT allein steuert: ein + # Separator auf dem Zielkreisel selbst leitet von dort weg, nicht dorthin. + # Ausgangsstationen vor dem naechsten Halt bekommen ihren Ablaufpfeil. + kreisel_by_id = {e.teile_id: e for e in elements + if e.is_circle and len(e.track_ids) >= 2} + for knoten in find_junctions(elements, []): + knoten_tros = {ketten_owner[s] for s in knoten.separators if s in ketten_owner} + if len(knoten_tros) != 1: + continue + tro_id = knoten_tros.pop() + sep_kreisel = set(knoten.sep_kreisel.values()) + for contact in knoten.contacts: + for ziel_id in contact.kreisel: + ziel = kreisel_by_id.get(ziel_id) + if (ziel is None or not sep_kreisel - {ziel_id} + or contact.weiche_id not in ziel.track_ids): + continue + ids = list(ziel.track_ids) + i = ids.index(contact.weiche_id) + folge = ids[i + 1:] + if ziel.rotation in (ROTATION_CW, ROTATION_CCW): + folge += ids[:i] + for tid in folge: + station = station_hosts.get(tid) + if station is not None and station.type_name == BOUNDARY_EXIT: + _add_chain_pair(tro_id, station.tro_id) + if tid in ketten_owner: + _add_chain_pair(tro_id, ketten_owner[tid]) + break + # Nur TROs, fuer die die Umlaufkette tatsaechlich einen praezisen # Nachfolger gefunden hat (precise_sources) - ein TRO ohne brauchbare # TrackIds-Abdeckung behaelt seine bisherigen (ungenaueren, aber nicht diff --git a/tests/fixtures/test_system_sep22_export.csv b/tests/fixtures/test_system_sep22_export.csv new file mode 100644 index 0000000..2ebd257 --- /dev/null +++ b/tests/fixtures/test_system_sep22_export.csv @@ -0,0 +1,31 @@ +Elementnummer;TeileArt;TeileId;Bezeichnung;Planquadrat;Anzahl;Position;Boundingbox;Insertpoint;K1;K2;K3;K4;Nachbarn;TrackIds;Fehler;Warnungen;Merkmale +1;"ILS 2.0 Kreisel";"0001";"Kreisel37";"A/7-B/8";1;"-2011.74, 994.84, 2000.00";"3100.00, 800.00, 1.00";"yab0Dy4YHoSAAAAAAAAAAAAA";"";"";"";"";"0009-L";"0024, 0021";"";"";{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "2.3", "Anzahl der Separatoren": "0", "Kreiselart": "STANDARD", "Anzahl der Scanner": "0", "Anzahl der Rampen": "0", "Höhe in m": "2.0", "Drehrichtung": "UZS", "Drehung": 0, "Name": "Kreisel37", "Geruest fuer Einzelmodul": true} +2;"ILS 2.0 Kreisel";"0002";"Kreisel38";"E/3-E/6";1;"4940.03, -4953.25, 2000.00";"800.00, 5300.00, 1.00";"S2D+i/vOHoSAAAAAAAAAWoJ4";"";"";"";"";"0007-L, 0007-R, 0003-L";"0026, 0015, 0030, 0014";"";"";{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "4.5", "Anzahl der Separatoren": "2", "Kreiselart": "STANDARD", "Anzahl der Scanner": "0", "Anzahl der Rampen": "0", "Höhe in m": "2.0", "Drehrichtung": "UZS", "Drehung": 90, "Name": "Kreisel38", "Geruest fuer Einzelmodul": true} +3;"ILS 2.0 Kreisel";"0003";"Kreisel39";"E/1-E/4";1;"5739.13, -9850.80, 2000.00";"800.00, 6095.71, 1.00";"V5J6gAABHoSAAAAAAAAAWoJ4";"";"";"";"";"0004-L, 0002-R";"0030, 0029";"";"";{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "5.3", "Anzahl der Separatoren": "0", "Kreiselart": "STANDARD", "Anzahl der Scanner": "0", "Anzahl der Rampen": "0", "Höhe in m": "2.0", "Drehrichtung": "GUZ", "Drehung": 90, "Name": "Kreisel39", "Geruest fuer Einzelmodul": true} +4;"ILS 2.0 Kreisel";"0004";"Kreisel40";"E/3-F/7";1;"6533.60, -3258.73, 2000.00";"800.00, 8689.42, 1.00";"Y7Hgi/sQHoSAAAAAAAAAWoJ4";"";"";"";"";"0005-R, 0003-R";"0016, 0029, 0017, 0028";"";"";{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "7.89", "Anzahl der Separatoren": "2", "Kreiselart": "STANDARD", "Anzahl der Scanner": "0", "Anzahl der Rampen": "0", "Höhe in m": "2.0", "Drehrichtung": "UZS", "Drehung": 90, "Name": "Kreisel40", "Geruest fuer Einzelmodul": true} +5;"ILS 2.0 Kreisel";"0005";"Kreisel41";"E/7-K/8";1;"11425.39, 1485.99, 2000.00";"10583.58, 800.00, 1.00";"XZdgFqymHoSAAAAAAAAAAAAA";"";"";"";"";"0006-L, 0006-R, 0004-L, 0004-R";"0018, 0027, 0028, 0020";"";"";{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "9.78", "Anzahl der Separatoren": "1", "Kreiselart": "STANDARD", "Anzahl der Scanner": "0", "Anzahl der Rampen": "0", "Höhe in m": "2.0", "Drehrichtung": "GUZ", "Drehung": 0, "Name": "Kreisel41", "Geruest fuer Einzelmodul": true} +6;"ILS 2.0 Kreisel";"0006";"Kreisel42";"E/8-F/10";1;"6533.60, 4145.31, 2000.00";"800.00, 4518.63, 1.00";"Y7HgHMcmHoSAAAAAAAAAWoJ4";"";"";"";"";"0005-L";"0019, 0027";"";"";{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "3.72", "Anzahl der Separatoren": "1", "Kreiselart": "STANDARD", "Anzahl der Scanner": "0", "Anzahl der Rampen": "0", "Höhe in m": "2.0", "Drehrichtung": "UZS", "Drehung": 90, "Name": "Kreisel42", "Geruest fuer Einzelmodul": true} +7;"ILS 2.0 Kreisel";"0007";"Kreisel43";"E/6-E/8";1;"4940.59, 96.75, 2000.00";"800.00, 4800.00, 1.00";"S2Mu3NruHoSAAAAAAAAAWoJ4";"";"";"";"";"0008-L, 0008-R, 0002-L, 0002-R";"0022, 0025, 0013, 0026";"";"";{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "4.0", "Anzahl der Separatoren": "2", "Kreiselart": "STANDARD", "Anzahl der Scanner": "0", "Anzahl der Rampen": "0", "Höhe in m": "2.0", "Drehrichtung": "GUZ", "Drehung": 90, "Name": "Kreisel43", "Geruest fuer Einzelmodul": true} +8;"ILS 2.0 Kreisel";"0008";"Kreisel44";"B/7-E/7";1;"2440.85, 505.79, 2000.00";"4200.00, 800.00, 1.00";"BTNyB7e+HoSAAAAAAAAAAAAA";"";"";"";"";"0009-R, 0007-L";"0025, 0011, 0023, 0012";"";"";{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "3.4", "Anzahl der Separatoren": "2", "Kreiselart": "STANDARD", "Anzahl der Scanner": "0", "Anzahl der Rampen": "0", "Höhe in m": "2.0", "Drehrichtung": "UZS", "Drehung": 0, "Name": "Kreisel44", "Geruest fuer Einzelmodul": true} +9;"ILS 2.0 Kreisel";"0009";"Kreisel45";"B/6-B/9";1;"-61.76, 1425.92, 2000.00";"800.00, 4800.00, 1.00";"/w7A8SMAHoSAAAAAAAAAWoJ4";"";"";"";"";"0001-L, 0001-R, 0008-L, 0008-R";"0010, 0024, 0023";"";"";{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "4.0", "Anzahl der Separatoren": "1", "Kreiselart": "STANDARD", "Anzahl der Scanner": "0", "Anzahl der Rampen": "0", "Höhe in m": "2.0", "Drehrichtung": "GUZ", "Drehung": 90, "Name": "Kreisel45", "Geruest fuer Einzelmodul": true} +10;"ILS 2.0 Separator";"0010";"Separator :11";"B/8";1;"-461.76, 1526.13, 2001.50";"150.00, 209.90, 3.00";"+PRAFl9EHoSAAAAAAAAAWoJ4";"/+33ADlFAE4g";"";"";"";"0023, 0024";"";"";"";{"Zuordnung": "0009-L", "ARTINR": "200000077", "Höhe": "2000", "Drehung": 90, "Typ": ""} +11;"ILS 2.0 Separator";"0011";"Separator :10";"C/7";1;"1244.39, 105.79, 1.50";"209.90, 150.00, 3.00";"EhK4AZ0+AAAAAAAAAAAAAAAA";"AC5EAAQhAAAA";"";"";"";"0025, 0023";"";"";"";{"Zuordnung": "0008-R", "ARTINR": "200000077", "Höhe": "0", "Drehung": 0, "Typ": ""} +12;"ILS 2.0 Separator";"0012";"Separator :9";"D/7";1;"3699.43, 905.79, 2001.50";"209.90, 150.00, 3.00";"OV0UDdI+HoSAAAAAAAAAf///";"AJLZACNhAE4g";"";"";"";"0023, 0025";"";"";"";{"Zuordnung": "0008-L", "ARTINR": "200000077", "Höhe": "2000", "Drehung": 180, "Typ": ""} +13;"ILS 2.0 Separator";"0013";"Separator :8";"E/6";1;"4540.59, -1493.47, 2001.50";"150.00, 209.90, 3.00";"RUiu6Ev0HoSAAAAAAAAAWoJ4";"ALFd/8NSAE4g";"";"";"";"0025, 0026";"";"";"";{"Zuordnung": "0007-L", "ARTINR": "200000077", "Höhe": "2000", "Drehung": 90, "Typ": ""} +14;"ILS 2.0 Separator";"0014";"Separator :7";"E/5";1;"4540.03, -3169.65, 2001.50";"150.00, 209.90, 3.00";"RUZ+0Iy8HoSAAAAAAAAApX2I";"ALFY/4aHAE4g";"";"";"";"0030, 0026";"";"";"";{"Zuordnung": "0002-L", "ARTINR": "200000077", "Höhe": "2000", "Drehung": 270, "Typ": ""} +15;"ILS 2.0 Separator";"0015";"Separator :6";"E/4";1;"5340.03, -6534.21, 2001.50";"150.00, 209.90, 3.00";"UXt+m2GQHoSAAAAAAAAAWoJ4";"ANCY/v5rAE4g";"";"";"";"0026, 0030";"";"";"";{"Zuordnung": "0002-R", "ARTINR": "200000077", "Höhe": "2000", "Drehung": 90, "Typ": ""} +16;"ILS 2.0 Separator";"0016";"Separator :5";"F/4";1;"6933.60, -6618.23, 2001.50";"150.00, 209.90, 3.00";"acxgmhlcHoSAAAAAAAAAWoJ4";"AQ7Y/vsjAE4g";"";"";"";"0028, 0029";"";"";"";{"Zuordnung": "0004-R", "ARTINR": "200000077", "Höhe": "2000", "Drehung": 90, "Typ": ""} +17;"ILS 2.0 Separator";"0017";"Separator :4";"E/7";1;"6133.60, 302.58, 2001.50";"150.00, 209.90, 3.00";"XZdgBYgiHoSAAAAAAAAApX2I";"AO+YAA4pAE4g";"";"";"";"0029, 0028";"";"";"";{"Zuordnung": "0004-L", "ARTINR": "200000077", "Höhe": "2000", "Drehung": 270, "Typ": ""} +18;"ILS 2.0 Separator";"0018";"Separator :3";"F/8";1;"7149.18, 1885.99, 2001.50";"209.90, 150.00, 3.00";"bCxOHMcmHoSAAAAAAAAAAAAA";"ARTsAEmrAE4g";"";"";"";"0020, 0027";"";"";"";{"Zuordnung": "0005-L", "ARTINR": "200000077", "Höhe": "2000", "Drehung": 0, "Typ": ""} +19;"ILS 2.0 Separator";"0019";"Separator :2";"F/8";1;"6933.60, 2908.49, 2001.50";"150.00, 209.90, 3.00";"acxgK3ccHoSAAAAAAAAAWoJ4";"AQ7YAG9FAE4g";"";"";"";"0027, 0027";"";"";"";{"Zuordnung": "0006-R", "ARTINR": "200000077", "Höhe": "2000", "Drehung": 90, "Typ": ""} +20;"ILS 2.0 BTMT Beladung";"0020";"BTMT Beladung :1";"I/7-J/8";1;"14374.25, 1186.94, 1955.31";"645.71, 397.50, 316.02";"f///EJImHoSAAAAAAAAAAAAA";"AiYBADU7AE6r";"Aj3vACprAE4g";"";"";"0028, 0018";"";"";"";{"ARTINR": "829662012", "Höhe": "2000", "Drehung": 0} +21;"ILS 2.0 BTMT Entladung";"0021";"BTMT Entladung :1";"A/7";1;"-2501.71, 212.89, 1847.09";"1468.14, 950.36, 467.01";"3bjiCN/+HoSAAAAAAAAAf/+r";"/7UPABabAE4f";"/4Hu//aMAD/1";"";"";"0024, 0024";"";"";"";{"ARTINR": "400100156", "Höhe": "2000", "Drehung": 179} +22;"ILS 2.0 Separator";"0022";"Separator :1";"E/8";1;"4540.59, 1258.01, 2001.50";"150.00, 209.90, 3.00";"RUiuEkfsHoSAAAAAAAAAWoJ4";"ALFdAC7MAE4g";"";"";"";"0026, 0025";"";"";"";{"Zuordnung": "0007-L", "ARTINR": "200000077", "Höhe": "2000", "Drehung": 90, "Typ": ""} +23;"ILS Weiche";"0023";"ILS Weiche :1";"B/7";1;"338.24, 505.79, 2000.00";"100.00, 250.00, 30.00";"";"";"";"";"";"0011, 0012";"";"";"";{"Erzeugt aus": "Kreisel-Beruehrpunkt", "Kreisel A": "0009", "Kreisel B": "0008", "Achse von Kreisel": "0008", "Beruehrung": "Kreis/Tangente"} +24;"ILS Weiche";"0024";"ILS Weiche :2";"B/7";1;"-461.76, 994.84, 2000.00";"100.00, 250.00, 30.00";"";"";"";"";"";"0021, 0021";"";"";"";{"Erzeugt aus": "Kreisel-Beruehrpunkt", "Kreisel A": "0009", "Kreisel B": "0001", "Achse von Kreisel": "0001", "Beruehrung": "Kreis/Tangente"} +25;"ILS Weiche";"0025";"ILS Weiche :3";"E/7";1;"4540.59, 505.79, 2000.00";"100.00, 250.00, 30.00";"";"";"";"";"";"0022, 0013";"";"";"";{"Erzeugt aus": "Kreisel-Beruehrpunkt", "Kreisel A": "0008", "Kreisel B": "0007", "Achse von Kreisel": "0008", "Beruehrung": "Kreis/Tangente"} +26;"ILS Weiche";"0026";"ILS Weiche :4";"E/6";1;"4940.31, -2303.25, 2000.00";"250.07, 100.17, 30.00";"";"";"";"";"";"0014, 0015";"";"";"";{"Erzeugt aus": "Kreisel-Beruehrpunkt", "Kreisel A": "0007", "Kreisel B": "0002", "Achse von Kreisel": "0007", "Beruehrung": "Kreis/Kreis"} +27;"ILS Weiche";"0027";"ILS Weiche :5";"F/8";1;"6533.60, 1885.99, 2000.00";"250.00, 100.00, 30.00";"";"";"";"";"";"0018, 0028";"";"";"";{"Erzeugt aus": "Kreisel-Beruehrpunkt", "Kreisel A": "0006", "Kreisel B": "0005", "Achse von Kreisel": "0006", "Beruehrung": "Kreis/Kreis"} +28;"ILS Weiche";"0028";"ILS Weiche :6";"F/7";1;"6533.60, 1085.78, 2000.00";"250.00, 100.00, 30.00";"";"";"";"";"";"0017, 0016";"";"";"";{"Erzeugt aus": "Kreisel-Beruehrpunkt", "Kreisel A": "0005", "Kreisel B": "0004", "Achse von Kreisel": "0005", "Beruehrung": "Kreis/Kreis"} +29;"ILS Weiche";"0029";"ILS Weiche :7";"E/3";1;"6136.36, -7203.05, 2000.00";"100.25, 250.10, 30.00";"";"";"";"";"";"0030, 0030";"";"";"";{"Erzeugt aus": "Kreisel-Beruehrpunkt", "Kreisel A": "0004", "Kreisel B": "0003", "Achse von Kreisel": "0004", "Beruehrung": "Kreis/Kreis"} +30;"ILS Weiche";"0030";"ILS Weiche :8";"E/3";1;"5339.58, -7202.95, 2000.00";"100.19, 250.07, 30.00";"";"";"";"";"";"0015, 0014";"";"";"";{"Erzeugt aus": "Kreisel-Beruehrpunkt", "Kreisel A": "0003", "Kreisel B": "0002", "Achse von Kreisel": "0003", "Beruehrung": "Kreis/Kreis"} diff --git a/tests/test_tro_link.py b/tests/test_tro_link.py new file mode 100644 index 0000000..e4fa272 --- /dev/null +++ b/tests/test_tro_link.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +"""Tests fuer tro_flow.link_tros - Uebergang durch eine Kreisel-Kreisel-Weiche. + +Fixture: Testanlage test_system (dxfmakros results/export.csv) mit einem +zusaetzlichen Separator 0022 auf Kreisel 0007. Kreisel 0009 hat nur einen +eigenen Separator (0010 vor Weiche 0024 zu Kreisel 0001 mit der Entladung); +in Kreisel 0009 gelangt man nur ueber Weiche 0023, die Separator 0011 auf +Kreisel 0008 steuert. Die Kreiselketten kennen Weichen nicht als Glied - ohne +eigene Weichenkante fehlte TRO(0011) -> TRO(0010), der Ausgang war vom +Eingang aus unerreichbar und stattdessen zeigte TRO(0010) rueckwaerts auf +TRO(0011). + +TROs werden ueber ihre Separatoren angesprochen, nicht ueber die IDs (die +haengen an der ID-Datei der Anlage). +""" + +from __future__ import annotations + +from pathlib import Path + +import pytest + +from material_flow import build_graph, read_elements +from tro_flow import BOUNDARY_ENTRY, BOUNDARY_EXIT, analyse_tros + +FIXTURES = Path(__file__).parent / "fixtures" + + +def _analyse(name: str): + path = FIXTURES / name + elements = read_elements(path, []) + graph = build_graph(elements, path.name, []) + return analyse_tros(graph, elements) + + +@pytest.fixture(scope="module") +def analysis(): + return _analyse("test_system_sep22_export.csv") + + +def _tro_mit_sep(analysis, sep_id: str) -> str: + return next(t.tro_id for t in analysis.tros if sep_id in t.separators) + + +def _erreichbar(edges, start: str) -> set[str]: + nach: dict[str, list[str]] = {} + for a, b in edges: + nach.setdefault(a, []).append(b) + seen, stack = {start}, [start] + while stack: + for nxt in nach.get(stack.pop(), []): + if nxt not in seen: + seen.add(nxt) + stack.append(nxt) + return seen + + +def test_weiche_fuehrt_auf_partnerkreisel(analysis): + von, nach = _tro_mit_sep(analysis, "0011"), _tro_mit_sep(analysis, "0010") + assert (von, nach) in analysis.edges + + +def test_keine_rueckwaertskante_ueber_die_weiche(analysis): + von, nach = _tro_mit_sep(analysis, "0010"), _tro_mit_sep(analysis, "0011") + assert (von, nach) not in analysis.edges + + +def test_ausgang_vom_eingang_erreichbar(analysis): + # Nicht fuer test_system_export.csv: dort fehlt auf Kreisel 0007 der + # Separator vor der Weiche zu Kreisel 0008 (erst 0022 hier steuert sie) - + # die Anlage ist dort physisch nicht durchgaengig. + eingang = next(b.tro_id for b in analysis.boundaries if b.type_name == BOUNDARY_ENTRY) + ausgang = next(b.tro_id for b in analysis.boundaries if b.type_name == BOUNDARY_EXIT) + assert ausgang in _erreichbar(analysis.edges, eingang)