CSV-Export: Nachbarschaft/bbox fuer Kreisel-Kreisel-Weichen, sepliste-Ketten und Separatoren repariert

Kreisel-Kreisel-Weichen fehlten bisher im Kreisel-Umlauf (compute_kreisel_umlauf),
wodurch angrenzende Separatoren auf falsche/fehlende Nachbarn zeigten. Die
kreisel_bounds-Matching-Box ignorierte ausserdem die tatsaechliche Kreiseldrehung
(faelschlich als achsparallel angenommen), was bei gedrehten langen Kreiseln
(Mubea Kreisel 0002) zu falschen Nachbarschaften fuehrte.

Die sepliste-XDATA (AS/SEP/ES-Reihenfolge je VF_n/GF_n) wurde nie ans Python-Item
durchgereicht - die gesamte Ketten-Nachbarschaftserkennung lief dadurch ins Leere.
Nach dem Beheben entstand eine Doppelzaehlung: die in einer Kette verpackten
Separatoren existieren bereits als echte Proxy-INSERTs (csv:sep-proxies-erzeugen);
build_separator_kette_items erzeugte zusaetzlich eigene Zeilen aus der sepliste.
Umgebaut zu map_separator_kette_items: ordnet die sepliste-Reihenfolge den
vorhandenen Proxy-Items zu (Match ueber Wrapper-ID + INSERT-Punkt) statt neue
Zeilen zu erzeugen - keine Doppelzaehlung mehr, Nachbarn korrekt gesetzt.

Ausserdem: vla-getboundingbox scheiterte in einem realen Export bei ALLEN
Bloecken (fehlende bbox ueberall), der Fehler wurde bisher still verschluckt.
REGENALL vor der Export-Schleife behebt das; eine neue Diagnose (exp-bbox-fail)
meldet kuenftige Ausfaelle statt sie zu verschlucken. Freie/eingebettete
Separatoren ohne bbox bekommen zusaetzlich einen Fallback aus einer konfigurierbaren
Symbol-Groesse (cfg/export.cfg [Boundingbox] separator_box_*).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-10 09:41:02 +02:00
parent e08b8b2b08
commit 27ae3df056
10 changed files with 1042 additions and 244 deletions
+143 -3
View File
@@ -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