export: Separator-Typ VF/GF aus der Ketten-Einheit statt Bau-XDATA

Der Typ (Merkmal "Typ") jeder Separator-Zeile kommt jetzt an EINER Stelle
aus der Einheiten-Schneidung csv:kette-einheiten (neu: csv:kette-sep-typen,
eingetragen in csv:ketten-verarbeiten) - dieselbe Quelle wie die
Einheiten-Boundingbox. VF = Separator direkt vor der Umlenkstation bzw.
zwischen Umlenk- und Motorstation, sonst GF.

Die bauzeitige XDATA SSG_SEP_TYP (ssg-sep-typ-xdata-schreiben/-lesen,
15 Einfuegestellen) entfaellt. Sie war teils falsch: der Separator vor dem
ES hinter einer Motorstation bekam "VF", und ein sep_nach-Separator einer
GF, den die folgende VF-Einheit als Einlauf nutzt, blieb "GF"
(HundM05: Sep1/5/7/9/11 und Sep2).

Unit-Tests csv:kette-sep-typen in tests/test_unit.lsp.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Samer Ayadi
2026-09-28 11:23:27 +02:00
co-authored by Claude Opus 5.5
parent 96ca43eff5
commit e67f7cc1aa
9 changed files with 85 additions and 105 deletions
+54 -52
View File
@@ -941,9 +941,9 @@
(setq zuordnung-fix-json
(strcat ",\"zuordnung_fix\":\"" (csv:json-escape (cdr zuordnung-fix-eintrag)) "\""))
)
;; Streckentyp (VF/GF) DIESES EINZELNEN Separators, bauzeitig gesetzt
;; (ssg-sep-typ-xdata-schreiben, siehe csv:sep-proxies-erzeugen/
;; -zuordnung-setzen) - NICHT vom Wrapper-Blocknamen ableitbar, da ein
;; Streckentyp (VF/GF) DIESES EINZELNEN Separators - der Typ der Einheit,
;; in der er in der Kette liegt (csv:kette-sep-typen, eingetragen von
;; csv:ketten-verarbeiten). NICHT vom Wrapper-Blocknamen ableitbar, da ein
;; VF_n/GF_n-Wrapper intern zwischen VF-/GF-Abschnitten wechseln kann.
;; export_csv.py schreibt diesen Wert in die Merkmale der Proxy-Zeile
;; (Feld "Typ").
@@ -1273,16 +1273,12 @@
)
;; --- Muster des AEUSSEREN Trennsteg-Blocks, der das Separator_SP-Symbol
;; und den Streckentyp-Marker traegt ---
;; ssg-sep-typ-xdata-schreiben (ssg_ks_insert.lsp) markiert bauzeitig NICHT
;; das Separator_SP-Symbol selbst, sondern seinen Verpacker
;; Staustrecke_Separator_SP_300_mm - der Grund: Separator_SP steckt als EIN
;; einziges, von der DWG-Blockdefinition geteiltes Sub-INSERT in JEDER
;; Staustrecke_Separator_SP_300_mm-Instanz (Block-Referenzen teilen sich ihre
;; Definition), eine XDATA-Markierung dort waere also fuer JEDEN Separator
;; der ganzen Zeichnung identisch. Staustrecke_Separator_SP_300_mm selbst ist
;; dagegen pro Einfuegung eine EIGENE Instanz mit eigenem Handle - genau dort
;; setzt der Bau seine Markierung.
;; traegt ---
;; Der Trennsteg Staustrecke_Separator_SP_300_mm ist der Kettenbaustein (mit
;; KS_EIN/KS_AUS, pro Einfuegung eine eigene Instanz); das Separator_SP-Symbol
;; darin steckt als EIN von der Blockdefinition geteiltes Sub-INSERT in jedem
;; Trennsteg und taugt daher nicht als Schluessel fuer einen einzelnen
;; Separator.
(defun csv:pattern-nested-separator-aussen ()
"Staustrecke_Separator_SP_300_mm*"
)
@@ -1324,20 +1320,12 @@
;; Die AS-/ES-Kettenenden laufen NICHT mehr hierueber - fuer sie setzt
;; csv:asmark-aktualisieren einen eigenen Marker (siehe dort).
;;
;; proxy-liste-Eintrag: (proxy-ename wrapper-ename typ (x y z) strecke-typ
;; trennsteg-ent) - trennsteg-ent = der verpackte Trennsteg (Kettenbaustein,
;; Schluessel fuer die ID-Vergabe in Kettenfolge, csv:ketten-ids-vergeben),
;; nil fuer ein Symbol ohne Trennsteg (Kreisel-Separator).
;; strecke-typ = "VF"/"GF"/nil, gelesen von ssg-sep-typ-xdata-lesen AM
;; AEUSSEREN Trennsteg-Insert (csv:pattern-nested-separator-aussen), NICHT am
;; Separator_SP-Symbol selbst (das ist Block-Definitions-geteilt, siehe dort)
;; und NICHT vom Wrapper-Blocknamen abgeleitet (fruehere Fehlannahme, siehe
;; lib/dump_vf_kette_inhalt.py): ein einzelner VF_n/GF_n-Wrapper kann intern
;; mehrfach zwischen Foerderer- und Gefaellestrecke-Abschnitten wechseln, der
;; Marker sitzt daher direkt am jeweiligen Separator-Insert (gesetzt bauzeitig
;; in vf_linienzug.lsp/Gefaellestrecke.lsp/vf_standard.lsp/vf_etage.lsp,
;; direkt nach dessen Einfuegung). Zuordnung Symbol<->Trennsteg ueber die
;; Symbollage innerhalb des Trennstegs (csv:trennsteg-zu-symbol).
;; proxy-liste-Eintrag: (proxy-ename wrapper-ename typ (x y z) trennsteg-ent)
;; - trennsteg-ent = der verpackte Trennsteg (Kettenbaustein, Schluessel fuer
;; die ID-Vergabe in Kettenfolge UND fuer den Streckentyp VF/GF, beides in
;; csv:ketten-verarbeiten), nil fuer ein Symbol ohne Trennsteg (Kreisel-
;; Separator). Zuordnung Symbol<->Trennsteg ueber die Symbollage innerhalb
;; des Trennstegs (csv:trennsteg-zu-symbol).
(defun csv:sep-proxies-erzeugen ( / ms recs aussen-paare rec aussen-rec proxy proxy-liste)
(setq recs (csv:nested-welt-records (csv:pattern-nested-separator)))
(setq aussen-paare (csv:trennsteg-paare
@@ -1357,7 +1345,6 @@
(if proxy
(setq proxy-liste
(cons (list proxy (nth 0 rec) (csv:proxy-typ (nth 2 rec)) (nth 3 rec)
(if aussen-rec (ssg-sep-typ-xdata-lesen (nth 1 aussen-rec)))
(if aussen-rec (nth 1 aussen-rec)))
proxy-liste)))
)
@@ -1368,8 +1355,8 @@
;; --- Temporaere Kopie je verpacktem uebrigen VF_n/GF_n-Baustein (Bogen/
;; Streckenelement/Umlenkstation/Motorstation) ---
;; Analog zu csv:sep-proxies-erzeugen, aber ohne die dortige "aussen"/XDATA-
;; Zusatzlogik (die existiert nur fuer Separator wegen SSG_SEP_TYP) und ohne
;; Analog zu csv:sep-proxies-erzeugen, aber ohne die dortige Trennsteg-
;; Zuordnung (Symbol im Trennsteg gibt es nur beim Separator) und ohne
;; ZUORDNUNG-Zuweisung: diese Elemente sind keine einem Carrier zugeordneten
;; Sensoren, sondern die Geometrie des Carriers (VF_n/GF_n) selbst - ARTINR/
;; LAYER kommen direkt aus den ATTDEFs der kopierten Original-Blockdefinition
@@ -1435,27 +1422,16 @@
;; festgenagelt; cs-zuordnung-lauf uebernimmt sie unveraendert und zaehlt den
;; Separator beim richtigen Carrier.
;;
;; Gleich nebenbei wird der bauzeitig ermittelte Streckentyp (VF/GF) dieses
;; EINZELNEN Separators (nth 4 rec, siehe csv:sep-proxies-erzeugen) ueber
;; *cs-sep-typ-by-handle* festgehalten. csv:block-to-json schreibt den Wert
;; als "strecke_typ" mit in die Proxy-Zeile. NICHT vom Wrapper-Blocknamen
;; ableiten (fruehere Fehlannahme) - ein einzelner VF_n/GF_n-Wrapper kann
;; intern mehrfach zwischen VF- und GF-Abschnitten wechseln.
;; proxy-liste = Records (proxy-ename wrapper-ename typ (x y z) strecke-typ),
;; proxy-liste = Records (proxy-ename wrapper-ename typ (x y z) trennsteg-ent),
;; siehe csv:sep-proxies-erzeugen. Rueckgabe: Anzahl festgenagelter Kopien.
(defun csv:sep-proxies-zuordnung-setzen (proxy-liste / rec proxy wrapper wrapper-id
handle gesetzt ohne-id strecke-typ)
handle gesetzt ohne-id)
(setq gesetzt 0 ohne-id 0)
(setq *cs-sep-fix-by-handle* nil)
(setq *cs-sep-typ-by-handle* nil)
(foreach rec proxy-liste
(setq proxy (nth 0 rec))
(setq wrapper (nth 1 rec))
(setq handle (cdr (assoc 5 (entget proxy))))
(setq strecke-typ (nth 4 rec))
(if strecke-typ
(setq *cs-sep-typ-by-handle*
(cons (cons handle strecke-typ) *cs-sep-typ-by-handle*)))
(setq wrapper-id (cdr (assoc "ID" (ssg-attrib-read wrapper))))
(if (and wrapper-id (> (strlen wrapper-id) 0))
(progn
@@ -1578,7 +1554,7 @@
)
;; --- Nach der ID-Vergabe: ID jeder Kopie an ihren sepliste-Eintrag haengen ---
;; proxy-liste = Records (proxy-ename wrapper-ename typ (x y z) strecke-typ)
;; proxy-liste = Records (proxy-ename wrapper-ename typ (x y z) trennsteg-ent)
;; aus csv:sep-proxies-erzeugen (das 5. Feld wird hier nicht gebraucht).
;; MUSS nach ssg-id-check-all laufen: vorher hat eine frisch erzeugte Kopie
;; noch keine ID.
@@ -1802,6 +1778,22 @@
(reverse erg)
)
;; --- Streckentyp (VF/GF) jedes Separators einer geordneten Kette ---
;; EINZIGE Quelle fuer das "Typ"-Merkmal der Separator-Zeilen: der Separator
;; erbt den Typ der Einheit, in die csv:kette-einheiten ihn schneidet - also
;; VF fuer den Separator direkt vor der Umlenkstation und jeden Separator
;; zwischen Umlenk- und Motorstation, sonst GF. Damit passen Separator-Typ und
;; Einheiten-Boundingbox per Konstruktion zusammen.
;; typen = Liste der Bausteintypen in Foerderrichtung (siehe csv:kette-typ).
;; Rueckgabe: ((index . "VF"/"GF") ...) fuer jeden "SEP"-Index, aufsteigend.
(defun csv:kette-sep-typen (typen / erg einheit idx)
(foreach einheit (csv:kette-einheiten typen)
(foreach idx (cadr einheit)
(if (= (nth idx typen) "SEP")
(setq erg (cons (cons idx (car einheit)) erg)))))
(vl-sort erg (function (lambda (a b) (< (car a) (car b)))))
)
;; --- Bounding-Box-Vereinigung mehrerer Entities ---
;; Verallgemeinert csv:get-bbox (siehe dort) von einer Entity auf eine Liste:
;; min/max ueber alle vla-getboundingbox-Ergebnisse, gleiche Fehler-
@@ -2437,6 +2429,9 @@
;; Die Export-CSV ist nach TeileId sortiert, damit stehen die Zeilen jeder
;; Kette jetzt von AS nach ES. Bereits vorhandene IDs (AS/ES-Marker mit
;; reservierter ID vom Wrapper) bleiben unangetastet.
;; Nebenbei (in BEIDEN Modi): Streckentyp VF/GF jeder Separator-Kopie aus
;; ihrer Einheit (csv:kette-sep-typen) nach *cs-sep-typ-by-handle* -
;; csv:block-to-json schreibt ihn als "strecke_typ" in die Separator-Zeile.
;; sep-proxies/element-proxies/asmarks = die Stellvertreter-Listen dieses
;; Laufs (letztes Feld jedes Records = verpackter Baustein).
;; Rueckgabe: Einheiten-Proxy-Records (proxy-ename wrapper-ename typ lfdnr) -
@@ -2444,14 +2439,15 @@
(defun csv:ketten-verarbeiten (sep-proxies element-proxies asmarks
/ alt gruppiert blockname ms traeger r naechste-id
wrapper teile einheit lfdnr mark starts
i teil u tr ergebnis res key)
i teil u tr ergebnis res key sep-typen)
(setq *cs-sep-typ-by-handle* nil)
(setq alt (csv:unitmark-bestand-loeschen))
(setq gruppiert (= *csv-export-modus* "group_vf_gf"))
(if gruppiert (setq blockname (csv:unitmark-blockdef-sicherstellen)))
(setq ms (vla-get-ModelSpace (vla-get-ActiveDocument (vlax-get-acad-object))))
;; Stellvertreter ueber (wrapper baustein) nachschlagbar machen.
(foreach r sep-proxies
(if (nth 5 r) (setq traeger (cons (cons (list (nth 1 r) (nth 5 r)) (nth 0 r)) traeger))))
(if (nth 4 r) (setq traeger (cons (cons (list (nth 1 r) (nth 4 r)) (nth 0 r)) traeger))))
(foreach r element-proxies
(if (nth 4 r) (setq traeger (cons (cons (list (nth 1 r) (nth 4 r)) (nth 0 r)) traeger))))
(foreach r asmarks
@@ -2461,6 +2457,7 @@
(setq teile (csv:kette-ordnen (csv:kette-teile wrapper)
(cdr (assoc 2 (entget wrapper)))))
(setq res (ssg-id-res-lesen wrapper))
(setq sep-typen (csv:kette-sep-typen (mapcar 'car teile)))
;; Einheiten (nur gruppiert); starts = ((erster-index key . proxy) ...)
(setq starts nil lfdnr 0)
(if (and gruppiert blockname)
@@ -2485,12 +2482,17 @@
(cdr (assoc (nth 1 u) res))))
(csv:res-merken wrapper (nth 1 u) (nth 2 u)))))
(if (setq tr (cdr (assoc (list wrapper (nth 1 (nth 1 teil))) traeger)))
(if (member (car teil) '("AS" "ES"))
(setq naechste-id (csv:id-vergeben tr naechste-id nil))
(progn
(setq key (csv:res-key-kette i))
(setq naechste-id (csv:id-vergeben tr naechste-id (cdr (assoc key res))))
(csv:res-merken wrapper key tr))))
(progn
(if (assoc i sep-typen)
(setq *cs-sep-typ-by-handle*
(cons (cons (cdr (assoc 5 (entget tr))) (cdr (assoc i sep-typen)))
*cs-sep-typ-by-handle*)))
(if (member (car teil) '("AS" "ES"))
(setq naechste-id (csv:id-vergeben tr naechste-id nil))
(progn
(setq key (csv:res-key-kette i))
(setq naechste-id (csv:id-vergeben tr naechste-id (cdr (assoc key res))))
(csv:res-merken wrapper key tr)))))
(setq i (1+ i)))
)
(if gruppiert