From 0e8d264b6aed606cb8b21aa57392e77d3b4bbf11 Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Thu, 11 Jun 2026 12:03:23 +0200 Subject: [PATCH] eigene Export Routine aus den Tests extrahiert --- Lisp/export.lsp | 550 ++++++++++++++++++++++++++++++++++++++++++++++++ Lisp/tests.lsp | 442 +------------------------------------- 2 files changed, 552 insertions(+), 440 deletions(-) create mode 100644 Lisp/export.lsp diff --git a/Lisp/export.lsp b/Lisp/export.lsp new file mode 100644 index 0000000..9ae7511 --- /dev/null +++ b/Lisp/export.lsp @@ -0,0 +1,550 @@ +;; ============================================================ +;; export.lsp - Export-Funktionen fuer INSERT-Bloecke +;; +;; Enthaelt: +;; - JSON-Sammler (csv:collect-export-blocks, csv:run-export) +;; - Python-basierter Export: EXPORTSIVAS, EXPORTCSV +;; - LISP-basierter Omniflo-Export: OMNI_EXPORT +;; ============================================================ + + +;; --- String fuer JSON escapen (Anfuehrungszeichen/Backslash) --- +(defun csv:json-escape (s) + (setq s (vl-string-subst "\\\\" "\\" s)) + (vl-string-subst "\\\"" "\"" s) +) + + +;; --- Attribute eines INSERT-Blocks als JSON-Objekt lesen --- +;; ename = Entity-Name des INSERT +;; Rueckgabe: String wie {"TAG1":"Wert1","TAG2":"Wert2"} +(defun csv:read-attribs (ename / obj ed typ tag wert parts) + (setq obj (entnext ename)) + (setq parts nil) + (while obj + (setq ed (entget obj)) + (setq typ (cdr (assoc 0 ed))) + (if (equal typ "SEQEND") (setq obj nil) + (progn + (if (equal typ "ATTRIB") + (setq parts (cons (strcat "\"" (csv:json-escape (cdr (assoc 2 ed))) + "\":\"" (csv:json-escape (cdr (assoc 1 ed))) "\"") + parts)) + ) + (setq obj (entnext obj)) + ) + ) + ) + (if parts + (progn + (setq parts (reverse parts)) + (strcat "{" (car parts) + (apply 'strcat (mapcar '(lambda (p) (strcat "," p)) (cdr parts))) + "}") + ) + "{}" + ) +) + + +;; --- Einen INSERT-Block als JSON-Objekt schreiben --- +(defun csv:block-to-json (ename / ed blk-name layer pt rotation handle attribs) + (setq ed (entget ename)) + (setq blk-name (cdr (assoc 2 ed))) + (setq layer (cdr (assoc 8 ed))) + (setq pt (cdr (assoc 10 ed))) + (setq rotation (cdr (assoc 50 ed))) + (setq handle (cdr (assoc 5 ed))) + (if (null rotation) (setq rotation 0.0)) + (if (cdr (assoc 66 ed)) + (setq attribs (csv:read-attribs ename)) + (setq attribs "{}") + ) + (strcat + " {\"block_name\":\"" (csv:json-escape blk-name) "\"" + ",\"layer\":\"" (csv:json-escape layer) "\"" + ",\"handle\":\"" (csv:json-escape handle) "\"" + ",\"x\":" (rtos (car pt) 2 4) + ",\"y\":" (rtos (cadr pt) 2 4) + ",\"z\":" (rtos (if (caddr pt) (caddr pt) 0.0) 2 4) + ",\"rotation\":" (rtos (* (/ rotation pi) 180.0) 2 4) + ",\"attribs\":" attribs + "}" + ) +) + + +;; --- Relevante Bloecke sammeln --- +;; Filtert INSERT-Entities auf exportierbare Bloecke: +;; KR_* = Kreisel Compound-Bloecke +;; AP110* = Omniflo Geraden +;; Omniflo Boegen/Weichen = rein numerische Blocknamen (SivasNr) +;; Vario* = VarioFoerderer-Bloecke +;; Gibt Auswahlsatz zurueck oder nil. +(defun csv:collect-export-blocks ( / ss-all ss-out i ename ed bname) + (setq ss-all (ssget "X" (list (cons 0 "INSERT")))) + (if (null ss-all) (setq ss-out nil) + (progn + (setq ss-out (ssadd)) + (setq i 0) + (while (setq ename (ssname ss-all i)) + (setq ed (entget ename)) + (setq bname (cdr (assoc 2 ed))) + (if (or + (wcmatch bname "KR_*,KREISEL_*,ECKRAD_*") + (wcmatch (strcase bname) "AP110*,AP_110*") + (wcmatch bname "Vario*,Staustrecke*,AUS_Element*,EIN_Element*") + ;; Rein numerische Namen = Omniflo SivasNr (Boegen/Weichen) + (wcmatch bname "#*") + ) + (ssadd ename ss-out) + ) + (setq i (1+ i)) + ) + (if (= (sslength ss-out) 0) (setq ss-out nil)) + ) + ) + ss-out +) + + +;; --- Gemeinsame Export-Funktion --- +;; Sammelt relevante Bloecke, schreibt JSON, ruft Python auf. +;; label = Anzeigename (z.B. "EXPORTCSV") +;; py-name = Python-Skript-Name (z.B. "export_csv.py") +;; csv-name = Ergebnis-CSV-Name (z.B. "export.csv") +(defun csv:run-export (label py-name csv-name / ss i ename fh out-pfad + py-skript ergebnis-pfad cmd first-block count) + (princ (strcat "\n[" label "] Sammle relevante Bloecke...")) + + (setq ss (csv:collect-export-blocks)) + (if (null ss) + (progn + (princ (strcat "\n[" label "] Keine relevanten Bloecke gefunden.")) + (princ) + ) + (progn + (setq count (sslength ss)) + (princ (strcat "\n[" label "] " (itoa count) " Bloecke gefunden.")) + + ;; JSON-Datei zusammenbauen + (setq out-pfad (strcat (getenv "DXFM_RESULTS") "/export_raw.json")) + (setq fh (open out-pfad "w")) + (if (null fh) + (progn + (princ (strcat "\n[" label "] FEHLER: Kann Datei nicht oeffnen: " out-pfad)) + (princ) + ) + (progn + (write-line "[" fh) + (setq i 0) + (setq first-block T) + (while (setq ename (ssname ss i)) + (if (not first-block) + (write-line "," fh) + ) + (write-line (csv:block-to-json ename) fh) + (setq first-block nil) + (setq i (1+ i)) + ) + (write-line "]" fh) + (close fh) + (princ (strcat "\n[" label "] JSON geschrieben: " out-pfad)) + + ;; Python-Skript aufrufen + (setq py-skript (strcat (getenv "DXFM_LIB") "/" py-name)) + (if (findfile py-skript) + (progn + (setq ergebnis-pfad (strcat (getenv "DXFM_RESULTS") "/" csv-name)) + (setq cmd (strcat "python \"" py-skript "\"" + " \"" out-pfad "\"" + " \"" (getenv "DXFM_DATA") "\"" + " \"" ergebnis-pfad "\"")) + (princ (strcat "\n[" label "] Rufe Python auf...")) + (startapp "cmd" (strcat "/c " cmd)) + (princ (strcat "\n[" label "] Export gestartet: " ergebnis-pfad)) + ) + (princ (strcat "\n[" label "] FEHLER: Python-Skript nicht gefunden: " py-skript)) + ) + ) + ) + ) + ) + (princ) +) + + +;; --- EXPORTSIVAS: Sivas-spezifischer CSV-Export mit Summierungszeilen --- +(defun c:EXPORTSIVAS () + (csv:run-export "EXPORTSIVAS" "export_sivas.py" "export_sivas.csv") +) + +;; --- EXPORTCSV: Einfache Item-Liste aller Bloecke (ohne Summierung) --- +(defun c:EXPORTCSV () + (csv:run-export "EXPORTCSV" "export_csv.py" "export.csv") +) + + +;; ============================================================ +;; LISP-basierter Omniflo-Export (ohne Python) +;; +;; Erkennt Omniflo Bloecke anhand Attribute: +;; TEILEART = "Omniflo Kurve" -> Bogen +;; TEILEART = "Omniflo Weiche" -> Weiche +;; Blockname AP110* -> Gerade +;; ============================================================ + +;; --- Attribut-Wert eines INSERT-Blocks nach Tag lesen --- +(defun csv:get-attrib (ename tag / obj ed typ atag) + (setq obj (entnext ename)) + (while obj + (setq ed (entget obj)) + (setq typ (cdr (assoc 0 ed))) + (if (equal typ "SEQEND") + (setq obj nil) + (progn + (if (and (equal typ "ATTRIB") + (= (strcase (cdr (assoc 2 ed))) (strcase tag))) + (progn (setq obj nil) (setq atag (cdr (assoc 1 ed)))) + (setq obj (entnext obj)) + ) + ) + ) + ) + atag +) + + +;; --- Omniflo-Block klassifizieren --- +;; Gibt "bogen", "weiche", "gerade" oder nil zurueck +(defun csv:omni-classify (ename bname / teileart) + (setq teileart (csv:get-attrib ename "TEILEART")) + (cond + ((and teileart (= teileart "Omniflo Kurve")) "bogen") + ((and teileart (= teileart "Omniflo Weiche")) "weiche") + ((wcmatch (strcase bname) "AP110*,AP_110*") "gerade") + (t nil) + ) +) + + +;; --- Weichen-Subtyp fuer Omniflo Sum Zaehlung bestimmen --- +(defun csv:omni-weichensubtyp (ename / wtyp beschr) + (setq wtyp (csv:get-attrib ename "WEICHENTYP")) + (setq beschr (csv:get-attrib ename "BESCHR")) + (if (null wtyp) (setq wtyp "")) + (if (null beschr) (setq beschr "")) + (cond + ((vl-string-search "WEICHENK" (strcase beschr)) "weichenkoerper") + ((= wtyp "Einzelweiche") "einzelweiche") + ((= wtyp "Doppelweiche") "doppelweiche") + ((= wtyp "Dreiwegeweiche") "dreiwegeweiche") + ((= wtyp "Deltaweiche") "deltaweiche") + ((= wtyp "Dreifachweiche") "deltaweiche") + ((= wtyp "Sternweiche") "sternweiche") + ((vl-string-search "DELTA" (strcase beschr)) "deltaweiche") + ((vl-string-search "STAR" (strcase beschr)) "sternweiche") + (t "einzelweiche") + ) +) + + +;; --- Merkmale-JSON fuer einen Bogen bauen --- +(defun csv:omni-bogen-merkmale (ename rotation / winkel radius sivasnr hoehe drehung) + (setq winkel (or (csv:get-attrib ename "WINKEL") "0")) + (setq radius (or (csv:get-attrib ename "RADIUS") "0")) + (setq sivasnr (or (csv:get-attrib ename "ARTINR") "")) + (setq hoehe (or (csv:get-attrib ename "HOEHE") "2000")) + (setq drehung (or (csv:get-attrib ename "DREHUNG") (rtos rotation 2 1))) + (strcat "{\"Kurvenwinkel\":" winkel + ",\"Radius\":" radius + ",\"H\\u00f6he\":\"" (csv:json-escape hoehe) "\"" + ",\"Drehung\":" drehung + ",\"SivasNummer\":\"" (csv:json-escape sivasnr) "\"}") +) + + +;; --- Merkmale-JSON fuer eine Weiche bauen --- +(defun csv:omni-weiche-merkmale (ename rotation / wtyp winkel sivasnr tef-str hoehe drehung) + (setq wtyp (or (csv:get-attrib ename "WEICHENTYP") "Einzelweiche")) + (setq winkel (or (csv:get-attrib ename "WINKEL") "0")) + (setq sivasnr (or (csv:get-attrib ename "ARTINR") "")) + (setq tef-str (csv:get-attrib ename "SIVASNR_TEF")) + (setq hoehe (or (csv:get-attrib ename "HOEHE") "2000")) + (setq drehung (or (csv:get-attrib ename "DREHUNG") (rtos rotation 2 1))) + (strcat "{\"Weichentyp\":\"" (csv:json-escape wtyp) "\"" + ",\"Richtung\":\"False\"" + ",\"Weichenwinkel\":" winkel + ",\"H\\u00f6he\":\"" (csv:json-escape hoehe) "\"" + ",\"Drehung\":" drehung + ",\"Antrieb Kurve\":" (if (and tef-str (> (strlen tef-str) 0)) "true" "false") + ",\"SivasNummer\":\"" (csv:json-escape sivasnr) "\"}") +) + + +;; --- Merkmale-JSON fuer eine Gerade bauen --- +(defun csv:omni-gerade-merkmale (ename rotation / laenge hoehe drehung) + (setq laenge (csv:get-attrib ename "LAENGE")) + (if (null laenge) (setq laenge (csv:get-attrib ename "A"))) + (if (null laenge) (setq laenge "2000")) + (setq hoehe (or (csv:get-attrib ename "HOEHE") "2000")) + (setq drehung (or (csv:get-attrib ename "DREHUNG") (rtos rotation 2 1))) + (strcat "{\"Anzahl der Separatoren\":\"0\"" + ",\"L\\u00e4nge in Meter\":\"" (csv:json-escape (rtos (/ (atof laenge) 1000.0) 2 2)) "\"" + ",\"Winkel\":\"0\"" + ",\"Anzahl der Scanner\":0" + ",\"H\\u00f6he oben\":\"" (csv:json-escape hoehe) "\"" + ",\"H\\u00f6he unten\":\"" (csv:json-escape hoehe) "\"" + ",\"Drehung\":" drehung + ",\"SivasNummer\":\"\"}") +) + + +;; --- Omniflo Sum Zeile bauen --- +(defun csv:omni-sum-zeile (elem-nr cnt-boegen cnt-wk cnt-einzel cnt-delta cnt-doppel cnt-stern len-ap110 len-ap60) + (strcat (itoa elem-nr) + ";\"Omniflo Sum\";\"autogenerated_of_json\";\"Omniflo sum\";1;" + "{\"Anzahl B\\u00f6gen\":" (itoa cnt-boegen) + ",\"Anzahl Weichengrundk\\u00f6rper\":" (itoa cnt-wk) + ",\"Anzahl Einwegweichen\":" (itoa cnt-einzel) + ",\"Anzahl Deltaweichen\":" (itoa cnt-delta) + ",\"Anzahl Doppelweichen und Dreiwegeweichen\":" (itoa cnt-doppel) + ",\"Anzahl Sternweichen\":" (itoa cnt-stern) + ",\"Gesamtl\\u00e4nge AP110\":" (rtos len-ap110 2 1) + ",\"Gesamtl\\u00e4nge AP60\":" (rtos len-ap60 2 1) + "}") +) + + +;; --- CSV-Zeile fuer ein Omniflo-Element bauen --- +(defun csv:omni-csv-line (elem-nr teileart bezeichnung merkmale-json) + (strcat (itoa elem-nr) + ";\"" teileart "\"" + ";\"shape_" (substr (rtos (* (getvar "CDATE") 1000000.0) 2 0) 1 8) + (substr (rtos (* (getvar "TDUSRTIMER") 1000000.0) 2 0) 1 8) "\"" + ";\"" bezeichnung "\"" + ";1" + ";" merkmale-json) +) + + +;; ============================================================ +;; C:OMNI_EXPORT - Omniflo-Elemente zaehlen und als CSV exportieren +;; Rein LISP-basiert, kein Python noetig. +;; ============================================================ +(defun c:OMNI_EXPORT ( / ss-all i ename ed bname rotation typ + elem-nr cnt-boegen cnt-weichen cnt-geraden + cnt-wk cnt-einzel cnt-delta cnt-doppel cnt-stern + len-ap110 len-ap60 laenge-str + fh out-pfad lines subtyp merkmale) + + (princ "\n[OMNI_EXPORT] Sammle Omniflo-Elemente...") + (setq ss-all (ssget "X" (list (cons 0 "INSERT")))) + (if (null ss-all) + (progn (princ "\n[OMNI_EXPORT] Keine INSERT-Bloecke in der Zeichnung.") (princ)) + (progn + (setq elem-nr 0) + (setq cnt-boegen 0 cnt-weichen 0 cnt-geraden 0) + (setq cnt-wk 0 cnt-einzel 0 cnt-delta 0 cnt-doppel 0 cnt-stern 0) + (setq len-ap110 0.0 len-ap60 0.0) + (setq lines '()) + + (setq i 0) + (while (setq ename (ssname ss-all i)) + (setq ed (entget ename)) + (setq bname (cdr (assoc 2 ed))) + (setq rotation (cdr (assoc 50 ed))) + (if (null rotation) (setq rotation 0.0)) + (setq rotation (* (/ rotation pi) 180.0)) + + (setq typ (csv:omni-classify ename bname)) + + (cond + ((= typ "bogen") + (setq elem-nr (1+ elem-nr)) + (setq cnt-boegen (1+ cnt-boegen)) + (setq merkmale (csv:omni-bogen-merkmale ename rotation)) + (setq lines (cons + (csv:omni-csv-line elem-nr "Omniflo Kurve" + (strcat "OFBogen :" (itoa cnt-boegen)) merkmale) + lines)) + ) + + ((= typ "weiche") + (setq elem-nr (1+ elem-nr)) + (setq cnt-weichen (1+ cnt-weichen)) + (setq subtyp (csv:omni-weichensubtyp ename)) + (cond + ((= subtyp "weichenkoerper") (setq cnt-wk (1+ cnt-wk))) + ((= subtyp "einzelweiche") (setq cnt-einzel (1+ cnt-einzel))) + ((= subtyp "deltaweiche") (setq cnt-delta (1+ cnt-delta))) + ((= subtyp "sternweiche") (setq cnt-stern (1+ cnt-stern))) + (t (setq cnt-doppel (1+ cnt-doppel))) + ) + (setq merkmale (csv:omni-weiche-merkmale ename rotation)) + (setq lines (cons + (csv:omni-csv-line elem-nr "Omniflo Weiche" + (strcat "OFWeiche :" (itoa cnt-weichen)) merkmale) + lines)) + ) + + ((= typ "gerade") + (setq elem-nr (1+ elem-nr)) + (setq cnt-geraden (1+ cnt-geraden)) + (setq laenge-str (csv:get-attrib ename "LAENGE")) + (if (null laenge-str) (setq laenge-str (csv:get-attrib ename "A"))) + (if (and laenge-str (> (strlen laenge-str) 0)) + (setq len-ap110 (+ len-ap110 (atof laenge-str))) + (setq len-ap110 (+ len-ap110 2000.0)) + ) + (setq merkmale (csv:omni-gerade-merkmale ename rotation)) + (setq lines (cons + (csv:omni-csv-line elem-nr "Omniflo Gerade" + (strcat "OFGerade :" (itoa cnt-geraden)) merkmale) + lines)) + ) + ) + + (setq i (1+ i)) + ) + + (princ (strcat "\n[OMNI_EXPORT] Gefunden: " + (itoa cnt-boegen) " Boegen, " + (itoa cnt-weichen) " Weichen, " + (itoa cnt-geraden) " Geraden")) + + (if (= elem-nr 0) + (princ "\n[OMNI_EXPORT] Keine Omniflo-Elemente gefunden.") + (progn + (setq out-pfad (strcat (getenv "DXFM_RESULTS") "/omniflo_export.csv")) + (setq fh (open out-pfad "w")) + (if (null fh) + (princ (strcat "\n[OMNI_EXPORT] FEHLER: Kann Datei nicht oeffnen: " out-pfad)) + (progn + (write-line "Elementnummer;TeileArt;TeileId;Bezeichnung;Anzahl;Merkmale" fh) + (foreach ln (reverse lines) + (write-line ln fh) + ) + (write-line + (csv:omni-sum-zeile (1+ elem-nr) + cnt-boegen cnt-wk cnt-einzel cnt-delta cnt-doppel cnt-stern + len-ap110 len-ap60) + fh) + (close fh) + (princ (strcat "\n[OMNI_EXPORT] CSV geschrieben: " out-pfad)) + (princ (strcat "\n[OMNI_EXPORT] Omniflo Sum: " + (itoa cnt-boegen) " Boegen, " + (itoa (+ cnt-einzel cnt-doppel cnt-delta cnt-stern cnt-wk)) " Weichen, " + (rtos len-ap110 2 0) " mm AP110")) + ) + ) + ) + ) + ) + ) + (princ) +) + + +;; ============================================================ +;; OMNIFLO HOEHE/DREHUNG AKTUALISIEREN +;; ============================================================ + +;; --- Hoehe eines Omniflo-Blocks aus der Zeichnung ermitteln --- +;; Liest z-Koordinate des Einfuegepunkts. +;; Falls der Block KS_EIN, KS_AUS oder K1-K4 enthaelt, +;; wird die minimale Z-Koordinate dieser Unterelemente + Block-Z verwendet. +(defun omni:get-block-hoehe (ename / ed bname pt z-insert blk-tbl sub-ent sub-ed sub-bname sub-pt z-list z-min) + (setq ed (entget ename)) + (setq bname (cdr (assoc 2 ed))) + (setq pt (cdr (assoc 10 ed))) + (setq z-insert (if (caddr pt) (caddr pt) 0.0)) + (setq blk-tbl (tblsearch "BLOCK" bname)) + (if (null blk-tbl) + z-insert + (progn + (setq sub-ent (entnext (cdr (assoc -2 blk-tbl)))) + (setq z-list nil) + (while sub-ent + (setq sub-ed (entget sub-ent)) + (if (= (cdr (assoc 0 sub-ed)) "INSERT") + (progn + (setq sub-bname (strcase (cdr (assoc 2 sub-ed)))) + (if (wcmatch sub-bname "KS_EIN,KS_AUS,K1,K2,K3,K4") + (progn + (setq sub-pt (cdr (assoc 10 sub-ed))) + (setq z-list (cons (if (caddr sub-pt) (caddr sub-pt) 0.0) z-list)) + ) + ) + ) + ) + (setq sub-ent (entnext sub-ent)) + ) + (if z-list + (progn + (setq z-min (car z-list)) + (foreach z (cdr z-list) + (if (< z z-min) (setq z-min z)) + ) + (+ z-insert z-min) + ) + z-insert + ) + ) + ) +) + + +;; --- HOEHE-Attribut eines Omniflo-Blocks setzen --- +;; Liest Z-Koordinate (ggf. aus KS-Unterblock) und schreibt als HOEHE-Attribut. +(defun omni:set-hoehe-attrib (ename / hoehe) + (setq hoehe (omni:get-block-hoehe ename)) + (ssg-attrib-set-on ename (list (cons "HOEHE" (rtos hoehe 2 1)))) + hoehe +) + + +;; --- DREHUNG-Attribut eines Omniflo-Blocks setzen --- +;; Liest CAD-Rotationswinkel (Gruppe 50, Bogenmass) und schreibt als DREHUNG-Attribut. +(defun omni:set-drehung-attrib (ename / ed rotation deg) + (setq ed (entget ename)) + (setq rotation (cdr (assoc 50 ed))) + (if (null rotation) (setq rotation 0.0)) + (setq deg (* (/ rotation pi) 180.0)) + (ssg-attrib-set-on ename (list (cons "DREHUNG" (rtos deg 2 1)))) + deg +) + + +;; ============================================================ +;; C:OMNI_UPDATE_ATTRIBS - HOEHE und DREHUNG aller Omniflo-Elemente aktualisieren +;; Setzt HOEHE aus Z-Koordinate (bzw. min. KS-Sub-Block) und +;; DREHUNG aus CAD-Rotationswinkel fuer alle Bloecke mit TEILEART-Attribut. +;; ============================================================ +(defun c:OMNI_UPDATE_ATTRIBS ( / ss i ename ed bname teileart count) + (setq ss (ssget "X" (list (cons 0 "INSERT")))) + (if (null ss) + (princ "\n[OMNI_UPDATE] Keine INSERT-Bloecke in der Zeichnung.") + (progn + (setq count 0) + (setq i 0) + (while (setq ename (ssname ss i)) + (setq ed (entget ename)) + (setq bname (cdr (assoc 2 ed))) + ;; Nur Omniflo-Elemente (erkennbar an TEILEART-Attribut oder AP110-Blockname) + (setq teileart (csv:get-attrib ename "TEILEART")) + (if (or teileart + (wcmatch (strcase bname) "AP110*,AP_110*")) + (progn + (omni:set-hoehe-attrib ename) + (omni:set-drehung-attrib ename) + (setq count (1+ count)) + ) + ) + (setq i (1+ i)) + ) + (princ (strcat "\n[OMNI_UPDATE] " (itoa count) " Elemente aktualisiert (HOEHE, DREHUNG).")) + ) + ) + (princ) +) diff --git a/Lisp/tests.lsp b/Lisp/tests.lsp index 8fce396..1b88e8e 100644 --- a/Lisp/tests.lsp +++ b/Lisp/tests.lsp @@ -1,5 +1,7 @@ ;; ============================================================ ;; tests.lsp - Test- und Hilfsfunktionen +;; +;; Export-Funktionen wurden nach export.lsp ausgelagert. ;; ============================================================ (defun c:CALLPYTHON ( / log-pfad py-skript return-datei cmd fh zeile) @@ -25,446 +27,6 @@ (princ) ) -;; ============================================================ -;; EXPORT - Relevante INSERT-Entities sammeln und als JSON exportieren -;; Anschliessend Python-Skript aufrufen fuer CSV-Erzeugung -;; ============================================================ - -;; --- String fuer JSON escapen (Anfuehrungszeichen/Backslash) --- -;; Nutzt vl-string-subst fuer die haeufigsten Faelle statt -;; zeichenweiser Verkettung (deutlich schneller bei langen Strings). -(defun csv:json-escape (s) - (setq s (vl-string-subst "\\\\" "\\" s)) - (vl-string-subst "\\\"" "\"" s) -) - -;; --- Attribute eines INSERT-Blocks als JSON-Objekt lesen --- -;; ename = Entity-Name des INSERT -;; Rueckgabe: String wie {"TAG1":"Wert1","TAG2":"Wert2"} -(defun csv:read-attribs (ename / obj ed typ tag wert parts) - (setq obj (entnext ename)) - (setq parts nil) - (while obj - (setq ed (entget obj)) - (setq typ (cdr (assoc 0 ed))) - (if (equal typ "SEQEND") (setq obj nil) - (progn - (if (equal typ "ATTRIB") - (setq parts (cons (strcat "\"" (csv:json-escape (cdr (assoc 2 ed))) - "\":\"" (csv:json-escape (cdr (assoc 1 ed))) "\"") - parts)) - ) - (setq obj (entnext obj)) - ) - ) - ) - (if parts - (progn - (setq parts (reverse parts)) - (strcat "{" (car parts) - (apply 'strcat (mapcar '(lambda (p) (strcat "," p)) (cdr parts))) - "}") - ) - "{}" - ) -) - -;; --- Einen INSERT-Block als JSON-Objekt schreiben --- -(defun csv:block-to-json (ename / ed blk-name layer pt rotation handle attribs) - (setq ed (entget ename)) - (setq blk-name (cdr (assoc 2 ed))) - (setq layer (cdr (assoc 8 ed))) - (setq pt (cdr (assoc 10 ed))) - (setq rotation (cdr (assoc 50 ed))) - (setq handle (cdr (assoc 5 ed))) - (if (null rotation) (setq rotation 0.0)) - (if (cdr (assoc 66 ed)) - (setq attribs (csv:read-attribs ename)) - (setq attribs "{}") - ) - (strcat - " {\"block_name\":\"" (csv:json-escape blk-name) "\"" - ",\"layer\":\"" (csv:json-escape layer) "\"" - ",\"handle\":\"" (csv:json-escape handle) "\"" - ",\"x\":" (rtos (car pt) 2 4) - ",\"y\":" (rtos (cadr pt) 2 4) - ",\"z\":" (rtos (if (caddr pt) (caddr pt) 0.0) 2 4) - ",\"rotation\":" (rtos (* (/ rotation pi) 180.0) 2 4) - ",\"attribs\":" attribs - "}" - ) -) - -;; --- Relevante Bloecke sammeln --- -;; Filtert INSERT-Entities auf exportierbare Bloecke: -;; KR_* = Kreisel Compound-Bloecke -;; AP110* = Omniflo Geraden -;; Omniflo Boegen/Weichen = rein numerische Blocknamen (SivasNr) -;; Vario* = VarioFoerderer-Bloecke -;; Gibt Auswahlsatz zurueck oder nil. -(defun csv:collect-export-blocks ( / ss-all ss-out i ename ed bname) - (setq ss-all (ssget "X" (list (cons 0 "INSERT")))) - (if (null ss-all) (setq ss-out nil) - (progn - (setq ss-out (ssadd)) - (setq i 0) - (while (setq ename (ssname ss-all i)) - (setq ed (entget ename)) - (setq bname (cdr (assoc 2 ed))) - (if (or - (wcmatch bname "KR_*,KREISEL_*,ECKRAD_*") - (wcmatch (strcase bname) "AP110*,AP_110*") - (wcmatch bname "Vario*,Staustrecke*,AUS_Element*,EIN_Element*") - ;; Rein numerische Namen = Omniflo SivasNr (Boegen/Weichen) - (wcmatch bname "#*") - ) - (ssadd ename ss-out) - ) - (setq i (1+ i)) - ) - (if (= (sslength ss-out) 0) (setq ss-out nil)) - ) - ) - ss-out -) - -;; --- Gemeinsame Export-Funktion --- -;; Sammelt relevante Bloecke, schreibt JSON, ruft Python auf. -;; label = Anzeigename (z.B. "EXPORTCSV") -;; py-name = Python-Skript-Name (z.B. "export_csv.py") -;; csv-name = Ergebnis-CSV-Name (z.B. "export.csv") -(defun csv:run-export (label py-name csv-name / ss i ename fh out-pfad - py-skript ergebnis-pfad cmd first-block count) - (princ (strcat "\n[" label "] Sammle relevante Bloecke...")) - - (setq ss (csv:collect-export-blocks)) - (if (null ss) - (progn - (princ (strcat "\n[" label "] Keine relevanten Bloecke gefunden.")) - (princ) - ) - (progn - (setq count (sslength ss)) - (princ (strcat "\n[" label "] " (itoa count) " Bloecke gefunden.")) - - ;; JSON-Datei zusammenbauen - (setq out-pfad (strcat (getenv "DXFM_RESULTS") "/export_raw.json")) - (setq fh (open out-pfad "w")) - (if (null fh) - (progn - (princ (strcat "\n[" label "] FEHLER: Kann Datei nicht oeffnen: " out-pfad)) - (princ) - ) - (progn - (write-line "[" fh) - (setq i 0) - (setq first-block T) - (while (setq ename (ssname ss i)) - (if (not first-block) - (write-line "," fh) - ) - (write-line (csv:block-to-json ename) fh) - (setq first-block nil) - (setq i (1+ i)) - ) - (write-line "]" fh) - (close fh) - (princ (strcat "\n[" label "] JSON geschrieben: " out-pfad)) - - ;; Python-Skript aufrufen - (setq py-skript (strcat (getenv "DXFM_LIB") "/" py-name)) - (if (findfile py-skript) - (progn - (setq ergebnis-pfad (strcat (getenv "DXFM_RESULTS") "/" csv-name)) - (setq cmd (strcat "python \"" py-skript "\"" - " \"" out-pfad "\"" - " \"" (getenv "DXFM_DATA") "\"" - " \"" ergebnis-pfad "\"")) - (princ (strcat "\n[" label "] Rufe Python auf...")) - (startapp "cmd" (strcat "/c " cmd)) - (princ (strcat "\n[" label "] Export gestartet: " ergebnis-pfad)) - ) - (princ (strcat "\n[" label "] FEHLER: Python-Skript nicht gefunden: " py-skript)) - ) - ) - ) - ) - ) - (princ) -) - -;; --- EXPORTSIVAS: Sivas-spezifischer CSV-Export mit Summierungszeilen --- -(defun c:EXPORTSIVAS () - (csv:run-export "EXPORTSIVAS" "export_sivas.py" "export_sivas.csv") -) - -;; --- EXPORTCSV: Einfache Item-Liste aller Bloecke (ohne Summierung) --- -(defun c:EXPORTCSV () - (csv:run-export "EXPORTCSV" "export_csv.py" "export.csv") -) - -;; ============================================================ -;; Omniflo-Elemente zaehlen und CSV-Export (rein LISP, ohne Python) -;; -;; Erkennt Omniflo Bloecke anhand Attribute: -;; TEILEART = "Omniflo Kurve" -> Bogen -;; TEILEART = "Omniflo Weiche" -> Weiche -;; Blockname AP110* -> Gerade -;; ============================================================ - -;; --- Attribut-Wert eines INSERT-Blocks nach Tag lesen --- -(defun csv:get-attrib (ename tag / obj ed typ atag) - (setq obj (entnext ename)) - (while obj - (setq ed (entget obj)) - (setq typ (cdr (assoc 0 ed))) - (if (equal typ "SEQEND") - (setq obj nil) - (progn - (if (and (equal typ "ATTRIB") - (= (strcase (cdr (assoc 2 ed))) (strcase tag))) - (progn (setq obj nil) (setq atag (cdr (assoc 1 ed)))) - (setq obj (entnext obj)) - ) - ) - ) - ) - atag -) - -;; --- Omniflo-Block klassifizieren --- -;; Gibt "bogen", "weiche", "gerade" oder nil zurueck -(defun csv:omni-classify (ename bname / teileart) - (setq teileart (csv:get-attrib ename "TEILEART")) - (cond - ((and teileart (= teileart "Omniflo Kurve")) "bogen") - ((and teileart (= teileart "Omniflo Weiche")) "weiche") - ((wcmatch (strcase bname) "AP110*,AP_110*") "gerade") - (t nil) - ) -) - -;; --- Weichen-Subtyp fuer Omniflo Sum Zaehlung bestimmen --- -;; Gibt "einzelweiche", "doppelweiche", "dreiwegeweiche", -;; "deltaweiche", "sternweiche" oder "weichenkoerper" zurueck -(defun csv:omni-weichensubtyp (ename / wtyp beschr) - (setq wtyp (csv:get-attrib ename "WEICHENTYP")) - (setq beschr (csv:get-attrib ename "BESCHR")) - (if (null wtyp) (setq wtyp "")) - (if (null beschr) (setq beschr "")) - (cond - ((vl-string-search "WEICHENK" (strcase beschr)) "weichenkoerper") - ((= wtyp "Einzelweiche") "einzelweiche") - ((= wtyp "Doppelweiche") "doppelweiche") - ((= wtyp "Dreiwegeweiche") "dreiwegeweiche") - ((= wtyp "Deltaweiche") "deltaweiche") - ((= wtyp "Dreifachweiche") "deltaweiche") - ((= wtyp "Sternweiche") "sternweiche") - ((vl-string-search "DELTA" (strcase beschr)) "deltaweiche") - ((vl-string-search "STAR" (strcase beschr)) "sternweiche") - (t "einzelweiche") - ) -) - -;; --- Merkmale-JSON fuer einen Bogen bauen --- -(defun csv:omni-bogen-merkmale (ename rotation / winkel radius sivasnr) - (setq winkel (if (csv:get-attrib ename "WINKEL") (csv:get-attrib ename "WINKEL") "0")) - (setq radius (if (csv:get-attrib ename "RADIUS") (csv:get-attrib ename "RADIUS") "0")) - (setq sivasnr (if (csv:get-attrib ename "ARTINR") (csv:get-attrib ename "ARTINR") "")) - (strcat "{\"L\\u00e4nge in Meter\":\"0\"" - ",\"Kurvenwinkel\":" winkel - ",\"Radius\":" radius - ",\"H\\u00f6he\":\"2000\"" - ",\"Drehung\":" (rtos rotation 2 1) - ",\"SivasNummer\":\"" (csv:json-escape sivasnr) "\"}") -) - -;; --- Merkmale-JSON fuer eine Weiche bauen --- -(defun csv:omni-weiche-merkmale (ename rotation / wtyp winkel sivasnr tef-str) - (setq wtyp (if (csv:get-attrib ename "WEICHENTYP") (csv:get-attrib ename "WEICHENTYP") "Einzelweiche")) - (setq winkel (if (csv:get-attrib ename "WINKEL") (csv:get-attrib ename "WINKEL") "0")) - (setq sivasnr (if (csv:get-attrib ename "ARTINR") (csv:get-attrib ename "ARTINR") "")) - (setq tef-str (csv:get-attrib ename "SIVASNR_TEF")) - (strcat "{\"L\\u00e4nge in Meter links\":null" - ",\"L\\u00e4nge in Meter rechts\":null" - ",\"L\\u00e4nge in Meter gerade\":null" - ",\"Weichentyp\":\"" (csv:json-escape wtyp) "\"" - ",\"Richtung\":\"False\"" - ",\"Weichenwinkel\":" winkel - ",\"H\\u00f6he\":\"2000\"" - ",\"Drehung\":" (rtos rotation 2 1) - ",\"Antrieb Kurve\":" (if (and tef-str (> (strlen tef-str) 0)) "true" "false") - ",\"SivasNummer\":\"" (csv:json-escape sivasnr) "\"}") -) - -;; --- Merkmale-JSON fuer eine Gerade bauen --- -(defun csv:omni-gerade-merkmale (ename rotation / laenge) - (setq laenge (csv:get-attrib ename "LAENGE")) - (if (null laenge) (setq laenge (csv:get-attrib ename "A"))) - (if (null laenge) (setq laenge "2000")) - (strcat "{\"Anzahl der Separatoren\":\"0\"" - ",\"L\\u00e4nge in Meter\":\"" (csv:json-escape (rtos (/ (atof laenge) 1000.0) 2 2)) "\"" - ",\"Winkel\":\"0\"" - ",\"Anzahl der Scanner\":0" - ",\"H\\u00f6he oben\":\"2000\"" - ",\"H\\u00f6he unten\":\"2000\"" - ",\"Drehung\":" (rtos rotation 2 1) - ",\"SivasNummer\":\"\"}") -) - -;; --- Omniflo Sum Zeile bauen --- -(defun csv:omni-sum-zeile (elem-nr cnt-boegen cnt-wk cnt-einzel cnt-delta cnt-doppel cnt-stern len-ap110 len-ap60) - (strcat (itoa elem-nr) - ";\"Omniflo Sum\";\"autogenerated_of_json\";\"Omniflo sum\";1;" - "{\"Anzahl B\\u00f6gen\":" (itoa cnt-boegen) - ",\"Anzahl Weichengrundk\\u00f6rper\":" (itoa cnt-wk) - ",\"Anzahl Einwegweichen\":" (itoa cnt-einzel) - ",\"Anzahl Deltaweichen\":" (itoa cnt-delta) - ",\"Anzahl Doppelweichen und Dreiwegeweichen\":" (itoa cnt-doppel) - ",\"Anzahl Sternweichen\":" (itoa cnt-stern) - ",\"Gesamtl\\u00e4nge AP110\":" (rtos len-ap110 2 1) - ",\"Gesamtl\\u00e4nge AP60\":" (rtos len-ap60 2 1) - "}") -) - -;; --- CSV-Zeile fuer ein Omniflo-Element bauen --- -(defun csv:omni-csv-line (elem-nr teileart bezeichnung merkmale-json) - (strcat (itoa elem-nr) - ";\"" teileart "\"" - ";\"shape_" (substr (rtos (* (getvar "CDATE") 1000000.0) 2 0) 1 8) - (substr (rtos (* (getvar "TDUSRTIMER") 1000000.0) 2 0) 1 8) "\"" - ";\"" bezeichnung "\"" - ";1" - ";" merkmale-json) -) - -;; ============================================================ -;; C:OMNI_EXPORT - Omniflo-Elemente zaehlen und als CSV exportieren -;; Rein LISP-basiert, kein Python noetig. -;; ============================================================ -(defun c:OMNI_EXPORT ( / ss-all i ename ed bname rotation typ - elem-nr cnt-boegen cnt-weichen cnt-geraden - cnt-wk cnt-einzel cnt-delta cnt-doppel cnt-stern - len-ap110 len-ap60 laenge-str - fh out-pfad lines subtyp merkmale) - - (princ "\n[OMNI_EXPORT] Sammle Omniflo-Elemente...") - (setq ss-all (ssget "X" (list (cons 0 "INSERT")))) - (if (null ss-all) - (progn (princ "\n[OMNI_EXPORT] Keine INSERT-Bloecke in der Zeichnung.") (princ)) - (progn - ;; Zaehler initialisieren - (setq elem-nr 0) - (setq cnt-boegen 0 cnt-weichen 0 cnt-geraden 0) - (setq cnt-wk 0 cnt-einzel 0 cnt-delta 0 cnt-doppel 0 cnt-stern 0) - (setq len-ap110 0.0 len-ap60 0.0) - (setq lines '()) - - ;; Alle INSERT-Entities durchgehen - (setq i 0) - (while (setq ename (ssname ss-all i)) - (setq ed (entget ename)) - (setq bname (cdr (assoc 2 ed))) - (setq rotation (cdr (assoc 50 ed))) - (if (null rotation) (setq rotation 0.0)) - (setq rotation (* (/ rotation pi) 180.0)) - - (setq typ (csv:omni-classify ename bname)) - - (cond - ;; --- Bogen --- - ((= typ "bogen") - (setq elem-nr (1+ elem-nr)) - (setq cnt-boegen (1+ cnt-boegen)) - (setq merkmale (csv:omni-bogen-merkmale ename rotation)) - (setq lines (cons - (csv:omni-csv-line elem-nr "Omniflo Kurve" - (strcat "OFBogen :" (itoa cnt-boegen)) merkmale) - lines)) - ) - - ;; --- Weiche --- - ((= typ "weiche") - (setq elem-nr (1+ elem-nr)) - (setq cnt-weichen (1+ cnt-weichen)) - (setq subtyp (csv:omni-weichensubtyp ename)) - (cond - ((= subtyp "weichenkoerper") (setq cnt-wk (1+ cnt-wk))) - ((= subtyp "einzelweiche") (setq cnt-einzel (1+ cnt-einzel))) - ((= subtyp "deltaweiche") (setq cnt-delta (1+ cnt-delta))) - ((= subtyp "sternweiche") (setq cnt-stern (1+ cnt-stern))) - (t (setq cnt-doppel (1+ cnt-doppel))) - ) - (setq merkmale (csv:omni-weiche-merkmale ename rotation)) - (setq lines (cons - (csv:omni-csv-line elem-nr "Omniflo Weiche" - (strcat "OFWeiche :" (itoa cnt-weichen)) merkmale) - lines)) - ) - - ;; --- Gerade (AP110) --- - ((= typ "gerade") - (setq elem-nr (1+ elem-nr)) - (setq cnt-geraden (1+ cnt-geraden)) - (setq laenge-str (csv:get-attrib ename "LAENGE")) - (if (null laenge-str) (setq laenge-str (csv:get-attrib ename "A"))) - (if (and laenge-str (> (strlen laenge-str) 0)) - (setq len-ap110 (+ len-ap110 (atof laenge-str))) - (setq len-ap110 (+ len-ap110 2000.0)) - ) - (setq merkmale (csv:omni-gerade-merkmale ename rotation)) - (setq lines (cons - (csv:omni-csv-line elem-nr "Omniflo Gerade" - (strcat "OFGerade :" (itoa cnt-geraden)) merkmale) - lines)) - ) - ) ;; cond - - (setq i (1+ i)) - ) ;; while - - ;; Ergebnis ausgeben - (princ (strcat "\n[OMNI_EXPORT] Gefunden: " - (itoa cnt-boegen) " Boegen, " - (itoa cnt-weichen) " Weichen, " - (itoa cnt-geraden) " Geraden")) - - (if (= elem-nr 0) - (princ "\n[OMNI_EXPORT] Keine Omniflo-Elemente gefunden.") - (progn - ;; CSV schreiben - (setq out-pfad (strcat (getenv "DXFM_RESULTS") "/omniflo_export.csv")) - (setq fh (open out-pfad "w")) - (if (null fh) - (princ (strcat "\n[OMNI_EXPORT] FEHLER: Kann Datei nicht oeffnen: " out-pfad)) - (progn - ;; Header - (write-line "Elementnummer;TeileArt;TeileId;Bezeichnung;Anzahl;Merkmale" fh) - ;; Einzelzeilen (lines ist rueckwaerts aufgebaut) - (foreach ln (reverse lines) - (write-line ln fh) - ) - ;; Omniflo Sum Zeile - (write-line - (csv:omni-sum-zeile (1+ elem-nr) - cnt-boegen cnt-wk cnt-einzel cnt-delta cnt-doppel cnt-stern - len-ap110 len-ap60) - fh) - (close fh) - (princ (strcat "\n[OMNI_EXPORT] CSV geschrieben: " out-pfad)) - (princ (strcat "\n[OMNI_EXPORT] Omniflo Sum: " - (itoa cnt-boegen) " Boegen, " - (itoa (+ cnt-einzel cnt-doppel cnt-delta cnt-stern cnt-wk)) " Weichen, " - (rtos len-ap110 2 0) " mm AP110")) - ) - ) - ) - ) - ) - ) - (princ) -) - ;; ============================================================ ;; TEST_FOERDERER - Automatischer Test ohne Benutzereingabe ;; Erzeugt 12 Variofoerderer (6x Auf, 6x Ab) mit deltaL=7000