diff --git a/Lisp/export.lsp b/Lisp/export.lsp index 182ebad..6680688 100644 --- a/Lisp/export.lsp +++ b/Lisp/export.lsp @@ -513,6 +513,16 @@ (atof (export:cfg "Boundingbox" "bb_minimum_height_mm" "1")) ) +;; Diagnose fuer csv:get-bbox: zaehlt fehlgeschlagene vla-getboundingbox- +;; Aufrufe und merkt sich die ERSTE Fehlermeldung samt betroffenem Block. Wird +;; von csv:run-export vor der Export-Schleife zurueckgesetzt und danach +;; ausgegeben - so sieht man in der BricsCAD-Konsole sofort, WARUM eine bbox +;; fehlt (frueher wurde der Fehler still zu nil verschluckt, und im JSON fehlte +;; nur das Feld). *csv-bbox-fail-count* = Anzahl, *csv-bbox-fail-first* = +;; "(Blockname) Meldung" des ersten Fehlers. +(setq *csv-bbox-fail-count* 0) +(setq *csv-bbox-fail-first* nil) + ;; --- Bounding-Box (WCS, achsparallel) eines INSERT-Blocks ermitteln --- ;; Erzwingt vorher ein vla-update (Regen), da vla-getboundingbox sonst auf ;; nicht-regenerierten oder auf eingefrorenen Layern liegenden Bloecken scheitert. @@ -527,7 +537,14 @@ (vla-getboundingbox obj 'll 'ur) (list (csv:pt->list ll) (csv:pt->list ur))))) (if (vl-catch-all-error-p res) - nil + (progn + ;; Fehler NICHT mehr still schlucken: zaehlen und erste Meldung merken. + (setq *csv-bbox-fail-count* (1+ (cond (*csv-bbox-fail-count*) (0)))) + (if (null *csv-bbox-fail-first*) + (setq *csv-bbox-fail-first* + (strcat "(" (cond ((cdr (assoc 2 (entget ename)))) ("?")) ") " + (vl-catch-all-error-message res)))) + nil) (progn (setq minpt (car res)) (setq maxpt (cadr res)) @@ -941,8 +958,103 @@ gesetzt ) -;; --- Temporaere Separator_SP-Kopien (csv:sep-proxies-erzeugen) nach dem -;; Export wieder entfernen --- +;; --- Fuer jeden Sepliste-Eintrag (AS/SEP/ES) eines VF_n/GF_n-Wrappers eine +;; ECHTE, temporaere Separator_SP-Kopie an dessen Weltkoordinate einfuegen --- +;; +;; Hintergrund: Seit die in einer VF_n/GF_n-Kette liegenden Separatoren (und die +;; AS/ES-Elemente) beim Bau nur noch als Koordinaten-Eintraege in der +;; "sepliste"-XDATA gefuehrt werden (ssg-sepliste-sammeln, ssg_ks_insert.lsp), +;; gibt es fuer sie KEIN reales INSERT mehr in der Zeichnung - vla-getboundingbox +;; kann also keine Box liefern, und der frueher genutzte Proxy-Mechanismus +;; csv:sep-proxies-erzeugen findet nichts (der sucht VERPACKTE Separator_SP- +;; Sub-Bloecke, die es nicht mehr gibt). Ohne Box fielen diese Separatoren aus +;; der Nachbarschafts-/Umlauf-/Zuordnungserkennung des Python-Exports. +;; +;; Diese Funktion schliesst die Luecke analog zu csv:sep-proxies-erzeugen: fuer +;; JEDEN Sepliste-Eintrag (typ SEP, AS ODER ES) wird ein echter, top-level +;; Separator_SP-INSERT der aktuellen Dimension an die gespeicherte Weltposition +;; (x y) gesetzt. Diese Kopie durchlaeuft danach unveraendert ID-Vergabe und +;; Export (Blockname-Muster Separator_SP* trifft zu) und liefert per +;; vla-getboundingbox die echte Symbol-Box. AS/ES bekommen dieselbe Symbol-Box +;; wie ein SEP - fuer die Nachbarschaftserkennung genuegt das; die AS/ES- +;; Sonderrolle (Kettenende am Kreisel) ergibt sich im Python-Teil aus der +;; sepliste-Reihenfolge, nicht aus der Boxgroesse. +;; +;; Die Drehung des Symbols ist in der sepliste NICHT gespeichert (nur typ/lfdnr/ +;; x/y) - naeherungsweise die Wrapper-Drehung uebernehmen (bei ~210x150mm +;; Symbol und 200mm Nachbarschaftstoleranz unkritisch). Einfuegen ueber +;; vla-InsertBlock (kein Kommandozeilen-Prompt, legt ATTRIBs mit Vorgabewerten +;; an - identisch zu csv:sep-proxies-erzeugen). +;; +;; Rueckgabe: Liste von Paaren (proxy-ename . wrapper-ename) - gleiches Format +;; wie csv:sep-proxies-erzeugen, sodass csv:sep-proxies-zuordnung-setzen (setzt +;; ZUORDNUNG = Wrapper-ID) und csv:sep-proxies-loeschen unveraendert wirken. +(defun csv:sepliste-proxies-erzeugen ( / ss-all ms i ename ed bname sepliste-app + sepliste blk-eff rotation wpt eintrag + block-obj xform-fehler T4 cosr sinr + proxy-liste) + (setq ss-all (ssget "X" (list (cons 0 "INSERT")))) + (if (and ss-all (car (atoms-family 1 '("SSG-SEPLISTE-XDATA-LESEN")))) + (progn + (setq ms (vla-get-ModelSpace (vla-get-ActiveDocument (vlax-get-acad-object)))) + (setq i 0) + (while (setq ename (ssname ss-all i)) + (setq ed (entget ename)) + (setq bname (cdr (assoc 2 ed))) + (setq sepliste-app + (cond + ((wcmatch (strcase bname) "VF_*") "SSG_VF_SEP") + ((wcmatch (strcase bname) "GF_*") "SSG_GF_SEP") + (t nil))) + (setq sepliste (if sepliste-app (ssg-sepliste-xdata-lesen ename sepliste-app))) + (if sepliste + (progn + ;; Symbol-Blockdefinition der aktuellen Dimension sicherstellen. + (setq blk-eff (ssg-ils-block-laden "Separator_SP")) + (setq rotation (cond ((cdr (assoc 50 ed))) (0.0))) + (setq cosr (cos rotation) sinr (sin rotation)) + (if blk-eff + (foreach eintrag sepliste + ;; (typ lfdnr x y) - Weltkoordinate direkt aus der Sepliste. + (setq wpt (list (nth 2 eintrag) (nth 3 eintrag) 0.0)) + (setq block-obj + (vl-catch-all-apply 'vla-InsertBlock + (list ms (vlax-3D-point '(0.0 0.0 0.0)) blk-eff 1.0 1.0 1.0 0.0))) + (cond + ((vl-catch-all-error-p block-obj) + (princ (ssg-textf "exp-sep-proxy-fehler" + (list blk-eff bname + (vl-catch-all-error-message block-obj))))) + (t + ;; Rz(rotation) + Verschiebung an die Sepliste-Weltposition + ;; in EINER TransformBy (wie csv:sep-proxies-erzeugen). + (setq T4 (vlax-tmatrix + (list (list cosr (- sinr) 0.0 (car wpt)) + (list sinr cosr 0.0 (cadr wpt)) + (list 0.0 0.0 1.0 (caddr wpt)) + (list 0.0 0.0 0.0 1.0)))) + (setq xform-fehler (vl-catch-all-apply 'vla-TransformBy (list block-obj T4))) + (if (vl-catch-all-error-p xform-fehler) + (progn + (princ (ssg-textf "exp-sep-proxy-fehler" + (list blk-eff bname + (vl-catch-all-error-message xform-fehler)))) + (vl-catch-all-apply 'vla-Delete (list block-obj))) + (setq proxy-liste + (cons (cons (vlax-vla-object->ename block-obj) ename) proxy-liste))))) + ) + ) + ) + ) + (setq i (1+ i)) + ) + ) + ) + proxy-liste +) + +;; --- Temporaere Separator_SP-Kopien (csv:sep-proxies-erzeugen / +;; csv:sepliste-proxies-erzeugen) nach dem Export wieder entfernen --- ;; proxy-liste = Paare (proxy-ename . wrapper-ename), nur der car wird geloescht. (defun csv:sep-proxies-loeschen (proxy-liste) (foreach paar proxy-liste (entdel (car paar))) @@ -1044,6 +1156,17 @@ ;; Verpackte Separator_SP-Symbole (siehe csv:sep-proxies-erzeugen) VOR der ;; ID-Vergabe durch temporaere, echte Kopien ersetzen - sie werden am Ende ;; dieser Funktion wieder entfernt (csv:sep-proxies-loeschen). + ;; + ;; HINWEIS: csv:sepliste-proxies-erzeugen (echte Kopien fuer die nur noch in + ;; der sepliste-XDATA gefuehrten SEP/AS/ES-Eintraege der VF_n/GF_n-Wrapper) + ;; ist BEWUSST NOCH NICHT eingehaengt: solange der Python-Export dieselben + ;; Ketten-Separatoren bereits aus der sepliste erzeugt (build_separator_kette_ + ;; items), wuerden beide Wege jeden Separator DOPPELT zaehlen. Der Umbau auf + ;; "LISP-Proxies fuehren, Python-Sonderweg raus" (inkl. Typmarker AS/ES) haengt + ;; ausserdem am generellen vla-getboundingbox-Ausfall (Kreisel/GF/VF haben in + ;; betroffenen Exporten ebenfalls keine bbox) - der ist zuerst zu klaeren. + ;; Die Funktion bleibt erhalten und ist einsatzbereit, sobald der Python- + ;; Sonderweg entfernt und AS/ES markiert sind. (setq sep-proxies (csv:sep-proxies-erzeugen)) ;; Vor dem Export: IDs aller Bloecke sicherstellen und Duplikate korrigieren. ;; Erst hier - also erst nachdem ALLE Kopien aus allen Wrapper-Bloecken @@ -1083,6 +1206,15 @@ (princ (ssg-textf "sens-skip" (list label))) ) ) + ;; Vor dem Sammeln/Schreiben EINMAL global regenerieren. vla-getboundingbox + ;; liefert nur auf regenerierten Objekten eine gueltige Box; ein pro-Objekt + ;; vla-update (csv:get-bbox) reicht dafuer in der Praxis nicht immer aus + ;; (fuehrte real dazu, dass in einem Export ALLE Bloecke ohne bbox blieben). + ;; REGENALL erzwingt die vollstaendige Regeneration der gesamten Zeichnung. + (vl-catch-all-apply '(lambda () (command "_.REGENALL"))) + ;; bbox-Fehlerdiagnose fuer diesen Lauf zuruecksetzen (siehe csv:get-bbox). + (setq *csv-bbox-fail-count* 0) + (setq *csv-bbox-fail-first* nil) (princ (ssg-textf "exp-collect-blocks" (list label))) (setq ss (csv:collect-export-blocks)) @@ -1133,6 +1265,14 @@ (write-line "]" fh) (close fh) (princ (ssg-textf "exp-json-written" (list label out-pfad))) + ;; bbox-Fehler dieses Laufs melden (falls csv:get-bbox scheiterte) - + ;; nennt Anzahl und die erste Fehlermeldung samt Block, damit die + ;; Ursache fehlender Bounding-Boxen sofort sichtbar ist statt still + ;; im JSON zu fehlen. + (if (and *csv-bbox-fail-count* (> *csv-bbox-fail-count* 0)) + (princ (ssg-textf "exp-bbox-fail" + (list (itoa *csv-bbox-fail-count*) + (cond (*csv-bbox-fail-first*) ("?")))))) ;; Python-Skript aufrufen. DXFM_LIB muss gesetzt sein - fehlt es ;; (z.B. weil BricsCAD nicht ueber bin/start_briscad.bat gestartet diff --git a/cfg/export.cfg b/cfg/export.cfg index 712bde3..8110e3f 100644 --- a/cfg/export.cfg +++ b/cfg/export.cfg @@ -173,6 +173,24 @@ element_box_laenge_mm=250 element_box_breite_mm=100 element_box_hoehe_mm=30 +# Feste Bounding-Box-Masse (mm) eines Separator-Symbols. Werden fuer die in +# einer VF_n/GF_n-Kette EINGEBETTETEN Separatoren gebraucht, die seit der +# Umstellung auf die "sepliste"-XDATA nicht mehr als eigene INSERT-Bloecke in +# der Zeichnung liegen (frueher wurden sie nur kurzzeitig als Kopie erzeugt, +# um sie zu nummerieren) - fuer sie kann vla-getboundingbox keine Box liefern, +# es gibt kein reales Objekt mehr. Ohne Box nehmen diese Separatoren an der +# Nachbarschafts-/Umlauf-Erkennung nicht teil (siehe lib/export_neighbors.py: +# compute_kreisel_umlauf/compute_sensor_zuordnung brauchen item["_bbox"]). +# Quelle der Masse: gemessenes Separator_SP-Symbol (Referenz-Export, achsen- +# paralleles Symbol ~210 x 150 mm Grundflaeche, 3D-Hoehe ~14 mm). LAENGE liegt +# laengs des Symbols (bei Drehung 0 entlang X), BREITE quer, HOEHE = Z. Die +# tatsaechliche Welt-AABB wird beim Export aus diesen Massen + der Symbol- +# Drehung berechnet (rotierte Box -> achsparallele Huelle). Defaults (falls +# nicht gesetzt): 210 / 150 / 14. +separator_box_laenge_mm=210 +separator_box_breite_mm=150 +separator_box_hoehe_mm=14 + [Kreisel] # Kreisel-Durchmesser (Antriebs-/Spannstation AN8/SP8) in mm. Quelle der # Wahrheit ist data/json/component_defaults.json ("kreisel"."durchmesser", diff --git a/lang/de_DE.json b/lang/de_DE.json index bd1e8df..6b41678 100644 --- a/lang/de_DE.json +++ b/lang/de_DE.json @@ -582,6 +582,7 @@ "exp-output-dir": "\n[%1] Ausgabeordner: %2", "exp-file-open-error": "\n[%1] FEHLER: Kann Datei nicht oeffnen: %2", "exp-json-written": "\n[%1] JSON geschrieben: %2", + "exp-bbox-fail": "\n[Export] WARNUNG: %1 Block/Bloecke ohne Bounding-Box (vla-getboundingbox scheiterte). Erster Fehler: %2", "exp-calling-python": "\n[%1] Rufe Python auf...", "exp-export-started": "\n[%1] Export gestartet: %2", "exp-dxfm-lib-missing": "\n[%1] FEHLER: Umgebungsvariable DXFM_LIB ist nicht gesetzt - BricsCAD wurde vermutlich nicht ueber bin/start_briscad.bat gestartet. CSV/JSON wurden geschrieben, der Python-Aufruf entfaellt.", diff --git a/lang/en_GB.json b/lang/en_GB.json index b564d06..e58028c 100644 --- a/lang/en_GB.json +++ b/lang/en_GB.json @@ -582,6 +582,7 @@ "exp-output-dir": "\n[%1] Output folder: %2", "exp-file-open-error": "\n[%1] ERROR: Cannot open file: %2", "exp-json-written": "\n[%1] JSON written: %2", + "exp-bbox-fail": "\n[Export] WARNING: %1 block(s) without bounding box (vla-getboundingbox failed). First error: %2", "exp-calling-python": "\n[%1] Calling Python...", "exp-export-started": "\n[%1] Export started: %2", "exp-dxfm-lib-missing": "\n[%1] ERROR: Environment variable DXFM_LIB is not set - BricsCAD was probably not started via bin/start_briscad.bat. CSV/JSON were written, the Python call is skipped.", diff --git a/lib/export_csv.py b/lib/export_csv.py index 9b50866..aa030b9 100644 --- a/lib/export_csv.py +++ b/lib/export_csv.py @@ -104,6 +104,7 @@ danach. """ import json +import math import sys import os @@ -115,6 +116,8 @@ from export_neighbors import ( load_omniflo_ks_tolerance_mm, load_kreisel_durchmesser_mm, load_element_box_mm, + load_separator_box_mm, + separator_bbox, load_collision_debug_target, compute_neighbor_ids, compute_neighbor_errors, @@ -136,6 +139,7 @@ NEIGHBOR_OMNIFLO_CELL_SIZE_MM = load_omniflo_cell_size_mm() NEIGHBOR_OMNIFLO_KS_TOLERANCE_MM = load_omniflo_ks_tolerance_mm() KREISEL_DURCHMESSER_MM = load_kreisel_durchmesser_mm() ELEMENT_BOX_MM = load_element_box_mm() +SEPARATOR_BOX_MM = load_separator_box_mm() NEIGHBOR_DEBUG_TARGET = load_collision_debug_target() @@ -433,6 +437,31 @@ def bbox_columns(block): } +def _fallback_separator_bbox(cols, block, separator_box_mm=None): + """Ergaenzt eine fehlende Bounding-Box (cols["_bbox"] is None) durch die + feste Separator-Symbol-Box aus cfg [Boundingbox] separator_box_* an der + realen INSERT-Position/-Drehung des Blocks. Wird fuer frei platzierte + Separator_SP-INSERTs gebraucht, deren vla-getboundingbox beim Export + scheiterte (z.B. eingefrorener Layer) - ohne "_bbox" fielen sie sonst aus + der Nachbarschafts-/Zuordnungserkennung. Hat der Block schon eine bbox, + bleibt cols unveraendert. + + Rueckgabe: (ggf. ergaenztes) cols-dict.""" + if cols.get("_bbox"): + return cols + if separator_box_mm is None: + separator_box_mm = SEPARATOR_BOX_MM + bbox = separator_bbox(block.get("x", 0.0) or 0.0, block.get("y", 0.0) or 0.0, + block.get("rotation", 0.0) or 0.0, + separator_box_mm=separator_box_mm, + z=block.get("z", 0.0) or 0.0) + cols = dict(cols) + cols["position"] = f'{bbox["cx"]:.2f}, {bbox["cy"]:.2f}, {bbox["cz"]:.2f}' + cols["boundingbox"] = f'{bbox["dx"]:.2f}, {bbox["dy"]:.2f}, {bbox["dz"]:.2f}' + cols["_bbox"] = bbox + return cols + + def planquadrat_column(block, planquadrat_cfg): """Berechnet das Planquadrat aus der Bounding-Box des Blocks, falls vorhanden (siehe export_planquadrat.py), sonst aus dem Einfuegepunkt. @@ -483,32 +512,39 @@ def max_numeric_teileid(items): return max_id -def build_kreisel_weiche_items(items, planquadrat_cfg, start_elem_nr, dbg=None): +def build_kreisel_weiche_items(items, planquadrat_cfg, start_elem_nr, switches, dbg=None): """Haengt fuer jeden Kreisel-Beruehrpunkt eine "ILS Weiche"-Zeile an items an (siehe export_neighbors.compute_kreisel_touch_switches). + switches = Rueckgabe von compute_kreisel_touch_switches, bereits VOR dem + Aufruf berechnet (der Aufrufer speist dieselbe Liste auch in + compute_kreisel_umlauf ein, damit die Weiche im Kreisel-Umlauf auftaucht - + siehe process_blocks). Jeder switches-Eintrag traegt seinen stabilen + "key" (sw["key"]) - hier wird KEIN neuer Schluessel erzeugt. + TeileId zaehlt aus der hoechsten bereits enthaltenen numerischen ID hoch (max_numeric_teileid), 4-stellig aufgefuellt wie die Kreisel-IDs. Anzahl - ist wie bei allen Zeilen 1; Nachbarn = die beiden Kreisel-IDs; K1-K4 und - Insertpoint bleiben leer; Position = Beruehrkoordinaten; Boundingbox = die - feste, an der Kreiselachse ausgerichtete Element-Box (element_box_mm, - cfg/export.cfg [Boundingbox]). + ist wie bei allen Zeilen 1; Nachbarn = die beiden Kreisel-IDs (durch den + Kreisel-Umlauf ggf. bereits um die eigentlichen Umlauf-Nachbarn ergaenzt/ + ersetzt, siehe process_blocks); K1-K4 und Insertpoint bleiben leer; + Position = Beruehrkoordinaten; Boundingbox = die feste, an der + Kreiselachse ausgerichtete Element-Box (element_box_mm, cfg/export.cfg + [Boundingbox]). - Rueckgabe: fortgeschriebene Elementnummer (start_elem_nr + Anzahl Weichen). + Rueckgabe: (fortgeschriebene Elementnummer, dict switches-"key" -> erzeugtes + Item) - die Key-Zuordnung braucht process_blocks, um nach dem Kreisel- + Umlauf die tatsaechliche "Nachbarn"-Spalte der Weiche zu setzen. """ - switches = compute_kreisel_touch_switches( - items, NEIGHBOR_TOLERANCE_MM, durchmesser_mm=KREISEL_DURCHMESSER_MM, - element_box_mm=ELEMENT_BOX_MM, dbg=dbg) - naechste_id = max_numeric_teileid(items) elem_nr = start_elem_nr + weiche_by_key = {} for n, sw in enumerate(switches, start=1): elem_nr += 1 naechste_id += 1 teileid = f"{naechste_id:04d}" planquadrat = (compute_planquadrat(sw["x"], sw["y"], planquadrat_cfg) if planquadrat_cfg is not None else "") - items.append({ + item = { "nr": elem_nr, "teileart": WEICHE_TEILEART, "teileid": teileid, @@ -527,8 +563,10 @@ def build_kreisel_weiche_items(items, planquadrat_cfg, start_elem_nr, dbg=None): "Achse von Kreisel": sw["achse_von"], "Beruehrung": sw["beruehrung"], }, - }) - return elem_nr + } + items.append(item) + weiche_by_key[sw["key"]] = item + return elem_nr, weiche_by_key def _strecke_typ_feld(teileart): @@ -539,7 +577,8 @@ def _strecke_typ_feld(teileart): return "Strecke" if teileart == "ILS 2.0 Gefaellestrecke" else "Förderer" -def build_strecke_schleus_items(items, planquadrat_cfg, start_elem_nr, sep_kette=None, dbg=None): +def build_strecke_schleus_items(items, planquadrat_cfg, start_elem_nr, sep_kette=None, + sep_kette_by_key=None, dbg=None): """Haengt fuer jedes Strecken-Ende mit anschliessendem Kreisel eine "ILS Ausschleuselement"- (Anfang) bzw. "ILS Einschleuselement"-Zeile (Ende) an items an (siehe export_neighbors.compute_strecke_kreisel_schleus @@ -553,18 +592,29 @@ def build_strecke_schleus_items(items, planquadrat_cfg, start_elem_nr, sep_kette sep_kette = Rueckgabe von export_neighbors.compute_sep_kette (keys "#" -> Eintrag mit typ/vorgaenger/nachfolger). Traegt die zugehoerige Strecke eine "sepliste" (neue LISP-XDATA, siehe - ssg-sepliste-xdata-schreiben), enthaelt "Nachbarn" NUR noch die IDs des - ketteninternen Vorgaengers/Nachfolgers (Separator oder je anderem - Kreisel-Ende) statt Kreisel-ID + Strecken-ID; die Kreisel-/Foerderer- - Zugehoerigkeit steht dann stattdessen in den Merkmalen ("Kreisel" + - "Förderer"/"Strecke" je Typ, analog zum "Zuordnung"-Feld der Separatoren). - Fehlt die sepliste (Altbestand-Wrapper ohne die neue XDATA), bleibt der - bisherige Nachbarn-Inhalt [kreisel_id, strecke_id] unveraendert erhalten. + ssg-sepliste-xdata-schreiben), bleibt "Nachbarn" hier zunaechst LEER und + der sep_kette-Schluessel dieser Zeile wird stattdessen in + sep_kette_by_key (dict, vom Aufrufer bereitgestellt und HIER befuellt) + eingetragen - process_blocks loest daraus NACH der Registrierung ALLER + SEP/AS/ES-Schluessel (auch der von map_separator_kette_items) die + tatsaechlichen TeileIds auf (eigener Block am Ende von process_blocks, + direkt nach beiden Aufrufen). Ein sep_kette-Schluessel ist naemlich KEINE TeileId, + sondern nur waehrend des Baus eindeutig - + ihn direkt in die CSV zu schreiben waere ein Bug (zeigte frueher auf + "#" statt auf den eigentlichen Nachbarn). Die + Kreisel-/Foerderer-Zugehoerigkeit steht bei sepliste-Zeilen stattdessen + in den Merkmalen ("Kreisel" + "Förderer"/"Strecke" je Typ, analog zum + "Zuordnung"-Feld der Separatoren). Fehlt die sepliste (Altbestand-Wrapper + ohne die neue XDATA), bleibt der bisherige Nachbarn-Inhalt + [kreisel_id, strecke_id] unveraendert erhalten (sofort aufgeloest, kein + sep_kette-Schluessel involviert). Rueckgabe: fortgeschriebene Elementnummer. """ if sep_kette is None: sep_kette = {} + if sep_kette_by_key is None: + sep_kette_by_key = {} schleus, warnings = compute_strecke_kreisel_schleus( items, durchmesser_mm=KREISEL_DURCHMESSER_MM, element_box_mm=ELEMENT_BOX_MM, dbg=dbg) @@ -595,14 +645,18 @@ def build_strecke_schleus_items(items, planquadrat_cfg, start_elem_nr, sep_kette strecke = strecke_by_id.get(sp["strecke_id"]) sepliste = strecke.get("sepliste") if strecke else None merkmale = {"Erzeugt aus": "Kreisel-Strecke-Kollision"} + sep_kette_key = None if sepliste: # Neue XDATA vorhanden: Nachbarn nur noch aus der Ketten-internen # Vorgaenger/Nachfolger-Beziehung (AS/ES ist immer das erste bzw. - # letzte Sepliste-Element seiner Strecke). + # letzte Sepliste-Element seiner Strecke). Die Keys (vorgaenger/ + # nachfolger) sind sep_kette-interne Schluessel, KEINE fertigen + # TeileIds - erst nach dem Bau ALLER SEP/AS/ES-Zeilen dieser Kette + # aufloesbar (siehe process_blocks, Abschnitt nach beiden Aufrufen, + # analog zum Kreisel-Umlauf/Weichen-Muster). lfdnr = sepliste[0]["lfdnr"] if sp["ende_label"] == "Anfang" else sepliste[-1]["lfdnr"] - key = f"{sp['strecke_id']}#{lfdnr}" - eintrag = sep_kette.get(key, {}) - nachbarn = [n for n in (eintrag.get("vorgaenger"), eintrag.get("nachfolger")) if n] + sep_kette_key = f"{sp['strecke_id']}#{lfdnr}" + nachbarn = [] # in process_blocks nachgetragen merkmale["Kreisel"] = sp["kreisel_id"] merkmale[_strecke_typ_feld(strecke.get("teileart", ""))] = sp["strecke_id"] else: @@ -611,7 +665,7 @@ def build_strecke_schleus_items(items, planquadrat_cfg, start_elem_nr, sep_kette merkmale["Strecke"] = sp["strecke_id"] merkmale["Streckenende"] = sp["ende_label"] - items.append({ + item = { "nr": elem_nr, "teileart": teileart, "teileid": teileid, @@ -624,63 +678,145 @@ def build_strecke_schleus_items(items, planquadrat_cfg, start_elem_nr, sep_kette "nachbarn": ", ".join(nachbarn), "fehler": "", "merkmale": merkmale, - }) + } + items.append(item) + if sep_kette_key is not None: + sep_kette_by_key[sep_kette_key] = item return elem_nr -def build_separator_kette_items(items, planquadrat_cfg, start_elem_nr, sep_kette, dbg=None): - """Haengt fuer jeden in einer VF_n/GF_n-Kette eingebetteten Separator - ("Staustrecke_Separator_SP_300_mm", ueber die neue "sepliste"-XDATA - bekannt - siehe ssg-sepliste-xdata-schreiben/compute_sep_kette) eine - eigene "ILS 2.0 Separator"-Zeile an. Bisher wurden diese internen - Ketten-Separatoren nur gezaehlt (ANZAHL_SEPARATOR), nicht einzeln - exportiert - anders als frei platzierte Separator_SP-Symbole. +def map_separator_kette_items(items, sep_kette, sep_kette_by_key=None, dbg=None): + """Ordnet jeden in einer VF_n/GF_n-Kette eingebetteten Separator + (sepliste-Eintrag typ "SEP", siehe compute_sep_kette) dem BEREITS + vorhandenen Separator-Item zu und traegt es unter seinem sep_kette- + Schluessel in sep_kette_by_key ein - fuer die Nachbar-Aufloesung in + resolve_umlauf_und_sepliste_nachbarn. - Nachbarn = ketteninterner Vorgaenger/Nachfolger (Separator oder AS/ES), - analog zur AS/ES-Nachbarn-Spalte in build_strecke_schleus_items. - Merkmale bekommen "Zuordnung" = Strecken-TeileId (wie bei frei - platzierten Separatoren ueber compute_sensor_zuordnung). + WICHTIG - erzeugt KEINE neuen Zeilen (frueher tat das + build_separator_kette_items): die in einer Kette verpackten Separatoren + liegen bereits als ECHTE Separator_SP-INSERTs in der Zeichnung - der + LISP-Export fuegt fuer jedes verpackte Symbol eine temporaere Kopie ein + (csv:sep-proxies-erzeugen, export.lsp), die den normalen freien-Separator- + Pfad in process_blocks durchlaeuft (mit echter vla-getboundingbox-Box, ID + und fest gesetzter ZUORDNUNG = Wrapper-ID ueber "zuordnung_fix"). Beide + Wege wuerden sonst dieselben physischen Separatoren DOPPELT zaehlen (26 + Proxy-INSERTs + 26 sepliste-Zeilen = 64 statt 38). Die sepliste liefert + hier nur noch die REIHENFOLGE (Vorgaenger/Nachfolger), nicht die Zeilen. - Rueckgabe: fortgeschriebene Elementnummer. + Zuordnung sepliste-SEP -> vorhandenes Separator-Item: ueber die + Wrapper-ID (Item-Merkmal "Zuordnung" == sep_kette-Eintrag "strecke_id", + fixiert durch den LISP-Proxy) UND den naechstgelegenen INSERT-Punkt + (Item-Felder "_x"/"_y" vs. sepliste-Koordinate x/y - beide sind der rohe + Sub-INSERT-Einfuegepunkt aus derselben Bauphase, daher deckungsgleich; + verifiziert 26/26 <300mm). Reicht der Wrapper mehrere Separatoren, trennt + der INSERT-Punkt sie; bei nur einem ist die Wrapper-ID schon eindeutig. + + Ein sepliste-SEP ohne passendes Item (sollte nicht vorkommen, da der Proxy + jeden verpackten Separator einfuegt) wird uebersprungen (dbg-Hinweis). """ - strecke_by_id = {it.get("teileid", ""): it for it in items - if it.get("teileart", "") in GF_VF_TEILEARTEN} + if sep_kette_by_key is None: + sep_kette_by_key = {} + # Vorhandene Separator-Items nach Wrapper-Zuordnung gruppieren (nur die mit + # fixierter Zuordnung = die Proxy-Kopien verpackter Ketten-Separatoren; + # frei platzierte Separatoren tragen keine sepliste und stoeren nicht). + sep_items_by_zuordnung = {} + for it in items: + if it.get("teileart", "") != "ILS 2.0 Separator": + continue + zuordnung = it.get("merkmale", {}).get("Zuordnung", "") + if zuordnung: + sep_items_by_zuordnung.setdefault(zuordnung, []).append(it) - naechste_id = max_numeric_teileid(items) - elem_nr = start_elem_nr - zaehler = 0 for key, eintrag in sep_kette.items(): if eintrag.get("typ") != "SEP": continue - elem_nr += 1 - naechste_id += 1 - zaehler += 1 - teileid = f"{naechste_id:04d}" - planquadrat = (compute_planquadrat(eintrag["x"], eintrag["y"], planquadrat_cfg) - if planquadrat_cfg is not None else "") - nachbarn = [n for n in (eintrag.get("vorgaenger"), eintrag.get("nachfolger")) if n] - strecke = strecke_by_id.get(eintrag["strecke_id"]) - merkmale = { - "Erzeugt aus": "VF/GF-Sepliste", - "Zuordnung": eintrag["strecke_id"], - } - if strecke: - merkmale[_strecke_typ_feld(strecke.get("teileart", ""))] = eintrag["strecke_id"] - items.append({ - "nr": elem_nr, - "teileart": "ILS 2.0 Separator", - "teileid": teileid, - "bezeichnung": f"Separator :{zaehler}", - "planquadrat": planquadrat, - "position": f'{eintrag["x"]:.2f}, {eintrag["y"]:.2f}, 0.00', - "boundingbox": "", - "insertpoint": "", - "k1": "", "k2": "", "k3": "", "k4": "", - "nachbarn": ", ".join(nachbarn), - "fehler": "", - "merkmale": merkmale, - }) - return elem_nr + kandidaten = sep_items_by_zuordnung.get(eintrag["strecke_id"], []) + if not kandidaten: + if dbg: + dbg(f" sepliste-SEP {key}: kein Separator-Item mit Zuordnung " + f"{eintrag['strecke_id']!r} gefunden - uebersprungen") + continue + # Naechster INSERT-Punkt zur sepliste-Koordinate. + sx, sy = eintrag.get("x", 0.0), eintrag.get("y", 0.0) + best = min(kandidaten, + key=lambda it: math.hypot(it.get("_x", 0.0) - sx, + it.get("_y", 0.0) - sy)) + sep_kette_by_key[key] = best + if dbg: + dbg(f" sepliste-SEP {key} -> Separator-Item TeileId " + f"{best.get('teileid', '')!r}") + return sep_kette_by_key + + +def resolve_umlauf_und_sepliste_nachbarn(items, kreisel_umlauf, sep_kette, + sep_kette_by_key, weiche_by_key): + """Loest die "Nachbarn"-Spalte aller Zeilen auf, die build_kreisel_weiche_items/ + build_strecke_schleus_items/map_separator_kette_items zunaechst leer + gelassen (bzw. deren Item nur registriert) haben, weil ihr(e) Nachbar(n) + beim eigenen Bau/der Registrierung noch nicht als TeileId feststand(en) + (Weiche vs. Separator im Kreisel-Umlauf, oder eine sepliste-Zeile, deren + Nachfolger erst danach registriert wird). + + Muss NACH allen drei Aufrufen laufen (ihre TeileIds stehen erst dann + fest). items wird IN-PLACE veraendert (item["nachbarn"]). + + kreisel_umlauf = Rueckgabe von export_neighbors.compute_kreisel_umlauf. + sep_kette = Rueckgabe von export_neighbors.compute_sep_kette. + sep_kette_by_key = dict sep_kette-Schluessel -> Item (befuellt von + build_strecke_schleus_items UND + map_separator_kette_items - DIESELBE dict fuer beide, + siehe process_blocks: ein sep_kette-Nachbar kann in der + jeweils anderen Funktion registriert worden sein). + weiche_by_key = dict switches-"key" -> erzeugtes Item (von + build_kreisel_weiche_items). + """ + # Gemeinsamer Lookup fuer BEIDE Schluesselarten, die in kreisel_umlauf und + # sep_kette als punkt_key/vorgaenger/nachfolger auftreten koennen: freie + # Separatoren (TeileId), Kreisel-Kreisel-Weichen (weiche_by_key) UND + # sepliste-Zeilen (sep_kette_by_key, Schluessel "#"). + # Ein Umlauf-Punkt kann naemlich ein AS/ES-Ende sein (sep_kette-Schluessel) + # und ein sep_kette-Vorgaenger/Nachfolger kann das freie Kreiselende gar + # nicht sein (das loest ausschliesslich compute_kreisel_umlauf auf) - erst + # der gemeinsame Lookup deckt alle Kombinationen ab. + separator_by_id = {it.get("teileid", ""): it for it in items + if it.get("teileart", "") == "ILS 2.0 Separator"} + alle_schluessel = {**sep_kette_by_key, **weiche_by_key, **separator_by_id} + + # Freie Separatoren, Weichen UND die AS/ES-Enden andockender Ketten + # bekommen ihre "Nachbarn"-Spalte aus dem Kreisel-Umlauf. + if kreisel_umlauf: + for punkte in kreisel_umlauf.values(): + for punkt_key, vorgaenger, nachfolger in punkte: + item = alle_schluessel.get(punkt_key) + if item is None: + continue + nachbarn = [] + for nachbar_key in (vorgaenger, nachfolger): + if not nachbar_key: + continue + nachbar_item = alle_schluessel.get(nachbar_key) + if nachbar_item is not None: + nachbarn.append(nachbar_item.get("teileid", "")) + if nachbarn: + item["nachbarn"] = ", ".join(nachbarn) + + # Ketteninterne sepliste-Nachbarn (SEP <-> SEP, SEP <-> AS/ES) - das + # jeweilige Kettenende (vorgaenger/nachfolger ist None, z.B. das AS-Ende + # ohne SEP davor) bleibt hier unveraendert, es wird stattdessen oben vom + # Kreisel-Umlauf gesetzt (compute_sep_kette dokumentiert diese Aufteilung). + for key, eintrag in sep_kette.items(): + item = sep_kette_by_key.get(key) + if item is None: + continue + nachbarn = [] + for nachbar_key in (eintrag.get("vorgaenger"), eintrag.get("nachfolger")): + if not nachbar_key: + continue + nachbar_item = alle_schluessel.get(nachbar_key) + if nachbar_item is not None: + nachbarn.append(nachbar_item.get("teileid", "")) + if nachbarn: + item["nachbarn"] = ", ".join(nachbarn) def process_blocks(blocks, lookup, dbg=None): @@ -792,6 +928,13 @@ def process_blocks(blocks, lookup, dbg=None): # Bestimmung der Ein-/Ausschleuselemente (compute_strecke_kreisel_schleus) "x": block.get("x", 0.0), "y": block.get("y", 0.0), + # Sepliste-XDATA (AS/SEP/ES-Reihenfolge) durchreichen - Quelle + # fuer compute_sep_kette/map_separator_kette_items (Ketten- + # interne Separatoren + AS/ES-Nachbarn). Ohne diese Weitergabe + # liefe die gesamte sepliste-basierte Nachbarverkettung ins + # Leere (das Feld stand im JSON, wurde aber nicht ans Item + # uebernommen). + "sepliste": block.get("sepliste"), **bbox_columns(block), }) continue @@ -811,6 +954,8 @@ def process_blocks(blocks, lookup, dbg=None): # Bestimmung der Ein-/Ausschleuselemente (compute_strecke_kreisel_schleus) "x": block.get("x", 0.0), "y": block.get("y", 0.0), + # Sepliste-XDATA durchreichen (siehe VF_N oben). + "sepliste": block.get("sepliste"), **bbox_columns(block), }) continue @@ -883,6 +1028,14 @@ def process_blocks(blocks, lookup, dbg=None): if matches_any(bname, BLOCKPATTERNS.get("pattern_separator", [])): elem_nr += 1 separator_count += 1 + cols = bbox_columns(block) + # Fehlende Bounding-Box (vla-getboundingbox scheiterte, z.B. + # eingefrorener Layer) durch die feste Separator-Symbol-Box aus + # cfg [Boundingbox] separator_box_* ersetzen - sonst nimmt der + # Separator an der Nachbarschafts-/Umlauf-/Zuordnungserkennung + # nicht teil (die brauchen "_bbox"). Position/Drehung des realen + # INSERTs sind ja bekannt. + cols = _fallback_separator_bbox(cols, block) items.append({ "nr": elem_nr, "teileart": "ILS 2.0 Separator", @@ -894,7 +1047,12 @@ def process_blocks(blocks, lookup, dbg=None): # Zuordnung, die compute_sensor_zuordnung unten nicht # ueberschreiben darf - siehe build_sensor_merkmale. "_zuordnung_fix": bool(block.get("zuordnung_fix")), - **bbox_columns(block), + # Roher INSERT-Punkt (nicht der bbox-Mittelpunkt) - dient + # map_separator_kette_items zum Zuordnen dieses (Proxy-) + # Separators zu seinem sepliste-Eintrag (Match ueber + # Wrapper-ID + naechster INSERT-Punkt, siehe dort). + "_x": block.get("x", 0.0), "_y": block.get("y", 0.0), + **cols, }) continue @@ -1020,37 +1178,46 @@ def process_blocks(blocks, lookup, dbg=None): # Strecke eine sepliste traegt (reiner Altbestand ohne neue XDATA). sep_kette = compute_sep_kette(items, dbg=dbg) + # Kreisel-Kreisel-Weichen VOR dem Umlauf berechnen (reine Geometrie, + # braucht keine TeileIds) - dieselbe Liste geht sowohl in + # compute_kreisel_umlauf (damit die Weiche als Verzweigungspunkt in + # BEIDEN beruehrenden Kreisel-Umlaeufen auftaucht) als auch in + # build_kreisel_weiche_items (das die tatsaechlichen Zeilen erzeugt). + touch_switches = compute_kreisel_touch_switches( + items, NEIGHBOR_TOLERANCE_MM, durchmesser_mm=KREISEL_DURCHMESSER_MM, + element_box_mm=ELEMENT_BOX_MM, dbg=dbg) + # Umlauf-Reihenfolge an jedem Kreisel: freie Separatoren (per Zuordnung - # oben bereits einem Kreisel zugeordnet) UND die AS/ES-Enden andockender - # Ketten (aus sep_kette), sortiert nach Winkel um die Kreiselachse (siehe - # compute_kreisel_umlauf - DREHRICHTUNG-Attribut bestimmt den Umlaufsinn). - # Freie Separator-Zeilen bekommen ihre "Nachbarn"-Spalte hier aus dem - # Umlauf statt leer zu bleiben; die AS/ES-Nachbarn selbst setzt weiterhin - # build_strecke_schleus_items (ketteninterner Vorgaenger/Nachfolger). + # oben bereits einem Kreisel zugeordnet), die AS/ES-Enden andockender + # Ketten (aus sep_kette) UND die Kreisel-Kreisel-Weichen (touch_switches), + # sortiert nach Winkel um die Kreiselachse (siehe compute_kreisel_umlauf - + # DREHRICHTUNG-Attribut bestimmt den Umlaufsinn). kreisel_umlauf = compute_kreisel_umlauf( items, sep_kette, NEIGHBOR_TOLERANCE_MM, - durchmesser_mm=KREISEL_DURCHMESSER_MM, dbg=dbg) - if kreisel_umlauf: - separator_by_id = {it.get("teileid", ""): it for it in items - if it.get("teileart", "") == "ILS 2.0 Separator"} - for punkte in kreisel_umlauf.values(): - for punkt_key, vorgaenger, nachfolger in punkte: - item = separator_by_id.get(punkt_key) - if item is None: - continue - nachbarn = [n for n in (vorgaenger, nachfolger) if n] - item["nachbarn"] = ", ".join(nachbarn) + durchmesser_mm=KREISEL_DURCHMESSER_MM, touch_switches=touch_switches, dbg=dbg) - # Nach der Kollisions-/Nachbarschaftserkennung: an jedem Kreisel- - # Beruehrpunkt eine ILS-Weiche anhaengen (eigene Zeilen am Listenende - - # sie nehmen an der Nachbarschaftserkennung selbst nicht teil, ihre - # Nachbarn sind fest die beiden beruehrenden Kreisel). Danach an jedem - # Strecken-Ende mit anschliessendem Kreisel ein Aus-/Einschleuselement, - # gefolgt von je einer Zeile pro in einer Kette eingebettetem Separator - - # die TeileId-Zaehlung laeuft ueber alle drei hinweg weiter. - elem_nr = build_kreisel_weiche_items(items, planquadrat_cfg, elem_nr, dbg=dbg) - elem_nr = build_strecke_schleus_items(items, planquadrat_cfg, elem_nr, sep_kette=sep_kette, dbg=dbg) - build_separator_kette_items(items, planquadrat_cfg, elem_nr, sep_kette, dbg=dbg) + # Neue Zeilen, deren "Nachbarn"-Spalte aus einem sep_kette-Schluessel + # aufgeloest werden muss, erzeugen: Kreisel-Kreisel-Weichen, dann Aus-/ + # Einschleuselemente (AS/ES). Ein sep_kette-Schluessel kann auf eine Zeile + # zeigen, die ERST DANACH registriert wird, darum erst NACH allen + # Registrierungen aufloesen (siehe unten) statt inline - frueherer Bug + # schrieb sonst den rohen Schluessel ("0026#3") statt der TeileId. + elem_nr, weiche_by_key = build_kreisel_weiche_items( + items, planquadrat_cfg, elem_nr, touch_switches, dbg=dbg) + sep_kette_by_key = {} + elem_nr = build_strecke_schleus_items( + items, planquadrat_cfg, elem_nr, sep_kette=sep_kette, + sep_kette_by_key=sep_kette_by_key, dbg=dbg) + # Die in einer Kette verpackten Separatoren erzeugen KEINE eigenen Zeilen - + # sie liegen bereits als (Proxy-)Separator_SP-Items vor (freier-Separator- + # Pfad oben). map_separator_kette_items ordnet ihnen nur ihren sepliste- + # Schluessel zu, damit die Nachbar-Reihenfolge (AS -> SEP -> ES) auf die + # vorhandenen Items angewandt werden kann (kein Doppel-Export). + map_separator_kette_items( + items, sep_kette, sep_kette_by_key=sep_kette_by_key, dbg=dbg) + + resolve_umlauf_und_sepliste_nachbarn( + items, kreisel_umlauf, sep_kette, sep_kette_by_key, weiche_by_key) # Nach dem Sammelheimen aller Zeilen: sortiert nach TeileId ausgeben, damit # Elementnummer (erste Spalte) und TeileId nach Moeglichkeit uebereinstimmen diff --git a/lib/export_neighbors.py b/lib/export_neighbors.py index 58d98a9..0761ee1 100644 --- a/lib/export_neighbors.py +++ b/lib/export_neighbors.py @@ -121,6 +121,56 @@ def load_element_box_mm(cfg_path=None): parser.getfloat("Boundingbox", "element_box_hoehe_mm", fallback=WEICHE_BOX_HOEHE_MM), ) + +# Fallback-Masse (mm) der festen Separator-Symbol-Bounding-Box, falls +# cfg/export.cfg [Boundingbox] separator_box_* nicht gesetzt/lesbar ist (siehe +# load_separator_box_mm). LAENGE laengs des Symbols (bei Drehung 0 entlang X), +# BREITE quer, HOEHE = Z. Gemessenes Separator_SP-Symbol (~210 x 150 x 14 mm). +SEPARATOR_BOX_LAENGE_MM = 210.0 +SEPARATOR_BOX_BREITE_MM = 150.0 +SEPARATOR_BOX_HOEHE_MM = 14.0 + + +def load_separator_box_mm(cfg_path=None): + """Feste Bounding-Box-Masse (Laenge, Breite, Hoehe in mm) eines Separator- + Symbols aus cfg/export.cfg [Boundingbox] separator_box_laenge_mm / + _breite_mm / _hoehe_mm. Gebraucht fuer die in einer VF_n/GF_n-Kette + eingebetteten Separatoren (sepliste-XDATA), die kein reales INSERT mehr + sind und darum von vla-getboundingbox keine Box bekommen. Fallback auf + SEPARATOR_BOX_*_MM, falls die Sektion/Schluessel fehlen. + Rueckgabe: (laenge, breite, hoehe).""" + if cfg_path is None: + cfg_path = cfg_path_from_env() + parser = load_export_cfg(cfg_path) + return ( + parser.getfloat("Boundingbox", "separator_box_laenge_mm", fallback=SEPARATOR_BOX_LAENGE_MM), + parser.getfloat("Boundingbox", "separator_box_breite_mm", fallback=SEPARATOR_BOX_BREITE_MM), + parser.getfloat("Boundingbox", "separator_box_hoehe_mm", fallback=SEPARATOR_BOX_HOEHE_MM), + ) + + +def separator_bbox(x, y, rotation_grad, separator_box_mm=None, z=0.0): + """Achsparallele Welt-Bounding-Box (_bbox-dict) eines Separator-Symbols an + Weltposition (x, y) mit Drehung rotation_grad. Die feste Symbol-Box + (separator_box_mm = (laenge, breite, hoehe)) wird um rotation_grad gedreht + und ihre achsparallele Welt-Huelle zurueckgegeben - fuer eingebettete + sepliste-Separatoren, die keine echte Zeichnungsgeometrie haben. + + Rueckgabe: dict {"cx","cy","cz","dx","dy","dz"} wie csv:get-bbox / die + "_bbox" der realen Bloecke (siehe export_csv.bbox_columns).""" + if separator_box_mm is None: + separator_box_mm = load_separator_box_mm() + laenge, breite, hoehe = separator_box_mm + # Laenge liegt bei Drehung 0 entlang X, Breite entlang Y (anders als + # _oriented_box_aabb, das die Laengsseite QUER zur Achse legt - hier ist + # es die reine Symbol-AABB, konsistent mit der gemessenen Referenz). + rot = math.radians(rotation_grad or 0.0) + c, s = abs(math.cos(rot)), abs(math.sin(rot)) + dx = laenge * c + breite * s + dy = laenge * s + breite * c + return {"cx": x, "cy": y, "cz": z, "dx": dx, "dy": dy, "dz": hoehe} + + # Mindestanzahl Partner (Nachbarn) je TeileArt fuer die Fehlerspalte "Fehler" # (siehe compute_neighbor_errors): Kreisel/Eckrad und Omniflo-Elemente # brauchen mindestens einen Partner, Gefaellestrecke/Foerderer/Strecke-Modul @@ -930,7 +980,13 @@ def compute_kreisel_touch_switches(items, tolerance_mm, durchmesser_mm=800.0, Rueckgabe: Liste von dicts (in items-Reihenfolge der Paare), je erzeugte Weiche: - {"x","y","z": Beruehrpunkt (mm), + {"key": "WEICHE##" - stabiler Schluessel, ueber den + compute_kreisel_umlauf die Weiche in BEIDE beruehrenden Kreisel- + Umlaeufe einhaengt (die Weiche gehoert als Verzweigungspunkt zu + beiden, anders als ein Separator oder ein AS/ES-Ende) UND + build_kreisel_weiche_items die zugehoerige TeileId nach dem Umlauf- + Aufbau wiederfindet, + "x","y","z": Beruehrpunkt (mm), "dx","dy","dz": Welt-AABB der ausgerichteten Box (mm), "nachbarn": [teileid_a, teileid_b], "achse_von": teileid des orientierungsgebenden Kreisels, @@ -987,6 +1043,7 @@ def compute_kreisel_touch_switches(items, tolerance_mm, durchmesser_mm=800.0, dx, dy, dz = _oriented_box_aabb(achse_rot, box_l, box_b, box_h) switches.append({ + "key": f"WEICHE#{id_a}#{id_b}", "x": tx, "y": ty, "z": tz, "dx": dx, "dy": dy, "dz": dz, "nachbarn": [id_a, id_b], @@ -1285,7 +1342,7 @@ def compute_sep_kette(items, dbg=None): Jeder Sepliste-Eintrag bekommt eine (innerhalb dieser Kette eindeutige) Schluessel-ID "#" - das ist die ID, mit der - build_strecke_schleus_items/build_separator_kette_items die spaeteren + build_strecke_schleus_items/map_separator_kette_items die spaeteren globalen TeileIds verknuepft (siehe export_csv.py). Vorgaenger/Nachfolger sind schlicht der vorherige/naechste Eintrag in der Sepliste (die bereits in Baureihenfolge vorliegt) - kein Rateverfahren noetig. @@ -1320,13 +1377,23 @@ def compute_sep_kette(items, dbg=None): return result -def compute_kreisel_umlauf(items, sep_kette, tolerance_mm, durchmesser_mm=800.0, dbg=None): +def compute_kreisel_umlauf(items, sep_kette, tolerance_mm, durchmesser_mm=800.0, + touch_switches=None, dbg=None): """Bringt fuer jeden echten Kreisel (KREISEL_SPLIT_TEILEART) alle dort liegenden Punkte - frei platzierte Separatoren (per compute_sensor_ - zuordnung bereits einer Kreiselhaelfte zugeordnet) UND die AS/ES-Enden + zuordnung bereits einer Kreiselhaelfte zugeordnet), die AS/ES-Enden aller andockenden VF_n/GF_n-Ketten (aus sep_kette, per BBox-Naehe wie - compute_strecke_kreisel_schleus zugeordnet) - in eine geschlossene - Umlauf-Reihenfolge (zirkulaer, siehe DREHRICHTUNG-Attribut). + compute_strecke_kreisel_schleus zugeordnet) UND die Kreisel-Kreisel- + Weichen (touch_switches, siehe compute_kreisel_touch_switches) - in eine + geschlossene Umlauf-Reihenfolge (zirkulaer, siehe DREHRICHTUNG-Attribut). + + Eine Kreisel-Kreisel-Weiche liegt (anders als ein Separator oder ein + AS/ES-Ende) auf GENAU EINEM Punkt, gehoert aber zu ZWEI Kreiseln - man + kann von Kreisel A zu Kreisel B UND umgekehrt wechseln. Sie wird darum + in punkte_je_kreisel BEIDER beruehrender Kreisel eingetragen (gleiche + Weltposition, gleicher "key" - siehe touch_switches), damit sie im + Umlauf jedes der beiden Kreisel zwischen den jeweils angrenzenden + Separatoren/AS-ES-Enden auftaucht statt spurlos zu fehlen. Winkel wird um den Kapsel-Mittelpunkt (Mitte AN8-/SP8-Achse, siehe _kreisel_capsule) gemessen, 0 Grad = Kapsel-Achsrichtung. UZS @@ -1336,12 +1403,15 @@ def compute_kreisel_umlauf(items, sep_kette, tolerance_mm, durchmesser_mm=800.0, items = dieselbe Liste wie bei compute_neighbor_ids/compute_sensor_ zuordnung. sep_kette = Rueckgabe von compute_sep_kette (fuer die AS/ES- - Punkte: x/y + strecke_id). + Punkte: x/y + strecke_id). touch_switches = Rueckgabe von + compute_kreisel_touch_switches (None/leer = wie bisher ohne Weichen im + Umlauf). Rueckgabe: dict {kreisel_teileid: [(punkt_key, vorgaenger_key, - nachfolger_key), ...]} in Umlaufreihenfolge - punkt_key ist entweder eine - Separator-TeileId (freie Separatoren) oder ein sep_kette-Schluessel - (AS/ES-Enden). Kreisel ohne zugeordnete Punkte liefern eine leere Liste. + nachfolger_key), ...]} in Umlaufreihenfolge - punkt_key ist eine + Separator-TeileId (freie Separatoren), ein sep_kette-Schluessel (AS/ES- + Enden) oder ein touch_switches-"key" (Kreisel-Kreisel-Weiche). Kreisel + ohne zugeordnete Punkte liefern eine leere Liste. """ half_tol = tolerance_mm / 2.0 kreisel = {} @@ -1355,13 +1425,27 @@ def compute_kreisel_umlauf(items, sep_kette, tolerance_mm, durchmesser_mm=800.0, # bestimmbar, wie compute_sensor_zuordnung es fuer die "Zuordnung"-Spalte # tut - hier direkt gegen die volle Kreisel-BBox statt der Haelften, weil # nur "gehoert zu diesem Kreisel" gebraucht wird, nicht links/rechts). + # + # Achsparallele Welt-AABB der Kapsel (a/b + Radius je Achse) statt einer + # Box mit fest "dx=durchmesser+achs_len, dy=durchmesser" - letzteres + # nimmt STILLSCHWEIGEND an, die Kreiselachse liegt entlang Welt-X. Bei + # einem um 90 Grad gedrehten Kreisel (Achse entlang Welt-Y, z.B. ein + # 20m-Kreisel laengs der Halle) drehte sich damit auch die Box um 90 Grad + # gegen die tatsaechliche Geometrie - schmal in Y (dort, wo der Kreisel in + # Wahrheit 20m lang ist) und ueberbreit in X (dort, wo er nur + # durchmesser_mm misst). Ergebnis: entfernte Punkte wurden faelschlich + # als "auf dem Kreisel" erkannt, waehrend tatsaechlich anliegende + # Separatoren durchfielen (realer Bug-Fall: Mubea, Kreisel 0002). kreisel_bounds = {} for tid, (cap, _dr) in kreisel.items(): - acx = (cap["a"][0] + cap["b"][0]) / 2.0 - acy = (cap["a"][1] + cap["b"][1]) / 2.0 - achs_len = math.hypot(cap["b"][0] - cap["a"][0], cap["b"][1] - cap["a"][1]) + r = cap["r"] + ax, ay = cap["a"] + bx, by = cap["b"] + minx, maxx = min(ax, bx) - r, max(ax, bx) + r + miny, maxy = min(ay, by) - r, max(ay, by) + r kreisel_bounds[tid] = _bounds( - {"cx": acx, "cy": acy, "dx": durchmesser_mm + achs_len, "dy": durchmesser_mm}, + {"cx": (minx + maxx) / 2.0, "cy": (miny + maxy) / 2.0, + "dx": maxx - minx, "dy": maxy - miny}, half_tol) punkte_je_kreisel = {tid: [] for tid in kreisel} @@ -1395,6 +1479,15 @@ def compute_kreisel_umlauf(items, sep_kette, tolerance_mm, durchmesser_mm=800.0, if best_tid is not None: punkte_je_kreisel[best_tid].append((key, eintrag["x"], eintrag["y"])) + # Kreisel-Kreisel-Weichen: die beiden beruehrenden Kreisel-IDs stehen + # bereits in sw["nachbarn"] (siehe compute_kreisel_touch_switches) - kein + # Naeherungsverfahren wie bei Separator/AS/ES noetig, die Weiche wird in + # BEIDE Umlaeufe eingetragen. + for sw in (touch_switches or []): + for tid in sw.get("nachbarn", []): + if tid in punkte_je_kreisel: + punkte_je_kreisel[tid].append((sw["key"], sw["x"], sw["y"])) + result = {} for tid, punkte in punkte_je_kreisel.items(): cap, drehrichtung = kreisel[tid] diff --git a/tests/reference/mubea_tests_export.csv b/tests/reference/mubea_tests_export.csv index 6a2bb63..57fae1d 100644 --- a/tests/reference/mubea_tests_export.csv +++ b/tests/reference/mubea_tests_export.csv @@ -1,123 +1,123 @@ Elementnummer;TeileArt;TeileId;Bezeichnung;Planquadrat;Anzahl;Position;Boundingbox;Insertpoint;K1;K2;K3;K4;Nachbarn;Fehler;Warnungen;Merkmale -1;"ILS 2.0 Kreisel";"0001";"Kreisel :3";"A/1-D/1";1;"3300.00, -5478.00, 1467.00";"5800.00, 800.00, 1.00";"BhqArGmQFmJ4AAAAAAAAAAAA";"";"";"";"";"0002-R";"";"";{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "5.0", "Anzahl der Separatoren": "2", "Kreiselart": "STANDARD", "Anzahl der Scanner": "1", "Anzahl der Rampen": "0", "Höhe in m": "1.47", "Drehrichtung": "UZS", "Drehung": 0, "Name": "Kreisel9", "Geruest fuer Einzelmodul": true} -2;"ILS 2.0 Kreisel";"0002";"Kreisel :2";"A/1-A/11";1;"0.00, 4529.50, 1467.00";"800.00, 20815.00, 1.00";"AAAApk8QFmJ4AAAAAAAAWoJ4";"";"";"";"";"0001-L, 0001-R, 0015, 0035, 0034, 0033, 0032, 0031, 0030, 0029, 0028, 0027, 0026, 0025, 0024, 0023, 0022, 0021, 0020, 0019, 0018, 0017, 0016, 0014, 0013";"";"";{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "20.02", "Anzahl der Separatoren": "4", "Kreiselart": "STANDARD", "Anzahl der Scanner": "4", "Anzahl der Rampen": "0", "Höhe in m": "1.47", "Drehrichtung": "UZS", "Drehung": 90, "Name": "Kreisel10", "Geruest fuer Einzelmodul": true} -3;"ILS 2.0 Separator";"0003";"Separator :38";"A/10";1;"-400.00, 13920.05, 1468.50";"150.00, 209.90, 3.00";"+eWAf///FmJ4AAAAAAAApX2I";"";"";"";"";"";"";"";{"Zuordnung": "0002-L", "ARTINR": "200000077", "Höhe": "1467", "Drehung": 270} -4;"ILS 2.0 Scanner";"0004";"Scanner :8";"A/10-A/11";1;"-40.00, 14000.00, 1467.00";"280.00, 150.00, 1.00";"+eWAf///FmJ4AAAAAAAAAAAA";"";"";"";"";"";"";"";{"Zuordnung": "0002-L", "ARTINR": "829534306", "Höhe": "1467", "Drehung": 0, "Naechster Separator": "0003"} -5;"ILS 2.0 Separator";"0005";"Separator :37";"A/1-B/2";1;"400.00, -3978.05, 1468.50";"150.00, 209.90, 3.00";"BhqAwmKQFmJ4AAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0014", "ARTINR": "200000077", "Höhe": "1467", "Drehung": 90} -6;"ILS 2.0 Scanner";"0006";"Scanner :7";"B/1";1;"760.00, -4083.00, 1467.00";"280.00, 150.00, 1.00";"BhqAwbLIFmJ4AAAAAAAAAAAA";"";"";"";"";"";"";"";{"Zuordnung": "0014", "ARTINR": "829534306", "Höhe": "1467", "Drehung": 0, "Naechster Separator": "0005"} -7;"ILS 2.0 Scanner";"0007";"Scanner :6";"A/2";1;"-40.00, -3390.00, 1467.00";"280.00, 150.00, 1.00";"+eWAzEXQFmJ4AAAAAAAAAAAA";"";"";"";"";"";"";"";{"Zuordnung": "0002-L", "ARTINR": "829534306", "Höhe": "1467", "Drehung": 0, "Naechster Separator": "0012"} -8;"ILS 2.0 Scanner";"0008";"Scanner :5";"G/3";1;"10670.00, -610.00, 1941.00";"280.00, 150.00, 1.00";"f///9rEwHZ4IAAAAAAAAAAAA";"";"";"";"";"";"";"";{"Zuordnung": "0010", "ARTINR": "829534306", "Höhe": "1941", "Drehung": 0, "Naechster Separator": "0042"} -9;"ILS 2.0 Scanner";"0009";"Scanner :4";"A/3";1;"-40.00, -400.00, 1467.00";"280.00, 150.00, 1.00";"+eWA+eWAFmJ4AAAAAAAAAAAA";"";"";"";"";"";"";"";{"Zuordnung": "0002-L", "ARTINR": "829534306", "Höhe": "1467", "Drehung": 0, "Naechster Separator": "0011"} -10;"ILS 2.0 Kreisel";"0010";"Kreisel :1";"F/1-F/11";1;"9910.00, 4529.50, 1941.00";"800.00, 20815.00, 1.00";"f///pk8QHZ4IAAAAAAAAWoJ4";"";"";"";"";"0035, 0034, 0033, 0032, 0031, 0030, 0029, 0028, 0027, 0026, 0025, 0024, 0023, 0022, 0021, 0020, 0019, 0018, 0017, 0016, 0014, 0013";"";"";{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "20.02", "Anzahl der Separatoren": "4", "Kreiselart": "STANDARD", "Anzahl der Scanner": "2", "Anzahl der Rampen": "0", "Höhe in m": "1.94", "Drehrichtung": "UZS", "Drehung": 90, "Name": "Kreisel11", "Geruest fuer Einzelmodul": true} -11;"ILS 2.0 Separator";"0011";"Separator :36";"A/3";1;"-400.00, -561.95, 1468.50";"150.00, 209.90, 3.00";"+eWA+FcQFmJ4AAAAAAAApX2I";"";"";"";"";"";"";"";{"Zuordnung": "0002-L", "ARTINR": "200000077", "Höhe": "1467", "Drehung": 270} -12;"ILS 2.0 Separator";"0012";"Separator :35";"A/2";1;"-400.00, -3554.95, 1468.50";"150.00, 209.90, 3.00";"+eWAyquoFmJ4AAAAAAAApX2I";"";"";"";"";"";"";"";{"Zuordnung": "0002-L", "ARTINR": "200000077", "Höhe": "1467", "Drehung": 270} -13;"ILS 2.0 Strecke";"0013";"VarioFoerderer :3";"A/10-F/11";1;"4942.50, 13708.26, 1702.81";"9226.40, 879.87, 1187.73";"BhqAf///FmJ4AAAAAAAAAAAA";"AA+gAieQADlO";"AXN8AiifAEvS";"";"";"0010-L, 0002-R";"";"";{"Typ": "Streckengruppe", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "3,3", "VF_Winkel": "21", "DeltaH_mm": "474", "DeltaL_mm": "9110", "L_VF_m": "2.32", "L_GF_m": "2.298,1.001", "Montagehoehe_m": "0.237", "Hoehe_Von_mm": "0", "Hoehe_Bis_mm": "474", "Antriebfahrtrichtung": "Auf", "Anzahl_Separator": "2", "Anzahl_Scanner": "0"} -14;"ILS 2.0 Strecke";"0014";"VarioFoerderer :2";"A/1-F/1";1;"4942.50, -4544.74, 1702.81";"9226.40, 879.87, 1187.73";"BhqAwO94FmJ4AAAAAAAAAAAA";"AA+g/16OADlO";"AXN8/1+eAEvS";"";"";"0010-L, 0002-R";"";"";{"Typ": "Streckengruppe", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "3,3", "VF_Winkel": "21", "DeltaH_mm": "474", "DeltaL_mm": "9110", "L_VF_m": "2.32", "L_GF_m": "2.298,1.001", "Montagehoehe_m": "0.237", "Hoehe_Von_mm": "0", "Hoehe_Bis_mm": "474", "Antriebfahrtrichtung": "Auf", "Anzahl_Separator": "2", "Anzahl_Scanner": "0"} -15;"ILS 2.0 Strecke";"0015";"VarioFoerderer :1";"A/4-A/10";1;"-631.28, 6537.44, 1556.12";"1018.09, 12779.64, 798.62";"+eWAAkCfFmJ4AAAAAAAAAAAA";"//BgAAXEADlO";"//BgAfjuADt7";"";"";"0002-L";"nur ein Partner";"";{"Typ": "Streckengruppe", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "3,3", "VF_Winkel": "9", "DeltaH_mm": "0", "DeltaL_mm": "12790", "L_VF_m": "4.809", "L_GF_m": "1.602,2.15", "Montagehoehe_m": "0", "Hoehe_Von_mm": "0", "Hoehe_Bis_mm": "0", "Antriebfahrtrichtung": "Auf", "Anzahl_Separator": "4", "Anzahl_Scanner": "1"} -16;"ILS 2.0 Gefaellestrecke";"0016";"Gefaellestrecke :20";"A/9-F/10";1;"4966.65, 12206.56, 1707.71";"9228.09, 1090.29, 636.57";"f///f///HZ4IAAAAAAAAAAAA";"AXN8AcigAEvS";"AA+YAceQADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -17;"ILS 2.0 Gefaellestrecke";"0017";"Gefaellestrecke :19";"A/9-F/9";1;"4966.65, 11406.56, 1707.71";"9228.09, 1090.29, 636.57";"f///f///HZ4IAAAAAAAAAAAA";"AXN8AalgAEvS";"AA+YAahQADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -18;"ILS 2.0 Gefaellestrecke";"0018";"Gefaellestrecke :18";"A/9-F/9";1;"4966.65, 10606.56, 1707.71";"9228.09, 1090.29, 636.57";"f///f///HZ4IAAAAAAAAAAAA";"AXN8AYogAEvS";"AA+YAYkQADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -19;"ILS 2.0 Gefaellestrecke";"0019";"Gefaellestrecke :17";"A/8-F/9";1;"4966.65, 9806.56, 1707.71";"9228.09, 1090.29, 636.57";"f///f///HZ4IAAAAAAAAAAAA";"AXN8AWrgAEvS";"AA+YAWnQADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -20;"ILS 2.0 Gefaellestrecke";"0020";"Gefaellestrecke :16";"A/8-F/8";1;"4966.65, 9006.56, 1707.71";"9228.09, 1090.29, 636.57";"f///f///HZ4IAAAAAAAAAAAA";"AXN8AUugAEvS";"AA+YAUqQADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -21;"ILS 2.0 Gefaellestrecke";"0021";"Gefaellestrecke :15";"A/7-F/8";1;"4966.65, 8206.56, 1707.71";"9228.09, 1090.29, 636.57";"f///fqXgHZ4IAAAAAAAAAAAA";"AXN8ASxgAEvS";"AA+YAStQADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -22;"ILS 2.0 Gefaellestrecke";"0022";"Gefaellestrecke :14";"A/7-F/7";1;"4966.65, 7406.56, 1707.71";"9228.09, 1090.29, 636.57";"f///cnDgHZ4IAAAAAAAAAAAA";"AXN8AQ0gAEvS";"AA+YAQwQADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -23;"ILS 2.0 Gefaellestrecke";"0023";"Gefaellestrecke :13";"A/7-F/7";1;"4966.65, 6606.56, 1707.71";"9228.09, 1090.29, 636.57";"f///ZjvgHZ4IAAAAAAAAAAAA";"AXN8AO3gAEvS";"AA+YAOzQADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -24;"ILS 2.0 Gefaellestrecke";"0024";"Gefaellestrecke :12";"A/6-F/7";1;"4966.65, 5806.56, 1707.71";"9228.09, 1090.29, 636.57";"f///WgbgHZ4IAAAAAAAAAAAA";"AXN8AM6gAEvS";"AA+YAM2QADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -25;"ILS 2.0 Gefaellestrecke";"0025";"Gefaellestrecke :11";"A/6-F/6";1;"4966.65, 5006.56, 1707.71";"9228.09, 1090.29, 636.57";"f///TdHgHZ4IAAAAAAAAAAAA";"AXN8AK9gAEvS";"AA+YAK5QADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -26;"ILS 2.0 Gefaellestrecke";"0026";"Gefaellestrecke :10";"A/5-F/6";1;"4966.65, 4206.56, 1707.71";"9228.09, 1090.29, 636.57";"f///QZzgHZ4IAAAAAAAAAAAA";"AXN8AJAgAEvS";"AA+YAI8QADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -27;"ILS 2.0 Gefaellestrecke";"0027";"Gefaellestrecke :9";"A/5-F/5";1;"4966.65, 3406.56, 1707.71";"9228.09, 1090.29, 636.57";"f///NWfgHZ4IAAAAAAAAAAAA";"AXN8AHDgAEvS";"AA+YAG/QADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -28;"ILS 2.0 Gefaellestrecke";"0028";"Gefaellestrecke :8";"A/5-F/5";1;"4966.65, 2606.56, 1707.71";"9228.09, 1090.29, 636.57";"f///KTLgHZ4IAAAAAAAAAAAA";"AXN8AFGgAEvS";"AA+YAFCQADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -29;"ILS 2.0 Gefaellestrecke";"0029";"Gefaellestrecke :7";"A/4-F/5";1;"4966.65, 1806.56, 1707.71";"9228.09, 1090.29, 636.57";"f///HP3gHZ4IAAAAAAAAAAAA";"AXN8ADJgAEvS";"AA+YADFQADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -30;"ILS 2.0 Gefaellestrecke";"0030";"Gefaellestrecke :6";"A/4-F/4";1;"4966.65, 1006.56, 1707.71";"9228.09, 1090.29, 636.57";"f///EMjgHZ4IAAAAAAAAAAAA";"AXN8ABMgAEvS";"AA+YABIQADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -31;"ILS 2.0 Gefaellestrecke";"0031";"Gefaellestrecke :5";"A/3-F/4";1;"4966.65, 206.56, 1707.71";"9228.09, 1090.29, 636.57";"f///BJPgHZ4IAAAAAAAAAAAA";"AXN8//PhAEvS";"AA+Y//LRADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -32;"ILS 2.0 Gefaellestrecke";"0032";"Gefaellestrecke :4";"A/3-F/3";1;"4966.65, -593.44, 1707.71";"9228.09, 1090.29, 636.57";"f///+F7gHZ4IAAAAAAAAAAAA";"AXN8/9ShAEvS";"AA+Y/9ORADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -33;"ILS 2.0 Gefaellestrecke";"0033";"Gefaellestrecke :3";"A/3-F/3";1;"4966.65, -1393.44, 1707.71";"9228.09, 1090.29, 636.57";"f///7CngHZ4IAAAAAAAAAAAA";"AXN8/7VhAEvS";"AA+Y/7RRADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -34;"ILS 2.0 Gefaellestrecke";"0034";"Gefaellestrecke :2";"A/2-F/3";1;"4966.65, -2193.44, 1707.71";"9228.09, 1090.29, 636.57";"f///3/TgHZ4IAAAAAAAAAAAA";"AXN8/5YhAEvS";"AA+Y/5URADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -35;"ILS 2.0 Gefaellestrecke";"0035";"Gefaellestrecke :1";"A/2-F/2";1;"4966.65, -2993.44, 1707.71";"9228.09, 1090.29, 636.57";"f///07/gHZ4IAAAAAAAAAAAA";"AXN8/3bhAEvS";"AA+Y/3XRADlD";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "1.941", "Hoehe_Von_mm": "1941", "Hoehe_Bis_mm": "1465", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} -36;"ILS 2.0 Separator";"0036";"Separator :34";"B/1";1;"1474.95, -5078.00, 1468.50";"209.90, 150.00, 3.00";"FZdYsoQQFmJ4AAAAAAAAAAAA";"";"";"";"";"0040, 0040";"";"";{"Zuordnung": "0014", "ARTINR": "200000077", "Höhe": "1467", "Drehung": 0} +1;"ILS 2.0 Kreisel";"0001";"Kreisel :3";"A/1-D/1";1;"3300.00, -5478.00, 1554.00";"5800.00, 800.00, 1.00";"BhqArGmQF7ZQAAAAAAAAAAAA";"";"";"";"";"0002-R";"";"";{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "5.0", "Anzahl der Separatoren": "2", "Kreiselart": "STANDARD", "Anzahl der Scanner": "1", "Anzahl der Rampen": "0", "Höhe in m": "1.55", "Drehrichtung": "UZS", "Drehung": 0, "Name": "Kreisel1", "Geruest fuer Einzelmodul": true} +2;"ILS 2.0 Kreisel";"0002";"Kreisel :2";"A/1-A/11";1;"0.00, 4529.50, 1554.00";"800.00, 20815.00, 1.00";"AAAApk8QF7ZQAAAAAAAAWoJ4";"";"";"";"";"0001-L, 0001-R, 0015, 0035, 0034, 0033, 0032, 0031, 0030, 0029, 0028, 0027, 0026, 0025, 0024, 0023, 0022, 0021, 0020, 0019, 0018, 0017, 0016, 0014, 0013";"";"";{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "20.02", "Anzahl der Separatoren": "4", "Kreiselart": "STANDARD", "Anzahl der Scanner": "4", "Anzahl der Rampen": "0", "Höhe in m": "1.55", "Drehrichtung": "UZS", "Drehung": 90, "Name": "Kreisel2", "Geruest fuer Einzelmodul": true} +3;"ILS 2.0 Separator";"0003";"Separator :38";"A/10";1;"-400.00, 13920.05, 1555.50";"150.00, 209.90, 3.00";"+eWAf///F7ZQAAAAAAAApX2I";"";"";"";"";"0118, 0121";"";"";{"Zuordnung": "0002-L", "ARTINR": "200000077", "Höhe": "1554", "Drehung": 270} +4;"ILS 2.0 Scanner";"0004";"Scanner :8";"A/10-A/11";1;"-40.00, 14000.00, 1554.00";"280.00, 150.00, 1.00";"+eWAf///F7ZQAAAAAAAAAAAA";"";"";"";"";"";"";"";{"Zuordnung": "0002-L", "ARTINR": "829534306", "Höhe": "1554", "Drehung": 0, "Naechster Separator": "0003"} +5;"ILS 2.0 Separator";"0005";"Separator :37";"A/1-B/2";1;"400.00, -3978.05, 1555.50";"150.00, 209.90, 3.00";"BhqAwmKQF7ZQAAAAAAAAWoJ4";"";"";"";"";"0078, 0119";"";"";{"Zuordnung": "0014", "ARTINR": "200000077", "Höhe": "1554", "Drehung": 90} +6;"ILS 2.0 Scanner";"0006";"Scanner :7";"B/1";1;"760.00, -4083.00, 1554.00";"280.00, 150.00, 1.00";"BhqAwbLIF7ZQAAAAAAAAAAAA";"";"";"";"";"";"";"";{"Zuordnung": "0014", "ARTINR": "829534306", "Höhe": "1554", "Drehung": 0, "Naechster Separator": "0005"} +7;"ILS 2.0 Scanner";"0007";"Scanner :6";"A/2";1;"-40.00, -3390.00, 1554.00";"280.00, 150.00, 1.00";"+eWAzEXQF7ZQAAAAAAAAAAAA";"";"";"";"";"";"";"";{"Zuordnung": "0002-L", "ARTINR": "829534306", "Höhe": "1554", "Drehung": 0, "Naechster Separator": "0012"} +8;"ILS 2.0 Scanner";"0008";"Scanner :5";"G/3";1;"10670.00, -610.00, 2028.00";"280.00, 150.00, 1.00";"f///9rEwHvHgAAAAAAAAAAAA";"";"";"";"";"";"";"";{"Zuordnung": "0010", "ARTINR": "829534306", "Höhe": "2028", "Drehung": 0, "Naechster Separator": "0042"} +9;"ILS 2.0 Scanner";"0009";"Scanner :4";"A/3";1;"-40.00, -400.00, 1554.00";"280.00, 150.00, 1.00";"+eWA+eWAF7ZQAAAAAAAAAAAA";"";"";"";"";"";"";"";{"Zuordnung": "0002-L", "ARTINR": "829534306", "Höhe": "1554", "Drehung": 0, "Naechster Separator": "0011"} +10;"ILS 2.0 Kreisel";"0010";"Kreisel :1";"F/1-F/11";1;"9910.00, 4529.50, 2028.00";"800.00, 20815.00, 1.00";"f///pk8QHvHgAAAAAAAAWoJ4";"";"";"";"";"0035, 0034, 0033, 0032, 0031, 0030, 0029, 0028, 0027, 0026, 0025, 0024, 0023, 0022, 0021, 0020, 0019, 0018, 0017, 0016, 0014, 0013";"";"";{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "20.02", "Anzahl der Separatoren": "4", "Kreiselart": "STANDARD", "Anzahl der Scanner": "2", "Anzahl der Rampen": "0", "Höhe in m": "2.03", "Drehrichtung": "UZS", "Drehung": 90, "Name": "Kreisel3", "Geruest fuer Einzelmodul": true} +11;"ILS 2.0 Separator";"0011";"Separator :36";"A/3";1;"-400.00, -561.95, 1555.50";"150.00, 209.90, 3.00";"+eWA+FcQF7ZQAAAAAAAApX2I";"";"";"";"";"0012, 0117";"";"";{"Zuordnung": "0002-L", "ARTINR": "200000077", "Höhe": "1554", "Drehung": 270} +12;"ILS 2.0 Separator";"0012";"Separator :35";"A/2";1;"-400.00, -3554.95, 1555.50";"150.00, 209.90, 3.00";"+eWAyquoF7ZQAAAAAAAApX2I";"";"";"";"";"0076, 0011";"";"";{"Zuordnung": "0002-L", "ARTINR": "200000077", "Höhe": "1554", "Drehung": 270} +13;"ILS 2.0 Strecke";"0013";"VarioFoerderer :3";"A/10-F/11";1;"4942.50, 13708.26, 1789.81";"9226.40, 879.87, 1187.73";"BhqAf///F7ZQAAAAAAAAAAAA";"AA+gAieQADy0";"AXN8AiifAE84";"";"";"0010-L, 0002-R";"";"";{"Typ": "Streckengruppe", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "3,3", "VF_Winkel": "21", "DeltaH_mm": "474", "DeltaL_mm": "9110", "L_VF_m": "2.32", "L_GF_m": "2.298,1.001", "Montagehoehe_m": "0.237", "Hoehe_Von_mm": "0", "Hoehe_Bis_mm": "474", "Antriebfahrtrichtung": "Auf", "Anzahl_Separator": "2", "Anzahl_Scanner": "0"} +14;"ILS 2.0 Strecke";"0014";"VarioFoerderer :2";"A/1-F/1";1;"4942.50, -4544.74, 1789.81";"9226.40, 879.87, 1187.73";"BhqAwO94F7ZQAAAAAAAAAAAA";"AA+g/16OADy0";"AXN8/1+eAE84";"";"";"0010-L, 0002-R";"";"";{"Typ": "Streckengruppe", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "3,3", "VF_Winkel": "21", "DeltaH_mm": "474", "DeltaL_mm": "9110", "L_VF_m": "2.32", "L_GF_m": "2.298,1.001", "Montagehoehe_m": "0.237", "Hoehe_Von_mm": "0", "Hoehe_Bis_mm": "474", "Antriebfahrtrichtung": "Auf", "Anzahl_Separator": "2", "Anzahl_Scanner": "0"} +15;"ILS 2.0 Strecke";"0015";"VarioFoerderer :1";"A/4-A/10";1;"-631.28, 6537.44, 1643.12";"1018.09, 12779.64, 798.62";"+eWAAkCfF7ZQAAAAAAAAAAAA";"//BgAAXEADy0";"//BgAfjuAD7h";"";"";"0002-L";"nur ein Partner";"";{"Typ": "Streckengruppe", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "3,3", "VF_Winkel": "9", "DeltaH_mm": "0", "DeltaL_mm": "12790", "L_VF_m": "4.809", "L_GF_m": "1.602,2.15", "Montagehoehe_m": "0", "Hoehe_Von_mm": "0", "Hoehe_Bis_mm": "0", "Antriebfahrtrichtung": "Auf", "Anzahl_Separator": "4", "Anzahl_Scanner": "1"} +16;"ILS 2.0 Gefaellestrecke";"0016";"Gefaellestrecke :20";"A/9-F/10";1;"4966.65, 12206.56, 1794.71";"9228.09, 1090.29, 636.57";"f///f///HvHgAAAAAAAAAAAA";"AXN8AcigAE84";"AA+YAceQADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +17;"ILS 2.0 Gefaellestrecke";"0017";"Gefaellestrecke :19";"A/9-F/9";1;"4966.65, 11406.56, 1794.71";"9228.09, 1090.29, 636.57";"f///f///HvHgAAAAAAAAAAAA";"AXN8AalgAE84";"AA+YAahQADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +18;"ILS 2.0 Gefaellestrecke";"0018";"Gefaellestrecke :18";"A/9-F/9";1;"4966.65, 10606.56, 1794.71";"9228.09, 1090.29, 636.57";"f///f///HvHgAAAAAAAAAAAA";"AXN8AYogAE84";"AA+YAYkQADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +19;"ILS 2.0 Gefaellestrecke";"0019";"Gefaellestrecke :17";"A/8-F/9";1;"4966.65, 9806.56, 1794.71";"9228.09, 1090.29, 636.57";"f///f///HvHgAAAAAAAAAAAA";"AXN8AWrgAE84";"AA+YAWnQADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +20;"ILS 2.0 Gefaellestrecke";"0020";"Gefaellestrecke :16";"A/8-F/8";1;"4966.65, 9006.56, 1794.71";"9228.09, 1090.29, 636.57";"f///f///HvHgAAAAAAAAAAAA";"AXN8AUugAE84";"AA+YAUqQADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +21;"ILS 2.0 Gefaellestrecke";"0021";"Gefaellestrecke :15";"A/7-F/8";1;"4966.65, 8206.56, 1794.71";"9228.09, 1090.29, 636.57";"f///fqXgHvHgAAAAAAAAAAAA";"AXN8ASxgAE84";"AA+YAStQADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +22;"ILS 2.0 Gefaellestrecke";"0022";"Gefaellestrecke :14";"A/7-F/7";1;"4966.65, 7406.56, 1794.71";"9228.09, 1090.29, 636.57";"f///cnDgHvHgAAAAAAAAAAAA";"AXN8AQ0gAE84";"AA+YAQwQADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +23;"ILS 2.0 Gefaellestrecke";"0023";"Gefaellestrecke :13";"A/7-F/7";1;"4966.65, 6606.56, 1794.71";"9228.09, 1090.29, 636.57";"f///ZjvgHvHgAAAAAAAAAAAA";"AXN8AO3gAE84";"AA+YAOzQADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +24;"ILS 2.0 Gefaellestrecke";"0024";"Gefaellestrecke :12";"A/6-F/7";1;"4966.65, 5806.56, 1794.71";"9228.09, 1090.29, 636.57";"f///WgbgHvHgAAAAAAAAAAAA";"AXN8AM6gAE84";"AA+YAM2QADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +25;"ILS 2.0 Gefaellestrecke";"0025";"Gefaellestrecke :11";"A/6-F/6";1;"4966.65, 5006.56, 1794.71";"9228.09, 1090.29, 636.57";"f///TdHgHvHgAAAAAAAAAAAA";"AXN8AK9gAE84";"AA+YAK5QADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +26;"ILS 2.0 Gefaellestrecke";"0026";"Gefaellestrecke :10";"A/5-F/6";1;"4966.65, 4206.56, 1794.71";"9228.09, 1090.29, 636.57";"f///QZzgHvHgAAAAAAAAAAAA";"AXN8AJAgAE84";"AA+YAI8QADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +27;"ILS 2.0 Gefaellestrecke";"0027";"Gefaellestrecke :9";"A/5-F/5";1;"4966.65, 3406.56, 1794.71";"9228.09, 1090.29, 636.57";"f///NWfgHvHgAAAAAAAAAAAA";"AXN8AHDgAE84";"AA+YAG/QADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +28;"ILS 2.0 Gefaellestrecke";"0028";"Gefaellestrecke :8";"A/5-F/5";1;"4966.65, 2606.56, 1794.71";"9228.09, 1090.29, 636.57";"f///KTLgHvHgAAAAAAAAAAAA";"AXN8AFGgAE84";"AA+YAFCQADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +29;"ILS 2.0 Gefaellestrecke";"0029";"Gefaellestrecke :7";"A/4-F/5";1;"4966.65, 1806.56, 1794.71";"9228.09, 1090.29, 636.57";"f///HP3gHvHgAAAAAAAAAAAA";"AXN8ADJgAE84";"AA+YADFQADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +30;"ILS 2.0 Gefaellestrecke";"0030";"Gefaellestrecke :6";"A/4-F/4";1;"4966.65, 1006.56, 1794.71";"9228.09, 1090.29, 636.57";"f///EMjgHvHgAAAAAAAAAAAA";"AXN8ABMgAE84";"AA+YABIQADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +31;"ILS 2.0 Gefaellestrecke";"0031";"Gefaellestrecke :5";"A/3-F/4";1;"4966.65, 206.56, 1794.71";"9228.09, 1090.29, 636.57";"f///BJPgHvHgAAAAAAAAAAAA";"AXN8//PhAE84";"AA+Y//LRADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +32;"ILS 2.0 Gefaellestrecke";"0032";"Gefaellestrecke :4";"A/3-F/3";1;"4966.65, -593.44, 1794.71";"9228.09, 1090.29, 636.57";"f///+F7gHvHgAAAAAAAAAAAA";"AXN8/9ShAE84";"AA+Y/9ORADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +33;"ILS 2.0 Gefaellestrecke";"0033";"Gefaellestrecke :3";"A/3-F/3";1;"4966.65, -1393.44, 1794.71";"9228.09, 1090.29, 636.57";"f///7CngHvHgAAAAAAAAAAAA";"AXN8/7VhAE84";"AA+Y/7RRADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +34;"ILS 2.0 Gefaellestrecke";"0034";"Gefaellestrecke :2";"A/2-F/3";1;"4966.65, -2193.44, 1794.71";"9228.09, 1090.29, 636.57";"f///3/TgHvHgAAAAAAAAAAAA";"AXN8/5YhAE84";"AA+Y/5URADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +35;"ILS 2.0 Gefaellestrecke";"0035";"Gefaellestrecke :1";"A/2-F/2";1;"4966.65, -2993.44, 1794.71";"9228.09, 1090.29, 636.57";"f///07/gHvHgAAAAAAAAAAAA";"AXN8/3bhAE84";"AA+Y/3XRADyp";"";"";"0010-L, 0002-R";"";"";{"Typ": "Gefaellestrecke", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "2.3", "VF_Winkel": "", "DeltaH_mm": "475", "DeltaL_mm": "9110", "L_VF_m": "", "L_GF_m": "7.954", "Montagehoehe_m": "2.028", "Hoehe_Von_mm": "2028", "Hoehe_Bis_mm": "1552", "Antriebfahrtrichtung": "", "Anzahl_Separator": "1", "Anzahl_Scanner": "0"} +36;"ILS 2.0 Separator";"0036";"Separator :34";"B/1";1;"1474.95, -5078.00, 1555.50";"209.90, 150.00, 3.00";"FZdYsoQQF7ZQAAAAAAAAAAAA";"";"";"";"";"0076, 0040";"";"";{"Zuordnung": "0014", "ARTINR": "200000077", "Höhe": "1554", "Drehung": 0} 37;"ILS 2.0 Separator";"0037";"Separator :33";"A/9";1;"-1026.00, 10723.05, 1634.50";"150.00, 209.90, 3.00";"8Fgwf///GOroAAAAAAAApX2I";"";"";"";"";"";"";"";{"Zuordnung": "0015", "ARTINR": "200000077", "Höhe": "1633", "Drehung": 270} 38;"ILS 2.0 Separator";"0038";"Separator :32";"A/6";1;"-1026.00, 5250.05, 1478.50";"150.00, 209.90, 3.00";"8FgwUQYwFomIAAAAAAAApX2I";"";"";"";"";"";"";"";{"Zuordnung": "0015", "ARTINR": "200000077", "Höhe": "1477", "Drehung": 270} 39;"ILS 2.0 Scanner";"0039";"Scanner :3";"A/6";1;"-1386.00, 5410.00, 1477.00";"280.00, 150.00, 1.00";"8FgwUozQFomIAAAAAAAAf///";"";"";"";"";"";"";"";{"Zuordnung": "0015", "ARTINR": "829534306", "Höhe": "1477", "Drehung": 180, "Naechster Separator": "0038"} -40;"ILS 2.0 Separator";"0040";"Separator :31";"D/1";1;"5355.05, -5878.00, 1468.50";"209.90, 150.00, 3.00";"UqBYpk8QFmJ4AAAAAAAAf///";"";"";"";"";"0036, 0036";"";"";{"Zuordnung": "0001-R", "ARTINR": "200000077", "Höhe": "1467", "Drehung": 180} -41;"ILS 2.0 Scanner";"0041";"Scanner :2";"B/1";1;"1415.00, -5460.00, 1467.00";"150.00, 280.00, 1.00";"FZdYsi4gFmJ4AAAAAAAApX2I";"";"";"";"";"";"";"";{"Zuordnung": "0001-L", "ARTINR": "829534306", "Höhe": "1467", "Drehung": 270, "Naechster Separator": "0036"} -42;"ILS 2.0 Separator";"0042";"Separator :30";"F/3";1;"10310.00, -440.05, 1942.50";"150.00, 209.90, 3.00";"f///+F7gHZ4IAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0010-R", "ARTINR": "200000077", "Höhe": "1941", "Drehung": 90} -43;"ILS 2.0 Separator";"0043";"Separator :29";"F/4";1;"10310.00, 159.95, 1942.50";"150.00, 209.90, 3.00";"f///AYagHZ4IAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0010-R", "ARTINR": "200000077", "Höhe": "1941", "Drehung": 90} -44;"ILS 2.0 Separator";"0044";"Separator :28";"F/1";1;"10310.00, -5013.05, 1942.50";"150.00, 209.90, 3.00";"f///speYHZ4IAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0010-R", "ARTINR": "200000077", "Höhe": "1941", "Drehung": 90} -45;"ILS 2.0 Separator";"0045";"Separator :27";"F/11";1;"9510.00, 14217.05, 1942.50";"150.00, 209.90, 3.00";"f///f///HZ4IAAAAAAAApX2I";"";"";"";"";"";"";"";{"Zuordnung": "0013", "ARTINR": "200000077", "Höhe": "1941", "Drehung": 270} -46;"ILS 2.0 Scanner";"0046";"Scanner :1";"F/2";1;"9870.00, -3557.00, 1941.00";"280.00, 150.00, 1.00";"f///ybl4HZ4IAAAAAAAAAAAA";"";"";"";"";"";"";"";{"Zuordnung": "0035", "ARTINR": "829534306", "Höhe": "1941", "Drehung": 0, "Naechster Separator": "0052"} -47;"ILS 2.0 BTMT Beladung";"0047";"BTMT Beladung :1";"F/3-G/4";1;"10410.95, 3.52, 1896.31";"397.50, 645.71, 316.02";"f////FaAHZ4IAAAAAAAApX2I";"Aamq//fEAEY9";"AZK8//OyAEvS";"";"";"";"";"";{"ARTINR": "829662012", "Höhe": "1941", "Drehung": 270} -48;"ILS 2.0 BTMT Entladung";"0048";"BTMT Entladung :2";"A/2-A/3";1;"-778.79, -1226.10, 1314.09";"937.40, 1459.85, 467.01";"+ccS6XJAFmJ4AAAAAAAAWoJ4";"//AT/7l0ADlO";"ACQS/8XxADiR";"";"";"";"";"";{"ARTINR": "400100156", "Höhe": "1467", "Drehung": 90} -49;"ILS 2.0 BTMT Entladung";"0049";"BTMT Entladung :1";"A/2-A/3";1;"-775.22, -2466.46, 1314.09";"937.40, 1459.85, 467.01";"+dUE1oUYFmJ4AAAAAAAAWoJ4";"//A2/4kBADlO";"ACQ1/5V+ADiR";"";"";"";"";"";{"ARTINR": "400100156", "Höhe": "1467", "Drehung": 90} -50;"ILS 2.0 Separator";"0050";"Separator :1";"F/10";1;"8953.10, 13509.62, 2092.73";"209.77, 150.00, 13.98";"f///gAABJwQBAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0013", "ARTINR": "200000077", "Höhe": "2556", "Drehung": 90} -51;"ILS 2.0 Separator";"0051";"Separator :2";"C/10";1;"3299.55, 13509.62, 1329.12";"209.77, 150.00, 13.98";"f///zd5aFt13AAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0013", "ARTINR": "200000077", "Höhe": "1498", "Drehung": 90} -52;"ILS 2.0 Separator";"0052";"Separator :3";"F/1";1;"8953.10, -4743.38, 2092.73";"209.77, 150.00, 13.98";"t58ogAABJwQBAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0014", "ARTINR": "200000077", "Höhe": "2556", "Drehung": 90} -53;"ILS 2.0 Separator";"0053";"Separator :4";"C/1";1;"3299.55, -4743.38, 1329.12";"209.77, 150.00, 13.98";"t58ozd5aFt13AAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0014", "ARTINR": "200000077", "Höhe": "1498", "Drehung": 90} -54;"ILS 2.0 Separator";"0054";"Separator :5";"A/10";1;"-702.98, 12296.45, 1664.35";"234.79, 256.67, 13.98";"ZxqegAABIY/QAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0015", "ARTINR": "200000077", "Höhe": "2199", "Drehung": 90} -55;"ILS 2.0 Separator";"0055";"Separator :6";"A/4";1;"-898.87, 1134.60, 1447.33";"234.79, 256.67, 13.98";"AzjD6muCFyzGAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0015", "ARTINR": "200000077", "Höhe": "1518", "Drehung": 90} -56;"ILS 2.0 Separator";"0056";"Separator :7";"B/10";1;"958.00, 12300.00, 1610.60";"209.86, 150.00, 11.31";"gAABDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0016", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -57;"ILS 2.0 Separator";"0057";"Separator :8";"B/9";1;"958.00, 11500.00, 1610.60";"209.86, 150.00, 11.31";"gAABDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0017", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -58;"ILS 2.0 Separator";"0058";"Separator :9";"B/9";1;"958.00, 10700.00, 1610.60";"209.86, 150.00, 11.31";"gAABDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0018", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -59;"ILS 2.0 Separator";"0059";"Separator :10";"B/8";1;"958.00, 9900.00, 1610.60";"209.86, 150.00, 11.31";"gAABDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0019", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -60;"ILS 2.0 Separator";"0060";"Separator :11";"B/8";1;"958.00, 9100.00, 1610.60";"209.86, 150.00, 11.31";"gAABDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0020", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -61;"ILS 2.0 Separator";"0061";"Separator :12";"B/8";1;"958.00, 8300.00, 1610.60";"209.86, 150.00, 11.31";"gVogDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0021", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -62;"ILS 2.0 Separator";"0062";"Separator :13";"B/7";1;"958.00, 7500.00, 1610.60";"209.86, 150.00, 11.31";"jY8gDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0022", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -63;"ILS 2.0 Separator";"0063";"Separator :14";"B/7";1;"958.00, 6700.00, 1610.60";"209.86, 150.00, 11.31";"mcQgDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0023", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -64;"ILS 2.0 Separator";"0064";"Separator :15";"B/6";1;"958.00, 5900.00, 1610.60";"209.86, 150.00, 11.31";"pfkgDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0024", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -65;"ILS 2.0 Separator";"0065";"Separator :16";"B/6";1;"958.00, 5100.00, 1610.60";"209.86, 150.00, 11.31";"si4gDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"0066, 0066";"";"";{"Zuordnung": "0025", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -66;"ILS 2.0 Separator";"0066";"Separator :17";"B/6";1;"958.00, 4300.00, 1610.60";"209.86, 150.00, 11.31";"vmMgDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"0065, 0065";"";"";{"Zuordnung": "0026", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -67;"ILS 2.0 Separator";"0067";"Separator :18";"B/5";1;"958.00, 3500.00, 1610.60";"209.86, 150.00, 11.31";"ypggDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0027", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -68;"ILS 2.0 Separator";"0068";"Separator :19";"B/5";1;"958.00, 2700.00, 1610.60";"209.86, 150.00, 11.31";"1s0gDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0028", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -69;"ILS 2.0 Separator";"0069";"Separator :20";"B/4";1;"958.00, 1900.00, 1610.60";"209.86, 150.00, 11.31";"4wIgDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0029", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -70;"ILS 2.0 Separator";"0070";"Separator :21";"B/4";1;"958.00, 1100.00, 1610.60";"209.86, 150.00, 11.31";"7zcgDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0030", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -71;"ILS 2.0 Separator";"0071";"Separator :22";"B/4";1;"958.00, 300.00, 1610.60";"209.86, 150.00, 11.31";"+2wgDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0031", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -72;"ILS 2.0 Separator";"0072";"Separator :23";"B/3";1;"958.00, -500.00, 1610.60";"209.86, 150.00, 11.31";"B6EfDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0032", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -73;"ILS 2.0 Separator";"0073";"Separator :24";"B/3";1;"958.00, -1300.00, 1610.60";"209.86, 150.00, 11.31";"E9YfDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0033", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -74;"ILS 2.0 Separator";"0074";"Separator :25";"B/2";1;"958.00, -2100.00, 1610.60";"209.86, 150.00, 11.31";"IAsfDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0034", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -75;"ILS 2.0 Separator";"0075";"Separator :26";"B/2";1;"958.00, -2900.00, 1610.60";"209.86, 150.00, 11.31";"LEAfDqpDF/RjAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0035", "ARTINR": "200000077", "Höhe": "1569", "Drehung": 90} -76;"ILS Weiche";"0076";"ILS Weiche :1";"A/1";1;"400.00, -5478.00, 1467.00";"250.00, 100.00, 30.00";"";"";"";"";"";"0002, 0001";"";"";{"Erzeugt aus": "Kreisel-Beruehrpunkt", "Kreisel A": "0002", "Kreisel B": "0001", "Achse von Kreisel": "0002", "Beruehrung": "Kreis/Kreis"} -77;"ILS Ausschleuselement";"0077";"ILS Ausschleuselement :1";"F/2";1;"9560.00, -3510.15, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0035";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0035", "Streckenende": "Anfang"} -78;"ILS Einschleuselement";"0078";"ILS Einschleuselement :1";"A/2";1;"349.20, -3537.65, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0035";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0035", "Streckenende": "Ende"} -79;"ILS Ausschleuselement";"0079";"ILS Ausschleuselement :2";"F/2";1;"9560.00, -2710.15, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0034";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0034", "Streckenende": "Anfang"} -80;"ILS Einschleuselement";"0080";"ILS Einschleuselement :2";"A/2";1;"349.20, -2737.65, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0034";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0034", "Streckenende": "Ende"} -81;"ILS Ausschleuselement";"0081";"ILS Ausschleuselement :3";"F/3";1;"9560.00, -1910.15, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0033";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0033", "Streckenende": "Anfang"} -82;"ILS Einschleuselement";"0082";"ILS Einschleuselement :3";"A/3";1;"349.20, -1937.65, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0033";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0033", "Streckenende": "Ende"} -83;"ILS Ausschleuselement";"0083";"ILS Ausschleuselement :4";"F/3";1;"9560.00, -1110.15, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0032";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0032", "Streckenende": "Anfang"} -84;"ILS Einschleuselement";"0084";"ILS Einschleuselement :4";"A/3";1;"349.20, -1137.65, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0032";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0032", "Streckenende": "Ende"} -85;"ILS Ausschleuselement";"0085";"ILS Ausschleuselement :5";"F/3";1;"9560.00, -310.15, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0031";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0031", "Streckenende": "Anfang"} -86;"ILS Einschleuselement";"0086";"ILS Einschleuselement :5";"A/3";1;"349.20, -337.65, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0031";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0031", "Streckenende": "Ende"} -87;"ILS Ausschleuselement";"0087";"ILS Ausschleuselement :6";"F/4";1;"9560.00, 489.75, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0030";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0030", "Streckenende": "Anfang"} -88;"ILS Einschleuselement";"0088";"ILS Einschleuselement :6";"A/4";1;"349.20, 462.25, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0030";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0030", "Streckenende": "Ende"} -89;"ILS Ausschleuselement";"0089";"ILS Ausschleuselement :7";"F/4";1;"9560.00, 1289.75, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0029";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0029", "Streckenende": "Anfang"} -90;"ILS Einschleuselement";"0090";"ILS Einschleuselement :7";"A/4";1;"349.20, 1262.25, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0029";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0029", "Streckenende": "Ende"} -91;"ILS Ausschleuselement";"0091";"ILS Ausschleuselement :8";"F/5";1;"9560.00, 2089.75, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0028";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0028", "Streckenende": "Anfang"} -92;"ILS Einschleuselement";"0092";"ILS Einschleuselement :8";"A/5";1;"349.20, 2062.25, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0028";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0028", "Streckenende": "Ende"} -93;"ILS Ausschleuselement";"0093";"ILS Ausschleuselement :9";"F/5";1;"9560.00, 2889.75, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0027";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0027", "Streckenende": "Anfang"} -94;"ILS Einschleuselement";"0094";"ILS Einschleuselement :9";"A/5";1;"349.20, 2862.25, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0027";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0027", "Streckenende": "Ende"} -95;"ILS Ausschleuselement";"0095";"ILS Ausschleuselement :10";"F/5";1;"9560.00, 3689.75, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0026";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0026", "Streckenende": "Anfang"} -96;"ILS Einschleuselement";"0096";"ILS Einschleuselement :10";"A/5";1;"349.20, 3662.25, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0026";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0026", "Streckenende": "Ende"} -97;"ILS Ausschleuselement";"0097";"ILS Ausschleuselement :11";"F/6";1;"9560.00, 4489.75, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0025";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0025", "Streckenende": "Anfang"} -98;"ILS Einschleuselement";"0098";"ILS Einschleuselement :11";"A/6";1;"349.20, 4462.25, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0025";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0025", "Streckenende": "Ende"} -99;"ILS Ausschleuselement";"0099";"ILS Ausschleuselement :12";"F/6";1;"9560.00, 5289.75, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0024";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0024", "Streckenende": "Anfang"} -100;"ILS Einschleuselement";"0100";"ILS Einschleuselement :12";"A/6";1;"349.20, 5262.25, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0024";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0024", "Streckenende": "Ende"} -101;"ILS Ausschleuselement";"0101";"ILS Ausschleuselement :13";"F/7";1;"9560.00, 6089.75, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0023";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0023", "Streckenende": "Anfang"} -102;"ILS Einschleuselement";"0102";"ILS Einschleuselement :13";"A/7";1;"349.20, 6062.25, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0023";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0023", "Streckenende": "Ende"} -103;"ILS Ausschleuselement";"0103";"ILS Ausschleuselement :14";"F/7";1;"9560.00, 6889.75, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0022";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0022", "Streckenende": "Anfang"} -104;"ILS Einschleuselement";"0104";"ILS Einschleuselement :14";"A/7";1;"349.20, 6862.25, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0022";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0022", "Streckenende": "Ende"} -105;"ILS Ausschleuselement";"0105";"ILS Ausschleuselement :15";"F/7";1;"9560.00, 7689.75, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0021";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0021", "Streckenende": "Anfang"} -106;"ILS Einschleuselement";"0106";"ILS Einschleuselement :15";"A/7";1;"349.20, 7662.25, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0021";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0021", "Streckenende": "Ende"} -107;"ILS Ausschleuselement";"0107";"ILS Ausschleuselement :16";"F/8";1;"9560.00, 8489.75, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0020";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0020", "Streckenende": "Anfang"} -108;"ILS Einschleuselement";"0108";"ILS Einschleuselement :16";"A/8";1;"349.20, 8462.25, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0020";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0020", "Streckenende": "Ende"} -109;"ILS Ausschleuselement";"0109";"ILS Ausschleuselement :17";"F/8";1;"9560.00, 9289.75, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0019";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0019", "Streckenende": "Anfang"} -110;"ILS Einschleuselement";"0110";"ILS Einschleuselement :17";"A/8";1;"349.20, 9262.25, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0019";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0019", "Streckenende": "Ende"} -111;"ILS Ausschleuselement";"0111";"ILS Ausschleuselement :18";"F/9";1;"9560.00, 10089.75, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0018";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0018", "Streckenende": "Anfang"} -112;"ILS Einschleuselement";"0112";"ILS Einschleuselement :18";"A/9";1;"349.20, 10062.25, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0018";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0018", "Streckenende": "Ende"} -113;"ILS Ausschleuselement";"0113";"ILS Ausschleuselement :19";"F/9";1;"9560.00, 10889.75, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0017";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0017", "Streckenende": "Anfang"} -114;"ILS Einschleuselement";"0114";"ILS Einschleuselement :19";"A/9";1;"349.20, 10862.25, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0017";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0017", "Streckenende": "Ende"} -115;"ILS Ausschleuselement";"0115";"ILS Ausschleuselement :20";"F/9";1;"9560.00, 11689.75, 1824.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0016";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0016", "Streckenende": "Anfang"} -116;"ILS Einschleuselement";"0116";"ILS Einschleuselement :20";"A/9";1;"349.20, 11662.25, 1587.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0016";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0016", "Streckenende": "Ende"} -117;"ILS Ausschleuselement";"0117";"ILS Ausschleuselement :21";"A/4";1;"-400.00, 97.60, 1511.56";"250.00, 100.00, 30.00";"";"";"";"";"";"0002, 0015";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0015", "Streckenende": "Anfang"} -118;"ILS Einschleuselement";"0118";"ILS Einschleuselement :21";"A/10";1;"-400.00, 12976.20, 1511.56";"250.00, 100.00, 30.00";"";"";"";"";"";"0002, 0015";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0015", "Streckenende": "Ende"} -119;"ILS Ausschleuselement";"0119";"ILS Ausschleuselement :22";"A/1";1;"350.00, -4133.15, 1584.90";"100.75, 250.30, 30.00";"";"";"";"";"";"0002, 0014";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0014", "Streckenende": "Anfang"} -120;"ILS Einschleuselement";"0120";"ILS Einschleuselement :22";"F/1";1;"9560.00, -4105.65, 1821.90";"100.75, 250.30, 30.00";"";"";"";"";"";"0010, 0014";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0014", "Streckenende": "Ende"} -121;"ILS Ausschleuselement";"0121";"ILS Ausschleuselement :23";"A/11";1;"350.00, 14119.85, 1584.90";"100.74, 250.30, 30.00";"";"";"";"";"";"0002, 0013";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0013", "Streckenende": "Anfang"} -122;"ILS Einschleuselement";"0122";"ILS Einschleuselement :23";"F/11";1;"9560.00, 14147.25, 1821.90";"100.74, 250.30, 30.00";"";"";"";"";"";"0010, 0013";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0013", "Streckenende": "Ende"} +40;"ILS 2.0 Separator";"0040";"Separator :31";"D/1";1;"5355.05, -5878.00, 1555.50";"209.90, 150.00, 3.00";"UqBYpk8QF7ZQAAAAAAAAf///";"";"";"";"";"0036, 0076";"";"";{"Zuordnung": "0001-R", "ARTINR": "200000077", "Höhe": "1554", "Drehung": 180} +41;"ILS 2.0 Scanner";"0041";"Scanner :2";"B/1";1;"1415.00, -5460.00, 1554.00";"150.00, 280.00, 1.00";"FZdYsi4gF7ZQAAAAAAAApX2I";"";"";"";"";"";"";"";{"Zuordnung": "0001-L", "ARTINR": "829534306", "Höhe": "1554", "Drehung": 270, "Naechster Separator": "0036"} +42;"ILS 2.0 Separator";"0042";"Separator :30";"F/3";1;"10310.00, -440.05, 2029.50";"150.00, 209.90, 3.00";"f///+F7gHvHgAAAAAAAAWoJ4";"";"";"";"";"0043, 0044";"";"";{"Zuordnung": "0010-R", "ARTINR": "200000077", "Höhe": "2028", "Drehung": 90} +43;"ILS 2.0 Separator";"0043";"Separator :29";"F/4";1;"10310.00, 159.95, 2029.50";"150.00, 209.90, 3.00";"f///AYagHvHgAAAAAAAAWoJ4";"";"";"";"";"0045, 0042";"";"";{"Zuordnung": "0010-R", "ARTINR": "200000077", "Höhe": "2028", "Drehung": 90} +44;"ILS 2.0 Separator";"0044";"Separator :28";"F/1";1;"10310.00, -5013.05, 2029.50";"150.00, 209.90, 3.00";"f///speYHvHgAAAAAAAAWoJ4";"";"";"";"";"0042, 0120";"";"";{"Zuordnung": "0010-R", "ARTINR": "200000077", "Höhe": "2028", "Drehung": 90} +45;"ILS 2.0 Separator";"0045";"Separator :27";"F/11";1;"9510.00, 14217.05, 2029.50";"150.00, 209.90, 3.00";"f///f///HvHgAAAAAAAApX2I";"";"";"";"";"0122, 0043";"";"";{"Zuordnung": "0013", "ARTINR": "200000077", "Höhe": "2028", "Drehung": 270} +46;"ILS 2.0 Scanner";"0046";"Scanner :1";"F/2";1;"9870.00, -3557.00, 2028.00";"280.00, 150.00, 1.00";"f///ybl4HvHgAAAAAAAAAAAA";"";"";"";"";"";"";"";{"Zuordnung": "0035", "ARTINR": "829534306", "Höhe": "2028", "Drehung": 0, "Naechster Separator": "0052"} +47;"ILS 2.0 BTMT Beladung";"0047";"BTMT Beladung :1";"F/3-G/4";1;"10410.95, 3.52, 1983.31";"397.50, 645.71, 316.02";"f////FaAHvHgAAAAAAAApX2I";"Aamq//fEAEmj";"AZK8//OyAE84";"";"";"";"";"";{"ARTINR": "829662012", "Höhe": "2028", "Drehung": 270} +48;"ILS 2.0 BTMT Entladung";"0048";"BTMT Entladung :2";"A/2-A/3";1;"-778.79, -1226.10, 1401.09";"937.40, 1459.85, 467.01";"+ccS6XJAF7ZQAAAAAAAAWoJ4";"//AT/7l0ADyz";"ACQS/8XxADv3";"";"";"";"";"";{"ARTINR": "400100156", "Höhe": "1554", "Drehung": 90} +49;"ILS 2.0 BTMT Entladung";"0049";"BTMT Entladung :1";"A/2-A/3";1;"-775.22, -2466.46, 1401.09";"937.40, 1459.85, 467.01";"+dUE1oUYF7ZQAAAAAAAAWoJ4";"//A2/4kBADyz";"ACQ1/5V+ADv3";"";"";"";"";"";{"ARTINR": "400100156", "Höhe": "1554", "Drehung": 90} +50;"ILS 2.0 Separator";"0050";"Separator :1";"F/10";1;"8953.10, 13509.62, 2179.73";"209.77, 150.00, 13.98";"f///gAABKFdiAAAAAAAAWoJ4";"";"";"";"";"0051, 0122";"";"";{"Zuordnung": "0013", "ARTINR": "200000077", "Höhe": "2643", "Drehung": 90} +51;"ILS 2.0 Separator";"0051";"Separator :2";"C/10";1;"3299.55, 13509.62, 1416.12";"209.77, 150.00, 13.98";"f///zfAjGDDYAAAAAAAAWoJ4";"";"";"";"";"0121, 0050";"";"";{"Zuordnung": "0013", "ARTINR": "200000077", "Höhe": "1585", "Drehung": 90} +52;"ILS 2.0 Separator";"0052";"Separator :3";"F/1";1;"8953.10, -4743.38, 2179.73";"209.77, 150.00, 13.98";"t58ogAABKFdiAAAAAAAAWoJ4";"";"";"";"";"0053, 0120";"";"";{"Zuordnung": "0014", "ARTINR": "200000077", "Höhe": "2643", "Drehung": 90} +53;"ILS 2.0 Separator";"0053";"Separator :4";"C/1";1;"3299.55, -4743.38, 1416.12";"209.77, 150.00, 13.98";"t58ozfAjGDDYAAAAAAAAWoJ4";"";"";"";"";"0119, 0052";"";"";{"Zuordnung": "0014", "ARTINR": "200000077", "Höhe": "1585", "Drehung": 90} +54;"ILS 2.0 Separator";"0054";"Separator :5";"A/10";1;"-702.98, 12296.45, 1751.35";"234.79, 256.67, 13.98";"ZxqegAABIuMxAAAAAAAAWoJ4";"";"";"";"";"0055, 0118";"";"";{"Zuordnung": "0015", "ARTINR": "200000077", "Höhe": "2286", "Drehung": 90} +55;"ILS 2.0 Separator";"0055";"Separator :6";"A/4";1;"-898.87, 1134.60, 1534.33";"234.79, 256.67, 13.98";"AzjD6n1MGIAnAAAAAAAAWoJ4";"";"";"";"";"0117, 0054";"";"";{"Zuordnung": "0015", "ARTINR": "200000077", "Höhe": "1605", "Drehung": 90} +56;"ILS 2.0 Separator";"0056";"Separator :7";"B/10";1;"958.00, 12300.00, 1697.60";"209.86, 150.00, 11.31";"gAABDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0115, 0116";"";"";{"Zuordnung": "0016", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +57;"ILS 2.0 Separator";"0057";"Separator :8";"B/9";1;"958.00, 11500.00, 1697.60";"209.86, 150.00, 11.31";"gAABDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0113, 0114";"";"";{"Zuordnung": "0017", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +58;"ILS 2.0 Separator";"0058";"Separator :9";"B/9";1;"958.00, 10700.00, 1697.60";"209.86, 150.00, 11.31";"gAABDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0111, 0112";"";"";{"Zuordnung": "0018", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +59;"ILS 2.0 Separator";"0059";"Separator :10";"B/8";1;"958.00, 9900.00, 1697.60";"209.86, 150.00, 11.31";"gAABDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0109, 0110";"";"";{"Zuordnung": "0019", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +60;"ILS 2.0 Separator";"0060";"Separator :11";"B/8";1;"958.00, 9100.00, 1697.60";"209.86, 150.00, 11.31";"gAABDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0107, 0108";"";"";{"Zuordnung": "0020", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +61;"ILS 2.0 Separator";"0061";"Separator :12";"B/8";1;"958.00, 8300.00, 1697.60";"209.86, 150.00, 11.31";"gVogDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0105, 0106";"";"";{"Zuordnung": "0021", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +62;"ILS 2.0 Separator";"0062";"Separator :13";"B/7";1;"958.00, 7500.00, 1697.60";"209.86, 150.00, 11.31";"jY8gDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0103, 0104";"";"";{"Zuordnung": "0022", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +63;"ILS 2.0 Separator";"0063";"Separator :14";"B/7";1;"958.00, 6700.00, 1697.60";"209.86, 150.00, 11.31";"mcQgDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0101, 0102";"";"";{"Zuordnung": "0023", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +64;"ILS 2.0 Separator";"0064";"Separator :15";"B/6";1;"958.00, 5900.00, 1697.60";"209.86, 150.00, 11.31";"pfkgDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0099, 0100";"";"";{"Zuordnung": "0024", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +65;"ILS 2.0 Separator";"0065";"Separator :16";"B/6";1;"958.00, 5100.00, 1697.60";"209.86, 150.00, 11.31";"si4gDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0097, 0098";"";"";{"Zuordnung": "0025", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +66;"ILS 2.0 Separator";"0066";"Separator :17";"B/6";1;"958.00, 4300.00, 1697.60";"209.86, 150.00, 11.31";"vmMgDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0095, 0096";"";"";{"Zuordnung": "0026", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +67;"ILS 2.0 Separator";"0067";"Separator :18";"B/5";1;"958.00, 3500.00, 1697.60";"209.86, 150.00, 11.31";"ypggDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0093, 0094";"";"";{"Zuordnung": "0027", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +68;"ILS 2.0 Separator";"0068";"Separator :19";"B/5";1;"958.00, 2700.00, 1697.60";"209.86, 150.00, 11.31";"1s0gDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0091, 0092";"";"";{"Zuordnung": "0028", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +69;"ILS 2.0 Separator";"0069";"Separator :20";"B/4";1;"958.00, 1900.00, 1697.60";"209.86, 150.00, 11.31";"4wIgDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0089, 0090";"";"";{"Zuordnung": "0029", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +70;"ILS 2.0 Separator";"0070";"Separator :21";"B/4";1;"958.00, 1100.00, 1697.60";"209.86, 150.00, 11.31";"7zcgDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0087, 0088";"";"";{"Zuordnung": "0030", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +71;"ILS 2.0 Separator";"0071";"Separator :22";"B/4";1;"958.00, 300.00, 1697.60";"209.86, 150.00, 11.31";"+2wgDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0085, 0086";"";"";{"Zuordnung": "0031", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +72;"ILS 2.0 Separator";"0072";"Separator :23";"B/3";1;"958.00, -500.00, 1697.60";"209.86, 150.00, 11.31";"B6EfDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0083, 0084";"";"";{"Zuordnung": "0032", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +73;"ILS 2.0 Separator";"0073";"Separator :24";"B/3";1;"958.00, -1300.00, 1697.60";"209.86, 150.00, 11.31";"E9YfDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0081, 0082";"";"";{"Zuordnung": "0033", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +74;"ILS 2.0 Separator";"0074";"Separator :25";"B/2";1;"958.00, -2100.00, 1697.60";"209.86, 150.00, 11.31";"IAsfDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0079, 0080";"";"";{"Zuordnung": "0034", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +75;"ILS 2.0 Separator";"0075";"Separator :26";"B/2";1;"958.00, -2900.00, 1697.60";"209.86, 150.00, 11.31";"LEAfDre5GUf3AAAAAAAAWoJ4";"";"";"";"";"0077, 0078";"";"";{"Zuordnung": "0035", "ARTINR": "200000077", "Höhe": "1656", "Drehung": 90} +76;"ILS Weiche";"0076";"ILS Weiche :1";"A/1";1;"400.00, -5478.00, 1554.00";"250.00, 100.00, 30.00";"";"";"";"";"";"0040, 0036";"";"";{"Erzeugt aus": "Kreisel-Beruehrpunkt", "Kreisel A": "0002", "Kreisel B": "0001", "Achse von Kreisel": "0002", "Beruehrung": "Kreis/Kreis"} +77;"ILS Ausschleuselement";"0077";"ILS Ausschleuselement :1";"F/2";1;"9560.00, -3510.15, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0075";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0035", "Streckenende": "Anfang"} +78;"ILS Einschleuselement";"0078";"ILS Einschleuselement :1";"A/2";1;"349.20, -3537.65, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0075";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0035", "Streckenende": "Ende"} +79;"ILS Ausschleuselement";"0079";"ILS Ausschleuselement :2";"F/2";1;"9560.00, -2710.15, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0074";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0034", "Streckenende": "Anfang"} +80;"ILS Einschleuselement";"0080";"ILS Einschleuselement :2";"A/2";1;"349.20, -2737.65, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0074";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0034", "Streckenende": "Ende"} +81;"ILS Ausschleuselement";"0081";"ILS Ausschleuselement :3";"F/3";1;"9560.00, -1910.15, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0073";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0033", "Streckenende": "Anfang"} +82;"ILS Einschleuselement";"0082";"ILS Einschleuselement :3";"A/3";1;"349.20, -1937.65, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0073";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0033", "Streckenende": "Ende"} +83;"ILS Ausschleuselement";"0083";"ILS Ausschleuselement :4";"F/3";1;"9560.00, -1110.15, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0072";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0032", "Streckenende": "Anfang"} +84;"ILS Einschleuselement";"0084";"ILS Einschleuselement :4";"A/3";1;"349.20, -1137.65, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0072";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0032", "Streckenende": "Ende"} +85;"ILS Ausschleuselement";"0085";"ILS Ausschleuselement :5";"F/3";1;"9560.00, -310.15, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0071";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0031", "Streckenende": "Anfang"} +86;"ILS Einschleuselement";"0086";"ILS Einschleuselement :5";"A/3";1;"349.20, -337.65, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0071";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0031", "Streckenende": "Ende"} +87;"ILS Ausschleuselement";"0087";"ILS Ausschleuselement :6";"F/4";1;"9560.00, 489.75, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0070";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0030", "Streckenende": "Anfang"} +88;"ILS Einschleuselement";"0088";"ILS Einschleuselement :6";"A/4";1;"349.20, 462.25, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0070";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0030", "Streckenende": "Ende"} +89;"ILS Ausschleuselement";"0089";"ILS Ausschleuselement :7";"F/4";1;"9560.00, 1289.75, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0069";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0029", "Streckenende": "Anfang"} +90;"ILS Einschleuselement";"0090";"ILS Einschleuselement :7";"A/4";1;"349.20, 1262.25, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0069";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0029", "Streckenende": "Ende"} +91;"ILS Ausschleuselement";"0091";"ILS Ausschleuselement :8";"F/5";1;"9560.00, 2089.75, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0068";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0028", "Streckenende": "Anfang"} +92;"ILS Einschleuselement";"0092";"ILS Einschleuselement :8";"A/5";1;"349.20, 2062.25, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0068";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0028", "Streckenende": "Ende"} +93;"ILS Ausschleuselement";"0093";"ILS Ausschleuselement :9";"F/5";1;"9560.00, 2889.75, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0067";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0027", "Streckenende": "Anfang"} +94;"ILS Einschleuselement";"0094";"ILS Einschleuselement :9";"A/5";1;"349.20, 2862.25, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0067";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0027", "Streckenende": "Ende"} +95;"ILS Ausschleuselement";"0095";"ILS Ausschleuselement :10";"F/5";1;"9560.00, 3689.75, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0066";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0026", "Streckenende": "Anfang"} +96;"ILS Einschleuselement";"0096";"ILS Einschleuselement :10";"A/5";1;"349.20, 3662.25, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0066";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0026", "Streckenende": "Ende"} +97;"ILS Ausschleuselement";"0097";"ILS Ausschleuselement :11";"F/6";1;"9560.00, 4489.75, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0065";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0025", "Streckenende": "Anfang"} +98;"ILS Einschleuselement";"0098";"ILS Einschleuselement :11";"A/6";1;"349.20, 4462.25, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0065";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0025", "Streckenende": "Ende"} +99;"ILS Ausschleuselement";"0099";"ILS Ausschleuselement :12";"F/6";1;"9560.00, 5289.75, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0064";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0024", "Streckenende": "Anfang"} +100;"ILS Einschleuselement";"0100";"ILS Einschleuselement :12";"A/6";1;"349.20, 5262.25, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0064";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0024", "Streckenende": "Ende"} +101;"ILS Ausschleuselement";"0101";"ILS Ausschleuselement :13";"F/7";1;"9560.00, 6089.75, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0063";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0023", "Streckenende": "Anfang"} +102;"ILS Einschleuselement";"0102";"ILS Einschleuselement :13";"A/7";1;"349.20, 6062.25, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0063";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0023", "Streckenende": "Ende"} +103;"ILS Ausschleuselement";"0103";"ILS Ausschleuselement :14";"F/7";1;"9560.00, 6889.75, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0062";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0022", "Streckenende": "Anfang"} +104;"ILS Einschleuselement";"0104";"ILS Einschleuselement :14";"A/7";1;"349.20, 6862.25, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0062";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0022", "Streckenende": "Ende"} +105;"ILS Ausschleuselement";"0105";"ILS Ausschleuselement :15";"F/7";1;"9560.00, 7689.75, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0061";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0021", "Streckenende": "Anfang"} +106;"ILS Einschleuselement";"0106";"ILS Einschleuselement :15";"A/7";1;"349.20, 7662.25, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0061";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0021", "Streckenende": "Ende"} +107;"ILS Ausschleuselement";"0107";"ILS Ausschleuselement :16";"F/8";1;"9560.00, 8489.75, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0060";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0020", "Streckenende": "Anfang"} +108;"ILS Einschleuselement";"0108";"ILS Einschleuselement :16";"A/8";1;"349.20, 8462.25, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0060";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0020", "Streckenende": "Ende"} +109;"ILS Ausschleuselement";"0109";"ILS Ausschleuselement :17";"F/8";1;"9560.00, 9289.75, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0059";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0019", "Streckenende": "Anfang"} +110;"ILS Einschleuselement";"0110";"ILS Einschleuselement :17";"A/8";1;"349.20, 9262.25, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0059";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0019", "Streckenende": "Ende"} +111;"ILS Ausschleuselement";"0111";"ILS Ausschleuselement :18";"F/9";1;"9560.00, 10089.75, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0058";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0018", "Streckenende": "Anfang"} +112;"ILS Einschleuselement";"0112";"ILS Einschleuselement :18";"A/9";1;"349.20, 10062.25, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0058";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0018", "Streckenende": "Ende"} +113;"ILS Ausschleuselement";"0113";"ILS Ausschleuselement :19";"F/9";1;"9560.00, 10889.75, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0057";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0017", "Streckenende": "Anfang"} +114;"ILS Einschleuselement";"0114";"ILS Einschleuselement :19";"A/9";1;"349.20, 10862.25, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0057";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0017", "Streckenende": "Ende"} +115;"ILS Ausschleuselement";"0115";"ILS Ausschleuselement :20";"F/9";1;"9560.00, 11689.75, 1911.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0056";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Strecke": "0016", "Streckenende": "Anfang"} +116;"ILS Einschleuselement";"0116";"ILS Einschleuselement :20";"A/9";1;"349.20, 11662.25, 1674.36";"100.75, 250.30, 30.00";"";"";"";"";"";"0056";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Strecke": "0016", "Streckenende": "Ende"} +117;"ILS Ausschleuselement";"0117";"ILS Ausschleuselement :21";"A/4";1;"-400.00, 97.60, 1598.56";"250.00, 100.00, 30.00";"";"";"";"";"";"0055";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Förderer": "0015", "Streckenende": "Anfang"} +118;"ILS Einschleuselement";"0118";"ILS Einschleuselement :21";"A/10";1;"-400.00, 12976.20, 1598.56";"250.00, 100.00, 30.00";"";"";"";"";"";"0054";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Förderer": "0015", "Streckenende": "Ende"} +119;"ILS Ausschleuselement";"0119";"ILS Ausschleuselement :22";"A/1";1;"350.00, -4133.15, 1671.90";"100.75, 250.30, 30.00";"";"";"";"";"";"0053";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Förderer": "0014", "Streckenende": "Anfang"} +120;"ILS Einschleuselement";"0120";"ILS Einschleuselement :22";"F/1";1;"9560.00, -4105.65, 1908.90";"100.75, 250.30, 30.00";"";"";"";"";"";"0052";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Förderer": "0014", "Streckenende": "Ende"} +121;"ILS Ausschleuselement";"0121";"ILS Ausschleuselement :23";"A/11";1;"350.00, 14119.85, 1671.90";"100.74, 250.30, 30.00";"";"";"";"";"";"0051";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0002", "Förderer": "0013", "Streckenende": "Anfang"} +122;"ILS Einschleuselement";"0122";"ILS Einschleuselement :23";"F/11";1;"9560.00, 14147.25, 1908.90";"100.74, 250.30, 30.00";"";"";"";"";"";"0050";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0010", "Förderer": "0013", "Streckenende": "Ende"} diff --git a/tests/reference/mubea_tests_sivas.csv b/tests/reference/mubea_tests_sivas.csv index d23c5ac..de69b73 100644 --- a/tests/reference/mubea_tests_sivas.csv +++ b/tests/reference/mubea_tests_sivas.csv @@ -1,11 +1,11 @@ Nr;TeileArt;SivasNummer;Bezeichnung;Dispogruppe;Anzahl;Laenge[mm];IDs;details -1;"ILS 2.0 Kreisel";"6200";"Kreisel11";20;1;;"0010";{"Hoehe in m": "1.941", "Kreiselart": "STANDARD", "Abstand (Kreiselachse A - Kreiselachse) in Meter": "20.02", "Anzahl der Separatoren": "4", "Anzahl der Scanner": "2", "Anzahl der Rampen": "0", "Geruest fuer Einzelmodul": true, "Geruestoption fuer Einzelmodul": "Schoenenberger Geruest"} -2;"ILS 2.0 Kreisel";"6200";"Kreisel10";20;1;;"0002";{"Hoehe in m": "1.467", "Kreiselart": "STANDARD", "Abstand (Kreiselachse A - Kreiselachse) in Meter": "20.02", "Anzahl der Separatoren": "4", "Anzahl der Scanner": "4", "Anzahl der Rampen": "0", "Geruest fuer Einzelmodul": true, "Geruestoption fuer Einzelmodul": "Schoenenberger Geruest"} -3;"ILS 2.0 Kreisel";"6200";"Kreisel9";20;1;;"0001";{"Hoehe in m": "1.467", "Kreiselart": "STANDARD", "Abstand (Kreiselachse A - Kreiselachse) in Meter": "5.0", "Anzahl der Separatoren": "2", "Anzahl der Scanner": "1", "Anzahl der Rampen": "0", "Geruest fuer Einzelmodul": true, "Geruestoption fuer Einzelmodul": "Schoenenberger Geruest"} +1;"ILS 2.0 Kreisel";"6200";"Kreisel3";20;1;;"0010";{"Hoehe in m": "2.028", "Kreiselart": "STANDARD", "Abstand (Kreiselachse A - Kreiselachse) in Meter": "20.02", "Anzahl der Separatoren": "4", "Anzahl der Scanner": "2", "Anzahl der Rampen": "0", "Geruest fuer Einzelmodul": true, "Geruestoption fuer Einzelmodul": "Schoenenberger Geruest"} +2;"ILS 2.0 Kreisel";"6200";"Kreisel2";20;1;;"0002";{"Hoehe in m": "1.554", "Kreiselart": "STANDARD", "Abstand (Kreiselachse A - Kreiselachse) in Meter": "20.02", "Anzahl der Separatoren": "4", "Anzahl der Scanner": "4", "Anzahl der Rampen": "0", "Geruest fuer Einzelmodul": true, "Geruestoption fuer Einzelmodul": "Schoenenberger Geruest"} +3;"ILS 2.0 Kreisel";"6200";"Kreisel1";20;1;;"0001";{"Hoehe in m": "1.554", "Kreiselart": "STANDARD", "Abstand (Kreiselachse A - Kreiselachse) in Meter": "5.0", "Anzahl der Separatoren": "2", "Anzahl der Scanner": "1", "Anzahl der Rampen": "0", "Geruest fuer Einzelmodul": true, "Geruestoption fuer Einzelmodul": "Schoenenberger Geruest"} 4;"BT - Beladung (mit Vereinzeler, ohne Separator)";"6215";"";20;1;;"0047";{} 5;"Abwurf fuer Klammerbuegel Sitzbezuege / Kleiderbuegel";"6215";"";20;2;;"0049, 0048";{} -6;"ILS 2.0 Strecke";"6220";"VF_4";20;1;;"0015";{"Hoehe in m": "0", "Anzahl Foerdergruppen": 1, "Anzahl Gefaellegruppen": 2, "GruppenteileGefaelle": {"AnzahlGeraden": 2, "Laenge in Meter": [1.602, 2.15], "Winkel": [3.0, 3.0], "AnzahlKurvenLinks90": 0, "AnzahlKurvenLinks60": 2, "AnzahlKurvenLinks30": 0, "AnzahlKurvenRechts90": 0, "AnzahlKurvenRechts60": 0, "AnzahlKurvenRechts30": 0}, "GruppenteileAngetrieben": {"MotorSeite": ["rechts"], "AnzahlGeraden": 1, "Laenge in Meter": [4.809], "Winkel": [9.0], "Foerderrichtung": ["Auf"], "AnzahlKurvenAussen90": 0, "AnzahlKurvenAussen60": 0, "AnzahlKurvenAussen30": 0, "AnzahlKurvenInnen90": 0, "AnzahlKurvenInnen60": 0, "AnzahlKurvenInnen30": 0}, "Anzahl der Separatoren": 4, "Anzahl der Scanner": 1, "Geruest fuer Einzelmodul": false, "Geruestoption fuer Einzelmodul": "Schoenenberger Geruest"} -7;"ILS 2.0 Strecke";"6220";"VF_3";20;1;;"0014";{"Hoehe in m": "0.237", "Anzahl Foerdergruppen": 1, "Anzahl Gefaellegruppen": 2, "GruppenteileGefaelle": {"AnzahlGeraden": 2, "Laenge in Meter": [2.298, 1.001], "Winkel": [3.0, 3.0], "AnzahlKurvenLinks90": 0, "AnzahlKurvenLinks60": 0, "AnzahlKurvenLinks30": 0, "AnzahlKurvenRechts90": 0, "AnzahlKurvenRechts60": 0, "AnzahlKurvenRechts30": 0}, "GruppenteileAngetrieben": {"MotorSeite": ["rechts"], "AnzahlGeraden": 1, "Laenge in Meter": [2.32], "Winkel": [21.0], "Foerderrichtung": ["Auf"], "AnzahlKurvenAussen90": 0, "AnzahlKurvenAussen60": 0, "AnzahlKurvenAussen30": 0, "AnzahlKurvenInnen90": 0, "AnzahlKurvenInnen60": 0, "AnzahlKurvenInnen30": 0}, "Anzahl der Separatoren": 2, "Anzahl der Scanner": 0, "Geruest fuer Einzelmodul": false, "Geruestoption fuer Einzelmodul": "Schoenenberger Geruest"} -8;"ILS 2.0 Strecke";"6220";"VF_2";20;1;;"0013";{"Hoehe in m": "0.237", "Anzahl Foerdergruppen": 1, "Anzahl Gefaellegruppen": 2, "GruppenteileGefaelle": {"AnzahlGeraden": 2, "Laenge in Meter": [2.298, 1.001], "Winkel": [3.0, 3.0], "AnzahlKurvenLinks90": 0, "AnzahlKurvenLinks60": 0, "AnzahlKurvenLinks30": 0, "AnzahlKurvenRechts90": 0, "AnzahlKurvenRechts60": 0, "AnzahlKurvenRechts30": 0}, "GruppenteileAngetrieben": {"MotorSeite": ["rechts"], "AnzahlGeraden": 1, "Laenge in Meter": [2.32], "Winkel": [21.0], "Foerderrichtung": ["Auf"], "AnzahlKurvenAussen90": 0, "AnzahlKurvenAussen60": 0, "AnzahlKurvenAussen30": 0, "AnzahlKurvenInnen90": 0, "AnzahlKurvenInnen60": 0, "AnzahlKurvenInnen30": 0}, "Anzahl der Separatoren": 2, "Anzahl der Scanner": 0, "Geruest fuer Einzelmodul": false, "Geruestoption fuer Einzelmodul": "Schoenenberger Geruest"} -9;"ILS 2.0 Gefaellestrecke";"6220";"GF_28, GF_27, GF_26, GF_25, GF_24, GF_23, GF_22, GF_21, GF_20, GF_19, GF_18, GF_17, GF_16, GF_15, GF_14, GF_13, GF_12, GF_11, GF_10, GF_9";20;20;;"0035, 0034, 0033, 0032, 0031, 0030, 0029, 0028, 0027, 0026, 0025, 0024, 0023, 0022, 0021, 0020, 0019, 0018, 0017, 0016";{"Hoehe in m": "1.941", "Typ": "Gefaellestrecke", "Laenge in Meter": "7.954", "Winkel": "2.3", "Anzahl der Separatoren": "1", "Anzahl der Scanner": "0", "Geruest fuer Einzelmodul": false, "Geruestoption fuer Einzelmodul": "Schoenenberger Geruest"} +6;"ILS 2.0 Strecke";"6220";"VF_3";20;1;;"0015";{"Hoehe in m": "0", "Anzahl Foerdergruppen": 1, "Anzahl Gefaellegruppen": 2, "GruppenteileGefaelle": {"AnzahlGeraden": 2, "Laenge in Meter": [1.602, 2.15], "Winkel": [3.0, 3.0], "AnzahlKurvenLinks90": 0, "AnzahlKurvenLinks60": 2, "AnzahlKurvenLinks30": 0, "AnzahlKurvenRechts90": 0, "AnzahlKurvenRechts60": 0, "AnzahlKurvenRechts30": 0}, "GruppenteileAngetrieben": {"MotorSeite": ["rechts"], "AnzahlGeraden": 1, "Laenge in Meter": [4.809], "Winkel": [9.0], "Foerderrichtung": ["Auf"], "AnzahlKurvenAussen90": 0, "AnzahlKurvenAussen60": 0, "AnzahlKurvenAussen30": 0, "AnzahlKurvenInnen90": 0, "AnzahlKurvenInnen60": 0, "AnzahlKurvenInnen30": 0}, "Anzahl der Separatoren": 4, "Anzahl der Scanner": 1, "Geruest fuer Einzelmodul": false, "Geruestoption fuer Einzelmodul": "Schoenenberger Geruest"} +7;"ILS 2.0 Strecke";"6220";"VF_2";20;1;;"0014";{"Hoehe in m": "0.237", "Anzahl Foerdergruppen": 1, "Anzahl Gefaellegruppen": 2, "GruppenteileGefaelle": {"AnzahlGeraden": 2, "Laenge in Meter": [2.298, 1.001], "Winkel": [3.0, 3.0], "AnzahlKurvenLinks90": 0, "AnzahlKurvenLinks60": 0, "AnzahlKurvenLinks30": 0, "AnzahlKurvenRechts90": 0, "AnzahlKurvenRechts60": 0, "AnzahlKurvenRechts30": 0}, "GruppenteileAngetrieben": {"MotorSeite": ["rechts"], "AnzahlGeraden": 1, "Laenge in Meter": [2.32], "Winkel": [21.0], "Foerderrichtung": ["Auf"], "AnzahlKurvenAussen90": 0, "AnzahlKurvenAussen60": 0, "AnzahlKurvenAussen30": 0, "AnzahlKurvenInnen90": 0, "AnzahlKurvenInnen60": 0, "AnzahlKurvenInnen30": 0}, "Anzahl der Separatoren": 2, "Anzahl der Scanner": 0, "Geruest fuer Einzelmodul": false, "Geruestoption fuer Einzelmodul": "Schoenenberger Geruest"} +8;"ILS 2.0 Strecke";"6220";"VF_1";20;1;;"0013";{"Hoehe in m": "0.237", "Anzahl Foerdergruppen": 1, "Anzahl Gefaellegruppen": 2, "GruppenteileGefaelle": {"AnzahlGeraden": 2, "Laenge in Meter": [2.298, 1.001], "Winkel": [3.0, 3.0], "AnzahlKurvenLinks90": 0, "AnzahlKurvenLinks60": 0, "AnzahlKurvenLinks30": 0, "AnzahlKurvenRechts90": 0, "AnzahlKurvenRechts60": 0, "AnzahlKurvenRechts30": 0}, "GruppenteileAngetrieben": {"MotorSeite": ["rechts"], "AnzahlGeraden": 1, "Laenge in Meter": [2.32], "Winkel": [21.0], "Foerderrichtung": ["Auf"], "AnzahlKurvenAussen90": 0, "AnzahlKurvenAussen60": 0, "AnzahlKurvenAussen30": 0, "AnzahlKurvenInnen90": 0, "AnzahlKurvenInnen60": 0, "AnzahlKurvenInnen30": 0}, "Anzahl der Separatoren": 2, "Anzahl der Scanner": 0, "Geruest fuer Einzelmodul": false, "Geruestoption fuer Einzelmodul": "Schoenenberger Geruest"} +9;"ILS 2.0 Gefaellestrecke";"6220";"GF_20, GF_19, GF_18, GF_17, GF_16, GF_15, GF_14, GF_13, GF_12, GF_11, GF_10, GF_9, GF_8, GF_7, GF_6, GF_5, GF_4, GF_3, GF_2, GF_1";20;20;;"0035, 0034, 0033, 0032, 0031, 0030, 0029, 0028, 0027, 0026, 0025, 0024, 0023, 0022, 0021, 0020, 0019, 0018, 0017, 0016";{"Hoehe in m": "2.028", "Typ": "Gefaellestrecke", "Laenge in Meter": "7.954", "Winkel": "2.3", "Anzahl der Separatoren": "1", "Anzahl der Scanner": "0", "Geruest fuer Einzelmodul": false, "Geruestoption fuer Einzelmodul": "Schoenenberger Geruest"} 10;"ILS 2.0 Automation und Pneumatik - Gesamtanlage";"6269";"";20;1;;"";{"Anzahl Kreisel": 3, "Anzahl Kreisel mit Pinband": 0, "Anzahl aller Separatoren in Kreisel mit PIN": 0, "Anzahl aller Separatoren in Kreisel ohne PIN": 10, "Anzahl Verbindungskreisel": 0, "Laengen aller Kreisel": 45.03, "Anzahl der Weichen": 0, "Anzahl der Eckraeder": 0, "Anzahl der einzelnen Gefaellestrecken": 20, "Anzahl der einzelnen Variofoerderer": 3, "Anzahl der Streckengruppen": 1, "Laengen aller Gefaellestrecken": 159.07999999999998, "Anzahl der Motoren Variofoerderer": 0, "Laengen aller Variofoerderer": 9.449, "Anzahl ETFs": 0, "Laengen aller ETFs": 0.0, "Anzahl aller Separatoren": 38, "Anzahl aller Scanner": 8, "Anzahl aller BTBeladung": 1, "Anzahl aller Abwurfstationen": 2} diff --git a/tests/test_export_kreisel_umlauf.py b/tests/test_export_kreisel_umlauf.py new file mode 100644 index 0000000..1e2f202 --- /dev/null +++ b/tests/test_export_kreisel_umlauf.py @@ -0,0 +1,282 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +test_export_kreisel_umlauf.py - Kreisel-Kreisel-Weiche im Umlauf. +Laeuft komplett ohne BricsCAD (reine Python-Geometrie, siehe lib/export_neighbors.py). + +Regressionstest fuer einen realen Mubea-Befund: zwei sich beruehrende Kreisel +erzeugen eine "ILS Weiche" am Beruehrpunkt (compute_kreisel_touch_switches). +Diese Weiche ist der Verzweigungspunkt zwischen beiden Kreiseln - ein +Separator direkt davor muss sie als Nachbarn bekommen, nicht (wie vor dem +Fix) einen Punkt vom jeweils ANDEREN Kreisel-Ende, weil die Weiche in +compute_kreisel_umlauf schlicht fehlte. +""" + +import os +import sys + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "lib")) + +from export_neighbors import ( # noqa: E402 + compute_kreisel_touch_switches, + compute_kreisel_umlauf, +) +from export_csv import ( # noqa: E402 + build_strecke_schleus_items, + map_separator_kette_items, + resolve_umlauf_und_sepliste_nachbarn, +) + +DURCHMESSER_MM = 800.0 +RADIUS_MM = DURCHMESSER_MM / 2.0 + + +def _kreisel(teileid, x0, y0, rotation, abstand=1000.0): + return { + "teileart": "ILS 2.0 Kreisel", + "teileid": teileid, + "x": x0, "y": y0, "z": 0.0, + "rotation": rotation, + "attribs": {"ABSTAND": str(abstand), "DREHRICHTUNG": "UZS"}, + "_bbox": {"cx": x0, "cy": y0, "cz": 0.0, + "dx": abstand + DURCHMESSER_MM, "dy": DURCHMESSER_MM}, + } + + +def _separator(teileid, x, y): + return { + "teileart": "ILS 2.0 Separator", + "teileid": teileid, + "_bbox": {"cx": x, "cy": y, "cz": 0.0, "dx": 150.0, "dy": 100.0}, + } + + +def _zwei_beruehrende_kreisel(): + """Zwei Kreisel, deren AN8-Enden sich exakt beruehren (End-an-End, wie im + Mubea-Fall: 'Kreis/Kreis'-Beruehrung an der jeweiligen AN8-Kappe). + + Kreisel 1 liegt entlang +X ab x=0 (AN8-Mitte bei radius=400, SP8-Mitte bei + radius+abstand=1400). Kreisel 2 liegt entlang -X ab x=800 (AN8-Mitte bei + 800-400=400) - beide AN8-Kappen beruehren sich bei x=400 (Kreis/Kreis). + """ + k1 = _kreisel("0001", 0.0, 0.0, 0.0) + k2 = _kreisel("0002", 800.0, 0.0, 180.0) + return [k1, k2] + + +class TestKreiselKreiselWeicheImUmlauf: + + def test_touch_switch_erkannt(self): + items = _zwei_beruehrende_kreisel() + switches = compute_kreisel_touch_switches(items, tolerance_mm=0.0, + durchmesser_mm=DURCHMESSER_MM) + assert len(switches) == 1 + sw = switches[0] + assert sorted(sw["nachbarn"]) == ["0001", "0002"] + assert sw["key"] == "WEICHE#0001#0002" + + def test_weiche_in_beiden_umlaeufen(self): + """Die Weiche muss als Punkt in BEIDEN Kreisel-Umlaeufen auftauchen - + sie ist der gemeinsame Verzweigungspunkt (K1->K2 und K2->K1).""" + items = _zwei_beruehrende_kreisel() + switches = compute_kreisel_touch_switches(items, tolerance_mm=0.0, + durchmesser_mm=DURCHMESSER_MM) + umlauf = compute_kreisel_umlauf(items, sep_kette={}, tolerance_mm=0.0, + durchmesser_mm=DURCHMESSER_MM, + touch_switches=switches) + weiche_key = switches[0]["key"] + for tid in ("0001", "0002"): + keys = [p[0] for p in umlauf[tid]] + assert weiche_key in keys, f"Weiche fehlt im Umlauf von Kreisel {tid}" + + def test_separator_bekommt_weiche_als_nachbar_nicht_anderen_kreisel(self): + """Realer Mubea-Befund: ein Separator, der unmittelbar VOR der + Kreisel-Kreisel-Weiche liegt (auf der AN8-Seite von Kreisel 1), muss + die Weiche als Umlauf-Nachbarn bekommen - nicht einen Punkt, der + eigentlich zu Kreisel 2 gehoert (das war der Bug: die Weiche fehlte + in punkte_je_kreisel, wodurch beide Separatoren am Beruehrpunkt auf + denselben (falschen) Nachbarn verwiesen).""" + items = _zwei_beruehrende_kreisel() + # Separator dicht vor der Beruehrung (x=390), gehoert zu Kreisel 1. + sep = _separator("0036", 390.0, 0.0) + items.append(sep) + + switches = compute_kreisel_touch_switches(items, tolerance_mm=0.0, + durchmesser_mm=DURCHMESSER_MM) + assert len(switches) == 1 + weiche_key = switches[0]["key"] + + umlauf = compute_kreisel_umlauf(items, sep_kette={}, tolerance_mm=50.0, + durchmesser_mm=DURCHMESSER_MM, + touch_switches=switches) + + punkte_k1 = {p[0]: (p[1], p[2]) for p in umlauf["0001"]} + assert "0036" in punkte_k1, "Separator 0036 fehlt im Umlauf von Kreisel 1" + vorgaenger, nachfolger = punkte_k1["0036"] + assert weiche_key in (vorgaenger, nachfolger), ( + f"Separator 0036 sollte die Kreisel-Kreisel-Weiche ({weiche_key}) " + f"als Umlauf-Nachbarn haben, hat aber vorgaenger={vorgaenger!r}, " + f"nachfolger={nachfolger!r}") + + +class TestKreiselBoundsRotationsUnabhaengig: + """Regressionstest fuer einen zweiten realen Mubea-Befund: ein um 90 Grad + gedrehter, sehr langer Kreisel (Achse entlang Welt-Y statt Welt-X) bekam + in compute_kreisel_umlauf eine falsch orientierte Matching-Box (schmal in + Y, ueberbreit in X statt umgekehrt) - kreisel_bounds baute die Box bisher + IMMER mit dx=durchmesser+achs_len/dy=durchmesser, unabhaengig von der + tatsaechlichen Drehung. Echte anliegende Separatoren (weit entfernt in X, + aber auf der Kreiselachse in Y) fielen dadurch durch, waehrend entfernte, + zufaellig in der ueberbreiten X-Box liegende Separatoren faelschlich als + Kreisel-Nachbarn erkannt wurden (Mubea Kreisel 0002, 20m lang, Drehung 90).""" + + def _langer_kreisel_90grad(self): + # Kreisel 0002 aus dem Mubea-Datensatz: x=0, y=4529.5, Drehung 90, + # ABSTAND=20020mm -> Achse verlaeuft entlang Welt-Y von y~4930 bis + # y~24950, nicht entlang Welt-X. + return _kreisel("0002", 0.0, 4529.5, 90.0, abstand=20020.0) + + def test_separator_auf_der_gedrehten_achse_wird_erkannt(self): + """Ein Separator, der WIRKLICH auf der (gedrehten) Kreiselachse liegt + (x nahe 0, y zwischen AN8- und SP8-Mitte), muss erkannt werden.""" + k = self._langer_kreisel_90grad() + sep = _separator("9001", 0.0, 10000.0) # liegt mitten auf der Achse + items = [k, sep] + umlauf = compute_kreisel_umlauf(items, sep_kette={}, tolerance_mm=200.0, + durchmesser_mm=DURCHMESSER_MM) + keys = [p[0] for p in umlauf["0002"]] + assert "9001" in keys, "Separator auf der gedrehten Kreiselachse wurde nicht erkannt" + + def test_separator_weit_neben_der_achse_wird_nicht_erkannt(self): + """Ein Separator, der (wie im Mubea-Fall Separator 0065/0066) 958mm + seitlich der schmalen Kreiselbreite (durchmesser=800mm, Radius 400mm) + liegt, gehoert NICHT zum Kreisel - er darf nicht ueber eine faelschlich + breite X-Box eingefangen werden.""" + k = self._langer_kreisel_90grad() + sep = _separator("0065", 958.0, 5100.0) + items = [k, sep] + umlauf = compute_kreisel_umlauf(items, sep_kette={}, tolerance_mm=200.0, + durchmesser_mm=DURCHMESSER_MM) + keys = [p[0] for p in umlauf["0002"]] + assert "0065" not in keys, ( + "Separator 958mm neben der Kreiselachse wurde faelschlich als " + "Kreisel-Nachbar erkannt (rotationsabhaengiger BBox-Bug)") + + +class TestSeplisteNachbarnAufgeloest: + """Regressionstest fuer einen dritten realen Mubea-Befund: die meisten + Separatoren blieben trotz sepliste-XDATA komplett ohne "Nachbarn". + + Architektur (nach dem Umbau "Proxy liefert Zeilen, sepliste nur + Reihenfolge"): die in einer Kette verpackten Separatoren liegen bereits als + echte (Proxy-)Separator_SP-Items vor (der LISP-Export fuegt je verpacktem + Symbol eine temporaere Kopie ein). map_separator_kette_items erzeugt daher + KEINE neuen Zeilen mehr, sondern ordnet jedem sepliste-SEP das vorhandene + Separator-Item zu (Match ueber Wrapper-ID + INSERT-Punkt) und traegt es in + sep_kette_by_key ein; die AS/ES-Zeilen kommen weiter aus + build_strecke_schleus_items. resolve_umlauf_und_sepliste_nachbarn setzt + dann die Nachbarn als ECHTE TeileIds (nicht die rohen sep_kette-Schluessel, + frueherer Bug).""" + + def _sepliste_kette(self): + """Ein Kreisel + eine Gefaellestrecke mit sepliste AS(1) -> SEP(2) -> + ES(3) PLUS das bereits vorhandene Proxy-Separator-Item fuer den SEP + (wie es der freie-Separator-Pfad in process_blocks erzeugt: TeileId, + Merkmal "Zuordnung" = Wrapper-ID, INSERT-Punkt _x/_y an der sepliste- + SEP-Koordinate). "nachbarn" auf der Strecke simuliert das Ergebnis von + compute_neighbor_ids (BBox-Ueberschneidung Strecke <-> Kreisel) - die + Vorbedingung, unter der compute_strecke_kreisel_schleus die AS/ES- + Schleuselemente erzeugt.""" + k = _kreisel("0001", 0.0, 0.0, 0.0, abstand=1000.0) + strecke = { + "teileart": "ILS 2.0 Gefaellestrecke", + "teileid": "0010", + "x": 5000.0, "y": 0.0, "z": 0.0, + "nachbarn": "0001", + "_bbox": {"cx": 5000.0, "cy": 0.0, "cz": 0.0, "dx": 8000.0, "dy": 300.0}, + "k1": "", "k2": "", + "sepliste": [ + {"typ": "AS", "lfdnr": 1, "x": 1500.0, "y": 0.0}, + {"typ": "SEP", "lfdnr": 2, "x": 5000.0, "y": 0.0}, + {"typ": "ES", "lfdnr": 3, "x": 8500.0, "y": 0.0}, + ], + } + # Proxy-Separator-Item (bereits vorhanden), Zuordnung = Wrapper-ID 0010, + # INSERT-Punkt an der sepliste-SEP-Koordinate (5000, 0). + proxy_sep = { + "teileart": "ILS 2.0 Separator", + "teileid": "0055", + "merkmale": {"Zuordnung": "0010"}, + "_x": 5000.0, "_y": 0.0, + "_bbox": {"cx": 5000.0, "cy": 0.0, "cz": 0.0, "dx": 150.0, "dy": 210.0}, + "nachbarn": "", + } + return [k, strecke, proxy_sep] + + def test_keine_rohen_sep_kette_schluessel_in_nachbarn(self): + from export_neighbors import compute_sep_kette + items = self._sepliste_kette() + sep_kette = compute_sep_kette(items) + assert set(sep_kette) == {"0010#1", "0010#2", "0010#3"} + + touch_switches = [] + weiche_by_key = {} + kreisel_umlauf = compute_kreisel_umlauf( + items, sep_kette, tolerance_mm=50.0, durchmesser_mm=DURCHMESSER_MM, + touch_switches=touch_switches) + + 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) + + resolve_umlauf_und_sepliste_nachbarn( + items, kreisel_umlauf, sep_kette, sep_kette_by_key, weiche_by_key) + + # AS/ES (neu erzeugt) + der bereits vorhandene Proxy-Separator. + sepliste_items = [it for it in items + if it.get("teileart") in + ("ILS 2.0 Separator", "ILS Ausschleuselement", "ILS Einschleuselement")] + assert len(sepliste_items) == 3, "AS/SEP/ES nicht alle vorhanden" + + for it in sepliste_items: + for nachbar in it["nachbarn"].split(","): + nachbar = nachbar.strip() + if not nachbar: + continue + assert "#" not in nachbar, ( + f'{it["teileart"]} {it["teileid"]}: "Nachbarn" enthaelt einen ' + f'unaufgeloesten sep_kette-Schluessel ({nachbar!r}) statt ' + f'einer TeileId') + + def test_sep_zeile_hat_as_und_es_als_nachbarn(self): + """Der Proxy-Separator (SEP-Position) muss nach der Aufloesung sowohl die + TeileId der AS- als auch der ES-Zeile als Nachbarn tragen.""" + from export_neighbors import compute_sep_kette + items = self._sepliste_kette() + sep_kette = compute_sep_kette(items) + kreisel_umlauf = compute_kreisel_umlauf( + items, sep_kette, tolerance_mm=50.0, durchmesser_mm=DURCHMESSER_MM, + touch_switches=[]) + 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) + resolve_umlauf_und_sepliste_nachbarn( + items, kreisel_umlauf, sep_kette, sep_kette_by_key, {}) + + as_item = sep_kette_by_key["0010#1"] + sep_item = sep_kette_by_key["0010#2"] + es_item = sep_kette_by_key["0010#3"] + + # Der SEP-Schluessel muss auf das vorhandene Proxy-Separator-Item zeigen. + assert sep_item["teileid"] == "0055", "sepliste-SEP nicht auf Proxy-Separator gemappt" + + sep_nachbarn = {n.strip() for n in sep_item["nachbarn"].split(",") if n.strip()} + assert sep_nachbarn == {as_item["teileid"], es_item["teileid"]}, ( + f'SEP-Zeile hat Nachbarn {sep_nachbarn!r}, erwartet ' + f'{{{as_item["teileid"]!r}, {es_item["teileid"]!r}}}') diff --git a/tests/test_export_separator_bbox.py b/tests/test_export_separator_bbox.py new file mode 100644 index 0000000..205fb97 --- /dev/null +++ b/tests/test_export_separator_bbox.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +test_export_separator_bbox.py - Feste Separator-Symbol-Bounding-Box. +Laeuft komplett ohne BricsCAD (reine Python-Logik). + +Regressionstest fuer einen realen Mubea-Befund: die meisten Separatoren +blieben ohne "Nachbarn", weil in ihrem export_raw.json KEINE Bounding-Box +stand. Zwei Ursachen: + + 1. In eine VF_n/GF_n-Kette EINGEBETTETE Separatoren sind seit der Umstellung + auf die "sepliste"-XDATA kein reales INSERT mehr - vla-getboundingbox kann + fuer sie keine Box liefern. + 2. Frei platzierte Separator_SP-INSERTs, deren vla-getboundingbox beim Export + scheiterte (z.B. eingefrorener Layer). + +Beide bekommen jetzt eine feste Symbol-Box aus cfg [Boundingbox] +separator_box_* (siehe export_neighbors.separator_bbox / load_separator_box_mm), +damit sie ein "_bbox" haben und an der Nachbarschafts-/Umlauf-/Zuordnungs- +erkennung teilnehmen. +""" + +import os +import sys + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "lib")) + +from export_neighbors import ( # noqa: E402 + separator_bbox, + load_separator_box_mm, + SEPARATOR_BOX_LAENGE_MM, + SEPARATOR_BOX_BREITE_MM, + SEPARATOR_BOX_HOEHE_MM, +) +from export_csv import ( # noqa: E402 + bbox_columns, + _fallback_separator_bbox, +) + + +class TestSeparatorBboxGeometrie: + + def test_unrotiert(self): + box = (210.0, 150.0, 14.0) + bb = separator_bbox(1000.0, 2000.0, 0.0, separator_box_mm=box) + assert bb["cx"] == 1000.0 and bb["cy"] == 2000.0 + assert abs(bb["dx"] - 210.0) < 1e-6, "Laenge liegt bei Drehung 0 entlang X" + assert abs(bb["dy"] - 150.0) < 1e-6, "Breite liegt bei Drehung 0 entlang Y" + assert abs(bb["dz"] - 14.0) < 1e-6 + + def test_um_90_grad_gedreht_vertauscht_dx_dy(self): + box = (210.0, 150.0, 14.0) + bb = separator_bbox(0.0, 0.0, 90.0, separator_box_mm=box) + assert abs(bb["dx"] - 150.0) < 1e-6, "bei 90 Grad liegt die Breite entlang X" + assert abs(bb["dy"] - 210.0) < 1e-6, "bei 90 Grad liegt die Laenge entlang Y" + + def test_default_masse_aus_cfg(self): + # load_separator_box_mm liest cfg/export.cfg; die Werte muessen positiv + # und plausibel sein (Symbol ~210 x 150 x 14). + laenge, breite, hoehe = load_separator_box_mm() + assert laenge > 0 and breite > 0 and hoehe > 0 + # Fallback-Konstanten muessen mit dem gemessenen Symbol uebereinstimmen + assert (SEPARATOR_BOX_LAENGE_MM, SEPARATOR_BOX_BREITE_MM, SEPARATOR_BOX_HOEHE_MM) == (210.0, 150.0, 14.0) + + +class TestFallbackSeparatorBbox: + + def test_fehlende_bbox_wird_ergaenzt(self): + """Ein Separator-INSERT ohne bbox (vla-getboundingbox scheiterte) + bekommt aus Position/Drehung + fester Box eine _bbox.""" + block = {"block_name": "Separator_SP_3D", "x": 5000.0, "y": -3000.0, + "z": 100.0, "rotation": 90.0, "attribs": {"ID": "0050"}} + cols = bbox_columns(block) + assert cols["_bbox"] is None, "Vorbedingung: Block hat keine bbox" + + cols = _fallback_separator_bbox(cols, block, separator_box_mm=(210.0, 150.0, 14.0)) + assert cols["_bbox"] is not None, "Fallback hat keine _bbox gesetzt" + assert cols["_bbox"]["cx"] == 5000.0 and cols["_bbox"]["cy"] == -3000.0 + # 90 Grad -> dx=Breite, dy=Laenge + assert abs(cols["_bbox"]["dx"] - 150.0) < 1e-6 + assert abs(cols["_bbox"]["dy"] - 210.0) < 1e-6 + assert cols["boundingbox"] != "", "Boundingbox-Spalte muss nun gefuellt sein" + + def test_vorhandene_bbox_bleibt_unveraendert(self): + """Hat der Block bereits eine echte bbox (vla-getboundingbox erfolgreich), + darf der Fallback sie NICHT ueberschreiben.""" + block = {"block_name": "Separator_SP_3D", "x": 5000.0, "y": -3000.0, + "rotation": 90.0, + "bbox": {"cx": 5001.0, "cy": -3002.0, "cz": 7.0, + "dx": 209.9, "dy": 150.0, "dz": 3.0}} + cols = bbox_columns(block) + assert cols["_bbox"] is not None + original = dict(cols["_bbox"]) + + cols2 = _fallback_separator_bbox(cols, block) + assert cols2["_bbox"] == original, "echte bbox wurde vom Fallback ueberschrieben"