;; ============================================================ ;; 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) --- ;; Konvertiert nicht-String-Werte (z.B. T, nil, Zahlen) defensiv in String. (defun csv:json-escape (s) (if (not (= (type s) 'STR)) (setq s (if s (vl-princ-to-string 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 ) ;; --- HOEHE/DREHUNG aller Omniflo-Elemente still aktualisieren --- ;; Wird automatisch vor jedem Export aufgerufen. (defun omni:update-all-attribs ( / ss i ename ed bname teileart) (setq ss (ssget "X" (list (cons 0 "INSERT")))) (if ss (progn (setq i 0) (while (setq ename (ssname ss i)) (setq ed (entget ename)) (setq bname (cdr (assoc 2 ed))) (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 i (1+ i)) ) ) ) ) ;; --- 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) ;; Vor dem Export: IDs aller Bloecke sicherstellen und Duplikate korrigieren (princ (strcat "\n[" label "] Pruefe und vergebe IDs...")) (ssg-id-check-all) ;; Vor dem Export HOEHE/DREHUNG aller Omniflo-Elemente aktualisieren (princ (strcat "\n[" label "] Aktualisiere Hoehe/Drehung...")) (omni:update-all-attribs) (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") (ssg-cfg-or "omniflo" "default_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") (ssg-cfg-or "omniflo" "default_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 (ssg-cfg-or "omniflo" "default_gerade_laenge" "2000"))) (setq hoehe (or (csv:get-attrib ename "HOEHE") (ssg-cfg-or "omniflo" "default_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) (ssg-cfg-or "infrastruktur" "mm_pro_meter" 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) "}") ) ;; ============================================================ ;; 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) ;; Vor dem Export: IDs aller Bloecke sicherstellen und Duplikate korrigieren (princ "\n[OMNI_EXPORT] Pruefe und vergebe IDs...") (ssg-id-check-all) ;; Vor dem Export HOEHE/DREHUNG aller Omniflo-Elemente aktualisieren (princ "\n[OMNI_EXPORT] Aktualisiere Hoehe/Drehung...") (omni:update-all-attribs) (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 (strcat (itoa elem-nr) ";\"Omniflo Kurve\"" ";\"" (or (csv:get-attrib ename "ID") "0000") "\"" ";\"" (strcat "OFBogen :" (itoa cnt-boegen)) "\"" ";1" ";" 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 (strcat (itoa elem-nr) ";\"Omniflo Weiche\"" ";\"" (or (csv:get-attrib ename "ID") "0000") "\"" ";\"" (strcat "OFWeiche :" (itoa cnt-weichen)) "\"" ";1" ";" 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 (float (atoi (ssg-cfg-or "omniflo" "default_gerade_laenge" "2000"))))) ) (setq merkmale (csv:omni-gerade-merkmale ename rotation)) (setq lines (cons (strcat (itoa elem-nr) ";\"Omniflo Gerade\"" ";\"" (or (csv:get-attrib ename "ID") "0000") "\"" ";\"" (strcat "OFGerade :" (itoa cnt-geraden)) "\"" ";1" ";" 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) )