sepliste: Bauteil-IDs eintragen, AS/ES ueber dauerhaften Marker sichtbar machen
Stufe 1 (LISP-Export-Pfad): export_raw.json enthaelt jetzt fuer jeden sepliste-Eintrag (AS/SEP/ES) einer VF_n/GF_n-Kette die ID des realen Bauteils, das ihn vertritt. - csv:sep-proxies-erzeugen (Separatoren) und die neuen AS/ES-Marker teilen sich csv:nested-welt-records/csv:block-einfuegen-welt zur Platzierung. - csv:sepliste-paare ordnet sepliste-Eintraege ihrem Bauteil exklusiv nach Abstand zu (kuerzester zuerst, dann verbraucht) statt "jeder Eintrag nimmt sich das naechste" - ein einzelner fehlerhafter Koordinatenwert (bekannter Bug: gespiegeltes x bei lfdnr=2) verschiebt dadurch keine andere Zuordnung mehr. - Neu: ZZ_ASES_MARKER - ein kleines Rechteck an jedem AS/ES-Kettenende, das nach dem Export STEHEN BLEIBT (anders als die temporaeren Separator-Kopien). Macht das sonst unsichtbare, in der Wrapper- Blockdefinition verpackte Kettenende in BricsCAD sichtbar/anklickbar und traegt seine ID unsichtbar am Attribut ID - dadurch behaelt ein AS/ES seine TeileId ueber Exportlaeufe hinweg. Wird bei jedem Export neu aufgebaut (Lage folgt der Kette), Wiederfund ueber ZUORDNUNG+TYP+ LFDNR, verwaiste Marker werden entfernt. In BricsCAD verifiziert (5 HundM05-Ketten, zwei Exportlaeufe: gleiche Marker-IDs, korrekte sepliste-"id"-Felder). Dabei einen realen Bug gefunden und behoben: die Blockdefinition des Markers uebernahm ueber einen ungefilterten entnext-Walk versehentlich auch die Attribute des zuletzt eingefuegten Blocks (VF_5 verlor dadurch alle Attribute inkl. ID) - jetzt auf LWPOLYLINE/ATTDEF gefiltert. 9 neue zeichnungsfreie Unit-Tests (csv:sepliste-paare/*, csv:asmark- finden/*, csv:proxy-typ/*), 4 neue de/en-Textschluessel (Paritaet geprueft). bin\run_tests.bat --lisp: 257/257 bestanden. Noch nicht enthalten (Stufe 2, Python): map_separator_kette_items nutzt das neue "id"-Feld noch nicht, build_strecke_schleus_items synthetisiert AS/ES-Zeilen weiterhin selbst statt die exportierten zu lesen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
9671fe4e04
commit
618ff3d86c
@@ -288,6 +288,19 @@
|
||||
(list (+ (car pt) (+ (* dx chz cv) (* dz chz sv)))
|
||||
(+ (cadr pt) (+ (* dx shz cv) (* dz shz sv)))
|
||||
(+ (caddr pt) (+ (* (- sv) dx) (* cv dz)))))
|
||||
;; Diagnose (Schalter "vf-sepliste", siehe ssg_ks_insert.lsp): DIESE Funktion
|
||||
;; setzt die Separatoren des Linienzugs, und da sie den Block ohne
|
||||
;; KS_EIN-Korrektur direkt nach pt schiebt, ist pt exakt der Gruppencode 10,
|
||||
;; den ssg-sepliste-sammeln spaeter einsammelt. Ein gespiegelter
|
||||
;; Sepliste-Eintrag muss also schon hier mit gespiegeltem pt ankommen.
|
||||
(if (car (atoms-family 1 '("SSG-SEPLISTE-DBG")))
|
||||
(ssg-sepliste-dbg
|
||||
(strcat "gf-insert-hz-with-ks " blockname
|
||||
" hz=" (rtos (float hz-grad) 2 2)
|
||||
" vert=" (rtos (float vert-grad) 2 2)
|
||||
" dx=" (rtos (float dx) 2 2) " dz=" (rtos (float dz) 2 2)
|
||||
" pt(=Gruppencode 10)=" (ssg-sepliste-dbg-pt pt)
|
||||
" endpunkt=" (ssg-sepliste-dbg-pt endpunkt))))
|
||||
(princ (ssg-textf "gf-status-hzks"
|
||||
(list blockname (rtos hz-grad 2 0) grad-zeichen
|
||||
(rtos vert-grad 2 1) grad-zeichen (rtos (caddr endpunkt) 2 1))))
|
||||
|
||||
+5
-1
@@ -423,8 +423,12 @@ Sammelt INSERT-Blöcke aus der Zeichnung und exportiert sie als JSON oder ruft P
|
||||
| `c:EXPORTSIVAS` | Alle Blöcke als JSON sammeln und `export_sivas.py` aufrufen (Sivas-CSV) |
|
||||
| `c:EXPORTCSV` | Alle Blöcke als JSON sammeln und `export_csv.py` aufrufen (einfache Item-Liste, inkl. Omniflo Bogen/Weiche/Gerade und abschließender "Omniflo Sum"-Zeile) |
|
||||
| `csv:collect-export-blocks` | Alle INSERT-Blöcke der Zeichnung als JSON-Array sammeln |
|
||||
| `csv:run-export py-skript json-datei output-csv` | Python-Skript mit gesammelten Daten aufrufen; legt vorher fuer in VF_n/GF_n/KREISEL_n **verpackte** Separator_SP_2D/_3D-Sub-INSERTs (Sensor-Symbol; siehe `ssg-collect-nested-inserts` in `ssg_core.lsp` - NICHT der interne Staustrecke_Separator_SP-Trennsteg) je eine echte, temporaere Kopie **an derselben Stelle** an (`csv:sep-proxies-erzeugen`, Position/Drehung/Skalierung ueber alle Verschachtelungsebenen hinweg identisch zum Vorbild - kein kosmetischer Versatz mehr, der die geometrische Sensor-Zuordnung verfaelschen wuerde), damit sie ganz normal ueber `ssg-id-check-all`/`csv:collect-export-blocks` erfasst werden, und entfernt sie danach wieder (`csv:sep-proxies-loeschen`). Reihenfolge ist wesentlich: **erst alle** Kopien aus allen Wrappern erzeugen, **dann** `ssg-id-check-all` (vergibt IDs oberhalb des globalen Maximums), **dann** `csv:sep-proxies-zuordnung-setzen` |
|
||||
| `csv:run-export py-skript json-datei output-csv` | Python-Skript mit gesammelten Daten aufrufen; legt vorher fuer in VF_n/GF_n/KREISEL_n **verpackte** Separator_SP_2D/_3D-Sub-INSERTs (Sensor-Symbol; siehe `ssg-collect-nested-inserts` in `ssg_core.lsp` - NICHT der interne Staustrecke_Separator_SP-Trennsteg) je eine echte, temporaere Kopie **an derselben Stelle** an (`csv:sep-proxies-erzeugen`, Position/Drehung/Skalierung ueber alle Verschachtelungsebenen hinweg identisch zum Vorbild - kein kosmetischer Versatz mehr, der die geometrische Sensor-Zuordnung verfaelschen wuerde), damit sie ganz normal ueber `ssg-id-check-all`/`csv:collect-export-blocks` erfasst werden, und entfernt sie danach wieder (`csv:sep-proxies-loeschen`). Die verpackten **AS-/ES-Schleuselemente** derselben Kette bekommen stattdessen einen DAUERHAFTEN Marker (`csv:asmark-aktualisieren`, siehe unten); beide Wege teilen sich die Platzierungsrechnung (`csv:nested-welt-records` + `csv:block-einfuegen-welt`). Reihenfolge ist wesentlich: **erst alle** Kopien aus allen Wrappern erzeugen, **dann** `ssg-id-check-all` (vergibt IDs oberhalb des globalen Maximums), **dann** `csv:sep-proxies-zuordnung-setzen` und `csv:sepliste-ids-setzen` |
|
||||
| `csv:sep-proxies-zuordnung-setzen proxy-liste` | ZUORDNUNG jeder Separator-Kopie auf die **ID ihres Wrapper-Blocks** setzen (ein in VF_n mit ID 0010 verpackter Separator erhaelt ZUORDNUNG 0010) und die Zuordnung ueber `*cs-sep-fix-by-handle*` fuer `cs-zuordnung-lauf` festnageln - fuer verpackte Separatoren ist der Carrier bekannt und wird nicht per Boundingbox geraten. Muss NACH `ssg-id-check-all` laufen, da ein frisch gebauter Wrapper vorher noch keine ID hat |
|
||||
| `csv:asmark-aktualisieren` | AS-/ES-Kettenenden sichtbar machen: setzt an jedes verpackte `AS_Element*`/`ES_Element*` einer VF_n/GF_n-Kette ein kleines Rechteck (Block `ZZ_ASES_MARKER`, Groesse aus `cfg/export.cfg` `[Marker]`, Layer aus `cfg/layer.cfg` `ases_marker`), das nach dem Export **stehen bleibt**. Unsichtbare Attribute ID/ZUORDNUNG/TYP/LFDNR/ELEMENT/ARTINR; die `ID` fuellt `ssg-id-check-all` und der naechste Export **uebernimmt sie**, ein AS/ES behaelt seine TeileId also ueber Laeufe hinweg. Baut bei jedem Export alle Marker neu auf (Wiederfinden ueber ZUORDNUNG+TYP+LFDNR) und entfernt verwaiste |
|
||||
| `csv:asmark-ids-setzen marker-liste` | Nach `ssg-id-check-all`: ZUORDNUNG (Wrapper-ID) am Marker nachtragen und seine ID am `sepliste`-Eintrag vermerken |
|
||||
| `csv:sepliste-ids-setzen proxy-liste` | ID jeder Kopie (Separator UND AS/ES, beide Listen zusammen) an ihren `sepliste`-Eintrag des Wrappers haengen; Ergebnis in `*csv-sepliste-id-by-handle*` (Key = Wrapper-Handle), von `csv:block-to-json` als Feld `id` je Eintrag geschrieben. Muss NACH `ssg-id-check-all` laufen |
|
||||
| `csv:sepliste-paare eintraege proxies` | Zuordnung `sepliste`-Eintrag -> Kopie: nur innerhalb desselben Typmarkers (`AS`/`ES`/`SEP`) und **exklusiv** (kuerzester Abstand zuerst, danach sind Eintrag und Kopie verbraucht). Damit verschiebt EIN fehlerhafter Koordinatenwert in der `sepliste` keine anderen Zuordnungen. Reine Rechenfunktion, getestet in `tests/test_unit.lsp` |
|
||||
| `csv:read-attribs ename` | Attribute eines INSERT als JSON-Objekt lesen |
|
||||
| `c:OMNI_UPDATE_ATTRIBS` | HOEHE/DREHUNG aller Omniflo-Elemente aus der Zeichnung aktualisieren |
|
||||
|
||||
|
||||
+672
-190
@@ -653,7 +653,7 @@
|
||||
handle attribs bbox bbox-json
|
||||
insert-quat insert-kos k-list warnung-json warnung-eintrag
|
||||
zuordnung-fix-json zuordnung-fix-eintrag sepliste-json sepliste-app sepliste
|
||||
sepliste-teile sepliste-first)
|
||||
sepliste-teile sepliste-first sepliste-ids sep-id)
|
||||
(setq ed (entget ename))
|
||||
(setq blk-name (cdr (assoc 2 ed)))
|
||||
(setq layer (cdr (assoc 8 ed)))
|
||||
@@ -765,14 +765,24 @@
|
||||
(setq sepliste (ssg-sepliste-xdata-lesen ename sepliste-app)))
|
||||
(if sepliste
|
||||
(progn
|
||||
;; ID des Bauteils, das zu diesem Eintrag gehoert: beim Export wird
|
||||
;; fuer JEDEN Eintrag (AS/SEP/ES) eine echte, temporaere Kopie des
|
||||
;; verpackten Originals eingefuegt und ueber ssg-id-check-all
|
||||
;; nummeriert; csv:sepliste-ids-setzen haengt die vergebene ID an den
|
||||
;; Eintrag (Key = Handle dieses Wrappers). Fehlt sie (Kopie nicht
|
||||
;; erzeugbar, Block ohne ID-ATTDEF, Altbestand), bleibt das Feld weg -
|
||||
;; der Python-Teil faellt dann auf seine Koordinaten-Zuordnung zurueck.
|
||||
(setq sepliste-ids (cdr (assoc handle *csv-sepliste-id-by-handle*)))
|
||||
(setq sepliste-teile "" sepliste-first t)
|
||||
(foreach e sepliste
|
||||
(setq sep-id (cdr (assoc (nth 1 e) sepliste-ids)))
|
||||
(setq sepliste-teile
|
||||
(strcat sepliste-teile (if sepliste-first "" ",")
|
||||
"{\"typ\":\"" (nth 0 e) "\""
|
||||
",\"lfdnr\":" (itoa (nth 1 e))
|
||||
",\"x\":" (rtos (nth 2 e) 2 2)
|
||||
",\"y\":" (rtos (nth 3 e) 2 2)
|
||||
(if sep-id (strcat ",\"id\":\"" (csv:json-escape sep-id) "\"") "")
|
||||
"}"))
|
||||
(setq sepliste-first nil)
|
||||
)
|
||||
@@ -818,6 +828,31 @@
|
||||
"Separator_SP_2D,Separator_SP_3D"
|
||||
)
|
||||
|
||||
;; --- Muster der verpackten AS-/ES-Schleuselemente ---
|
||||
;; AS_Element_*/ES_Element_* sind die beiden Kettenenden einer VF_n/GF_n-
|
||||
;; Strecke (Ein-/Ausschleusung zum Kreisel). Sie stecken - wie die Separator-
|
||||
;; Symbole - als Sub-INSERTs in der Wrapper-Blockdefinition und sind damit
|
||||
;; fuer (ssget "X" ...) unsichtbar. Dieses Muster findet sie in der
|
||||
;; Blockdefinition (csv:nested-welt-records); gesetzt wird an ihrer Stelle
|
||||
;; NICHT eine Kopie des Elements, sondern der dauerhafte Marker
|
||||
;; ZZ_ASES_MARKER (csv:asmark-aktualisieren).
|
||||
(defun csv:pattern-nested-schleus ()
|
||||
(export:pattern "pattern_schleuselement" "AS_Element*,ES_Element*")
|
||||
)
|
||||
|
||||
;; --- Typmarker eines ausgepackten Originals aus seinem Blocknamen ---
|
||||
;; Liefert dieselben drei Marker, die ssg-sepliste-sammeln (ssg_ks_insert.lsp)
|
||||
;; in die sepliste schreibt: "AS"/"ES"/"SEP". Ueber ihn wird eine Kopie ihrem
|
||||
;; sepliste-Eintrag zugeordnet (csv:sepliste-paare) - zugeordnet wird nur
|
||||
;; innerhalb desselben Typs.
|
||||
(defun csv:proxy-typ (bname)
|
||||
(cond
|
||||
((wcmatch (strcase bname) "AS_ELEMENT*") "AS")
|
||||
((wcmatch (strcase bname) "ES_ELEMENT*") "ES")
|
||||
(t "SEP")
|
||||
)
|
||||
)
|
||||
|
||||
;; --- Muster der Compound-("Wrapper"-)Bloecke, deren Definition ueberhaupt
|
||||
;; auf verpackte Separator_SP-Symbole durchsucht wird (KR_n/KREISEL_n/
|
||||
;; ECKRAD_n/VF_n/GF_n) - alle anderen INSERTs (Omniflo, eigenstaendige
|
||||
@@ -835,18 +870,23 @@
|
||||
(if (or (null f) (equal f 0.0 1e-12)) 1.0 f)
|
||||
)
|
||||
|
||||
;; --- Fuer jedes verpackte Separator_SP-Symbol eine ECHTE, temporaere Kopie
|
||||
;; an DERSELBEN Stelle in den Modellraum einfuegen ---
|
||||
;; Separator_SP-Sensor-Symbole, die beim Zusammenbau von VF_n/GF_n/
|
||||
;; KREISEL_n in die Compound-Blockdefinition "verpackt" wurden (siehe
|
||||
;; ssg-collect-nested-inserts), sind fuer (ssget "X" ...) unsichtbar - und
|
||||
;; damit weder fuer ssg-id-check-all (eigene ID) noch csv:collect-export-
|
||||
;; blocks (JSON-Zeile) erreichbar. Statt beide Sammel-Funktionen dafuer
|
||||
;; anzupassen, wird hier VOR der ID-Vergabe (csv:run-export) fuer jeden Fund
|
||||
;; eine ECHTE Kopie desselben Blocks eingefuegt.
|
||||
;; Diese Kopie ist ein normaler, top-level INSERT und durchlaeuft ID-
|
||||
;; Vergabe/Export danach unveraendert ueber die bestehenden Funktionen -
|
||||
;; deren Blockname-Muster (Separator_SP*) trifft ja bereits zu.
|
||||
;; --- Fuer jedes verpackte Original die Weltlage ermitteln und daran ein
|
||||
;; echtes Objekt in den Modellraum setzen ---
|
||||
;; nested-pattern = wcmatch-Muster der zu suchenden Sub-INSERTs, siehe
|
||||
;; csv:pattern-nested-separator (Separator-Symbole) bzw.
|
||||
;; csv:pattern-nested-schleus (AS-/ES-Schleuselemente).
|
||||
;;
|
||||
;; Sub-Bloecke, die beim Zusammenbau von VF_n/GF_n/KREISEL_n in die Compound-
|
||||
;; Blockdefinition "verpackt" wurden (siehe ssg-collect-nested-inserts), sind
|
||||
;; fuer (ssget "X" ...) unsichtbar - und damit weder fuer ssg-id-check-all
|
||||
;; (eigene ID) noch csv:collect-export-blocks (JSON-Zeile) erreichbar, und in
|
||||
;; der Zeichnung auch nicht als eigenes Objekt anklickbar. Diese Funktion
|
||||
;; liefert ihre Weltlage, ohne die Zeichnung anzufassen; was daran gesetzt
|
||||
;; wird, entscheidet der Aufrufer:
|
||||
;; - csv:sep-proxies-erzeugen -> temporaere Kopie des Symbols selbst
|
||||
;; (wird nach dem Export wieder geloescht)
|
||||
;; - csv:asmark-aktualisieren -> dauerhafter AS/ES-Marker (bleibt stehen
|
||||
;; und traegt die ID ueber Laeufe hinweg)
|
||||
;;
|
||||
;; Die Kopie steht bewusst EXAKT auf der Weltposition/-drehung/-skalierung
|
||||
;; ihres verpackten Vorbilds (frueher: +500 mm Versatz in Blockrichtung, rein
|
||||
@@ -859,39 +899,24 @@
|
||||
;; Skalierung relativ zur Wrapper-Definition); hier kommt nur noch die
|
||||
;; Platzierung des top-level INSERT darauf.
|
||||
;;
|
||||
;; Einfuegen ueber vla-InsertBlock (ActiveX) statt "command _.INSERT": das
|
||||
;; legt fuer einen Block mit ATTDEFs automatisch ATTRIB-Entities mit den
|
||||
;; Vorgabewerten an (wie TEFInsert.lsp/tefl-insert-element, ssg_ks_insert.lsp
|
||||
;; u.a. bereits nutzen) - OHNE jeden einzelnen Insert-Prompt (Blockname/
|
||||
;; Einfuegepunkt/Skalierung/Drehwinkel) ins Kommandozeilen-Fenster zu
|
||||
;; schreiben. "command _.INSERT" wuerde das bei JEDEM verpackten Fund tun,
|
||||
;; selbst wenn alle Werte per LISP vorgegeben sind - bei mehreren Funden
|
||||
;; entsprechend viel Bildschirm-Rauschen. vla-get-ModelSpace wird hier LOKAL
|
||||
;; ermittelt statt den (evtl. noch unbelegten) globalen "modelspace" aus
|
||||
;; vf_core.lsp/Gefaellestrecke.lsp/ssg_ks_insert.lsp vorauszusetzen - die
|
||||
;; koennten in dieser Sitzung noch gar nicht geladen worden sein, falls die
|
||||
;; Zeichnung mit bereits vorhandenen VF_n/GF_n-Bloecken geoeffnet und direkt
|
||||
;; exportiert wird, ohne vorher FOERDERANLAGE/GEFAELLESTRECKE aufzurufen.
|
||||
;;
|
||||
;; Rueckgabe: Liste von Paaren (proxy-ename . wrapper-ename) - der Wrapper
|
||||
;; wird mitgefuehrt, weil erst NACH der ID-Vergabe daraus die ZUORDNUNG der
|
||||
;; Kopie gesetzt werden kann (csv:sep-proxies-zuordnung-setzen). Die
|
||||
;; proxy-enames dienen ausserdem csv:sep-proxies-loeschen nach dem Export.
|
||||
(defun csv:sep-proxies-erzeugen ( / ms ss-all i ename ed bname nested pt rotation
|
||||
;; Rueckgabe: Liste von Records
|
||||
;; (wrapper-ename nested-ent nested-bname (x y z) R sx sy sz)
|
||||
;; mit der fertigen Weltlage jedes Fundes (R = volle 3x3-Orientierung).
|
||||
(defun csv:nested-welt-records (nested-pattern
|
||||
/ ss-all i ename ed bname nested pt rotation
|
||||
extrusion0 R0 psx psy psz rec nested-ent nested-bname
|
||||
local-pt R-nested R-final scaled-pt rot-pt world-pt
|
||||
T4 block-obj xform-fehler proxy-liste)
|
||||
records)
|
||||
(setq ss-all (ssget "X" (list (cons 0 "INSERT"))))
|
||||
(if ss-all
|
||||
(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 nested
|
||||
(if (wcmatch bname (csv:pattern-wrapper-fuer-proxies))
|
||||
(ssg-collect-nested-inserts bname (csv:pattern-nested-separator))
|
||||
(ssg-collect-nested-inserts bname nested-pattern)
|
||||
)
|
||||
)
|
||||
(if nested
|
||||
@@ -922,50 +947,10 @@
|
||||
(+ (cadr pt) (cadr rot-pt))
|
||||
(+ (caddr pt) (caddr rot-pt))))
|
||||
(setq R-final (mat3-mul-mat3 R0 R-nested))
|
||||
;; Volle 3D-Orientierung statt bisher nur eines Z-Drehwinkels:
|
||||
;; ein einzelner Skalar-Drehwinkel kann eine Kippung ausserhalb
|
||||
;; der XY-Ebene (Gefaellestrecke-/VF-Neigung) gar nicht
|
||||
;; darstellen. Deshalb - wie insert-block-ks-to-ks (vf_core.lsp)
|
||||
;; - am Ursprung mit Rotation=0 einfuegen und die komplette
|
||||
;; Lage (Drehung UND Verschiebung) in EINER vla-TransformBy
|
||||
;; anwenden, statt Rotation als vla-InsertBlock-Parameter.
|
||||
(setq T4 (vlax-tmatrix
|
||||
(list (list (car (car R-final)) (cadr (car R-final)) (caddr (car R-final)) (car world-pt))
|
||||
(list (car (cadr R-final)) (cadr (cadr R-final)) (caddr (cadr R-final)) (cadr world-pt))
|
||||
(list (car (caddr R-final)) (cadr (caddr R-final)) (caddr (caddr R-final)) (caddr world-pt))
|
||||
(list 0.0 0.0 0.0 1.0))))
|
||||
;; Gekapselt, weil hier - anders als beim frueheren festen
|
||||
;; 1.0/1.0/1.0 - die tatsaechlichen Skalierungsfaktoren
|
||||
;; durchgereicht werden: ein einzelner Sonderfall (entartete
|
||||
;; Skalierung, gespiegelter Zwischenblock) darf nicht den
|
||||
;; kompletten Export der Zeichnung abbrechen, sondern nur diese
|
||||
;; eine Kopie ausfallen lassen - mit Meldung, welcher Block.
|
||||
(setq block-obj
|
||||
(vl-catch-all-apply 'vla-InsertBlock
|
||||
(list ms (vlax-3D-point '(0.0 0.0 0.0)) nested-bname
|
||||
(csv:skalierung-oder-eins (* psx (nth 3 rec)))
|
||||
(csv:skalierung-oder-eins (* psy (nth 4 rec)))
|
||||
(csv:skalierung-oder-eins (* psz (nth 5 rec)))
|
||||
0.0)))
|
||||
(cond
|
||||
((vl-catch-all-error-p block-obj)
|
||||
(princ (ssg-textf "exp-sep-proxy-fehler"
|
||||
(list nested-bname bname
|
||||
(vl-catch-all-error-message block-obj)))))
|
||||
(t
|
||||
(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 nested-bname 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 records
|
||||
(cons (list ename nested-ent nested-bname world-pt R-final
|
||||
(* psx (nth 3 rec)) (* psy (nth 4 rec)) (* psz (nth 5 rec)))
|
||||
records))
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -973,7 +958,91 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
proxy-liste
|
||||
(reverse records)
|
||||
)
|
||||
|
||||
;; --- Einen Block an einer vollen 3D-Weltlage einfuegen ---
|
||||
;; ms = ModelSpace-Objekt (der Aufrufer holt es EINMAL, nicht je Block)
|
||||
;; bname = einzufuegende Blockdefinition
|
||||
;; world-pt/R = Weltposition und volle 3x3-Orientierung (siehe
|
||||
;; csv:nested-welt-records)
|
||||
;; sx/sy/sz = Skalierung; der AS/ES-Marker fuegt bewusst mit 1.0 ein (ein
|
||||
;; gestauchtes Rechteck waere als Marker unbrauchbar), die
|
||||
;; Separator-Kopie mit der tatsaechlichen Skalierung ihres
|
||||
;; Vorbilds.
|
||||
;; kontext = Blockname des Wrappers, nur fuer die Fehlermeldung.
|
||||
;;
|
||||
;; Volle 3D-Orientierung statt eines einzelnen Z-Drehwinkels: ein Skalar-
|
||||
;; Drehwinkel kann eine Kippung ausserhalb der XY-Ebene (Gefaellestrecke-/
|
||||
;; VF-Neigung) gar nicht darstellen. Deshalb - wie insert-block-ks-to-ks
|
||||
;; (vf_core.lsp) - am Ursprung mit Rotation=0 einfuegen und die komplette Lage
|
||||
;; (Drehung UND Verschiebung) in EINER vla-TransformBy anwenden.
|
||||
;;
|
||||
;; Einfuegen ueber vla-InsertBlock (ActiveX) statt "command _.INSERT": das legt
|
||||
;; fuer einen Block mit ATTDEFs automatisch ATTRIB-Entities mit den Vorgabe-
|
||||
;; werten an - OHNE jeden einzelnen Insert-Prompt (Blockname/Einfuegepunkt/
|
||||
;; Skalierung/Drehwinkel) ins Kommandozeilen-Fenster zu schreiben.
|
||||
;;
|
||||
;; Beide ActiveX-Aufrufe sind gekapselt: ein einzelner Sonderfall (entartete
|
||||
;; Skalierung, gespiegelter Zwischenblock) darf nicht den kompletten Export der
|
||||
;; Zeichnung abbrechen, sondern nur dieses eine Objekt ausfallen lassen - mit
|
||||
;; Meldung, welcher Block. Rueckgabe: ename des neuen INSERT oder nil.
|
||||
(defun csv:block-einfuegen-welt (ms bname world-pt R sx sy sz kontext
|
||||
/ T4 block-obj xform-fehler erg)
|
||||
(setq T4 (vlax-tmatrix
|
||||
(list (list (car (car R)) (cadr (car R)) (caddr (car R)) (car world-pt))
|
||||
(list (car (cadr R)) (cadr (cadr R)) (caddr (cadr R)) (cadr world-pt))
|
||||
(list (car (caddr R)) (cadr (caddr R)) (caddr (caddr R)) (caddr world-pt))
|
||||
(list 0.0 0.0 0.0 1.0))))
|
||||
(setq block-obj
|
||||
(vl-catch-all-apply 'vla-InsertBlock
|
||||
(list ms (vlax-3D-point '(0.0 0.0 0.0)) bname
|
||||
(csv:skalierung-oder-eins sx)
|
||||
(csv:skalierung-oder-eins sy)
|
||||
(csv:skalierung-oder-eins sz)
|
||||
0.0)))
|
||||
(cond
|
||||
((vl-catch-all-error-p block-obj)
|
||||
(princ (ssg-textf "exp-sep-proxy-fehler"
|
||||
(list bname kontext (vl-catch-all-error-message block-obj))))
|
||||
(setq erg nil))
|
||||
(t
|
||||
(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 bname kontext (vl-catch-all-error-message xform-fehler))))
|
||||
(vl-catch-all-apply 'vla-Delete (list block-obj))
|
||||
(setq erg nil))
|
||||
(setq erg (vlax-vla-object->ename block-obj))
|
||||
)
|
||||
)
|
||||
)
|
||||
erg
|
||||
)
|
||||
|
||||
;; --- Temporaere Kopie je verpacktem Separator_SP-Symbol ---
|
||||
;; Setzt csv:nested-welt-records + csv:block-einfuegen-welt zusammen: fuer
|
||||
;; jeden Fund eine ECHTE Kopie DESSELBEN Blocks an derselben Weltlage.
|
||||
;; Die AS-/ES-Kettenenden laufen NICHT mehr hierueber - fuer sie setzt
|
||||
;; csv:asmark-aktualisieren einen dauerhaften Marker (siehe dort).
|
||||
(defun csv:sep-proxies-erzeugen ( / ms recs rec proxy proxy-liste)
|
||||
(setq recs (csv:nested-welt-records (csv:pattern-nested-separator)))
|
||||
(if recs
|
||||
(progn
|
||||
(setq ms (vla-get-ModelSpace (vla-get-ActiveDocument (vlax-get-acad-object))))
|
||||
(foreach rec recs
|
||||
(setq proxy (csv:block-einfuegen-welt ms (nth 2 rec) (nth 3 rec) (nth 4 rec)
|
||||
(nth 5 rec) (nth 6 rec) (nth 7 rec)
|
||||
(cdr (assoc 2 (entget (nth 0 rec))))))
|
||||
(if proxy
|
||||
(setq proxy-liste
|
||||
(cons (list proxy (nth 0 rec) (csv:proxy-typ (nth 2 rec)) (nth 3 rec))
|
||||
proxy-liste)))
|
||||
)
|
||||
)
|
||||
)
|
||||
(reverse proxy-liste)
|
||||
)
|
||||
|
||||
;; --- ZUORDNUNG der temporaeren Separator-Kopien aus ihrem Wrapper setzen ---
|
||||
@@ -991,14 +1060,15 @@
|
||||
;; Zuordnung ueber *cs-sep-fix-by-handle* (Key = Entity-Handle der Kopie)
|
||||
;; festgenagelt; cs-zuordnung-lauf uebernimmt sie unveraendert und zaehlt den
|
||||
;; Separator beim richtigen Carrier.
|
||||
;; Rueckgabe: Anzahl festgenagelter Kopien.
|
||||
(defun csv:sep-proxies-zuordnung-setzen (proxy-liste / paar proxy wrapper wrapper-id
|
||||
;; proxy-liste = Records (proxy-ename wrapper-ename typ (x y z)), siehe
|
||||
;; csv:nested-proxies-erzeugen. Rueckgabe: Anzahl festgenagelter Kopien.
|
||||
(defun csv:sep-proxies-zuordnung-setzen (proxy-liste / rec proxy wrapper wrapper-id
|
||||
handle gesetzt ohne-id)
|
||||
(setq gesetzt 0 ohne-id 0)
|
||||
(setq *cs-sep-fix-by-handle* nil)
|
||||
(foreach paar proxy-liste
|
||||
(setq proxy (car paar))
|
||||
(setq wrapper (cdr paar))
|
||||
(foreach rec proxy-liste
|
||||
(setq proxy (nth 0 rec))
|
||||
(setq wrapper (nth 1 rec))
|
||||
(setq wrapper-id (cdr (assoc "ID" (ssg-attrib-read wrapper))))
|
||||
(if (and wrapper-id (> (strlen wrapper-id) 0))
|
||||
(progn
|
||||
@@ -1020,107 +1090,507 @@
|
||||
gesetzt
|
||||
)
|
||||
|
||||
;; --- Fuer jeden Sepliste-Eintrag (AS/SEP/ES) eines VF_n/GF_n-Wrappers eine
|
||||
;; ECHTE, temporaere Separator_SP-Kopie an dessen Weltkoordinate einfuegen ---
|
||||
;; --- Globale Zuordnung sepliste-Eintrag -> ID der zugehoerigen Kopie ---
|
||||
;; Key = Handle des VF_n/GF_n-Wrappers, Wert = Alist ((lfdnr . "0031") ...).
|
||||
;; Wird von csv:sepliste-ids-setzen NACH der ID-Vergabe gefuellt, von
|
||||
;; csv:block-to-json beim Schreiben des "sepliste"-Arrays gelesen und von
|
||||
;; csv:sep-proxies-loeschen wieder zurueckgesetzt - die IDs gehoeren den
|
||||
;; temporaeren Kopien dieses EINEN Exportlaufs.
|
||||
(setq *csv-sepliste-id-by-handle* nil)
|
||||
|
||||
;; --- Einen sepliste-Eintrag mit der ID seines Bauteils vermerken ---
|
||||
;; Zwei Quellen schreiben in dieselbe Zuordnung - die dauerhaften AS/ES-Marker
|
||||
;; (csv:asmark-ids-setzen) und die temporaeren Separator-Kopien
|
||||
;; (csv:sepliste-ids-setzen). Beide muessen sich den Eintrag EINES Wrappers
|
||||
;; teilen: ein zweites Paar (handle . alist) waere fuer assoc unsichtbar, die
|
||||
;; zuerst eingetragene Liste wuerde immer gewinnen. Darum hier zusammenfuehren
|
||||
;; statt vorne anzuhaengen.
|
||||
(defun csv:sepliste-id-merken (handle lfdnr id / eintrag)
|
||||
(setq eintrag (assoc handle *csv-sepliste-id-by-handle*))
|
||||
(if eintrag
|
||||
(setq *csv-sepliste-id-by-handle*
|
||||
(subst (cons handle (append (cdr eintrag) (list (cons lfdnr id))))
|
||||
eintrag *csv-sepliste-id-by-handle*))
|
||||
(setq *csv-sepliste-id-by-handle*
|
||||
(cons (cons handle (list (cons lfdnr id))) *csv-sepliste-id-by-handle*))
|
||||
)
|
||||
id
|
||||
)
|
||||
|
||||
;; --- Abstands-Schwelle (mm) fuer die Meldung einer auffaelligen Zuordnung ---
|
||||
;; Oberhalb dieses Abstands zwischen sepliste-Koordinate und tatsaechlicher
|
||||
;; Lage der zugehoerigen Kopie wird gemeldet (die Zuordnung selbst bleibt
|
||||
;; gueltig, siehe csv:sepliste-paare). Grosszuegig angesetzt: der SEP-Eintrag
|
||||
;; nennt den Einfuegepunkt des Trennstegs (Staustrecke_Separator_SP_300_mm),
|
||||
;; die Kopie das darin steckende Sensor-Symbol - ein Versatz in dieser
|
||||
;; Groessenordnung ist normal, benachbarte Kettenglieder liegen dagegen
|
||||
;; deutlich weiter auseinander (Staustrecken-Module ab 500 mm).
|
||||
(defun csv:sepliste-abstand-warnung-mm () 500.0)
|
||||
|
||||
;; --- sepliste-Eintraege und ausgepackte Kopien einander zuordnen ---
|
||||
;; eintraege = ((typ lfdnr x y) ...) wie ssg-sepliste-xdata-lesen sie liefert.
|
||||
;; proxies = ((typ x y) ...) - Reihenfolge beliebig, der INDEX in dieser
|
||||
;; Liste (0-basiert) ist der Schluessel im Ergebnis.
|
||||
;; Rueckgabe: ((lfdnr index abstand) ...), aufsteigend nach lfdnr; Eintraege
|
||||
;; ohne Partner fehlen darin.
|
||||
;;
|
||||
;; 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.
|
||||
;; Zugeordnet wird nur innerhalb desselben Typmarkers (AS/ES/SEP) und
|
||||
;; EXKLUSIV: alle Paare eines Typs werden nach Abstand sortiert, das kuerzeste
|
||||
;; zuerst genommen, danach sind Eintrag UND Kopie verbraucht. Das ist bewusst
|
||||
;; nicht "je Eintrag die naechste Kopie" (so macht es map_separator_kette_items
|
||||
;; in export_csv.py): waehlen zwei Eintraege dieselbe Kopie, bleibt eine Kopie
|
||||
;; ohne Eintrag und ein Eintrag ohne ID. Die exklusive Variante ist ausserdem
|
||||
;; gegen EINEN fehlerhaften Koordinatenwert unempfindlich - alle uebrigen
|
||||
;; Eintraege finden ihre Kopie ueber den kurzen Abstand zuerst, der fehlerhafte
|
||||
;; bekommt den Rest zugeteilt (mit entsprechend grossem Abstand, den
|
||||
;; csv:sepliste-ids-setzen meldet).
|
||||
;;
|
||||
;; 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 Sortierung ist eine STRIKTE Totalordnung (Abstand, dann lfdnr, dann
|
||||
;; Index): vl-sort wirft Elemente weg, die unter der Vergleichsfunktion als
|
||||
;; gleich gelten - zwei Paare mit identischem Abstand wuerden sonst zu einem
|
||||
;; verschmelzen und ein Eintrag bliebe ohne ID.
|
||||
;;
|
||||
;; 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))))
|
||||
;; Reine Rechenfunktion (keine Zeichnung, keine Datei) - getestet in
|
||||
;; tests/test_unit.lsp (tu-tests-export, Testfaelle "csv:sepliste-paare/*").
|
||||
(defun csv:sepliste-paare (eintraege proxies / kandidaten e p i dx dy
|
||||
benutzt-e benutzt-p erg)
|
||||
(setq kandidaten nil)
|
||||
(foreach e eintraege
|
||||
(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
|
||||
(foreach p proxies
|
||||
(if (= (nth 0 e) (nth 0 p))
|
||||
(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 dx (- (nth 2 e) (nth 1 p)))
|
||||
(setq dy (- (nth 3 e) (nth 2 p)))
|
||||
(setq kandidaten
|
||||
(cons (list (sqrt (+ (* dx dx) (* dy dy))) (nth 1 e) i) kandidaten))
|
||||
)
|
||||
)
|
||||
(setq i (1+ i))
|
||||
)
|
||||
)
|
||||
(setq kandidaten
|
||||
(vl-sort kandidaten
|
||||
(function (lambda (a b)
|
||||
(cond
|
||||
((/= (nth 0 a) (nth 0 b)) (< (nth 0 a) (nth 0 b)))
|
||||
((/= (nth 1 a) (nth 1 b)) (< (nth 1 a) (nth 1 b)))
|
||||
(t (< (nth 2 a) (nth 2 b)))
|
||||
)))))
|
||||
(setq erg nil benutzt-e nil benutzt-p nil)
|
||||
(foreach k kandidaten
|
||||
(if (and (not (member (nth 1 k) benutzt-e))
|
||||
(not (member (nth 2 k) benutzt-p)))
|
||||
(progn
|
||||
(setq benutzt-e (cons (nth 1 k) benutzt-e))
|
||||
(setq benutzt-p (cons (nth 2 k) benutzt-p))
|
||||
(setq erg (cons (list (nth 1 k) (nth 2 k) (nth 0 k)) erg))
|
||||
)
|
||||
proxy-liste
|
||||
)
|
||||
)
|
||||
(vl-sort erg (function (lambda (a b) (< (car a) (car b)))))
|
||||
)
|
||||
|
||||
;; --- 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)))
|
||||
;; --- Nach der ID-Vergabe: ID jeder Kopie an ihren sepliste-Eintrag haengen ---
|
||||
;; proxy-liste = Records (proxy-ename wrapper-ename typ (x y z)) aus
|
||||
;; csv:sep-proxies-erzeugen UND csv:schleus-proxies-erzeugen - beide Listen
|
||||
;; zusammen uebergeben, AS/ES und SEP stehen in DERSELBEN sepliste.
|
||||
;; MUSS nach ssg-id-check-all laufen: vorher hat eine frisch erzeugte Kopie
|
||||
;; noch keine ID.
|
||||
;;
|
||||
;; Ergebnis steht in *csv-sepliste-id-by-handle*; csv:block-to-json schreibt
|
||||
;; es als Feld "id" in jeden sepliste-Eintrag. Damit muss der Python-Teil die
|
||||
;; Kette nicht mehr ueber Koordinaten-Naehe auf reale Teile zurueckrechnen -
|
||||
;; die Zuordnung steht bereits im Export.
|
||||
;; Rueckgabe: Anzahl der Eintraege, die eine ID bekommen haben.
|
||||
(defun csv:sepliste-ids-setzen (proxy-liste / wrapper-enames rec wrapper ed bname
|
||||
handle app sepliste eigene proxies paare paar
|
||||
proxy-rec id typen e relevant gesetzt ohne-id fehlend)
|
||||
(setq gesetzt 0 ohne-id 0)
|
||||
;; Wrapper einsammeln (jeder nur einmal, in Reihenfolge seiner ersten Kopie).
|
||||
(setq wrapper-enames nil)
|
||||
(foreach rec proxy-liste
|
||||
(if (not (member (nth 1 rec) wrapper-enames))
|
||||
(setq wrapper-enames (cons (nth 1 rec) wrapper-enames))))
|
||||
(foreach wrapper (reverse wrapper-enames)
|
||||
(setq ed (entget wrapper))
|
||||
(setq bname (cdr (assoc 2 ed)))
|
||||
(setq handle (cdr (assoc 5 ed)))
|
||||
(setq app
|
||||
(cond
|
||||
((wcmatch (strcase bname) "VF_*") "SSG_VF_SEP")
|
||||
((wcmatch (strcase bname) "GF_*") "SSG_GF_SEP")
|
||||
(t nil)))
|
||||
(setq sepliste
|
||||
(if (and app (car (atoms-family 1 '("SSG-SEPLISTE-XDATA-LESEN"))))
|
||||
(ssg-sepliste-xdata-lesen wrapper app)))
|
||||
(if sepliste
|
||||
(progn
|
||||
;; Nur die Kopien DIESES Wrappers, in Erzeugungsreihenfolge - der Index
|
||||
;; im Ergebnis von csv:sepliste-paare zeigt in genau diese Liste.
|
||||
(setq eigene nil)
|
||||
(foreach rec proxy-liste
|
||||
(if (eq (nth 1 rec) wrapper) (setq eigene (cons rec eigene))))
|
||||
(setq eigene (reverse eigene))
|
||||
(setq proxies
|
||||
(mapcar (function (lambda (r) (list (nth 2 r) (car (nth 3 r)) (cadr (nth 3 r)))))
|
||||
eigene))
|
||||
(setq paare (csv:sepliste-paare sepliste proxies))
|
||||
(foreach paar paare
|
||||
(setq proxy-rec (nth (nth 1 paar) eigene))
|
||||
(setq id (cdr (assoc "ID" (ssg-attrib-read (nth 0 proxy-rec)))))
|
||||
(if (and id (> (strlen id) 0))
|
||||
(progn
|
||||
(csv:sepliste-id-merken handle (nth 0 paar) id)
|
||||
(setq gesetzt (1+ gesetzt))
|
||||
)
|
||||
(setq ohne-id (1+ ohne-id))
|
||||
)
|
||||
;; Auffaellig weit auseinander: die sepliste-Koordinate passt nicht
|
||||
;; zur tatsaechlichen Lage des Bauteils (bekannter Fehlerfall:
|
||||
;; gespiegelte x-Koordinate beim Bau). Die Zuordnung bleibt gueltig -
|
||||
;; sie entsteht exklusiv, nicht ueber diesen Abstand -, wird aber
|
||||
;; gemeldet, damit die Ursache nicht unbemerkt bleibt.
|
||||
(if (> (nth 2 paar) (csv:sepliste-abstand-warnung-mm))
|
||||
(princ (ssg-textf "exp-sepliste-abstand"
|
||||
(list bname (nth 2 proxy-rec) (itoa (nth 0 paar))
|
||||
(rtos (nth 2 paar) 2 0))))
|
||||
)
|
||||
)
|
||||
;; Fehlende Partner NUR unter den Typen zaehlen, die diese Liste
|
||||
;; ueberhaupt bedient: AS/ES kommen hier nicht vor (dafuer gibt es die
|
||||
;; Marker, siehe csv:asmark-ids-setzen), ihre Eintraege waeren sonst
|
||||
;; jedes Mal als "ohne Kopie" gemeldet.
|
||||
(setq typen nil)
|
||||
(foreach rec eigene
|
||||
(if (not (member (nth 2 rec) typen)) (setq typen (cons (nth 2 rec) typen))))
|
||||
(setq relevant 0)
|
||||
(foreach e sepliste
|
||||
(if (member (nth 0 e) typen) (setq relevant (1+ relevant))))
|
||||
(setq fehlend (- relevant (length paare)))
|
||||
(if (> fehlend 0)
|
||||
(princ (ssg-textf "exp-sepliste-ohne-proxy" (list bname (itoa fehlend)))))
|
||||
)
|
||||
)
|
||||
)
|
||||
(if (> gesetzt 0)
|
||||
(princ (ssg-textf "exp-sepliste-ids" (list (itoa gesetzt)))))
|
||||
(if (> ohne-id 0)
|
||||
(princ (ssg-textf "exp-sepliste-ohne-id" (list (itoa ohne-id)))))
|
||||
gesetzt
|
||||
)
|
||||
|
||||
;; ===========================================================================
|
||||
;; AS-/ES-Marker (ZZ_ASES_MARKER)
|
||||
;; ===========================================================================
|
||||
;; Ein kleines Rechteck, das der Export an JEDES AS-/ES-Ende einer VF_n/GF_n-
|
||||
;; Kette setzt und das dort DAUERHAFT stehen bleibt. Es ist zweierlei:
|
||||
;;
|
||||
;; Sichtbarmachung - die Kettenenden stecken verpackt in der Wrapper-
|
||||
;; Blockdefinition (AS_Element_*/ES_Element_*) und sind in der Zeichnung
|
||||
;; sonst weder anklickbar noch als eigenes Objekt erkennbar.
|
||||
;; ID-Traeger - das (unsichtbare) ID-Attribut des Markers fuellt
|
||||
;; ssg-id-check-all, und der naechste Export VERWENDET DENSELBEN MARKER
|
||||
;; WIEDER. Ein AS/ES behaelt seine TeileId dadurch ueber Exportlaeufe
|
||||
;; hinweg - anders als die temporaeren Separator-Kopien, die bei jedem Lauf
|
||||
;; neu entstehen und neue IDs bekommen.
|
||||
;;
|
||||
;; Der Marker ist abgeleitete Geometrie: csv:asmark-aktualisieren baut bei
|
||||
;; JEDEM Export alle Marker neu auf (Lage folgt damit automatisch einer
|
||||
;; umgebauten Kette) und uebernimmt dabei nur die ID des bisherigen Markers.
|
||||
;; Nicht wiederverwendete Marker werden geloescht - ein Marker ohne Kette
|
||||
;; bleibt also nicht als Karteileiche stehen.
|
||||
|
||||
(defun csv:asmark-blockname () "ZZ_ASES_MARKER")
|
||||
|
||||
;; Kantenlaenge (mm) des Rechtecks, aus cfg/export.cfg [Marker].
|
||||
(defun csv:asmark-groesse-mm ()
|
||||
(atof (export:cfg "Marker" "ases_groesse_mm" "200"))
|
||||
)
|
||||
|
||||
;; Attribut-Schema des Markers. Alle ATTDEFs sind UNSICHTBAR
|
||||
;; (ssg-attrib-make-defs setzt Flag 70=1) - sichtbar ist nur das Rechteck.
|
||||
;; ID - fuellt ssg-id-check-all; wird beim naechsten Export uebernommen
|
||||
;; ZUORDNUNG - ID des VF_n/GF_n-Wrappers, zu dem das Kettenende gehoert
|
||||
;; (zugleich der Schluessel, ueber den der Marker wiedergefunden
|
||||
;; wird, siehe csv:asmark-finden)
|
||||
;; TYP - "AS" oder "ES", wie in der sepliste (ssg-sepliste-sammeln)
|
||||
;; LFDNR - lfdnr des zugehoerigen sepliste-Eintrags
|
||||
;; ELEMENT - Blockname des echten Schleuselements (AS_Element_90_links_3D):
|
||||
;; haelt die Variante (30/90, links/rechts, 2D/3D) fest, die der
|
||||
;; Marker selbst nicht mehr zeigt
|
||||
;; ARTINR - Sivas-Nummer aus dem Attribut des echten Elements
|
||||
(setq *csv-asmark-attrib-defs*
|
||||
'(("ID" "") ("ZUORDNUNG" "") ("TYP" "") ("LFDNR" "") ("ELEMENT" "") ("ARTINR" ""))
|
||||
)
|
||||
|
||||
;; --- Blockdefinition des Markers bei Bedarf anlegen ---
|
||||
;; Es gibt bewusst KEINE DWG dafuer: der Marker ist reine Hilfsgeometrie und
|
||||
;; soll in jeder Zeichnung ohne Blockbibliothek entstehen koennen. Aufbau wie
|
||||
;; bei den Geruest-Baugruppen (GeruestInsert.lsp): Geometrie + ATTDEFs in den
|
||||
;; Modellraum zeichnen, alles seit lastEnt einsammeln, per "_.-BLOCK" zur
|
||||
;; Definition machen (das entfernt die Vorlage-Entities wieder).
|
||||
;; Die Geometrie liegt auf Layer "0", damit der Marker den Layer seiner
|
||||
;; Blockreferenz annimmt (den setzt csv:asmark-aktualisieren aus cfg/layer.cfg).
|
||||
;;
|
||||
;; WICHTIG - der Auswahlsatz nimmt NUR die beiden hier erzeugten Entity-Typen
|
||||
;; auf: (entlast) liefert bei einer Blockreferenz MIT Attributen die Referenz
|
||||
;; selbst, und (entnext) steigt von dort in deren ATTRIB-Unterentities ab. Ohne
|
||||
;; Filter landen also die Attribute des zuletzt eingefuegten Blocks (z.B. eines
|
||||
;; gerade gebauten VF_n) mit im Auswahlsatz - "_.-BLOCK" verschiebt sie in die
|
||||
;; neue Blockdefinition und der Block steht danach OHNE Attribute da (real
|
||||
;; beobachtet: VF_5 verlor beim ersten Export saemtliche Attribute, inklusive
|
||||
;; seiner ID).
|
||||
;; Rueckgabe: Blockname oder nil.
|
||||
(defun csv:asmark-blockdef-sicherstellen ( / name h lastEnt ss e typ)
|
||||
(setq name (csv:asmark-blockname))
|
||||
(if (tblsearch "BLOCK" name)
|
||||
name
|
||||
(progn
|
||||
(setq h (/ (csv:asmark-groesse-mm) 2.0))
|
||||
(setq lastEnt (entlast))
|
||||
(entmake (list '(0 . "LWPOLYLINE") '(100 . "AcDbEntity") '(8 . "0")
|
||||
'(100 . "AcDbPolyline") '(90 . 4) '(70 . 1)
|
||||
(cons 10 (list (- h) (- h)))
|
||||
(cons 10 (list h (- h)))
|
||||
(cons 10 (list h h))
|
||||
(cons 10 (list (- h) h))))
|
||||
(ssg-attrib-make-defs *csv-asmark-attrib-defs* (/ h 2.0))
|
||||
(setq ss (ssadd))
|
||||
(setq e (if lastEnt (entnext lastEnt) (entnext)))
|
||||
(while e
|
||||
(setq typ (cdr (assoc 0 (entget e))))
|
||||
(if (member typ '("LWPOLYLINE" "ATTDEF")) (ssadd e ss))
|
||||
(setq e (entnext e))
|
||||
)
|
||||
(command "_.-BLOCK" name (list 0.0 0.0 0.0) ss "")
|
||||
(if (tblsearch "BLOCK" name)
|
||||
(progn (princ (ssg-textf "exp-asmark-blockdef" (list name))) name)
|
||||
(progn (princ (ssg-textf "exp-asmark-blockdef-fehler" (list name))) nil)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; --- Vorhandene Marker der Zeichnung einsammeln ---
|
||||
;; Rueckgabe: Liste von (ename zuordnung typ lfdnr id), alle Werte als String
|
||||
;; (fehlende Attribute als "").
|
||||
(defun csv:asmark-sammeln ( / ss i ename attribs out)
|
||||
(setq ss (ssget "X" (list (cons 0 "INSERT") (cons 2 (csv:asmark-blockname)))))
|
||||
(if ss
|
||||
(progn
|
||||
(setq i 0)
|
||||
(while (setq ename (ssname ss i))
|
||||
(setq attribs (ssg-attrib-read ename))
|
||||
(setq out
|
||||
(cons (list ename
|
||||
(cond ((cdr (assoc "ZUORDNUNG" attribs))) (""))
|
||||
(cond ((cdr (assoc "TYP" attribs))) (""))
|
||||
(cond ((cdr (assoc "LFDNR" attribs))) (""))
|
||||
(cond ((cdr (assoc "ID" attribs))) ("")))
|
||||
out))
|
||||
(setq i (1+ i))
|
||||
)
|
||||
)
|
||||
)
|
||||
(reverse out)
|
||||
)
|
||||
|
||||
;; --- Den Marker eines Kettenendes im Bestand suchen ---
|
||||
;; Schluessel: Wrapper-ID + Typ + lfdnr (alles Strings). Bewusst NICHT ueber
|
||||
;; die Position: eine Kette, die verschoben oder umgebaut wurde, soll ihre
|
||||
;; TeileIds behalten. Ein Wrapper OHNE ID (frisch gebaut, ssg-id-check-all lief
|
||||
;; noch nicht) findet folgerichtig nichts - seine Marker entstehen neu; die
|
||||
;; ZUORDNUNG wird nach der ID-Vergabe nachgetragen (csv:asmark-ids-setzen),
|
||||
;; sodass es beim naechsten Export passt.
|
||||
(defun csv:asmark-finden (bestand zuordnung typ lfdnr / m treffer)
|
||||
(foreach m bestand
|
||||
(if (and (null treffer)
|
||||
(= (nth 1 m) zuordnung)
|
||||
(= (nth 2 m) typ)
|
||||
(= (nth 3 m) lfdnr))
|
||||
(setq treffer m)
|
||||
)
|
||||
)
|
||||
treffer
|
||||
)
|
||||
|
||||
;; --- Alle AS-/ES-Marker der Zeichnung neu aufbauen ---
|
||||
;; Laeuft VOR ssg-id-check-all (csv:export-vorbereiten): neue Marker haben dann
|
||||
;; noch kein ID-Attribut und werden dort nummeriert, uebernommene tragen die ID
|
||||
;; ihres Vorgaengers und behalten sie.
|
||||
;;
|
||||
;; Ablauf je VF_n/GF_n-Wrapper mit sepliste:
|
||||
;; 1. Weltlage aller verpackten AS-/ES-Elemente holen (csv:nested-welt-records)
|
||||
;; 2. sie den AS-/ES-Eintraegen der sepliste zuordnen (csv:sepliste-paare -
|
||||
;; dieselbe exklusive Zuordnung wie bei den Separator-Kopien; SEP-Eintraege
|
||||
;; finden hier keinen Partner und bleiben unberuehrt)
|
||||
;; 3. je Paar den bisherigen Marker suchen, seine ID merken, ihn loeschen und
|
||||
;; an der AKTUELLEN Lage neu setzen
|
||||
;; Was danach im Bestand uebrig ist, gehoert zu keiner Kette mehr und wird
|
||||
;; geloescht.
|
||||
;;
|
||||
;; Rueckgabe: Liste von Records (marker-ename wrapper-ename typ lfdnr) fuer
|
||||
;; csv:asmark-ids-setzen.
|
||||
(defun csv:asmark-aktualisieren ( / recs bestand blockname ms wrapper-enames rec
|
||||
wrapper ed bname wrapper-id app sepliste eigene
|
||||
proxies paare paar elem lfdnr typ alt alt-id
|
||||
mark artinr m neu uebernommen verwaist ergebnis)
|
||||
(setq neu 0 uebernommen 0 verwaist 0)
|
||||
(setq recs (csv:nested-welt-records (csv:pattern-nested-schleus)))
|
||||
(setq bestand (csv:asmark-sammeln))
|
||||
(setq blockname (if recs (csv:asmark-blockdef-sicherstellen)))
|
||||
(if blockname
|
||||
(progn
|
||||
(setq ms (vla-get-ModelSpace (vla-get-ActiveDocument (vlax-get-acad-object))))
|
||||
(setq wrapper-enames nil)
|
||||
(foreach rec recs
|
||||
(if (not (member (nth 0 rec) wrapper-enames))
|
||||
(setq wrapper-enames (cons (nth 0 rec) wrapper-enames))))
|
||||
(foreach wrapper (reverse wrapper-enames)
|
||||
(setq ed (entget wrapper))
|
||||
(setq bname (cdr (assoc 2 ed)))
|
||||
(setq wrapper-id (cond ((cdr (assoc "ID" (ssg-attrib-read wrapper)))) ("")))
|
||||
(setq app
|
||||
(cond
|
||||
((wcmatch (strcase bname) "VF_*") "SSG_VF_SEP")
|
||||
((wcmatch (strcase bname) "GF_*") "SSG_GF_SEP")
|
||||
(t nil)))
|
||||
(setq sepliste
|
||||
(if (and app (car (atoms-family 1 '("SSG-SEPLISTE-XDATA-LESEN"))))
|
||||
(ssg-sepliste-xdata-lesen wrapper app)))
|
||||
(if sepliste
|
||||
(progn
|
||||
(setq eigene nil)
|
||||
(foreach rec recs
|
||||
(if (eq (nth 0 rec) wrapper) (setq eigene (cons rec eigene))))
|
||||
(setq eigene (reverse eigene))
|
||||
(setq proxies
|
||||
(mapcar (function (lambda (r)
|
||||
(list (csv:proxy-typ (nth 2 r)) (car (nth 3 r)) (cadr (nth 3 r)))))
|
||||
eigene))
|
||||
(setq paare (csv:sepliste-paare sepliste proxies))
|
||||
(foreach paar paare
|
||||
(setq lfdnr (nth 0 paar))
|
||||
(setq elem (nth (nth 1 paar) eigene))
|
||||
(setq typ (csv:proxy-typ (nth 2 elem)))
|
||||
(setq alt (csv:asmark-finden bestand wrapper-id typ (itoa lfdnr)))
|
||||
(setq alt-id "")
|
||||
(if alt
|
||||
(progn
|
||||
(setq alt-id (nth 4 alt))
|
||||
(entdel (nth 0 alt))
|
||||
(setq bestand (vl-remove alt bestand))
|
||||
(setq uebernommen (1+ uebernommen))
|
||||
)
|
||||
(setq neu (1+ neu))
|
||||
)
|
||||
;; Marker mit Skalierung 1.0 einfuegen - die Skalierung des
|
||||
;; Elements gehoert dem Element, ein gestauchtes Marker-Rechteck
|
||||
;; waere als Positionszeichen unbrauchbar. Orientierung folgt
|
||||
;; dagegen dem Element (auch bei geneigter Kette).
|
||||
(setq mark (csv:block-einfuegen-welt ms blockname (nth 3 elem) (nth 4 elem)
|
||||
1.0 1.0 1.0 bname))
|
||||
(if mark
|
||||
(progn
|
||||
;; ARTINR nur lesen, wenn der Sub-INSERT ueberhaupt ATTRIBs
|
||||
;; fuehrt (Gruppe 66 = 1): ssg-attrib-read wandert per entnext
|
||||
;; bis zum SEQEND - fehlt der, laeuft es ueber das Element
|
||||
;; hinaus durch die restliche Blockdefinition und liefert das
|
||||
;; ARTINR IRGENDEINES spaeteren Bausteins der Kette.
|
||||
(setq artinr "")
|
||||
(if (equal 1 (cdr (assoc 66 (entget (nth 1 elem)))))
|
||||
(setq artinr
|
||||
(cond ((cdr (assoc "ARTINR" (ssg-attrib-read (nth 1 elem))))) (""))))
|
||||
(ssg-attrib-set-on mark
|
||||
(list (cons "ID" alt-id)
|
||||
(cons "ZUORDNUNG" wrapper-id)
|
||||
(cons "TYP" typ)
|
||||
(cons "LFDNR" (itoa lfdnr))
|
||||
(cons "ELEMENT" (nth 2 elem))
|
||||
(cons "ARTINR" artinr)))
|
||||
(ssg-layer-setzen mark "ases_marker")
|
||||
(setq ergebnis (cons (list mark wrapper typ lfdnr) ergebnis))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
;; Rest des Bestands: kein Kettenende mehr dahinter (Kette geloescht, Eintrag
|
||||
;; entfallen, Wrapper ohne sepliste). Marker sind abgeleitete Geometrie -
|
||||
;; ohne Kette bleiben sie nicht stehen.
|
||||
(foreach m bestand
|
||||
(entdel (nth 0 m))
|
||||
(setq verwaist (1+ verwaist))
|
||||
)
|
||||
(if (or (> neu 0) (> uebernommen 0) (> verwaist 0))
|
||||
(princ (ssg-textf "exp-asmark-bilanz"
|
||||
(list (itoa neu) (itoa uebernommen) (itoa verwaist)))))
|
||||
(reverse ergebnis)
|
||||
)
|
||||
|
||||
;; --- Nach der ID-Vergabe: Marker-ID an den sepliste-Eintrag haengen ---
|
||||
;; marker-liste = Records (marker-ename wrapper-ename typ lfdnr) aus
|
||||
;; csv:asmark-aktualisieren. Zwei Aufgaben:
|
||||
;; 1. ZUORDNUNG nachtragen - beim Setzen der Marker kann der Wrapper noch
|
||||
;; keine ID gehabt haben (frisch gebaute Kette). Ohne sie faende der
|
||||
;; NAECHSTE Export den Marker nicht wieder und legte ihn samt neuer ID
|
||||
;; erneut an; die TeileId waere dann doch nicht stabil.
|
||||
;; 2. die ID des Markers unter *csv-sepliste-id-by-handle* eintragen, damit
|
||||
;; csv:block-to-json sie als Feld "id" am AS-/ES-Eintrag schreibt.
|
||||
;; Rueckgabe: Anzahl der Eintraege mit ID.
|
||||
(defun csv:asmark-ids-setzen (marker-liste / rec mark wrapper handle wrapper-id id
|
||||
gesetzt ohne-id)
|
||||
(setq gesetzt 0 ohne-id 0)
|
||||
(foreach rec marker-liste
|
||||
(setq mark (nth 0 rec))
|
||||
(setq wrapper (nth 1 rec))
|
||||
(setq handle (cdr (assoc 5 (entget wrapper))))
|
||||
(setq wrapper-id (cdr (assoc "ID" (ssg-attrib-read wrapper))))
|
||||
(if (and wrapper-id (> (strlen wrapper-id) 0))
|
||||
(ssg-attrib-set-on mark (list (cons "ZUORDNUNG" wrapper-id))))
|
||||
(setq id (cdr (assoc "ID" (ssg-attrib-read mark))))
|
||||
(if (and id (> (strlen id) 0))
|
||||
(progn
|
||||
(csv:sepliste-id-merken handle (nth 3 rec) id)
|
||||
(setq gesetzt (1+ gesetzt))
|
||||
)
|
||||
(setq ohne-id (1+ ohne-id))
|
||||
)
|
||||
)
|
||||
(if (> gesetzt 0)
|
||||
(princ (ssg-textf "exp-asmark-ids" (list (itoa gesetzt)))))
|
||||
(if (> ohne-id 0)
|
||||
(princ (ssg-textf "exp-sepliste-ohne-id" (list (itoa ohne-id)))))
|
||||
gesetzt
|
||||
)
|
||||
|
||||
;; --- Temporaere Kopien (csv:sep-proxies-erzeugen /
|
||||
;; csv:schleus-proxies-erzeugen) nach dem Export wieder entfernen ---
|
||||
;; proxy-liste = Records (proxy-ename wrapper-ename typ (x y z)), nur der car
|
||||
;; (die Kopie selbst) wird geloescht.
|
||||
;;
|
||||
;; Der Debug-Schalter "csv_leave_proxies" (ssg_dbg.lsp) unterdrueckt das
|
||||
;; Loeschen: die Kopien bleiben zur Ansicht in der Zeichnung stehen, damit sich
|
||||
;; die tatsaechliche Lage der exportierten Separatoren gegen die
|
||||
;; sepliste-Koordinaten pruefen laesst. *cs-sep-fix-by-handle* und
|
||||
;; *csv-sepliste-id-by-handle* werden trotzdem zurueckgesetzt - sie gelten nur
|
||||
;; fuer den gerade gelaufenen Export.
|
||||
(defun csv:sep-proxies-loeschen (proxy-liste / behalten)
|
||||
(setq behalten (and (car (atoms-family 1 '("DBG-SCHALTER-P")))
|
||||
(dbg-schalter-p "csv_leave_proxies")))
|
||||
(if behalten
|
||||
(princ (strcat "\n[EXPORT] csv_leave_proxies=1: "
|
||||
(itoa (length proxy-liste))
|
||||
" Separator-Proxy-Kopie(n) bleiben in der Zeichnung"
|
||||
" (Abschalten: (dbg-schalter-off \"csv_leave_proxies\"))"))
|
||||
(foreach rec proxy-liste (entdel (car rec)))
|
||||
)
|
||||
(setq *cs-sep-fix-by-handle* nil)
|
||||
(setq *csv-sepliste-id-by-handle* nil)
|
||||
(princ)
|
||||
)
|
||||
|
||||
@@ -1132,6 +1602,12 @@
|
||||
;; Omniflo Boegen/Weichen = rein numerische Blocknamen (SivasNr)
|
||||
;; Vario* = VarioFoerderer-Bloecke
|
||||
;; GF_* = Gefaellestrecke Compound-Bloecke
|
||||
;; ZZ_ASES_MARKER = die Marker der AS-/ES-Kettenenden einer VF_n/GF_n-Strecke
|
||||
;; (siehe csv:asmark-aktualisieren; pattern_ases_marker in cfg/export.cfg).
|
||||
;; Das Kettenende selbst steckt verpackt in der Wrapper-Blockdefinition und
|
||||
;; waere sonst weder sichtbar noch exportierbar; der Marker vertritt es -
|
||||
;; mit eigener, ueber Exportlaeufe stabiler ID und den Attributen
|
||||
;; TYP/LFDNR/ELEMENT/ARTINR.
|
||||
;; Separator_SP*/S-LP*, Scanner* = eigenstaendige Sensor-Bloecke (siehe
|
||||
;; pattern_separator/pattern_scanner in cfg/export.cfg). Landen in
|
||||
;; export_raw.json fuer BEIDE Exporte (EXPORTCSV/EXPORTSIVAS teilen sich
|
||||
@@ -1170,6 +1646,7 @@
|
||||
(wcmatch (strcase bname) (export:pattern "pattern_gerade" "AP110*,AP_110*"))
|
||||
(wcmatch bname (export:pattern "pattern_strecke"
|
||||
"Vario*,Staustrecke*,AUS_Element*,EIN_Element*,VF_*,GF_*"))
|
||||
(wcmatch bname (export:pattern "pattern_ases_marker" "ZZ_ASES_MARKER*"))
|
||||
(wcmatch bname (export:pattern "pattern_separator" "Separator_SP*,S-LP*"))
|
||||
(wcmatch bname (export:pattern "pattern_scanner" "Scanner*"))
|
||||
(wcmatch bname (export:pattern "pattern_btmt_beladung" "BTMT-Beladung*"))
|
||||
@@ -1227,25 +1704,19 @@
|
||||
;; den Zeichnungszustand herrichten - Separator-Proxies einpacken, IDs
|
||||
;; sicherstellen, Proxy-Zuordnung setzen, Omniflo-Attribute (HOEHE/DREHUNG)
|
||||
;; aktualisieren, Separator-/Scanner-Zuordnung pruefen, global regenerieren und
|
||||
;; die bbox-Fehlerdiagnose zuruecksetzen. Rueckgabe: die Liste der erzeugten
|
||||
;; Separator-Proxies (der Aufrufer entfernt sie am Ende wieder). label dient
|
||||
;; nur den Meldungen.
|
||||
(defun csv:export-vorbereiten (label / sep-proxies)
|
||||
;; die bbox-Fehlerdiagnose zuruecksetzen. Rueckgabe: die Liste ALLER erzeugten
|
||||
;; Kopien - Separatoren UND AS/ES-Schleuselemente (der Aufrufer entfernt sie am
|
||||
;; Ende wieder). label dient nur den Meldungen.
|
||||
(defun csv:export-vorbereiten (label / sep-proxies asmarks)
|
||||
;; Verpackte Separator_SP-Symbole (siehe csv:sep-proxies-erzeugen) VOR der
|
||||
;; ID-Vergabe durch temporaere, echte Kopien ersetzen - sie werden am Ende
|
||||
;; von csv:run-export 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))
|
||||
;; Die AS-/ES-Kettenenden stecken ebenfalls verpackt im Wrapper, bekommen
|
||||
;; aber KEINE temporaere Kopie, sondern einen DAUERHAFTEN Marker
|
||||
;; (ZZ_ASES_MARKER): er macht das Kettenende in der Zeichnung sichtbar und
|
||||
;; traegt dessen ID ueber Exportlaeufe hinweg (siehe csv:asmark-*).
|
||||
(setq asmarks (csv:asmark-aktualisieren))
|
||||
;; Vor dem Export: IDs aller Bloecke sicherstellen und Duplikate korrigieren.
|
||||
;; Erst hier - also erst nachdem ALLE Kopien aus allen Wrapper-Bloecken
|
||||
;; stehen - wird ueberhaupt eine ID vergeben. ssg-id-check-all ermittelt
|
||||
@@ -1256,8 +1727,17 @@
|
||||
(ssg-id-check-all)
|
||||
;; Jetzt steht die ID jedes Wrappers fest: die bekannte (nicht geratene)
|
||||
;; ZUORDNUNG der verpackten Separatoren auf die Wrapper-ID setzen und fuer
|
||||
;; cs-zuordnung-lauf festnageln.
|
||||
;; cs-zuordnung-lauf festnageln. Nur fuer die Separator-Kopien - die
|
||||
;; AS/ES-Marker sind keine Sensoren und werden nicht gezaehlt (ihre
|
||||
;; ZUORDNUNG setzt csv:asmark-ids-setzen).
|
||||
(csv:sep-proxies-zuordnung-setzen sep-proxies)
|
||||
;; Ebenfalls erst jetzt moeglich: die ID jedes Bauteils an seinen sepliste-
|
||||
;; Eintrag haengen (csv:block-to-json schreibt sie als Feld "id" mit) -
|
||||
;; AS/ES ueber die Marker, SEP ueber die temporaeren Kopien. Beide schreiben
|
||||
;; in dieselbe Zuordnung, die hier einmal zurueckgesetzt wird.
|
||||
(setq *csv-sepliste-id-by-handle* nil)
|
||||
(csv:asmark-ids-setzen asmarks)
|
||||
(csv:sepliste-ids-setzen sep-proxies)
|
||||
;; Vor dem Export HOEHE/DREHUNG aller Omniflo-Elemente aktualisieren
|
||||
(princ (ssg-textf "exp-update-hoehe-drehung" (list label)))
|
||||
(omni:update-all-attribs)
|
||||
@@ -1293,6 +1773,8 @@
|
||||
;; bbox-Fehlerdiagnose fuer diesen Lauf zuruecksetzen (siehe csv:get-bbox).
|
||||
(setq *csv-bbox-fail-count* 0)
|
||||
(setq *csv-bbox-fail-first* nil)
|
||||
;; Nur die TEMPORAEREN Kopien zurueckgeben - die AS/ES-Marker bleiben
|
||||
;; bewusst in der Zeichnung stehen und duerfen nicht mitgeloescht werden.
|
||||
sep-proxies)
|
||||
|
||||
;; --- Python-Export-Skript aufrufen und Ergebnis auswerten ---------------
|
||||
@@ -1361,7 +1843,7 @@
|
||||
first-block count out-dir sep-proxies)
|
||||
;; Zeichnungszustand fuer den Export herrichten (Proxies, IDs, Zuordnung,
|
||||
;; Attribut-Update, Sep/Scan-Zaehlung, REGENALL, bbox-Reset) - ausgelagert.
|
||||
;; Rueckgabe: die erzeugten Separator-Proxies (unten wieder zu entfernen).
|
||||
;; Rueckgabe: alle erzeugten Kopien (unten wieder zu entfernen).
|
||||
(setq sep-proxies (csv:export-vorbereiten label))
|
||||
(princ (ssg-textf "exp-collect-blocks" (list label)))
|
||||
|
||||
@@ -1428,7 +1910,7 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
;; Temporaere Separator-/Scanner-Kopien wieder entfernen - sie haben ihren
|
||||
;; Temporaere Separator-/AS-/ES-Kopien wieder entfernen - sie haben ihren
|
||||
;; Zweck (ID-Vergabe + JSON-Zeile ueber die obigen, unveraenderten
|
||||
;; Sammel-Funktionen) erfuellt.
|
||||
(csv:sep-proxies-loeschen sep-proxies)
|
||||
|
||||
@@ -62,6 +62,31 @@
|
||||
(if (not (assoc nm *dbg-schalter*))
|
||||
(setq *dbg-schalter* (cons (cons nm 1) *dbg-schalter*))))
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; TEMPORAER - Diagnose "gespiegelte Sepliste-Koordinate" (lfdnr=2)
|
||||
;;
|
||||
;; Beide Schalter hier stehen NUR fuer diese Fehlersuche auf 1 und werden
|
||||
;; danach wieder entfernt (mitsamt der zugehoerigen Instrumentierung in
|
||||
;; ssg_ks_insert.lsp/Gefaellestrecke.lsp/vf_core.lsp bzw. dem Guard in
|
||||
;; csv:sep-proxies-loeschen, export.lsp). Sie sind bewusst vorregistriert,
|
||||
;; damit nach einem BricsCAD-Neustart ohne weiteres Zutun protokolliert wird.
|
||||
;;
|
||||
;; vf-sepliste - protokolliert den kompletten Weg der
|
||||
;; Sepliste-Koordinaten beim Bau einer VF-/GF-Kette
|
||||
;; nach DXFM_LOG/vf_sepliste.dbg (eigene Datei, nicht
|
||||
;; ueber *dbg-path*).
|
||||
;; csv_leave_proxies - laesst die temporaeren Separator_SP-Kopien, die der
|
||||
;; Export aus den Wrappern auspackt, nach dem Export in
|
||||
;; der Zeichnung stehen, damit ihre tatsaechliche Lage
|
||||
;; in BricsCAD gegen die sepliste-Koordinaten geprueft
|
||||
;; werden kann. ACHTUNG: die Kopien werden bei JEDEM
|
||||
;; Export neu erzeugt und sammeln sich an - Zeichnung
|
||||
;; danach nicht speichern.
|
||||
;; ------------------------------------------------------------
|
||||
(foreach nm '("vf-sepliste" "csv_leave_proxies")
|
||||
(if (not (assoc nm *dbg-schalter*))
|
||||
(setq *dbg-schalter* (cons (cons nm 1) *dbg-schalter*))))
|
||||
|
||||
(defun dbg-schalter-set (name wert)
|
||||
(setq *dbg-schalter*
|
||||
(cons (cons name wert)
|
||||
|
||||
@@ -60,6 +60,12 @@
|
||||
(wcmatch bname "KR_*,KREISEL_*,ECKRAD_*")
|
||||
(wcmatch (strcase bname) "AP110*,AP_110*,AP60*,AP_60*,APG110*")
|
||||
(wcmatch bname "Vario*,Staustrecke*,AUS_Element*,EIN_Element*,VF_*,GF_*")
|
||||
;; ZZ_ASES_MARKER: die Marker der AS-/ES-Kettenenden (siehe
|
||||
;; csv:asmark-aktualisieren, export.lsp). Sie brauchen eine ID -
|
||||
;; sie vertreten das Kettenende im Export ("sepliste"-Feld "id"
|
||||
;; und eigene JSON-Zeile) und behalten sie ueber Laeufe hinweg,
|
||||
;; weil der Marker in der Zeichnung stehen bleibt.
|
||||
(wcmatch bname "ZZ_ASES_MARKER*")
|
||||
(wcmatch bname "Separator_SP*,S-LP*,Scanner*")
|
||||
(wcmatch bname "BTMT-Beladung*,SC_Entladung*")
|
||||
(wcmatch bname "Eingang*,Ausgang*")
|
||||
|
||||
+113
-5
@@ -220,6 +220,14 @@
|
||||
(+ (car einfuegepunkt) (- (* chv dx-loc) (* shv dy-loc)))
|
||||
(+ (cadr einfuegepunkt) (+ (* shv dx-loc) (* chv dy-loc)))
|
||||
(+ (caddr einfuegepunkt) dz-loc)))
|
||||
(ssg-sepliste-dbg
|
||||
(strcat "insert-block-by-ks " blockname
|
||||
" hz=" (rtos (float hz) 2 2)
|
||||
" einfuegepunkt=" (ssg-sepliste-dbg-pt einfuegepunkt)
|
||||
" ks_ein_lokal=" (ssg-sepliste-dbg-pt (car ks-ein))
|
||||
" ks_aus_lokal=" (ssg-sepliste-dbg-pt (car ks-aus))
|
||||
" offset(=Gruppencode 10)=" (ssg-sepliste-dbg-pt offset)
|
||||
" ausgang=" (ssg-sepliste-dbg-pt ausgang)))
|
||||
(princ (ssg-textf "vfc-ks-aus-xyz"
|
||||
(list (rtos (car ausgang) 2 2) (rtos (cadr ausgang) 2 2) (rtos (caddr ausgang) 2 2))))
|
||||
ausgang
|
||||
@@ -266,6 +274,12 @@
|
||||
(+ (car startpunkt) (* laenge chv cvv))
|
||||
(+ (cadr startpunkt) (* laenge shv cvv))
|
||||
(+ (caddr startpunkt) (* laenge (- svv)))))
|
||||
(ssg-sepliste-dbg
|
||||
(strcat "insert-inclined-scaled-block " blockname
|
||||
" laenge=" (rtos laenge 2 2) " winkel=" (rtos (float winkel) 2 2)
|
||||
" hz=" (rtos (float hz) 2 2) " scale=" (rtos scale 2 4)
|
||||
" startpunkt(=Gruppencode 10)=" (ssg-sepliste-dbg-pt startpunkt)
|
||||
" endpunkt=" (ssg-sepliste-dbg-pt endpunkt)))
|
||||
(princ (ssg-textf "vfc-endpunkt-xyz"
|
||||
(list (rtos (car endpunkt) 2 2) (rtos (cadr endpunkt) 2 2) (rtos (caddr endpunkt) 2 2))))
|
||||
endpunkt
|
||||
@@ -346,6 +360,17 @@
|
||||
(+ (car startpunkt) (+ (* dx chv cvv) (* dz chv svv)))
|
||||
(+ (cadr startpunkt) (+ (* dx shv cvv) (* dz shv svv)))
|
||||
(+ (caddr startpunkt) (+ (* dx (- svv)) (* dz cvv)))))
|
||||
(ssg-sepliste-dbg
|
||||
(strcat "insert-rotated-block-with-ks " blockname
|
||||
" winkel=" (rtos (float winkel) 2 2) " hz=" (rtos (float hz) 2 2)
|
||||
" startpunkt=" (ssg-sepliste-dbg-pt startpunkt)
|
||||
" ks_ein_lokal=" (ssg-sepliste-dbg-pt (list ein-x ein-y ein-z))
|
||||
" ks_aus_lokal=" (if ks-aus-raw
|
||||
(ssg-sepliste-dbg-pt (list aus-x aus-y aus-z))
|
||||
"nil (Fallback dx/dz aus cfg)")
|
||||
" dx=" (rtos dx 2 2) " dz=" (rtos dz 2 2)
|
||||
" ins-pt(=Gruppencode 10)=" (ssg-sepliste-dbg-pt ins-pt)
|
||||
" endpunkt=" (ssg-sepliste-dbg-pt endpunkt)))
|
||||
(princ (ssg-textf "vfc-endpunkt-xyz-dxdz"
|
||||
(list (rtos (car endpunkt) 2 2) (rtos (cadr endpunkt) 2 2) (rtos (caddr endpunkt) 2 2)
|
||||
(rtos dx 2 1) (rtos dz 2 1))))
|
||||
@@ -371,6 +396,73 @@
|
||||
;; bekommt nur eine laufende Nummer innerhalb der Liste. Der Export bildet
|
||||
;; daraus bei Bedarf eigene, global fortlaufende TeileIds.
|
||||
|
||||
;; --- Diagnose-Protokoll (Schalter "vf-sepliste", siehe ssg_dbg.lsp) ---------
|
||||
;; TEMPORAER fuer die Fehlersuche "gespiegelte Sepliste-Koordinate (lfdnr=2)" -
|
||||
;; nach Abschluss mitsamt Schalter wieder entfernen.
|
||||
;; Der Schalter ist in ssg_dbg.lsp mit Default 1 vorregistriert, das Protokoll
|
||||
;; laeuft also nach einem BricsCAD-Neustart ohne weiteres Zutun. Es genuegt,
|
||||
;; EINE VF-/GF-Kette zu bauen - das Protokoll landet in
|
||||
;; DXFM_LOG/vf_sepliste.dbg. Protokolliert wird der komplette Weg der
|
||||
;; Sepliste-Koordinaten: je Einfuegeprimitive der Startpunkt, die am Block
|
||||
;; gemessenen KS_EIN/KS_AUS-Lokalpunkte, der daraus berechnete
|
||||
;; Block-Einfuegepunkt (ins-pt = genau der Wert, den die Sepliste spaeter als
|
||||
;; Gruppencode 10 einsammelt) und der Folgepunkt - sowie am Ende die
|
||||
;; entnext-Wanderung von ssg-sepliste-sammeln mit JEDEM gefundenen INSERT.
|
||||
;; Hintergrund: im Export tauchen Sepliste-Koordinaten auf, die nicht zur
|
||||
;; sichtbaren Geometrie passen (x exakt negiert) - die Herkunft dieses Werts
|
||||
;; ist ohne Laufzeit-Protokoll nicht zu klaeren.
|
||||
;;
|
||||
;; Nutzt NUR die Schalterverwaltung aus ssg_dbg.lsp, aber BEWUSST einen eigenen
|
||||
;; Dateihandle statt dbgopen/dbgmsg: ssg_dbg fuehrt mit *dbg-path* genau EINE
|
||||
;; global offene Datei. Der Linienzug-Bau (vfl-modus1, Schalter per Default EIN)
|
||||
;; oeffnet seine vfl_modus1.dbg und haelt *dbg-path* damit besetzt - die
|
||||
;; Sepliste-Zeilen waeren sonst stillschweigend dort gelandet statt in einer
|
||||
;; eigenen Datei. Genau dieser Bau ist aber der zu protokollierende Vorgang.
|
||||
(if (not (boundp '*ssg-sepliste-dbg-pfad*)) (setq *ssg-sepliste-dbg-pfad* nil))
|
||||
|
||||
;; Legt die Datei beim ERSTEN Aufruf je Sitzung an (leert sie dabei) und
|
||||
;; liefert den Pfad; danach nur noch den gemerkten Pfad. nil = Schalter aus.
|
||||
(defun ssg-sepliste-dbg-oeffnen ( / dir fh)
|
||||
(if (and (car (atoms-family 1 '("DBG-SCHALTER-P")))
|
||||
(dbg-schalter-p "vf-sepliste"))
|
||||
(progn
|
||||
(if (null *ssg-sepliste-dbg-pfad*)
|
||||
(progn
|
||||
(setq dir (getenv "DXFM_LOG"))
|
||||
(if (or (null dir) (= dir "")) (setq dir "."))
|
||||
(if (and (/= (substr dir (strlen dir) 1) "\\")
|
||||
(/= (substr dir (strlen dir) 1) "/"))
|
||||
(setq dir (strcat dir "\\")))
|
||||
(setq *ssg-sepliste-dbg-pfad* (strcat dir "vf_sepliste.dbg"))
|
||||
(setq fh (open *ssg-sepliste-dbg-pfad* "w"))
|
||||
(if fh
|
||||
(progn
|
||||
(write-line "=== vf-sepliste Diagnose ===" fh)
|
||||
(close fh)
|
||||
(princ (strcat "\n[DBG] vf-sepliste-Protokoll: " *ssg-sepliste-dbg-pfad*)))
|
||||
(progn
|
||||
(princ (strcat "\n[DBG] FEHLER: " *ssg-sepliste-dbg-pfad*
|
||||
" nicht schreibbar"))
|
||||
(setq *ssg-sepliste-dbg-pfad* nil)))))
|
||||
*ssg-sepliste-dbg-pfad*)
|
||||
nil))
|
||||
|
||||
;; Eine Zeile anhaengen (kein Puffer - ein Bau erzeugt nur wenige hundert
|
||||
;; Zeilen, dafuer geht keine Zeile verloren, wenn der Bau abbricht).
|
||||
(defun ssg-sepliste-dbg (msg / pfad fh)
|
||||
(if (setq pfad (ssg-sepliste-dbg-oeffnen))
|
||||
(progn
|
||||
(setq fh (open pfad "a"))
|
||||
(if fh (progn (write-line msg fh) (close fh)))))
|
||||
(princ))
|
||||
|
||||
;; Punkt (x y z) kompakt als "(x, y, z)" - nil-sicher.
|
||||
(defun ssg-sepliste-dbg-pt (pt)
|
||||
(if (and pt (listp pt))
|
||||
(strcat "(" (rtos (car pt) 2 2) ", " (rtos (cadr pt) 2 2) ", "
|
||||
(rtos (cond ((caddr pt)) (0.0)) 2 2) ")")
|
||||
"nil"))
|
||||
|
||||
;; Einfaches Chunking eines Strings in Stuecke <= n Zeichen (DXF-Limit einer
|
||||
;; 1000-Gruppe ist 255 Byte) - eigenstaendige Kopie statt vfl-chunk-string
|
||||
;; (vf_linienzug.lsp), da diese Datei laut Lademechanismus VOR vf_linienzug
|
||||
@@ -387,22 +479,32 @@
|
||||
;; Baureihenfolge (identische entnext-Wanderung wie die Auswahlsatz-Sammlung
|
||||
;; der Aufrufer, nur mit wcmatch-Filter). Rueckgabe: Liste von
|
||||
;; (typ lfdnr x y), typ = "SEP"/"AS"/"ES", lfdnr 1-basiert in Baureihenfolge.
|
||||
(defun ssg-sepliste-sammeln (lastEnt / ent bname typ lfdnr pt liste)
|
||||
(defun ssg-sepliste-sammeln (lastEnt / ent ed bname typ lfdnr pt liste)
|
||||
(ssg-sepliste-dbg "=== ssg-sepliste-sammeln: entnext-Wanderung ab lastEnt ===")
|
||||
(setq liste '() lfdnr 0)
|
||||
(setq ent (if lastEnt (entnext lastEnt) (entnext)))
|
||||
(while ent
|
||||
(if (= (cdr (assoc 0 (entget ent))) "INSERT")
|
||||
(setq ed (entget ent))
|
||||
(if (= (cdr (assoc 0 ed)) "INSERT")
|
||||
(progn
|
||||
(setq bname (cdr (assoc 2 (entget ent))))
|
||||
(setq bname (cdr (assoc 2 ed)))
|
||||
(setq typ (cond
|
||||
((wcmatch bname "Staustrecke_Separator_SP_300_mm*") "SEP")
|
||||
((wcmatch bname "AS_Element_*") "AS")
|
||||
((wcmatch bname "ES_Element_*") "ES")
|
||||
(t nil)))
|
||||
(setq pt (cdr (assoc 10 ed)))
|
||||
;; JEDEN INSERT protokollieren (auch die nicht klassifizierten) - nur so
|
||||
;; laesst sich im .dbg nachvollziehen, welches Entity einen auffaelligen
|
||||
;; Einfuegepunkt liefert und in welcher Reihenfolge es entstand.
|
||||
(ssg-sepliste-dbg
|
||||
(strcat "INSERT " bname
|
||||
" handle=" (cond ((cdr (assoc 5 ed))) ("-"))
|
||||
" typ=" (cond (typ) ("-"))
|
||||
" pt=" (ssg-sepliste-dbg-pt pt)))
|
||||
(if typ
|
||||
(progn
|
||||
(setq lfdnr (1+ lfdnr))
|
||||
(setq pt (cdr (assoc 10 (entget ent))))
|
||||
(setq liste (cons (list typ lfdnr (car pt) (cadr pt)) liste))
|
||||
)
|
||||
)
|
||||
@@ -410,7 +512,13 @@
|
||||
)
|
||||
(setq ent (entnext ent))
|
||||
)
|
||||
(reverse liste)
|
||||
(setq liste (reverse liste))
|
||||
(ssg-sepliste-dbg (strcat "Ergebnis: " (itoa (length liste)) " Sepliste-Eintraege"))
|
||||
(foreach e liste
|
||||
(ssg-sepliste-dbg
|
||||
(strcat " " (nth 0 e) " lfdnr=" (itoa (nth 1 e))
|
||||
" x=" (rtos (nth 2 e) 2 2) " y=" (rtos (nth 3 e) 2 2))))
|
||||
liste
|
||||
)
|
||||
|
||||
;; Koordinate mit GENAU 2 Nachkommastellen formatieren - bewusst OHNE rtos.
|
||||
|
||||
@@ -402,6 +402,16 @@
|
||||
(setq xu-out (mat3-mul-vec3 R xu-aus)
|
||||
yu-out (mat3-mul-vec3 R yu-aus)
|
||||
zu-out (mat3-mul-vec3 R zu-aus))
|
||||
;; Diagnose (Schalter "vf-sepliste", siehe ssg_ks_insert.lsp): setzt im
|
||||
;; Linienzug die AS-/ES-Elemente, also den ERSTEN und LETZTEN Sepliste-Eintrag.
|
||||
;; Die Translation (tx ty tz) ist hier der Gruppencode 10 des Blocks.
|
||||
(if (car (atoms-family 1 '("SSG-SEPLISTE-DBG")))
|
||||
(ssg-sepliste-dbg
|
||||
(strcat "insert-block-ks-to-ks " blockname
|
||||
" ziel-P=" (ssg-sepliste-dbg-pt P-t)
|
||||
" ks_ein_lokal=" (ssg-sepliste-dbg-pt P-ein)
|
||||
" translation(=Gruppencode 10)=" (ssg-sepliste-dbg-pt (list tx ty tz))
|
||||
" ks_aus_welt=" (ssg-sepliste-dbg-pt P-out))))
|
||||
(princ (ssg-textf "vfc-block-eingefuegt-ksaus"
|
||||
(list blockname (rtos (car P-out) 2 2) (rtos (cadr P-out) 2 2) (rtos (caddr P-out) 2 2))))
|
||||
(list P-out xu-out yu-out zu-out))
|
||||
|
||||
@@ -48,6 +48,25 @@
|
||||
# den DWGs (ssg-id-check-all fuellt es vor jedem Export, siehe
|
||||
# ssg-id-collect-blocks in ssg_id.lsp).
|
||||
#
|
||||
# pattern_schleuselement: die AS-/ES-Schleuselemente an den Enden einer
|
||||
# VF_n/GF_n-Kette. Sie liegen in der gespeicherten Zeichnung NICHT als eigener
|
||||
# top-level INSERT vor, sondern verpackt in der Wrapper-Blockdefinition. Dieses
|
||||
# Muster dient nur der SUCHE in der Blockdefinition (csv:nested-welt-records in
|
||||
# Lisp/export.lsp) - exportiert wird nicht das Element selbst, sondern sein
|
||||
# Marker (siehe pattern_ases_marker).
|
||||
#
|
||||
# pattern_ases_marker: der Marker, den der Export an jedes AS-/ES-Kettenende
|
||||
# setzt (ZZ_ASES_MARKER, ein kleines Rechteck, csv:asmark-aktualisieren in
|
||||
# Lisp/export.lsp). Er bleibt nach dem Export in der Zeichnung stehen, macht
|
||||
# das sonst unsichtbare Kettenende anklickbar und traegt dessen ID ueber
|
||||
# Exportlaeufe hinweg (Attribute ID/ZUORDNUNG/TYP/LFDNR/ELEMENT/ARTINR, alle
|
||||
# unsichtbar). Die ID landet im "sepliste"-Array des Wrappers (Feld "id" je
|
||||
# Eintrag) UND als eigene Zeile in export_raw.json. Von Lisp's Block-SAMMLUNG
|
||||
# genutzt; die Python-Klassifikation kennt das Muster noch nicht (der Block
|
||||
# faellt dort durch alle Muster und wird uebersprungen) - sobald sie es kennt,
|
||||
# ersetzt sie damit die bisher in Python synthetisierten Ein-/Ausschleus-
|
||||
# element-Zeilen (build_strecke_schleus_items).
|
||||
#
|
||||
# pattern_geruest: Geruest-Baugruppen (GeruestInsert.lsp, GR_<id>_<timestamp>).
|
||||
# Eigenstaendig wie BTMT, kein ANZAHL_*-Attribut an einem Carrier - export_csv.py
|
||||
# UND export_sivas.py fuehren sie als eigene TeileArt-Zeilen.
|
||||
@@ -61,6 +80,8 @@ pattern_strecke= Vario*, Staustrecke*, AUS_Element*, EIN_Element*, VF_
|
||||
pattern_variofoerderer= VF_*
|
||||
pattern_gefaellestrecke= GF_*
|
||||
pattern_strecke_module= Vario*, Staustrecke*, AUS_Element*, EIN_Element*
|
||||
pattern_schleuselement= AS_Element*, ES_Element*
|
||||
pattern_ases_marker= ZZ_ASES_MARKER*
|
||||
pattern_separator= Separator_SP*, S-LP*
|
||||
pattern_scanner= Scanner*
|
||||
pattern_btmt_beladung= BTMT-Beladung*
|
||||
@@ -169,6 +190,17 @@ omniflo_ks_toleranz_mm=10
|
||||
# Ueberschneidungstest - zur Diagnose, warum (keine) Nachbarn gefunden werden.
|
||||
debug_log=1
|
||||
|
||||
[Marker]
|
||||
# Kantenlaenge (mm) des quadratischen Markers, den der Export an jedes AS-/ES-
|
||||
# Kettenende einer VF_n/GF_n-Strecke setzt (Block ZZ_ASES_MARKER, siehe
|
||||
# csv:asmark-* in Lisp/export.lsp). Der Marker sitzt MITTIG auf dem
|
||||
# Einfuegepunkt des Schleuselements und folgt dessen Drehung. Nur optisch
|
||||
# relevant - Nachbarschaft/Zuordnung rechnen nicht mit dieser Groesse.
|
||||
# Wirkt erst, wenn die Blockdefinition NEU angelegt wird: in einer Zeichnung,
|
||||
# die ZZ_ASES_MARKER schon kennt, bleibt die vorhandene Groesse bestehen
|
||||
# (Block ueber _PURGE entfernen, um sie neu zu erzeugen). Default 200.
|
||||
ases_groesse_mm=200
|
||||
|
||||
[Boundingbox]
|
||||
# Mindesthoehe (Z-Ausdehnung) der von export.lsp (csv:get-bbox, per
|
||||
# vla-getboundingbox) ermittelten Bounding-Box. Flache 2D-Bloecke (Draufsicht)
|
||||
|
||||
@@ -132,6 +132,12 @@ gefaellestrecke = _3D_ILS_SP, 3
|
||||
# ============================================================
|
||||
[allgemein]
|
||||
|
||||
# Marker der AS-/ES-Kettenenden (Block ZZ_ASES_MARKER), den der Export an
|
||||
# jedes Schleuselement einer VF_n/GF_n-Strecke setzt - siehe csv:asmark-* in
|
||||
# Lisp/export.lsp. Reine Hilfsgeometrie wie die Planquadrate, darum ein
|
||||
# eigener, leicht abschaltbarer Layer.
|
||||
ases_marker = ZZ_ASES_Marker, 6
|
||||
|
||||
# Kreisel-Tangenten (die beiden Linien zwischen AN8 und SP8).
|
||||
# HINWEIS: "S_LP" ist der bisher hart im Code stehende Name. Der
|
||||
# Firmenstandard kennt nur "ILS_LP" - S_LP ist sehr wahrscheinlich ein
|
||||
|
||||
+103
-9
@@ -12,9 +12,12 @@ BricsCAD (LISP) Python
|
||||
───────────────── ──────
|
||||
c:EXPORTCSV
|
||||
-> csv:run-export
|
||||
-> Proxies fuer verpackte
|
||||
-> Kopien fuer verpackte
|
||||
Separatoren einfuegen
|
||||
-> AS/ES-Marker aufbauen
|
||||
-> IDs vergeben (ssg-id-check-all)
|
||||
-> IDs in die sepliste
|
||||
eintragen
|
||||
-> Separator-/Scanner-Zuordnung
|
||||
(count_sep_scan.lsp)
|
||||
-> REGENALL
|
||||
@@ -48,15 +51,32 @@ Bounding-Boxen braucht).
|
||||
durchlaeuft danach ID-Vergabe und Export ganz normal ueber den freien-
|
||||
Separator-Pfad (Blockname-Muster `Separator_SP*` trifft zu) und bekommt
|
||||
dadurch eine echte `vla-getboundingbox`-Box, die das verpackte Original nie
|
||||
haben koennte. Rueckgabe: Liste `(proxy-ename . wrapper-ename)`.
|
||||
haben koennte. Rueckgabe: Liste von Records
|
||||
`(proxy-ename wrapper-ename typ (x y z))`.
|
||||
1b. **`csv:asmark-aktualisieren`** — die AS-/ES-Enden derselben Kette
|
||||
(`AS_Element*`/`ES_Element*`, Muster `pattern_schleuselement`) bekommen
|
||||
KEINE temporaere Kopie, sondern einen DAUERHAFTEN Marker — siehe eigener
|
||||
Abschnitt "Der AS/ES-Marker" unten. Beide Wege teilen sich die
|
||||
Platzierungsrechnung (`csv:nested-welt-records` liefert die Weltlage jedes
|
||||
verpackten Fundes, `csv:block-einfuegen-welt` setzt ein Objekt dorthin).
|
||||
2. **`ssg-id-check-all`** — vergibt fehlende IDs (inkl. der frisch erzeugten
|
||||
Proxies) und korrigiert Duplikate. Muss NACH den Proxies laufen, sonst
|
||||
wuerden diese Kopien numerisch nie erfasst.
|
||||
wuerden diese Kopien numerisch nie erfasst. `ssg-id-collect-blocks`
|
||||
(`ssg_id.lsp`) erfasst dafuer auch `AS_Element*`/`ES_Element*`.
|
||||
3. **`csv:sep-proxies-zuordnung-setzen`** — jetzt steht die ID jedes Wrappers
|
||||
fest: die Proxy-Kopie bekommt `ZUORDNUNG = Wrapper-ID` fest zugewiesen
|
||||
(nicht geraten) und wird zusaetzlich in `*cs-sep-fix-by-handle*` vermerkt,
|
||||
damit `count_sep_scan.lsp` diesen Wert spaeter nicht per Geometrie
|
||||
ueberschreibt.
|
||||
ueberschreibt. Nur fuer die Separator-Kopien — AS/ES sind keine Sensoren.
|
||||
3b. **`csv:asmark-ids-setzen` + `csv:sepliste-ids-setzen`** — ebenfalls erst
|
||||
jetzt moeglich: jedes Bauteil wird seinem `sepliste`-Eintrag zugeordnet und
|
||||
seine ID unter `*csv-sepliste-id-by-handle*` (Key = Wrapper-Handle)
|
||||
abgelegt; `csv:block-to-json` schreibt sie als Feld `id` in den Eintrag.
|
||||
AS/ES laufen ueber die Marker (die ihre ID schon kennen, die Zuordnung
|
||||
steht im Marker-Attribut `LFDNR`), SEP ueber die temporaeren Kopien und
|
||||
`csv:sepliste-paare` — siehe eigener Abschnitt unten. `csv:asmark-ids-setzen`
|
||||
traegt zusaetzlich die `ZUORDNUNG` (Wrapper-ID) am Marker nach; ohne sie
|
||||
faende der naechste Export den Marker nicht wieder.
|
||||
4. **`omni:update-all-attribs`** — Hoehe/Drehung aller Omniflo-Elemente vor
|
||||
dem Export aktualisieren.
|
||||
5. **`count_sep_scan.lsp::cs-zuordnung-lauf`** (nur bei Bedarf, siehe
|
||||
@@ -88,7 +108,7 @@ Pro INSERT wird ein JSON-Objekt geschrieben:
|
||||
| `bbox` | `csv:get-bbox` (`vla-getboundingbox`) | NUR wenn `include-bbox=T` und der Aufruf gelingt; fehlt sonst komplett im JSON |
|
||||
| `warnung` | `*cs-scanner-warnung-by-handle*` | strittige Scanner-Zuordnung aus `cs-zuordnung-lauf` |
|
||||
| `zuordnung_fix` | `*cs-sep-fix-by-handle*` | nur bei Proxy-Kopien: die feststehende Wrapper-ID |
|
||||
| `sepliste` | `ssg-sepliste-xdata-lesen` | nur bei VF_n/GF_n, siehe eigener Abschnitt |
|
||||
| `sepliste` | `ssg-sepliste-xdata-lesen` + `*csv-sepliste-id-by-handle*` | nur bei VF_n/GF_n, siehe eigener Abschnitt |
|
||||
|
||||
**K1-K4 je Blocktyp:** normale ILS-Bloecke fuehren echte K1-K4-Sub-Bloecke.
|
||||
Omniflo-Geraden (`AP110*`) haben keine echten K-Bloecke — K1/K2 werden aus
|
||||
@@ -132,6 +152,80 @@ Separatoren als Eintraege mit Vorgaenger-/Nachfolger-Wissen. Python fuehrt
|
||||
beides zusammen (siehe `map_separator_kette_items` unten) statt sie doppelt
|
||||
zu zaehlen.
|
||||
|
||||
### Das Feld `id` je sepliste-Eintrag
|
||||
|
||||
Seit `csv:sepliste-ids-setzen` traegt JEDER Eintrag zusaetzlich die `id` des
|
||||
realen Bauteils, das ihn in der Zeichnung vertritt:
|
||||
|
||||
```json
|
||||
{"typ": "AS", "lfdnr": 1, "x": 5070.1, "y": 1199.2, "id": "0031"}
|
||||
```
|
||||
|
||||
Das ist dieselbe ID, die die zugehoerige temporaere Kopie in ihrer eigenen
|
||||
JSON-Zeile traegt — die Verbindung "Kettenglied <-> reales Teil" steht damit
|
||||
schon im Export und muss in Python nicht mehr ueber Koordinaten-Naehe geraten
|
||||
werden (`map_separator_kette_items`, siehe unten; solange Python das Feld noch
|
||||
nicht liest, aendert sich dort nichts). Das Feld fehlt, wenn keine Kopie
|
||||
erzeugt werden konnte oder deren ID-Attribut leer blieb — Altbestand und
|
||||
Fehlerfaelle verhalten sich damit wie bisher.
|
||||
|
||||
### Der AS/ES-Marker (`ZZ_ASES_MARKER`)
|
||||
|
||||
Die beiden Kettenenden stecken als `AS_Element_*`/`ES_Element_*` verpackt in
|
||||
der Wrapper-Blockdefinition: in der Zeichnung sind sie weder anklickbar noch
|
||||
einzeln erkennbar, und `(ssget "X" ...)` findet sie nicht. `csv:asmark-*`
|
||||
(`Lisp/export.lsp`) setzt darum an jedes Ende ein kleines Rechteck, das nach
|
||||
dem Export in der Zeichnung STEHEN BLEIBT:
|
||||
|
||||
- **Sichtbarmachung** — Kantenlaenge aus `cfg/export.cfg` `[Marker]`
|
||||
`ases_groesse_mm` (Default 200 mm), mittig auf dem Einfuegepunkt des
|
||||
Schleuselements, in dessen Drehung (auch bei geneigter Kette). Layer aus
|
||||
`cfg/layer.cfg` `[allgemein]` `ases_marker` — abschaltbar wie jede andere
|
||||
Hilfsgeometrie. Die Blockdefinition wird bei Bedarf zur Laufzeit erzeugt
|
||||
(`csv:asmark-blockdef-sicherstellen`, Rechteck + ATTDEFs + `_.-BLOCK`), es
|
||||
gibt keine DWG dafuer.
|
||||
- **ID-Traeger** — die Attribute (alle unsichtbar) sind
|
||||
`ID`, `ZUORDNUNG` (Wrapper-ID), `TYP` (`AS`/`ES`), `LFDNR` (sepliste-Eintrag),
|
||||
`ELEMENT` (Blockname des echten Elements, haelt die Variante 30/90,
|
||||
links/rechts, 2D/3D fest) und `ARTINR`. `ssg-id-check-all` fuellt die `ID`,
|
||||
und weil der Marker liegen bleibt, **behaelt ein AS/ES seine TeileId ueber
|
||||
Exportlaeufe hinweg** — im Unterschied zu den Separator-Kopien, die jeder
|
||||
Lauf neu erzeugt und neu nummeriert.
|
||||
|
||||
Der Marker ist abgeleitete Geometrie: jeder Export baut ihn neu auf (die Lage
|
||||
folgt damit automatisch einer umgebauten Kette) und uebernimmt vom bisherigen
|
||||
Marker nur dessen `ID`. Wiedergefunden wird er ueber (`ZUORDNUNG`, `TYP`,
|
||||
`LFDNR`) — bewusst nicht ueber die Position, damit eine verschobene Kette ihre
|
||||
TeileIds behaelt. Was am Ende keinem Kettenende mehr entspricht (Kette
|
||||
geloescht, Eintrag entfallen), wird geloescht; Karteileichen entstehen nicht.
|
||||
Ein frisch gebauter Wrapper hat beim Setzen der Marker noch keine ID — seine
|
||||
Marker bekommen die `ZUORDNUNG` nach der ID-Vergabe nachgetragen und sind ab
|
||||
dem naechsten Export wiederfindbar.
|
||||
|
||||
Im Export ist der Marker eine eigene Zeile (`pattern_ases_marker` in
|
||||
`cfg/export.cfg`) und liefert die `id` des AS-/ES-Eintrags in der `sepliste`.
|
||||
|
||||
**Zuordnung Eintrag -> Kopie (`csv:sepliste-paare`).** Verglichen wird nur
|
||||
innerhalb desselben Typmarkers (`AS`/`ES`/`SEP`) und EXKLUSIV: alle Paare
|
||||
eines Typs werden nach Abstand sortiert, das kuerzeste zuerst genommen, danach
|
||||
sind Eintrag UND Kopie verbraucht. Zwei Gruende gegen das naheliegende "je
|
||||
Eintrag die naechste Kopie":
|
||||
|
||||
- waehlen zwei Eintraege dieselbe Kopie, bleibt eine Kopie ohne Eintrag und
|
||||
ein Eintrag ohne ID (genau dieses Muster verursacht in Python die
|
||||
Separatoren ohne `Nachbarn`/`TrackIds`);
|
||||
- EIN fehlerhafter Koordinatenwert in der sepliste (bekannter Fall: gespiegeltes
|
||||
`x` bei `lfdnr=2`) verschiebt so keine anderen Zuordnungen mehr — alle
|
||||
uebrigen Eintraege finden ihre Kopie ueber den kurzen Abstand zuerst, der
|
||||
fehlerhafte bekommt den Rest zugeteilt. Liegt dieser Rest weiter als
|
||||
`csv:sepliste-abstand-warnung-mm` (500 mm) entfernt, meldet der Export das
|
||||
(`exp-sepliste-abstand`), ohne die Zuordnung zu verwerfen.
|
||||
|
||||
Die Sortierung ist eine strikte Totalordnung (Abstand, dann `lfdnr`, dann
|
||||
Index) — `vl-sort` wirft Elemente weg, die unter der Vergleichsfunktion gleich
|
||||
sind, zwei Paare mit identischem Abstand wuerden sonst zu einem verschmelzen.
|
||||
Getestet in `tests/test_unit.lsp` (`csv:sepliste-paare/*`, zeichnungsfrei).
|
||||
|
||||
## Phase 2 (Python): `lib/export_csv.py::process_blocks`
|
||||
|
||||
Aufruf: `python export_csv.py <export_raw.json> <data_dir> <output.csv>`.
|
||||
@@ -215,10 +309,10 @@ relevanten Felder):
|
||||
"k2": "AAAAQwAATkAAAAAA...",
|
||||
"bbox": {"min": [10800.0, 4850.0, 0.0], "max": [13000.0, 5150.0, 300.0]},
|
||||
"sepliste": [
|
||||
["AS", 1, 10800.0, 5000.0],
|
||||
["SEP", 2, 11600.0, 5000.0],
|
||||
["SEP", 3, 12300.0, 5000.0],
|
||||
["ES", 4, 13000.0, 5000.0]
|
||||
{"typ": "AS", "lfdnr": 1, "x": 10800.0, "y": 5000.0, "id": "0025"},
|
||||
{"typ": "SEP", "lfdnr": 2, "x": 11600.0, "y": 5000.0, "id": "0022"},
|
||||
{"typ": "SEP", "lfdnr": 3, "x": 12300.0, "y": 5000.0, "id": "0023"},
|
||||
{"typ": "ES", "lfdnr": 4, "x": 13000.0, "y": 5000.0, "id": "0026"}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
+9
-1
@@ -700,9 +700,17 @@
|
||||
"plq-geloescht": "\n[DELETE_PLANQUADRATE] Planquadrat-Raster entfernt (%1 Einfuegung(en)).",
|
||||
"plq-nichts-zu-loeschen": "\n[DELETE_PLANQUADRATE] Kein Planquadrat-Raster in der Zeichnung vorhanden.",
|
||||
"exp-check-ids": "\n[%1] Pruefe und vergebe IDs...",
|
||||
"exp-sep-proxy-fehler": "\n[EXPORT] WARNUNG: Kopie des verpackten Separators '%1' aus Block '%2' fehlgeschlagen (%3) - dieser Separator fehlt im Export.",
|
||||
"exp-sep-proxy-fehler": "\n[EXPORT] WARNUNG: Kopie von '%1' aus Block '%2' fehlgeschlagen (%3) - dieses Element fehlt im Export.",
|
||||
"exp-sep-zuordnung": "\n[%1] verpackte Separator-Kopie(n): ZUORDNUNG aus der ID des Wrapper-Blocks gesetzt.",
|
||||
"exp-sep-zuordnung-ohne-id": "\n[%1] verpackte Separator-Kopie(n) ohne Wrapper-ID - ZUORDNUNG wird geometrisch bestimmt.",
|
||||
"exp-sepliste-ids": "\n[EXPORT] %1 sepliste-Eintrag/Eintraege mit der ID des zugehoerigen Bauteils versehen.",
|
||||
"exp-sepliste-ohne-id": "\n[EXPORT] %1 sepliste-Eintrag/Eintraege ohne ID - die Kopie hat kein gefuelltes ID-Attribut.",
|
||||
"exp-sepliste-ohne-proxy": "\n[EXPORT] WARNUNG: Block '%1': %2 sepliste-Eintrag/Eintraege ohne passende Kopie - diese Eintraege bleiben im Export ohne ID.",
|
||||
"exp-sepliste-abstand": "\n[EXPORT] WARNUNG: Block '%1': %2-Eintrag lfdnr=%3 liegt %4 mm von seinem Bauteil entfernt - sepliste-Koordinate pruefen (Zuordnung bleibt gueltig).",
|
||||
"exp-asmark-blockdef": "\n[EXPORT] Blockdefinition '%1' fuer die AS/ES-Marker angelegt.",
|
||||
"exp-asmark-blockdef-fehler": "\n[EXPORT] WARNUNG: Blockdefinition '%1' konnte nicht angelegt werden - es werden keine AS/ES-Marker gesetzt.",
|
||||
"exp-asmark-bilanz": "\n[EXPORT] AS/ES-Marker: %1 neu, %2 mit bisheriger ID uebernommen, %3 verwaiste entfernt.",
|
||||
"exp-asmark-ids": "\n[EXPORT] %1 AS/ES-Marker mit ihrer ID am sepliste-Eintrag vermerkt.",
|
||||
"exp-update-hoehe-drehung": "\n[%1] Aktualisiere Hoehe/Drehung...",
|
||||
"exp-collect-blocks": "\n[%1] Sammle relevante Bloecke...",
|
||||
"exp-no-blocks-found": "\n[%1] Keine relevanten Bloecke gefunden.",
|
||||
|
||||
+9
-1
@@ -700,9 +700,17 @@
|
||||
"plq-geloescht": "\n[DELETE_PLANQUADRATE] Planquadrat grid removed (%1 insertion(s)).",
|
||||
"plq-nichts-zu-loeschen": "\n[DELETE_PLANQUADRATE] No Planquadrat grid found in the drawing.",
|
||||
"exp-check-ids": "\n[%1] Checking and assigning IDs...",
|
||||
"exp-sep-proxy-fehler": "\n[EXPORT] WARNING: copying the packed separator '%1' out of block '%2' failed (%3) - this separator is missing from the export.",
|
||||
"exp-sep-proxy-fehler": "\n[EXPORT] WARNING: copying '%1' out of block '%2' failed (%3) - this element is missing from the export.",
|
||||
"exp-sep-zuordnung": "\n[%1] packed separator copy/copies: ZUORDNUNG set from the wrapper block ID.",
|
||||
"exp-sep-zuordnung-ohne-id": "\n[%1] packed separator copy/copies without a wrapper ID - ZUORDNUNG determined geometrically.",
|
||||
"exp-sepliste-ids": "\n[EXPORT] %1 sepliste entry/entries tagged with the ID of the matching part.",
|
||||
"exp-sepliste-ohne-id": "\n[EXPORT] %1 sepliste entry/entries without an ID - the copy has no ID attribute value.",
|
||||
"exp-sepliste-ohne-proxy": "\n[EXPORT] WARNING: block '%1': %2 sepliste entry/entries without a matching copy - those entries stay without an ID in the export.",
|
||||
"exp-sepliste-abstand": "\n[EXPORT] WARNING: block '%1': %2 entry lfdnr=%3 is %4 mm away from its part - check the sepliste coordinate (the mapping stays valid).",
|
||||
"exp-asmark-blockdef": "\n[EXPORT] Block definition '%1' for the AS/ES markers created.",
|
||||
"exp-asmark-blockdef-fehler": "\n[EXPORT] WARNING: block definition '%1' could not be created - no AS/ES markers are placed.",
|
||||
"exp-asmark-bilanz": "\n[EXPORT] AS/ES markers: %1 new, %2 kept with their previous ID, %3 orphaned ones removed.",
|
||||
"exp-asmark-ids": "\n[EXPORT] %1 AS/ES marker ID(s) recorded at their sepliste entry.",
|
||||
"exp-update-hoehe-drehung": "\n[%1] Updating height/rotation...",
|
||||
"exp-collect-blocks": "\n[%1] Collecting relevant blocks...",
|
||||
"exp-no-blocks-found": "\n[%1] No relevant blocks found.",
|
||||
|
||||
+103
-8
@@ -44,6 +44,7 @@ from export_neighbors import (
|
||||
compute_strecke_kreisel_schleus,
|
||||
compute_sep_kette,
|
||||
compute_kreisel_umlauf,
|
||||
dbg_highlight,
|
||||
SENSOR_TEILEARTEN,
|
||||
WEICHE_TEILEART,
|
||||
GF_VF_TEILEARTEN,
|
||||
@@ -683,9 +684,30 @@ def map_separator_kette_items(items, sep_kette, sep_kette_by_key=None, dbg=None)
|
||||
if zuordnung:
|
||||
sep_items_by_zuordnung.setdefault(zuordnung, []).append(it)
|
||||
|
||||
if dbg:
|
||||
dbg("=== map_separator_kette_items: Kandidatenpools je Zuordnung ===")
|
||||
for zuordnung, kandidaten in sep_items_by_zuordnung.items():
|
||||
dbg(f" Zuordnung {zuordnung!r}: "
|
||||
f"{[k.get('teileid', '') for k in kandidaten]}")
|
||||
dbg("")
|
||||
dbg("=== map_separator_kette_items: sepliste-SEP -> Separator-Item ===")
|
||||
|
||||
# id(item) -> Liste der sep_kette-Keys, die genau dieses Item als
|
||||
# naechsten Kandidaten gewaehlt haben - Diagnose der NICHT-exklusiven
|
||||
# Zuordnung (jeder Key sucht unabhaengig im vollen Pool, siehe Docstring):
|
||||
# waehlen zwei Keys denselben Kandidaten, bleibt ein anderer Kandidat im
|
||||
# selben Pool ohne jeden sep_kette-Eintrag und damit ohne Nachbarn/TrackIds.
|
||||
gewaehlt_von = {}
|
||||
# Zuordnungen, fuer die es ueberhaupt sepliste-SEP-Schluessel gibt. Nur in
|
||||
# DIESEN Pools ist ein nicht gewaehlter Kandidat auffaellig; frei auf einem
|
||||
# Kreisel platzierte Separatoren tragen keine sepliste und bekommen ihre
|
||||
# Nachbarn aus dem Kreisel-Umlauf (siehe resolve_umlauf_und_sepliste_nachbarn).
|
||||
zuordnungen_mit_sepliste = set()
|
||||
|
||||
for key, eintrag in sep_kette.items():
|
||||
if eintrag.get("typ") != "SEP":
|
||||
continue
|
||||
zuordnungen_mit_sepliste.add(eintrag["strecke_id"])
|
||||
kandidaten = sep_items_by_zuordnung.get(eintrag["strecke_id"], [])
|
||||
if not kandidaten:
|
||||
if dbg:
|
||||
@@ -694,18 +716,48 @@ def map_separator_kette_items(items, sep_kette, sep_kette_by_key=None, dbg=None)
|
||||
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))
|
||||
entfernungen = sorted(
|
||||
((math.hypot(it.get("_x", 0.0) - sx, it.get("_y", 0.0) - sy), it)
|
||||
for it in kandidaten),
|
||||
key=lambda p: p[0])
|
||||
best_d, best = entfernungen[0]
|
||||
sep_kette_by_key[key] = best
|
||||
gewaehlt_von.setdefault(id(best), []).append(key)
|
||||
if dbg:
|
||||
dbg(f" sepliste-SEP {key} -> Separator-Item TeileId "
|
||||
f"{best.get('teileid', '')!r}")
|
||||
rangliste = ", ".join(f"{it.get('teileid', '')!r}={d:.0f}mm"
|
||||
for d, it in entfernungen)
|
||||
dbg(f" sepliste-SEP {key} (x={sx:.0f},y={sy:.0f}) -> Separator-Item "
|
||||
f"TeileId {best.get('teileid', '')!r} (d={best_d:.0f}mm); "
|
||||
f"Kandidaten sortiert: [{rangliste}]"
|
||||
f"{dbg_highlight(best.get('teileid', ''))}")
|
||||
|
||||
if dbg:
|
||||
dbg("")
|
||||
mehrfach = {iid: keys for iid, keys in gewaehlt_von.items() if len(keys) > 1}
|
||||
if mehrfach:
|
||||
dbg(" WARNUNG: folgende Separator-Items wurden von MEHREREN "
|
||||
"sepliste-Keys unabhaengig als naechster Kandidat gewaehlt "
|
||||
"(nicht-exklusive Zuordnung):")
|
||||
for keys in mehrfach.values():
|
||||
teileid = sep_kette_by_key[keys[0]].get("teileid", "")
|
||||
dbg(f" TeileId {teileid!r} gewaehlt von Keys: {keys}"
|
||||
f"{dbg_highlight(teileid)}")
|
||||
gewaehlte_ids = set(gewaehlt_von.keys())
|
||||
for zuordnung, kandidaten in sep_items_by_zuordnung.items():
|
||||
if zuordnung not in zuordnungen_mit_sepliste:
|
||||
continue
|
||||
for it in kandidaten:
|
||||
if id(it) not in gewaehlte_ids:
|
||||
teileid = it.get("teileid", "")
|
||||
dbg(f" Separator-Item TeileId {teileid!r} (Zuordnung "
|
||||
f"{zuordnung!r}) wurde von KEINEM sepliste-Key gewaehlt "
|
||||
f"- bleibt ohne sep_kette-Eintrag, damit ohne Nachbarn/"
|
||||
f"TrackIds{dbg_highlight(teileid)}")
|
||||
return sep_kette_by_key
|
||||
|
||||
|
||||
def resolve_umlauf_und_sepliste_nachbarn(items, kreisel_umlauf, sep_kette,
|
||||
sep_kette_by_key, weiche_by_key):
|
||||
sep_kette_by_key, weiche_by_key, dbg=None):
|
||||
"""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)
|
||||
@@ -740,13 +792,27 @@ def resolve_umlauf_und_sepliste_nachbarn(items, kreisel_umlauf, sep_kette,
|
||||
if it.get("teileart", "") in KREISEL_UMLAUF_TEILEARTEN}
|
||||
alle_schluessel = {**sep_kette_by_key, **weiche_by_key, **freipunkt_by_id}
|
||||
|
||||
if dbg:
|
||||
dbg("=== resolve_umlauf_und_sepliste_nachbarn ===")
|
||||
dbg(f" freipunkt_by_id: {sorted(freipunkt_by_id.keys())}")
|
||||
dbg(f" sep_kette_by_key: "
|
||||
f"{[(k, v.get('teileid', '')) for k, v in sep_kette_by_key.items()]}")
|
||||
dbg(f" weiche_by_key: "
|
||||
f"{[(k, v.get('teileid', '')) for k, v in weiche_by_key.items()]}")
|
||||
dbg("")
|
||||
dbg(" -- Pass 1: aus kreisel_umlauf --")
|
||||
|
||||
# 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 kreisel_tid, punkte in kreisel_umlauf.items():
|
||||
for punkt_key, vorgaenger, nachfolger in punkte:
|
||||
item = alle_schluessel.get(punkt_key)
|
||||
if item is None:
|
||||
if dbg:
|
||||
dbg(f" Kreisel {kreisel_tid} Punkt {punkt_key!r}: "
|
||||
f"KEIN Item in alle_schluessel gefunden - "
|
||||
f"uebersprungen{dbg_highlight(punkt_key)}")
|
||||
continue
|
||||
nachbarn = []
|
||||
for nachbar_key in (vorgaenger, nachfolger):
|
||||
@@ -755,8 +821,26 @@ def resolve_umlauf_und_sepliste_nachbarn(items, kreisel_umlauf, sep_kette,
|
||||
nachbar_item = alle_schluessel.get(nachbar_key)
|
||||
if nachbar_item is not None:
|
||||
nachbarn.append(nachbar_item.get("teileid", ""))
|
||||
elif dbg:
|
||||
dbg(f" Kreisel {kreisel_tid} Punkt {punkt_key!r}: "
|
||||
f"Nachbar-Key {nachbar_key!r} nicht in alle_schluessel "
|
||||
f"aufloesbar{dbg_highlight(item.get('teileid', ''))}")
|
||||
teileid = item.get("teileid", "")
|
||||
if nachbarn:
|
||||
item["nachbarn"] = ", ".join(nachbarn)
|
||||
if dbg:
|
||||
dbg(f" Kreisel {kreisel_tid} Punkt {punkt_key!r} "
|
||||
f"(TeileId {teileid!r}): nachbarn={nachbarn}"
|
||||
f"{dbg_highlight(teileid)}")
|
||||
elif dbg:
|
||||
dbg(f" Kreisel {kreisel_tid} Punkt {punkt_key!r} "
|
||||
f"(TeileId {teileid!r}): KEINE Nachbarn aufgeloest "
|
||||
f"(vorgaenger={vorgaenger!r}, nachfolger={nachfolger!r})"
|
||||
f"{dbg_highlight(teileid)}")
|
||||
|
||||
if dbg:
|
||||
dbg("")
|
||||
dbg(" -- Pass 2: ketteninterne sepliste-Nachbarn --")
|
||||
|
||||
# Ketteninterne sepliste-Nachbarn (SEP <-> SEP, SEP <-> AS/ES) - das
|
||||
# jeweilige Kettenende (vorgaenger/nachfolger ist None, z.B. das AS-Ende
|
||||
@@ -765,6 +849,10 @@ def resolve_umlauf_und_sepliste_nachbarn(items, kreisel_umlauf, sep_kette,
|
||||
for key, eintrag in sep_kette.items():
|
||||
item = sep_kette_by_key.get(key)
|
||||
if item is None:
|
||||
if dbg:
|
||||
dbg(f" sepliste-Key {key!r} (typ={eintrag.get('typ')!r}): "
|
||||
f"KEIN Item in sep_kette_by_key - uebersprungen "
|
||||
f"(siehe map_separator_kette_items){dbg_highlight(key)}")
|
||||
continue
|
||||
nachbarn = []
|
||||
for nachbar_key in (eintrag.get("vorgaenger"), eintrag.get("nachfolger")):
|
||||
@@ -773,8 +861,15 @@ def resolve_umlauf_und_sepliste_nachbarn(items, kreisel_umlauf, sep_kette,
|
||||
nachbar_item = alle_schluessel.get(nachbar_key)
|
||||
if nachbar_item is not None:
|
||||
nachbarn.append(nachbar_item.get("teileid", ""))
|
||||
teileid = item.get("teileid", "")
|
||||
if nachbarn:
|
||||
item["nachbarn"] = ", ".join(nachbarn)
|
||||
if dbg:
|
||||
dbg(f" sepliste-Key {key!r} (TeileId {teileid!r}): "
|
||||
f"vorgaenger={eintrag.get('vorgaenger')!r} "
|
||||
f"nachfolger={eintrag.get('nachfolger')!r} -> "
|
||||
f"nachbarn={nachbarn} item.nachbarn={item.get('nachbarn', '')!r}"
|
||||
f"{dbg_highlight(teileid)}")
|
||||
|
||||
|
||||
def write_separatorliste_merkmale(items, sep_kette_by_key, dbg=None):
|
||||
@@ -1333,7 +1428,7 @@ def process_blocks(blocks, lookup, dbg=None):
|
||||
write_separatorliste_merkmale(items, sep_kette_by_key, dbg=dbg)
|
||||
|
||||
resolve_umlauf_und_sepliste_nachbarn(
|
||||
items, kreisel_umlauf, sep_kette, sep_kette_by_key, weiche_by_key)
|
||||
items, kreisel_umlauf, sep_kette, sep_kette_by_key, weiche_by_key, dbg=dbg)
|
||||
|
||||
# Spalte "TrackIds" je Kreisel: dieselben Umlauf-Punkte (freie
|
||||
# Separatoren, AS/ES-Enden, Kreisel-Kreisel-Weichen), die oben schon die
|
||||
|
||||
+34
-1
@@ -95,6 +95,19 @@ KREISEL_UMLAUF_TEILEARTEN = {
|
||||
"Eingang", "Ausgang",
|
||||
}
|
||||
|
||||
# Temporaerer Diagnose-Filter fuers Debuglog (siehe [Nachbarschaft] debug_log
|
||||
# in cfg/export.cfg): markiert Zeilen zu diesen TeileIds im .dbg-Log
|
||||
# besonders, um die fehlende Nachbarn-/TrackIds-Zuordnung einzelner
|
||||
# Separatoren (0025/0029/0031/0035) nachzuvollziehen. Nach Abschluss der
|
||||
# Diagnose wieder auf einen leeren Set zuruecksetzen oder entfernen.
|
||||
DEBUG_HIGHLIGHT_TEILEIDS = {"0025", "0029", "0031", "0035"}
|
||||
|
||||
|
||||
def dbg_highlight(teileid):
|
||||
"""Suffix fuer eine Debuglog-Zeile, wenn teileid in
|
||||
DEBUG_HIGHLIGHT_TEILEIDS steht - sonst leerer String."""
|
||||
return " <<<< ZIEL-ID" if str(teileid) in DEBUG_HIGHLIGHT_TEILEIDS else ""
|
||||
|
||||
# Nur "ILS 2.0 Kreisel" (echte Kreisel-Bloecke mit AN8/Antrieb + SP8/Spann-
|
||||
# station + ABSTAND-Attribut) werden links/rechts gesplittet - "ILS 2.0
|
||||
# Eckrad" hat keine dieser zwei Stationen und bleibt eine einzelne BBox.
|
||||
@@ -1480,15 +1493,32 @@ def compute_kreisel_umlauf(items, sep_kette, tolerance_mm, durchmesser_mm=800.0,
|
||||
for item in items:
|
||||
if item.get("teileart", "") not in KREISEL_UMLAUF_TEILEARTEN:
|
||||
continue
|
||||
teileid = item.get("teileid", "")
|
||||
bbox = item.get("_bbox")
|
||||
if not bbox:
|
||||
if dbg:
|
||||
dbg(f" Umlauf-Kandidat {teileid!r} ({item.get('teileart', '')!r}): "
|
||||
f"KEINE Bounding-Box - kann keinem Kreisel zugeordnet werden"
|
||||
f"{dbg_highlight(teileid)}")
|
||||
continue
|
||||
bounds = _bounds(bbox, half_tol)
|
||||
matched_tid = None
|
||||
for tid, kb in kreisel_bounds.items():
|
||||
if _overlaps(bounds, kb):
|
||||
punkte_je_kreisel[tid].append(
|
||||
(item.get("teileid", ""), bbox.get("cx", 0.0), bbox.get("cy", 0.0)))
|
||||
(teileid, bbox.get("cx", 0.0), bbox.get("cy", 0.0)))
|
||||
matched_tid = tid
|
||||
break
|
||||
if dbg:
|
||||
if matched_tid is not None:
|
||||
dbg(f" Umlauf-Kandidat {teileid!r} ({item.get('teileart', '')!r}) "
|
||||
f"bbox(cx={bbox.get('cx', 0):.0f},cy={bbox.get('cy', 0):.0f}) "
|
||||
f"-> Kreisel {matched_tid}{dbg_highlight(teileid)}")
|
||||
else:
|
||||
dbg(f" Umlauf-Kandidat {teileid!r} ({item.get('teileart', '')!r}) "
|
||||
f"bbox(cx={bbox.get('cx', 0):.0f},cy={bbox.get('cy', 0):.0f}) "
|
||||
f"-> KEIN Kreisel in Reichweite (bounds={_fmt_bounds(bounds)})"
|
||||
f"{dbg_highlight(teileid)}")
|
||||
|
||||
# AS/ES-Enden jeder Kette mit sepliste: naechstgelegener Kreisel (wie
|
||||
# compute_strecke_kreisel_schleus._nearest), aber direkt aus sep_kette
|
||||
@@ -1591,5 +1621,8 @@ def compute_kreisel_umlauf(items, sep_kette, tolerance_mm, durchmesser_mm=800.0,
|
||||
if dbg:
|
||||
dbg(f" Kreisel {tid} ({drehrichtung}): Umlauf "
|
||||
f"{' -> '.join(p[0] for p in sortiert)}")
|
||||
for punkt_key, vorgaenger, nachfolger in umlauf:
|
||||
dbg(f" Punkt {punkt_key!r}: vorgaenger={vorgaenger!r} "
|
||||
f"nachfolger={nachfolger!r}{dbg_highlight(punkt_key)}")
|
||||
|
||||
return result
|
||||
|
||||
@@ -301,6 +301,15 @@
|
||||
;; ------------------------------------------------------------
|
||||
;; TESTS: export.lsp - CSV/KOS-Kodierung
|
||||
;; ------------------------------------------------------------
|
||||
;; Hilfsfunktion der csv:sepliste-paare-Tests: nur (lfdnr index) vergleichen,
|
||||
;; nicht den Fliesskomma-Abstand. Bewusst auf Top-Level (nicht im Testblock):
|
||||
;; per defun IN einem Testblock definierte Funktionen sind in BricsCAD im
|
||||
;; laufenden Durchlauf nicht zuverlaessig gebunden (siehe Ladearchitektur oben).
|
||||
(defun tu-paare (e p)
|
||||
(mapcar (function (lambda (x) (list (nth 0 x) (nth 1 x))))
|
||||
(csv:sepliste-paare e p))
|
||||
)
|
||||
|
||||
(defun tu-tests-export ()
|
||||
(princ "\n[export]")
|
||||
|
||||
@@ -324,6 +333,62 @@
|
||||
|
||||
;; json-escape: Anfuehrungszeichen maskieren
|
||||
(tu-eq "csv:json-escape/quote" "a\\\"b" (csv:json-escape "a\"b"))
|
||||
|
||||
;; --- csv:sepliste-paare: sepliste-Eintrag <-> ausgepackte Kopie ---------
|
||||
;; Reine Rechenfunktion (Eintraege + Kopien rein, (lfdnr index abstand)
|
||||
;; raus) - hier ohne Zeichnung testbar. Im Export liefert
|
||||
;; csv:sepliste-ids-setzen die Kopien in Erzeugungsreihenfolge; nur der
|
||||
;; Index zaehlt, darum vergleichen die Tests (lfdnr index) statt der
|
||||
;; Fliesskomma-Abstaende.
|
||||
(tu-eq "csv:sepliste-paare/leer" nil (csv:sepliste-paare nil nil))
|
||||
|
||||
;; Gerade Kette AS -> SEP -> SEP -> ES; Kopien bewusst in anderer
|
||||
;; Reihenfolge als die sepliste (die Erzeugungsreihenfolge der Kopien folgt
|
||||
;; der Blockdefinition, nicht der Bauabfolge).
|
||||
(setq _e '(("AS" 1 0.0 0.0) ("SEP" 2 1000.0 0.0) ("SEP" 3 2000.0 0.0) ("ES" 4 3000.0 0.0)))
|
||||
(setq _p '(("SEP" 2000.0 0.0) ("AS" 0.0 0.0) ("ES" 3000.0 0.0) ("SEP" 1000.0 0.0)))
|
||||
(tu-eq "csv:sepliste-paare/kette" '((1 1) (2 3) (3 0) (4 2)) (tu-paare _e _p))
|
||||
|
||||
;; EIN fehlerhafter Koordinatenwert (bekannter Fehlerfall: gespiegeltes x
|
||||
;; bei lfdnr=2) darf die uebrigen Zuordnungen nicht verschieben - die
|
||||
;; exklusive Vergabe teilt dem fehlerhaften Eintrag den Rest zu.
|
||||
(setq _e '(("SEP" 1 1000.0 0.0) ("SEP" 2 -1000.0 -5000.0) ("SEP" 3 3000.0 0.0)))
|
||||
(setq _p '(("SEP" 1000.0 0.0) ("SEP" 2000.0 0.0) ("SEP" 3000.0 0.0)))
|
||||
(tu-eq "csv:sepliste-paare/gespiegelte-koordinate" '((1 0) (2 1) (3 2)) (tu-paare _e _p))
|
||||
|
||||
;; Gleiche Abstaende duerfen kein Paar verschlucken: vl-sort wirft
|
||||
;; Elemente weg, die unter der Vergleichsfunktion gleich sind - deshalb
|
||||
;; sortiert csv:sepliste-paare nach (Abstand, lfdnr, Index).
|
||||
(setq _e '(("SEP" 1 0.0 0.0) ("SEP" 2 0.0 0.0)))
|
||||
(setq _p '(("SEP" 0.0 0.0) ("SEP" 0.0 0.0)))
|
||||
(tu-eq "csv:sepliste-paare/gleiche-abstaende" '((1 0) (2 1)) (tu-paare _e _p))
|
||||
|
||||
;; Typ trennt: eine AS-Kopie wird nie einem SEP-Eintrag zugeteilt, der
|
||||
;; SEP-Eintrag bleibt ohne Partner (und im Export ohne ID).
|
||||
(setq _e '(("AS" 1 0.0 0.0) ("SEP" 2 10.0 0.0)))
|
||||
(setq _p '(("AS" 5.0 0.0)))
|
||||
(tu-eq "csv:sepliste-paare/typ-trennt" '((1 0)) (tu-paare _e _p))
|
||||
|
||||
;; --- csv:asmark-finden: bisherigen AS/ES-Marker im Bestand wiederfinden ---
|
||||
;; Schluessel ist (Wrapper-ID, Typ, lfdnr) - alle drei muessen passen, sonst
|
||||
;; bekaeme ein Kettenende die ID eines fremden Markers. Bestandsformat:
|
||||
;; (ename zuordnung typ lfdnr id), siehe csv:asmark-sammeln.
|
||||
(setq _mk '((ME1 "0021" "AS" "1" "0031")
|
||||
(ME2 "0021" "ES" "4" "0032")
|
||||
(ME3 "0022" "AS" "1" "0033")))
|
||||
(tu-eq "csv:asmark-finden/treffer"
|
||||
'(ME2 "0021" "ES" "4" "0032") (csv:asmark-finden _mk "0021" "ES" "4"))
|
||||
(tu-eq "csv:asmark-finden/anderer-wrapper"
|
||||
'(ME3 "0022" "AS" "1" "0033") (csv:asmark-finden _mk "0022" "AS" "1"))
|
||||
(tu-nil "csv:asmark-finden/falsche-lfdnr" (csv:asmark-finden _mk "0021" "AS" "2"))
|
||||
(tu-nil "csv:asmark-finden/falscher-typ" (csv:asmark-finden _mk "0021" "SEP" "1"))
|
||||
(tu-nil "csv:asmark-finden/ohne-wrapper-id" (csv:asmark-finden _mk "" "AS" "1"))
|
||||
(tu-nil "csv:asmark-finden/leerer-bestand" (csv:asmark-finden nil "0021" "AS" "1"))
|
||||
|
||||
;; csv:proxy-typ: Typmarker aus dem Blocknamen (Grundlage der Zuordnung).
|
||||
(tu-eq "csv:proxy-typ/as" "AS" (csv:proxy-typ "AS_Element_90_links_3D"))
|
||||
(tu-eq "csv:proxy-typ/es" "ES" (csv:proxy-typ "ES_Element_30_rechts_2D"))
|
||||
(tu-eq "csv:proxy-typ/sep" "SEP" (csv:proxy-typ "Separator_SP_3D"))
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user