export_csv: VF_n/GF_n-Einzelelemente (Boegen, Streckenelemente, Umlenk-/Motorstation) als Proxy-Zeilen exportieren
Bisher tauchten nur der Wrapper selbst, verpackte Separatoren und AS/ES- Kettenenden als eigene CSV-Zeilen auf - die uebrigen Kettenbausteine (Boegen, gerade Foerderer-/Gefaellestrecken-Segmente, Umlenk-/Motorstation) blieben nur in der Wrapper-Blockdefinition verpackt. csv:element-proxies- erzeugen (analog zu csv:sep-proxies-erzeugen) fuegt fuer jeden Fund eine temporaere Kopie ein, K1/K2 kommen aus dem EIGENEN KS_EIN/KS_AUS jedes Elements (nicht dem Gesamt-AS/ES der Kette) und bleiben leer, wo keines existiert (z.B. das nie tatsaechlich eingefuegte Vario_Kurve_*). Zusaetzlicher Fix: csv:get-k-kos-strings ignorierte bisher die Skalierung des Top-Level-Inserts - fuer Staustrecke_SP_1000_mm (das per Laenge nicht- uniform skaliert wird) waere K2 damit falsch gewesen, unabhaengig von der tatsaechlich gebauten Segmentlaenge. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
4f1a0e0b5b
commit
f751a90076
+146
-10
@@ -352,7 +352,17 @@
|
||||
;; Weltpunkt (realer Bug: K1 landete beim Vorzeichen von X/Y gespiegelt weit
|
||||
;; ausserhalb der eigenen Boundingbox, sichtbar als fehlendes K-Kreuz in
|
||||
;; sps_skel/HundM05_bbs.svg trotz gefuelltem K1 in der CSV).
|
||||
(defun csv:get-k-kos-strings (ename pt parent-R / ed bname blk-tbl sub-ent sub-ed
|
||||
;; sx/sy/sz: Skalierung des Top-Level-Inserts ename selbst (Gruppencodes
|
||||
;; 41/42/43), auf sub-pt-real anzuwenden BEVOR in Weltkoordinaten gedreht
|
||||
;; wird - noetig fuer nicht-uniform skalierte Bloecke wie Staustrecke_SP_
|
||||
;; 1000_mm (per Laenge auf der X-Achse gestreckt, siehe insert-inclined-
|
||||
;; scaled-block, Lisp/ssg_ks_insert.lsp:260). Ohne diese Skalierung wuerde
|
||||
;; K2 dort so berichtet, als waere der Block unskaliert (1:1) eingefuegt -
|
||||
;; derselbe Fehler, den csv:vfgf-ks-loc fuer AS-/ES-Elemente schon per
|
||||
;; elem-sx/elem-sy/elem-sz vermeidet (siehe dort). Fuer alle bisherigen
|
||||
;; Aufrufer (Omniflo/Kreisel/AS-ES-Marker, durchweg uniform mit 1.0 skaliert
|
||||
;; eingefuegt) ist die Multiplikation ein No-Op - unveraendertes Verhalten.
|
||||
(defun csv:get-k-kos-strings (ename pt parent-R sx sy sz / ed bname blk-tbl sub-ent sub-ed
|
||||
sub-bname sub-pt sub-extrusion sub-pt-real world-pt
|
||||
target is-real result)
|
||||
(setq ed (entget ename))
|
||||
@@ -389,6 +399,9 @@
|
||||
(setq sub-pt (list (car sub-pt) (cadr sub-pt) 0.0)))
|
||||
(setq sub-extrusion (cond ((cdr (assoc 210 sub-ed))) ('(0.0 0.0 1.0))))
|
||||
(setq sub-pt-real (mat3-mul-vec3 (mat3-ocs-matrix sub-extrusion) sub-pt))
|
||||
(setq sub-pt-real (list (* sx (car sub-pt-real))
|
||||
(* sy (cadr sub-pt-real))
|
||||
(* sz (caddr sub-pt-real))))
|
||||
(setq world-pt (csv:local-to-world pt parent-R sub-pt-real))
|
||||
(setq result (cons
|
||||
(cons target
|
||||
@@ -650,7 +663,7 @@
|
||||
;; csv:get-k-kos-strings) werden immer geschrieben, unabhaengig von
|
||||
;; include-bbox -- Kodierung ueber csv:kos-encode (siehe dort).
|
||||
(defun csv:block-to-json (ename include-bbox / ed blk-name layer pt rotation extrusion R-world
|
||||
handle attribs bbox bbox-json
|
||||
handle attribs bbox bbox-json psx psy psz
|
||||
insert-quat insert-kos k-list warnung-json warnung-eintrag
|
||||
zuordnung-fix-json zuordnung-fix-eintrag
|
||||
strecke-typ-json strecke-typ-eintrag
|
||||
@@ -683,7 +696,10 @@
|
||||
(setq insert-kos (csv:kos-encode
|
||||
(car pt) (cadr pt) (if (caddr pt) (caddr pt) 0.0)
|
||||
(nth 0 insert-quat) (nth 1 insert-quat) (nth 2 insert-quat) (nth 3 insert-quat)))
|
||||
(setq k-list (csv:get-k-kos-strings ename pt R-world))
|
||||
(setq psx (cond ((cdr (assoc 41 ed))) (1.0)))
|
||||
(setq psy (cond ((cdr (assoc 42 ed))) (1.0)))
|
||||
(setq psz (cond ((cdr (assoc 43 ed))) (1.0)))
|
||||
(setq k-list (csv:get-k-kos-strings ename pt R-world psx psy psz))
|
||||
;; Omniflo-Geraden fuehren keine echten K-Bloecke - K1/K2 aus der Geometrie
|
||||
;; (Anfang/Ende ueber Laenge + Rotation) synthetisieren, damit sie im Export
|
||||
;; wie echte Anschluss-Koordinatensysteme erscheinen und in der Nachbar-
|
||||
@@ -856,6 +872,24 @@
|
||||
"Separator_SP_2D,Separator_SP_3D"
|
||||
)
|
||||
|
||||
;; --- Muster der uebrigen verpackten VF_n/GF_n-Bausteine (Boegen, gerade
|
||||
;; Foerderer-/Gefaellestrecken-Segmente, Umlenk-/Motorstation) ---
|
||||
;; Wie csv:pattern-nested-separator/-schleus: diese Bausteine stecken als
|
||||
;; Sub-INSERTs in der Wrapper-Blockdefinition und sind fuer (ssget "X" ...)
|
||||
;; unsichtbar. EIN kombiniertes Muster fuer alle vier Familien (statt vier
|
||||
;; getrennter csv:nested-welt-records-Aufrufe) haelt den zusaetzlichen
|
||||
;; Scan-Aufwand auf EINEN weiteren Durchlauf der ganzen Zeichnung beschraenkt
|
||||
;; - csv:element-teileart klassifiziert danach anhand des Blocknamens, in
|
||||
;; welche TeileArt-Familie ein Treffer faellt.
|
||||
(defun csv:pattern-nested-element ()
|
||||
(strcat
|
||||
(export:pattern "pattern_nested_bogen" "Gefaellebogen_*,Vario_Bogen_*,Vario_Kurve_*")
|
||||
"," (export:pattern "pattern_nested_streckenelement" "Staustrecke_SP_1000_mm*")
|
||||
"," (export:pattern "pattern_nested_umlenkstation" "Vario_Umlenkstation_*")
|
||||
"," (export:pattern "pattern_nested_motorstation" "Vario_Motorstation_*")
|
||||
)
|
||||
)
|
||||
|
||||
;; --- 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-
|
||||
@@ -881,6 +915,30 @@
|
||||
)
|
||||
)
|
||||
|
||||
;; --- TeileArt-Familie eines ausgepackten Elements aus seinem Blocknamen ---
|
||||
;; Reiner Namensklassifikator (parallel zu csv:proxy-typ), file-frei testbar
|
||||
;; (tests/test_unit.lsp). Vario_Bogen_* deckt sowohl die _TEF_-Variante (VF-
|
||||
;; Vertikalboegen) als auch die reine Variante ohne _TEF_ (GF-eigene Vertikal-
|
||||
;; boegen) ab - beide auf denselben TeileArt-Bucket "BOGEN", darum ist -
|
||||
;; anders als bei vfl-kette-typ (vf_linienzug.lsp) - keine _TEF_-zuerst-
|
||||
;; Reihenfolge noetig. Vario_Kurve_* ist laut Code-Kommentar (vf_linienzug.lsp)
|
||||
;; aktuell nirgends im Projekt tatsaechlich eingefuegt, aber zur Vollstaendig-
|
||||
;; keit mit aufgenommen. Liefert nil fuer alles andere (sollte bei einem
|
||||
;; ueber csv:pattern-nested-element gefundenen Treffer nie vorkommen -
|
||||
;; defensive Absicherung, falls Muster und cond je auseinanderlaufen).
|
||||
(defun csv:element-teileart (bname / bn)
|
||||
(setq bn (strcase bname))
|
||||
(cond
|
||||
((wcmatch bn "GEFAELLEBOGEN_*") "BOGEN")
|
||||
((wcmatch bn "VARIO_KURVE_*") "BOGEN")
|
||||
((wcmatch bn "VARIO_BOGEN_*") "BOGEN")
|
||||
((wcmatch bn "STAUSTRECKE_SP_1000_MM*") "STRECKENELEMENT")
|
||||
((wcmatch bn "VARIO_UMLENKSTATION_*") "UMLENKSTATION")
|
||||
((wcmatch bn "VARIO_MOTORSTATION_*") "MOTORSTATION")
|
||||
(t nil)
|
||||
)
|
||||
)
|
||||
|
||||
;; --- 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
|
||||
@@ -1120,6 +1178,57 @@
|
||||
(reverse proxy-liste)
|
||||
)
|
||||
|
||||
;; --- Temporaere Kopie je verpacktem uebrigen VF_n/GF_n-Baustein (Bogen/
|
||||
;; Streckenelement/Umlenkstation/Motorstation) ---
|
||||
;; Analog zu csv:sep-proxies-erzeugen, aber ohne die dortige "aussen"/XDATA-
|
||||
;; Zusatzlogik (die existiert nur fuer Separator wegen SSG_SEP_TYP) und ohne
|
||||
;; ZUORDNUNG-Zuweisung: diese Elemente sind keine einem Carrier zugeordneten
|
||||
;; Sensoren, sondern die Geometrie des Carriers (VF_n/GF_n) selbst - ARTINR/
|
||||
;; LAYER kommen direkt aus den ATTDEFs der kopierten Original-Blockdefinition
|
||||
;; (ssg-attrib-read auf die Kopie), wie bei Separator.
|
||||
;;
|
||||
;; proxy-liste-Eintrag: (proxy-ename wrapper-ename teileart-key (x y z)).
|
||||
;; teileart-key (aus csv:element-teileart) wird NICHT ins JSON geschrieben -
|
||||
;; Python klassifiziert die TeileArt ohnehin ueber block_name + die vier
|
||||
;; pattern_nested_*-Keys aus cfg/export.cfg, wie jede andere Familie auch.
|
||||
(defun csv:element-proxies-erzeugen ( / ms recs rec proxy proxy-liste)
|
||||
(setq recs (csv:nested-welt-records (csv:pattern-nested-element)))
|
||||
(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:element-teileart (nth 2 rec)) (nth 3 rec))
|
||||
proxy-liste)))
|
||||
)
|
||||
)
|
||||
)
|
||||
(reverse proxy-liste)
|
||||
)
|
||||
|
||||
;; --- Temporaere Element-Kopien nach dem Export wieder entfernen ---
|
||||
;; Eigene, minimale Loeschfunktion statt csv:sep-proxies-loeschen wieder-
|
||||
;; zuverwenden: *cs-sep-fix-by-handle*/*cs-sep-typ-by-handle*/
|
||||
;; *csv-sepliste-id-by-handle* bleiben separator-/AS-/ES-spezifisch, diese
|
||||
;; Elemente haben keine Entsprechung davon. Nutzt denselben Debug-Schalter
|
||||
;; "csv_leave_proxies" wie Separator, fuer konsistentes Debugging.
|
||||
(defun csv:element-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))
|
||||
" Element-Proxy-Kopie(n) bleiben in der Zeichnung"
|
||||
" (Abschalten: (dbg-schalter-off \"csv_leave_proxies\"))"))
|
||||
(foreach rec proxy-liste (entdel (car rec)))
|
||||
)
|
||||
(princ)
|
||||
)
|
||||
|
||||
;; --- ZUORDNUNG der temporaeren Separator-Kopien aus ihrem Wrapper setzen ---
|
||||
;; MUSS nach ssg-id-check-all laufen: erst dann steht die ID des Wrapper-
|
||||
;; Blocks (VF_n/GF_n/KREISEL_n) fest - ein frisch gebauter Wrapper kann beim
|
||||
@@ -1741,6 +1850,21 @@
|
||||
(wcmatch bname (export:pattern "pattern_eingang" "Eingang*"))
|
||||
(wcmatch bname (export:pattern "pattern_ausgang" "Ausgang*"))
|
||||
(wcmatch bname (export:pattern "pattern_geruest" "GR_*"))
|
||||
;; Uebrige verpackte VF_n/GF_n-Bausteine (Boegen, gerade
|
||||
;; Foerderer-/Gefaellestrecken-Segmente, Umlenk-/Motorstation) -
|
||||
;; siehe csv:element-proxies-erzeugen. pattern_strecke oben
|
||||
;; wuerde die meisten davon schon per Praefix (Vario*/
|
||||
;; Staustrecke*) miterfassen, NUR Gefaellebogen_* nicht - die
|
||||
;; vier expliziten Klauseln schliessen diese Luecke und machen
|
||||
;; die Zugehoerigkeit klar. Kein Duplikate-Risiko: eine ssadd-
|
||||
;; Selektion kann dieselbe Entity nicht zweimal enthalten, egal
|
||||
;; wie viele Klauseln hier matchen.
|
||||
(wcmatch bname (export:pattern "pattern_nested_bogen"
|
||||
"Gefaellebogen_*,Vario_Bogen_*,Vario_Kurve_*"))
|
||||
(wcmatch bname (export:pattern "pattern_nested_streckenelement"
|
||||
"Staustrecke_SP_1000_mm*"))
|
||||
(wcmatch bname (export:pattern "pattern_nested_umlenkstation" "Vario_Umlenkstation_*"))
|
||||
(wcmatch bname (export:pattern "pattern_nested_motorstation" "Vario_Motorstation_*"))
|
||||
;; Rein numerische Namen = Omniflo SivasNr (Boegen/Weichen)
|
||||
;; Rein LISP-intern (Python klassifiziert Omniflo stattdessen
|
||||
;; ueber exakten Katalog-Match), daher fest im Code statt in
|
||||
@@ -1794,7 +1918,7 @@
|
||||
;; 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)
|
||||
(defun csv:export-vorbereiten (label / sep-proxies asmarks element-proxies)
|
||||
;; 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).
|
||||
@@ -1804,6 +1928,13 @@
|
||||
;; (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))
|
||||
;; Die uebrigen Kettenbausteine (Boegen, gerade Foerderer-/Gefaellestrecken-
|
||||
;; Segmente, Umlenk-/Motorstation) ebenso wie die Separatoren durch
|
||||
;; temporaere Kopien ersetzen - siehe csv:element-proxies-erzeugen. MUSS wie
|
||||
;; sep-proxies VOR ssg-id-check-all stehen, damit die frischen Kopien in
|
||||
;; dessen Lauf mit nummeriert werden (siehe ssg-id-collect-blocks,
|
||||
;; ssg_id.lsp).
|
||||
(setq element-proxies (csv:element-proxies-erzeugen))
|
||||
;; 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
|
||||
@@ -1862,7 +1993,7 @@
|
||||
(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)
|
||||
(list sep-proxies element-proxies))
|
||||
|
||||
;; --- Python-Export-Skript aufrufen und Ergebnis auswerten ---------------
|
||||
;; Aus csv:run-export ausgelagert: das fertige raw-JSON (out-pfad) an das
|
||||
@@ -1927,11 +2058,14 @@
|
||||
;; include-bbox = T -> Bounding-Box je Block ermitteln und mit exportieren
|
||||
;; (siehe csv:block-to-json); fuer EXPORTSIVAS nil.
|
||||
(defun csv:run-export (label py-name csv-name include-bbox / ss i ename fh out-pfad
|
||||
first-block count out-dir sep-proxies)
|
||||
first-block count out-dir sep-proxies element-proxies
|
||||
vorbereitung-ergebnis)
|
||||
;; Zeichnungszustand fuer den Export herrichten (Proxies, IDs, Zuordnung,
|
||||
;; Attribut-Update, Sep/Scan-Zaehlung, REGENALL, bbox-Reset) - ausgelagert.
|
||||
;; Rueckgabe: alle erzeugten Kopien (unten wieder zu entfernen).
|
||||
(setq sep-proxies (csv:export-vorbereiten label))
|
||||
;; Rueckgabe: (sep-proxies element-proxies), beide unten wieder zu entfernen.
|
||||
(setq vorbereitung-ergebnis (csv:export-vorbereiten label))
|
||||
(setq sep-proxies (nth 0 vorbereitung-ergebnis))
|
||||
(setq element-proxies (nth 1 vorbereitung-ergebnis))
|
||||
(princ (ssg-textf "exp-collect-blocks" (list label)))
|
||||
|
||||
(setq ss (csv:collect-export-blocks))
|
||||
@@ -1997,10 +2131,12 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
;; Temporaere Separator-/AS-/ES-Kopien wieder entfernen - sie haben ihren
|
||||
;; Temporaere Separator-/Element-Kopien wieder entfernen - sie haben ihren
|
||||
;; Zweck (ID-Vergabe + JSON-Zeile ueber die obigen, unveraenderten
|
||||
;; Sammel-Funktionen) erfuellt.
|
||||
;; Sammel-Funktionen) erfuellt. Die AS-/ES-Marker (ZZ_ASES_MARKER) bleiben
|
||||
;; bewusst stehen (siehe csv:export-vorbereiten).
|
||||
(csv:sep-proxies-loeschen sep-proxies)
|
||||
(csv:element-proxies-loeschen element-proxies)
|
||||
(princ)
|
||||
)
|
||||
|
||||
|
||||
+7
-1
@@ -45,6 +45,12 @@
|
||||
;; Spalte (auch auf Kreiseln) bekommen.
|
||||
;; GR_* (Geruest-Baugruppen, siehe pattern_geruest in cfg/export.cfg) ebenso -
|
||||
;; das ID-ATTDEF steht seit *geruest-attrib-defs* zur Verfuegung.
|
||||
;; Gefaellebogen_* (siehe pattern_nested_bogen in cfg/export.cfg): einer der
|
||||
;; Bausteine einer GF-Kette, verpackt in VF_n/GF_n; wird beim Export ebenso
|
||||
;; als temporaere Kopie ausgepackt wie die uebrigen Vario_*/Staustrecke_*-
|
||||
;; Bausteine (csv:element-proxies-erzeugen, export.lsp) - anders als diese
|
||||
;; faengt "Gefaellebogen" aber KEINES der obigen Praefixe ab und braucht
|
||||
;; daher eine eigene Klausel.
|
||||
(defun ssg-id-collect-blocks ( / ss-all ss-out i ename ed bname)
|
||||
(dbgf "ssg-id-collect-blocks")
|
||||
(setq ss-all (ssget "X" (list (cons 0 "INSERT"))))
|
||||
@@ -59,7 +65,7 @@
|
||||
(if (or
|
||||
(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_*")
|
||||
(wcmatch bname "Vario*,Staustrecke*,Gefaellebogen*,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"
|
||||
|
||||
@@ -70,6 +70,22 @@
|
||||
# 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.
|
||||
#
|
||||
# pattern_nested_bogen/_streckenelement/_umlenkstation/_motorstation: die
|
||||
# uebrigen Bausteine einer VF_n/GF_n-Kette (Boegen, gerade Foerderer-/
|
||||
# Gefaellestrecken-Segmente, Umlenk-/Motorstation). Wie pattern_schleuselement
|
||||
# liegen sie NICHT als eigener top-level INSERT vor, sondern verpackt in der
|
||||
# Wrapper-Blockdefinition - die Muster dienen der SUCHE dort
|
||||
# (csv:nested-welt-records). Exportiert wird eine TEMPORAERE Kopie des
|
||||
# jeweiligen Original-Blocks (csv:element-proxies-erzeugen, wie bei
|
||||
# Separator/pattern_separator), die nach dem Export wieder geloescht wird.
|
||||
# Vario_Kurve_* ist laut Code-Kommentar (vf_linienzug.lsp) aktuell nirgends
|
||||
# im Projekt tatsaechlich eingefuegt - nur zur Vollstaendigkeit gelistet.
|
||||
# Staustrecke_SP_1000_mm wird beim Bau per Laenge NICHT-UNIFORM skaliert
|
||||
# (insert-inclined-scaled-block) - csv:get-k-kos-strings beruecksichtigt das
|
||||
# beim Lesen von K1/K2 (sx/sy/sz-Parameter). export_sivas.py schliesst diese
|
||||
# vier Muster wie Separator/Scanner aus (Stueckzahl steckt schon in den
|
||||
# GF_Bogen_*/VF_Bogen_*/ANZAHL_VF/ANZAHL_GF-Attributen des Wrappers).
|
||||
# ============================================================
|
||||
|
||||
[blockpattern]
|
||||
@@ -89,6 +105,10 @@ pattern_btmt_entladung= SC_Entladung*
|
||||
pattern_eingang= Eingang*
|
||||
pattern_ausgang= Ausgang*
|
||||
pattern_geruest= GR_*
|
||||
pattern_nested_bogen= Gefaellebogen_*, Vario_Bogen_*, Vario_Kurve_*
|
||||
pattern_nested_streckenelement= Staustrecke_SP_1000_mm*
|
||||
pattern_nested_umlenkstation= Vario_Umlenkstation_*
|
||||
pattern_nested_motorstation= Vario_Motorstation_*
|
||||
pattern_ks_subblocks= KS_EIN, KS_AUS, K1, K2, K3, K4
|
||||
|
||||
[python]
|
||||
|
||||
@@ -253,6 +253,25 @@ def build_sensor_merkmale(block):
|
||||
}
|
||||
|
||||
|
||||
def build_element_merkmale(block):
|
||||
"""Merkmale-Dict fuer eine ausgepackte VF_n/GF_n-Sub-Komponente (Bogen/
|
||||
Streckenelement/Umlenkstation/Motorstation) - siehe csv:element-proxies-
|
||||
erzeugen (export.lsp) und pattern_nested_bogen/_streckenelement/
|
||||
_umlenkstation/_motorstation in cfg/export.cfg.
|
||||
|
||||
ARTINR/LAYER kommen direkt aus den ATTDEFs der ausgepackten Original-
|
||||
Blockdefinition (ssg-attrib-read auf der temporaeren Kopie) - dieselbe
|
||||
Quelle wie bei Separator/Scanner (build_sensor_merkmale), aber OHNE
|
||||
"Zuordnung"-Feld: diese Elemente sind keine einem Carrier zugeordneten
|
||||
Sensoren, sondern die Geometrie des Carriers selbst."""
|
||||
attribs = block.get("attribs", {})
|
||||
return {
|
||||
"ARTINR": attribs.get("ARTINR", ""),
|
||||
"Höhe": get_hoehe(block),
|
||||
"Drehung": get_drehung(block),
|
||||
}
|
||||
|
||||
|
||||
def build_btmt_merkmale(block):
|
||||
"""Merkmale-Dict fuer eine eigenstaendige BTMT-Beladung/SC_Entladung-Station
|
||||
(siehe pattern_btmt_beladung/pattern_btmt_entladung in cfg/export.cfg).
|
||||
@@ -916,6 +935,10 @@ def process_blocks(blocks, lookup, dbg=None):
|
||||
vf_count = 0
|
||||
gf_count = 0
|
||||
strecke_modul_count = 0
|
||||
strecke_bogen_count = 0
|
||||
streckenelement_count = 0
|
||||
umlenkstation_count = 0
|
||||
motorstation_count = 0
|
||||
separator_count = 0
|
||||
scanner_count = 0
|
||||
btmt_beladung_count = 0
|
||||
@@ -1130,6 +1153,71 @@ def process_blocks(blocks, lookup, dbg=None):
|
||||
})
|
||||
continue
|
||||
|
||||
# Ausgepackte VF_n/GF_n-Sub-Komponenten (Boegen, gerade Foerderer-/
|
||||
# Gefaellestrecken-Segmente, Umlenk-/Motorstation) - temporaere Kopien,
|
||||
# siehe csv:element-proxies-erzeugen (export.lsp). MUESSEN vor
|
||||
# pattern_strecke_module geprueft werden: dessen Muster ("Vario*,
|
||||
# Staustrecke*, ...") wuerde diese Bloecke sonst zuerst abfangen und
|
||||
# als generische "ILS 2.0 Strecke - Modul"-Zeile ohne K1/K2 ausgeben.
|
||||
# k1/k2 brauchen hier keine Sonderbehandlung - bbox_columns() liest
|
||||
# sie bereits generisch aus dem "k1"/"k2"-Feld des JSON-Rows
|
||||
# (csv:get-k-kos-strings), genau wie bei jedem anderen Block.
|
||||
if matches_any(bname, BLOCKPATTERNS.get("pattern_nested_bogen", [])):
|
||||
elem_nr += 1
|
||||
strecke_bogen_count += 1
|
||||
items.append({
|
||||
"nr": elem_nr,
|
||||
"teileart": "ILS 2.0 Bogen",
|
||||
"teileid": block.get("attribs", {}).get("ID") or format_sensor_id("BOG", strecke_bogen_count),
|
||||
"bezeichnung": f"Bogen :{strecke_bogen_count}",
|
||||
"planquadrat": planquadrat_column(block, planquadrat_cfg),
|
||||
"merkmale": build_element_merkmale(block),
|
||||
**bbox_columns(block),
|
||||
})
|
||||
continue
|
||||
|
||||
if matches_any(bname, BLOCKPATTERNS.get("pattern_nested_streckenelement", [])):
|
||||
elem_nr += 1
|
||||
streckenelement_count += 1
|
||||
items.append({
|
||||
"nr": elem_nr,
|
||||
"teileart": "ILS 2.0 Streckenelement",
|
||||
"teileid": block.get("attribs", {}).get("ID") or format_sensor_id("STR", streckenelement_count),
|
||||
"bezeichnung": f"Streckenelement :{streckenelement_count}",
|
||||
"planquadrat": planquadrat_column(block, planquadrat_cfg),
|
||||
"merkmale": build_element_merkmale(block),
|
||||
**bbox_columns(block),
|
||||
})
|
||||
continue
|
||||
|
||||
if matches_any(bname, BLOCKPATTERNS.get("pattern_nested_umlenkstation", [])):
|
||||
elem_nr += 1
|
||||
umlenkstation_count += 1
|
||||
items.append({
|
||||
"nr": elem_nr,
|
||||
"teileart": "ILS 2.0 Umlenkstation",
|
||||
"teileid": block.get("attribs", {}).get("ID") or format_sensor_id("UML", umlenkstation_count),
|
||||
"bezeichnung": f"Umlenkstation :{umlenkstation_count}",
|
||||
"planquadrat": planquadrat_column(block, planquadrat_cfg),
|
||||
"merkmale": build_element_merkmale(block),
|
||||
**bbox_columns(block),
|
||||
})
|
||||
continue
|
||||
|
||||
if matches_any(bname, BLOCKPATTERNS.get("pattern_nested_motorstation", [])):
|
||||
elem_nr += 1
|
||||
motorstation_count += 1
|
||||
items.append({
|
||||
"nr": elem_nr,
|
||||
"teileart": "ILS 2.0 Motorstation",
|
||||
"teileid": block.get("attribs", {}).get("ID") or format_sensor_id("MOT", motorstation_count),
|
||||
"bezeichnung": f"Motorstation :{motorstation_count}",
|
||||
"planquadrat": planquadrat_column(block, planquadrat_cfg),
|
||||
"merkmale": build_element_merkmale(block),
|
||||
**bbox_columns(block),
|
||||
})
|
||||
continue
|
||||
|
||||
# ILS Strecke-Module (Vario/Staustrecke-Einzelkomponenten)
|
||||
if matches_any(bname, BLOCKPATTERNS.get("pattern_strecke_module", [])):
|
||||
elem_nr += 1
|
||||
|
||||
@@ -410,8 +410,21 @@ SKIP_BLOCKS = set(BLOCKPATTERNS.get("pattern_ks_subblocks", ["K1", "K2", "K3", "
|
||||
# ueber die ANZAHL_SEPARATOR/ANZAHL_SCANNER-Attribute des zugehoerigen
|
||||
# Kreisel/GF/VF-Blocks gezaehlt (siehe kreisel_signature/build_*_details
|
||||
# oben) - ein zusaetzlicher eigener Eintrag wuerde doppelt zaehlen.
|
||||
#
|
||||
# Dieselbe Ueberlegung gilt fuer die ausgepackten VF_n/GF_n-Sub-Komponenten
|
||||
# (Boegen, gerade Foerderer-/Gefaellestrecken-Segmente, Umlenk-/Motorstation -
|
||||
# siehe csv:element-proxies-erzeugen, export.lsp): ihre Stueckzahl steckt
|
||||
# bereits in den GF_Bogen_*/VF_Bogen_*/ANZAHL_VF/ANZAHL_GF-Attributen des
|
||||
# Wrappers (*strecke-attr-gruppe*, ssg_core.lsp) - ein eigener Sivas-Eintrag
|
||||
# wuerde ebenso doppelt zaehlen. Muss VOR der pattern_strecke_module-Pruefung
|
||||
# unten greifen, sonst faengt deren generisches "ILS 2.0 Strecke"-Sammeln
|
||||
# diese Kopien zuerst ab.
|
||||
SEP_SCANNER_PATTERNS = (
|
||||
BLOCKPATTERNS.get("pattern_separator", []) + BLOCKPATTERNS.get("pattern_scanner", [])
|
||||
+ BLOCKPATTERNS.get("pattern_nested_bogen", [])
|
||||
+ BLOCKPATTERNS.get("pattern_nested_streckenelement", [])
|
||||
+ BLOCKPATTERNS.get("pattern_nested_umlenkstation", [])
|
||||
+ BLOCKPATTERNS.get("pattern_nested_motorstation", [])
|
||||
)
|
||||
|
||||
# Sivas-Nummern und Bezeichnungen je ILS-Elementtyp
|
||||
|
||||
+15
-7
@@ -20,13 +20,21 @@ import os
|
||||
import pytest
|
||||
|
||||
|
||||
# TeileArt-Werte, die einen SENSOR beschreiben statt einer Vario-Strecke -
|
||||
# csv:sep-proxies-erzeugen (export.lsp, Commit e2f0384) erfasst seither auch
|
||||
# Separator_SP-Symbole, die als Sub-INSERT in der VF_n-Blockdefinition
|
||||
# verpackt sind, und exportiert je Fund eine eigene Zeile. Foerderer kennt
|
||||
# nur diese eine Sensorart (kein Scanner); die vollstaendige Liste steht in
|
||||
# test_export_ids.py:SENSOR_TEILEARTEN.
|
||||
NEBEN_TEILEARTEN = {"ILS 2.0 Separator"}
|
||||
# TeileArt-Werte, die einen SENSOR bzw. ein Streckenbauteil beschreiben statt
|
||||
# einer Vario-Strecke selbst - csv:sep-proxies-erzeugen (export.lsp, Commit
|
||||
# e2f0384) erfasst auch Separator_SP-Symbole, die als Sub-INSERT in der
|
||||
# VF_n-Blockdefinition verpackt sind, und exportiert je Fund eine eigene
|
||||
# Zeile. csv:element-proxies-erzeugen (export.lsp) erfasst ebenso die
|
||||
# uebrigen verpackten Bausteine (Boegen, gerade Foerderer-/Gefaellestrecken-
|
||||
# Segmente, Umlenk-/Motorstation) als je eigene Zeile. Foerderer kennt kein
|
||||
# Scanner; die vollstaendige Liste steht in test_export_ids.py:SENSOR_TEILEARTEN.
|
||||
NEBEN_TEILEARTEN = {
|
||||
"ILS 2.0 Separator",
|
||||
"ILS 2.0 Bogen",
|
||||
"ILS 2.0 Streckenelement",
|
||||
"ILS 2.0 Umlenkstation",
|
||||
"ILS 2.0 Motorstation",
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -10,8 +10,10 @@ Prueft:
|
||||
Modus 3 uebernimmt deltaH/deltaL aus Modus 2)
|
||||
"""
|
||||
|
||||
import csv
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
|
||||
@@ -232,3 +234,136 @@ class TestGefaellestreckeModusKonsistenz:
|
||||
f'von {quelle_id}={m2["delta_h_mm"]} ab '
|
||||
f'(Toleranz {self.DELTA_H_TOLERANZ_MM} mm)'
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Klasse 4: CSV-Export-Pruefung (gefaellestrecke_tests_export.csv)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# TeileArt-Werte, die einen Sensor bzw. ein Streckenbauteil beschreiben statt
|
||||
# einer GF-Strecke selbst - csv:element-proxies-erzeugen (export.lsp) erfasst
|
||||
# die verpackten Bausteine (Boegen, gerade Foerderer-/Gefaellestrecken-
|
||||
# Segmente, Umlenk-/Motorstation) als je eigene Zeile, wie schon
|
||||
# csv:sep-proxies-erzeugen fuer Separator_SP-Symbole; siehe
|
||||
# test_foerderer.py:NEBEN_TEILEARTEN (analoge Konstante dort, erste GF-eigene
|
||||
# CSV-Struktur-Pruefung hier - vorher gab es fuer GF-Ketten noch keine).
|
||||
NEBEN_TEILEARTEN = {
|
||||
"ILS 2.0 Separator",
|
||||
"ILS 2.0 Bogen",
|
||||
"ILS 2.0 Streckenelement",
|
||||
"ILS 2.0 Umlenkstation",
|
||||
"ILS 2.0 Motorstation",
|
||||
}
|
||||
|
||||
|
||||
class TestGefaellestreckeExportCSV:
|
||||
"""Prueft den CSV-Export aus BricsCAD (gefaellestrecke_tests_export.csv,
|
||||
aus TEST_EXPORT_ALL)."""
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self):
|
||||
csv_path = os.path.join(_output_dir(), "gefaellestrecke_tests_export.csv")
|
||||
if not os.path.exists(csv_path):
|
||||
pytest.skip(
|
||||
"gefaellestrecke_tests_export.csv nicht vorhanden - "
|
||||
"TEST_GEFAELLESTRECKE und anschliessend TEST_EXPORT_ALL in BricsCAD ausfuehren"
|
||||
)
|
||||
self.rows = []
|
||||
with open(csv_path, "r", encoding="utf-8") as f:
|
||||
reader = csv.reader(f, delimiter=";")
|
||||
self.header = next(reader)
|
||||
for row in reader:
|
||||
self.rows.append(row)
|
||||
self.col = {name: i for i, name in enumerate(self.header)}
|
||||
|
||||
def _cell(self, row, spalte):
|
||||
i = self.col.get(spalte)
|
||||
if i is None or i >= len(row):
|
||||
return None
|
||||
return row[i]
|
||||
|
||||
def test_teileart_bekannt(self):
|
||||
"""Jede Zeile ist entweder eine GF-Strecke oder eine der bekannten
|
||||
Neben-TeileArten - keine unerwartete dritte Art."""
|
||||
bekannt = {"ILS 2.0 Gefaellestrecke", "ILS 2.0 Strecke"} | NEBEN_TEILEARTEN
|
||||
for i, row in enumerate(self.rows):
|
||||
teileart = self._cell(row, "TeileArt")
|
||||
if teileart is None:
|
||||
continue
|
||||
assert teileart.strip('"') in bekannt, (
|
||||
f"Zeile {i + 2}: unbekannte TeileArt '{teileart}'"
|
||||
)
|
||||
|
||||
def test_element_zeilen_haben_k1_oder_k2(self):
|
||||
"""Bogen/Umlenkstation/Motorstation-Zeilen sollten zuverlaessig ein
|
||||
eigenes KS_EIN/KS_AUS tragen (anders als Vario_Kurve_*, das laut
|
||||
Code-Kommentar nie tatsaechlich eingefuegt wird und daher hier auch
|
||||
nie auftaucht) - K1 ODER K2 muss gefuellt sein. Streckenelement wird
|
||||
hier NICHT geprueft (dafuer siehe
|
||||
test_streckenelement_laenge_stimmt_mit_k1_k2_ueberein unten)."""
|
||||
pruef_teilearten = {"ILS 2.0 Bogen", "ILS 2.0 Umlenkstation", "ILS 2.0 Motorstation"}
|
||||
for i, row in enumerate(self.rows):
|
||||
teileart = self._cell(row, "TeileArt")
|
||||
if teileart is None or teileart.strip('"') not in pruef_teilearten:
|
||||
continue
|
||||
k1 = self._cell(row, "K1")
|
||||
k2 = self._cell(row, "K2")
|
||||
assert (k1 and k1.strip('"')) or (k2 and k2.strip('"')), (
|
||||
f"Zeile {i + 2}: TeileArt='{teileart}' hat weder K1 noch K2 gefuellt"
|
||||
)
|
||||
|
||||
def test_streckenelement_laenge_stimmt_mit_k1_k2_ueberein(self):
|
||||
"""Regressionstest fuer den csv:get-k-kos-strings-Skalierungsfix:
|
||||
Staustrecke_SP_1000_mm wird beim Bau per Laenge NICHT-UNIFORM skaliert
|
||||
(insert-inclined-scaled-block) - ohne die sx/sy/sz-Beruecksichtigung
|
||||
in csv:get-k-kos-strings waere K2 dort so berichtet, als waere der
|
||||
Block unskaliert (1000mm) eingefuegt, unabhaengig von der tatsaechlich
|
||||
gebauten Segmentlaenge. Der K1->K2-Abstand einer Streckenelement-Zeile
|
||||
muss daher der Boundingbox-Ausdehnung (die reale, gebaute Laenge)
|
||||
entsprechen, NICHT literal 1000mm, sofern das Segment gestreckt wurde."""
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "lib"))
|
||||
from export_neighbors import _decode_trans_xy
|
||||
|
||||
gefunden = 0
|
||||
for i, row in enumerate(self.rows):
|
||||
teileart = self._cell(row, "TeileArt")
|
||||
if teileart is None or teileart.strip('"') != "ILS 2.0 Streckenelement":
|
||||
continue
|
||||
k1_str = self._cell(row, "K1")
|
||||
k2_str = self._cell(row, "K2")
|
||||
if not k1_str or not k2_str:
|
||||
continue
|
||||
p1 = _decode_trans_xy(k1_str.strip('"'))
|
||||
p2 = _decode_trans_xy(k2_str.strip('"'))
|
||||
if p1 is None or p2 is None:
|
||||
continue
|
||||
k1_k2_laenge = ((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2) ** 0.5
|
||||
# Nur Segmente pruefen, deren reale Laenge sichtbar von 1000mm
|
||||
# abweicht - sonst waere ein (durch den Bug) falsch auf 1000mm
|
||||
# zurueckfallender Wert zufaellig nicht von einem korrekten zu
|
||||
# unterscheiden.
|
||||
if abs(k1_k2_laenge - 1000.0) < 50.0:
|
||||
continue
|
||||
gefunden += 1
|
||||
boundingbox = self._cell(row, "Boundingbox")
|
||||
assert boundingbox, f"Zeile {i + 2}: Boundingbox fehlt"
|
||||
dx, dy, dz = (float(v) for v in boundingbox.strip('"').split(","))
|
||||
bbox_diagonale = (dx ** 2 + dy ** 2) ** 0.5
|
||||
# Toleranz: die Boundingbox-Diagonale ist ein Oberwert (das
|
||||
# Element kann geneigt/gedreht sein), der K1-K2-Abstand darf sie
|
||||
# nicht wesentlich ueberschreiten - waere er trotz Streckung immer
|
||||
# ~1000mm (der Bug), wuerde er bei stark gestreckten Segmenten
|
||||
# deutlich UNTER der Bounding-Box-Diagonale liegen.
|
||||
assert k1_k2_laenge <= bbox_diagonale + 50.0, (
|
||||
f"Zeile {i + 2}: K1->K2-Abstand={k1_k2_laenge:.0f}mm groesser als "
|
||||
f"Boundingbox-Diagonale={bbox_diagonale:.0f}mm"
|
||||
)
|
||||
assert k1_k2_laenge >= 50.0, (
|
||||
f"Zeile {i + 2}: K1->K2-Abstand={k1_k2_laenge:.0f}mm verdaechtig klein "
|
||||
f"(Skalierungsfix eventuell nicht wirksam)"
|
||||
)
|
||||
if gefunden == 0:
|
||||
pytest.skip(
|
||||
"keine Streckenelement-Zeile mit von 1000mm abweichender "
|
||||
"K1-K2-Laenge gefunden - Testdaten enthalten kein gestrecktes Segment"
|
||||
)
|
||||
|
||||
@@ -389,6 +389,27 @@
|
||||
(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"))
|
||||
|
||||
;; csv:element-teileart: TeileArt-Familie eines ausgepackten VF_n/GF_n-
|
||||
;; Bausteins aus dem Blocknamen (Boegen/Streckenelement/Umlenk-/Motor-
|
||||
;; station). Vario_Bogen_* deckt sowohl die _TEF_- als auch die reine
|
||||
;; GF-Variante ab, beide auf denselben Bucket "BOGEN".
|
||||
(tu-eq "csv:element-teileart/gefaellebogen" "BOGEN"
|
||||
(csv:element-teileart "Gefaellebogen_links_90_R500"))
|
||||
(tu-eq "csv:element-teileart/vario-bogen-tef" "BOGEN"
|
||||
(csv:element-teileart "Vario_Bogen_auf_3_TEF_rechts"))
|
||||
(tu-eq "csv:element-teileart/vario-bogen-gf" "BOGEN"
|
||||
(csv:element-teileart "Vario_Bogen_ab_6_rechts"))
|
||||
(tu-eq "csv:element-teileart/vario-kurve" "BOGEN"
|
||||
(csv:element-teileart "Vario_Kurve_links_30_TEF_innen"))
|
||||
(tu-eq "csv:element-teileart/streckenelement" "STRECKENELEMENT"
|
||||
(csv:element-teileart "Staustrecke_SP_1000_mm"))
|
||||
(tu-eq "csv:element-teileart/umlenkstation" "UMLENKSTATION"
|
||||
(csv:element-teileart "Vario_Umlenkstation_500mm_links"))
|
||||
(tu-eq "csv:element-teileart/motorstation" "MOTORSTATION"
|
||||
(csv:element-teileart "Vario_Motorstation_500mm_rechts"))
|
||||
(tu-eq "csv:element-teileart/unbekannt" nil
|
||||
(csv:element-teileart "AS_Element_90_links"))
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user