diff --git a/Lisp/KreiselInsert.lsp b/Lisp/KreiselInsert.lsp new file mode 100644 index 0000000..ab57c29 --- /dev/null +++ b/Lisp/KreiselInsert.lsp @@ -0,0 +1,1197 @@ +;; KreiselInsert.lsp +;; Kreisel Modul-Einfuegesystem mit Compound-Block + Attribute +;; Version: 6.0 (Attribute, Redraw, 2-Linien-Connect) +;; Setzt ssg_core.lsp voraus. +;; ============================================ + +;; ============================================================ +;; TEIL 1: GLOBALE EINSTELLUNGEN +;; ============================================================ + +;; Zähler für Nummerierung (werden in Zeichnung gespeichert) +(if (null #Kreisel_LetzteNr) + (setq #Kreisel_LetzteNr 0) +) +(if (null #Eckrad_LetzteNr) + (setq #Eckrad_LetzteNr 0) +) + +;; Block-Pfad +(setq block-pfad (getenv "DXFM_BLOCKS")) + +(if (or (null block-pfad) (= block-pfad "")) + (progn + (setq block-pfad "C:/Users/y.wang/Documents/dxfmakros/Blocks/") + (alert (strcat "Umgebungsvariable DXFM_BLOCKS nicht gefunden.\nNutze Standardpfad: " block-pfad)) + ) + (setq block-pfad (strcat (vl-string-right-trim "/" (vl-string-translate "\\" "/" block-pfad)) "/")) +) + +(setq *block-path* block-pfad) +(princ (strcat "\nBlock-Pfad aktiv: " block-pfad)) + +;; Kreisel-Geometrie-Konstanten +(setq *kreisel-durchmesser* 800.0) ;; Kreisdurchmesser AN8/SP8 +(setq *kreisel-pin-abstand* 100.0) ;; Einrueckung PIN-Linie vom Kreisrand +(setq *kreisel-default-laenge* 2300.0) ;; Standard-Tangentenlaenge +(setq *kreisel-default-hoehe* 2000.0) ;; Standard-Höhe (Z-Koordinate) + +;; Attribut-Definitionen: ((TAG DEFAULT) ...) +(setq *kreisel-attrib-defs* + '(("NAME" "") + ("DREHRICHTUNG" "UZS") + ("N_SEPARATOREN" "2") + ("KREISELART" "STANDARD") + ("N_SCANNER" "0") + ("N_RAMPEN" "0") + ("DREHUNG" "0") + ("ABSTAND" "2300") + ("NUMMER" "0") + ("HOEHE" "0")) +) + +;; Eckrad-Einstellungen +(setq *eckrad-default-hoehe* 2000.0) ;; Standard-Höhe (Z-Koordinate) + +;; Eckrad Attribut-Definitionen: ((TAG DEFAULT) ...) +(setq *eckrad-attrib-defs* + '(("NAME" "") + ("DREHRICHTUNG" "UZS") + ("DREHUNG" "0") + ("NUMMER" "0") + ("HOEHE" "0")) +) + +;; Letzter gewaehlter Typ (gespeichert zwischen Aufrufen) +(if (null #Kreisel_Typ) (setq #Kreisel_Typ "STANDARD")) + +;; Beschriftungs-Einstellungen (NUR EINMAL definieren!) +(setq *kreisel-beschriftung-layer* "S_KRS_BESCHR") +(setq *kreisel-beschriftung-hoehe* 100.0) ;; Texthöhe in mm +(setq *kreisel-beschriftung-farbe* 7) ;; 7 = weiß +(setq *kreisel-beschriftung-abstand-oben* 0.0) ;; Abstand über Kreisel-Mitte +(setq *kreisel-beschriftung-schriftart* "Arial") ;; Schriftart + + +;; ============================================================ +;; TEIL 2: HILFSFUNKTIONEN +;; ============================================================ + +;; Funktion zum Erstellen/Setzen der Schriftart Arial +(defun kreisel-setup-textstyle ( / style-name) + (setq style-name "Kreisel_Arial") + + ;; Prüfen ob der Textstil bereits existiert + (if (not (tblsearch "STYLE" style-name)) + (progn + ;; Neuen Textstil mit Arial erstellen + (command "_.STYLE" style-name "Arial" 0 1 0 "N" "N" "N") + (princ (strcat "\n-> Textstil '" style-name "' mit Arial erstellt")) + ) + ) + + ;; Aktuellen Textstil setzen + (setvar "TEXTSTYLE" style-name) + style-name +) + +;; Allgemeine Nummerierung: Naechste freie Nummer fuer einen Komponententyp ermitteln +;; blockprefix = Blockname-Praefix fuer ssget (z.B. "KREISEL_*" oder "ECKRAD_*") +;; lastNrVar = Symbol der globalen Zaehler-Variable (z.B. '#Kreisel_LetzteNr) +;; Rueckgabe: naechste freie Nummer (integer) +(defun component-next-number (blockprefix lastNrVar / maxNr tag val ss i ent attribs lastNr result) + (dbgf "component-next-number") + (dbg 'blockprefix) + (dbg 'lastNrVar) + (setq maxNr 0) + (setq lastNr (eval lastNrVar)) + (dbgp (strcat "lastNr=" (itoa lastNr))) + (if (setq ss (ssget "_X" (list '(0 . "INSERT") (cons 2 blockprefix)))) + (progn + (dbgp (strcat "Gefundene Bloecke: " (itoa (sslength ss)))) + (setq i 0) + (repeat (sslength ss) + (setq ent (ssname ss i)) + (setq attribs (ssg-attrib-read ent)) + (setq tag (cdr (assoc "NUMMER" attribs))) + (if (and tag (setq val (atoi tag)) (> val maxNr)) + (setq maxNr val) + ) + (setq i (1+ i)) + ) + ) + (dbgp "Keine bestehenden Bloecke gefunden") + ) + (if (= maxNr 0) + (setq maxNr lastNr) + ) + (set lastNrVar (1+ maxNr)) + (setq result (eval lastNrVar)) + (dbgp (strcat "Naechste Nummer: " (itoa result))) + (dbgreturn result) +) + +;; Wrapper: Naechste Kreisel-Nummer +(defun kreisel-next-number ( / result) + (dbgf "kreisel-next-number") + (setq result (component-next-number "KREISEL_*" '#Kreisel_LetzteNr)) + (dbgreturn result) +) + +;; Wrapper: Naechste Eckrad-Nummer +(defun eckrad-next-number ( / result) + (dbgf "eckrad-next-number") + (setq result (component-next-number "ECKRAD_*" '#Eckrad_LetzteNr)) + (dbgreturn result) +) + +;; Beschriftungstext erzeugen +(defun kreisel-make-label (nummer abstand kreiselart / textStr insertPoint radius mitteX mitteY textHoehe) + ;; Text: "KREISEL 1: PIN_4000" + (setq textStr (strcat "KREISEL " (itoa nummer) ": " kreiselart "_" (rtos abstand 2 0))) + + ;; Geometrie berechnen + (setq radius (/ *kreisel-durchmesser* 2.0)) + + ;; Mitte zwischen AN8 und SP8 (X-Mitte des gesamten Kreisels) + (setq mitteX (+ radius (/ abstand 2.0))) + + ;; Y-Position: Leicht über der mitteX + (setq mitteY *kreisel-beschriftung-abstand-oben*) + + ;; Texthöhe + (setq textHoehe *kreisel-beschriftung-hoehe*) ;; 100 mm + + ;; Position + (setq insertPoint (list mitteX mitteY 0)) + + ;; Schriftart Arial einstellen + (kreisel-setup-textstyle) + + ;; Layer erstellen + (ssg-make-layer *kreisel-beschriftung-layer* (itoa *kreisel-beschriftung-farbe*) T) + + ;; Text mit entmake erstellen (zentriert) + (entmake (list + '(0 . "TEXT") + (cons 8 *kreisel-beschriftung-layer*) + (cons 10 insertPoint) + (cons 40 textHoehe) + (cons 1 textStr) + (cons 50 0.0) + (cons 7 "Kreisel_Arial") ;; Arial Textstil + (cons 62 *kreisel-beschriftung-farbe*) + '(72 . 1) ;; Horizontale Ausrichtung: Mitte + '(73 . 2) ;; Vertikale Ausrichtung: Mitte + (cons 11 insertPoint) ;; Ausrichtungspunkt + )) + + (princ (strcat "\n-> Beschriftung: " textStr " (Höhe=" (rtos textHoehe 2 0) "mm, Arial, zentriert)")) + textStr +) + +;; ... Rest Ihrer Funktionen (kreisel-ask-typ, kreisel-project-point, etc.) + +;; Kreiselart abfragen. Rueckgabe: "PIN" oder "STANDARD" +(defun kreisel-ask-typ ( / typNum typ) + (princ "\n[1] STANDARD (ohne PIN)") + (princ "\n[2] PIN") + (princ (strcat "\nBitte waehlen <" (if (= #Kreisel_Typ "PIN") "2" "1") ">: ")) + (setq typNum (getstring "")) + (cond + ((= typNum "2") (setq typ "PIN")) + (t (setq typ "STANDARD")) + ) + (setq #Kreisel_Typ typ) + typ +) + +;; Punkt auf Gerade projizieren (Fusspunkt der Senkrechten) +(defun kreisel-project-point (pt lstart lend / dx dy tval) + (setq dx (- (car lend) (car lstart)) + dy (- (cadr lend) (cadr lstart))) + (setq tval (/ (+ (* (- (car pt) (car lstart)) dx) + (* (- (cadr pt) (cadr lstart)) dy)) + (+ (* dx dx) (* dy dy)))) + (list (+ (car lstart) (* tval dx)) + (+ (cadr lstart) (* tval dy))) +) + +;; Linien-Endpunkte aus LINE-Entity lesen. Rueckgabe: ((sx sy sz) (ex ey ez)) +(defun kreisel-get-line-pts (ent / ed p10 p11) + (setq ed (entget ent)) + (setq p10 (cdr (assoc 10 ed)) + p11 (cdr (assoc 11 ed))) + (list p10 p11) +) + +;; Pruefen ob zwei Richtungsvektoren parallel sind +(defun kreisel-parallel-p (d1 d2 / cross len1 len2) + (setq cross (abs (- (* (car d1) (cadr d2)) (* (cadr d1) (car d2)))) + len1 (sqrt (+ (* (car d1) (car d1)) (* (cadr d1) (cadr d1)))) + len2 (sqrt (+ (* (car d2) (car d2)) (* (cadr d2) (cadr d2))))) + (< (/ cross (* len1 len2)) 0.01) +) + + +;; Attribut-Funktionen: ssg-attrib-read, ssg-attrib-merge, +;; ssg-attrib-defaults, ssg-attrib-make-defs aus ssg_core.lsp + + +;; ============================================================ +;; TEIL 3: COMPOUND BLOCK ERZEUGEN UND EINFUEGEN +;; ============================================================ + +;; Zeichnet Kreisel-Geometrie bei (0,0), erzeugt Block mit Attributen, +;; fuegt ihn ein und setzt Attribut-Werte. +;; +;; basePoint = Einfuegepunkt (2D-Liste), AN-Seite +;; abstand = Tangentenlaenge zwischen Kreismitten +;; rotation = Einfuegewinkel in Grad (0=rechts, 90=oben, 180=links, 270=unten) +;; attribs = alist mit Attribut-Ueberschreibungen (nil = alles Defaults) +;; ABSTAND und DREHUNG werden automatisch aus den Parametern gesetzt. +;; KREISELART bestimmt ob PIN-Linien gezeichnet werden. +;; +;; Blockgeometrie (bei Rotation 0, horizontal): +;; Basispunkt (0,0) = linke Kreistangente (AN-Seite) +;; AN8 Zentrum bei (radius, 0) +;; SP8 Zentrum bei (radius+abstand, 0) +;; Gesamtbreite = durchmesser + abstand +;; +;; Rueckgabe: Entity-Name des eingefuegten Blocks + +(defun draw-module (basePoint abstand rotation attribs / lastEnt ss e bname + radius pin-y is-pin + oldAttreq oldAttdia + kreisel-nummer block-exists + z-hoehe block-hoehe + insertPoint block-ent + att-entity att-data att-tag new-value + beforeAtt) + + ;; Attribute vorbereiten + (setq attribs (ssg-attrib-merge attribs *kreisel-attrib-defs*)) + (setq attribs (subst (cons "ABSTAND" (rtos abstand 2 0)) + (assoc "ABSTAND" attribs) attribs)) + (setq attribs (subst (cons "DREHUNG" (rtos rotation 2 1)) + (assoc "DREHUNG" attribs) attribs)) + (setq attribs (subst (cons "HOEHE" (rtos (if (caddr basePoint) (caddr basePoint) 0.0) 2 1)) + (assoc "HOEHE" attribs) attribs)) + (setq is-pin (equal (cdr (assoc "KREISELART" attribs)) "PIN")) + + ;; NUMMER: Bestehende beibehalten (Redraw/Edit), sonst neue vergeben + (setq kreisel-nummer (atoi (cdr (assoc "NUMMER" attribs)))) + (if (<= kreisel-nummer 0) + (progn + (setq kreisel-nummer (kreisel-next-number)) + (setq attribs (subst (cons "NUMMER" (itoa kreisel-nummer)) + (assoc "NUMMER" attribs) attribs)) + ) + ) + + ;; NAME automatisch setzen: "KreiselN" + (setq attribs (subst (cons "NAME" (strcat "Kreisel" (itoa kreisel-nummer))) + (assoc "NAME" attribs) attribs)) + + ;; --- HÖHE BESTIMMEN --- + ;; Priorität 1: Aus basePoint (wenn 3D Punkt mit Z > 0) + ;; Priorität 2: Aus Attribut HOEHE (wenn vorhanden) + ;; Priorität 3: Default 0 + (if (and basePoint (caddr basePoint) (> (caddr basePoint) 0)) + (progn + (setq z-hoehe (caddr basePoint)) + (setq block-hoehe (rtos z-hoehe 2 0)) + (princ (strcat "\n-> Höhe aus Basispunkt übernommen: " block-hoehe)) + ) + (progn + ;; Höhe aus Attributen lesen + (setq block-hoehe (cdr (assoc "HOEHE" attribs))) + (if (or (null block-hoehe) (= block-hoehe "")) + (setq block-hoehe "0") + ) + (setq z-hoehe (atof block-hoehe)) + ) + ) + + ;; Attribut HOEHE aktualisieren + (setq attribs (subst (cons "HOEHE" block-hoehe) + (assoc "HOEHE" attribs) attribs)) + + ;; Abgeleitete Masse + (setq radius (/ *kreisel-durchmesser* 2.0)) + (setq pin-y (- radius *kreisel-pin-abstand*)) + + ;; Blockname Format: KREISEL_1_PIN_2300 oder KREISEL_1_STANDARD_2300 + (setq bname (strcat "KREISEL_" + (itoa kreisel-nummer) "_" + (if is-pin "PIN" "STANDARD") "_" + (rtos abstand 2 0))) + + ;; Blocknamen bereinigen (Punkt durch nichts ersetzen, da wir keine Dezimalstellen wollen) + (setq bname (vl-string-subst "" "." bname)) + + ;; Pruefen ob Block bereits existiert + (setq block-exists (tblsearch "BLOCK" bname)) + + ;; ATTREQ/ATTDIA und OSMODE VOR Sub-Block-Insertions setzen, damit INSERT + ;; nicht nach Attributwerten fragt und OSNAP die Koordinaten nicht verschiebt + (setvar "ATTREQ" 0) + (setvar "ATTDIA" 0) + (setvar "OSMODE" 0) + + ;; --- Geometrie NUR zeichnen, wenn Block noch nicht existiert --- + (if (not block-exists) + (progn + ;; WICHTIG: Vor dem Zeichnen den aktuellen letzten Entity merken + ;; Aber wenn die Zeichnung leer ist, setzen wir lastEnt auf nil + (if (setq lastEnt (entlast)) + (progn + ;; Falls lastEnt ein INSERT mit Attributen ist, muessen wir + ;; bis zum SEQEND navigieren, da entnext sonst in die + ;; ATTRIB-Sub-Entities hineinlaeuft + (if (and (= (cdr (assoc 0 (entget lastEnt))) "INSERT") + (= (cdr (assoc 66 (entget lastEnt))) 1)) + (progn + (setq lastEnt (entnext lastEnt)) + (while (and lastEnt + (/= (cdr (assoc 0 (entget lastEnt))) "SEQEND")) + (setq lastEnt (entnext lastEnt)) + ) + ;; lastEnt ist jetzt SEQEND - entnext darauf gibt das naechste Top-Level-Entity + ) + ) + ) + (setq lastEnt nil) ;; Zeichnung ist leer + ) + + ;; AN8 Kreis (Antriebsstation) bei (radius, 0) + (command "_.INSERT" (strcat block-pfad "AN8.dwg") (list radius 0.0 0.0) 1 1 0) + + ;; SP8 Kreis (Spannstation) bei (radius+abstand, 0) + (command "_.INSERT" (strcat block-pfad "SP8.dwg") (list (+ radius abstand) 0.0 0.0) 1 1 0) + + ;; Tangenten auf Layer S_LP + (ssg-make-layer "S_LP" "7" T) + (if is-pin + (setvar "CECOLOR" "5") + (setvar "CECOLOR" "1") + ) + + ;; Obere Tangente + (command "_.LINE" (list radius radius 0) (list (+ radius abstand) radius 0) "") + ;; Untere Tangente + (command "_.LINE" (list radius (- radius) 0) (list (+ radius abstand) (- radius) 0) "") + + ;; PIN-Linien + (if is-pin + (progn + (ssg-make-layer "pinbereich" "3" T) + (setvar "CECOLOR" "3") + + ;; Obere PIN-Linie + (command "_.LINE" (list *kreisel-durchmesser* pin-y 0) (list (float abstand) pin-y 0) "") + ;; Untere PIN-Linie + (command "_.LINE" (list *kreisel-durchmesser* (- pin-y) 0) (list (float abstand) (- pin-y) 0) "") + ) + ) + + ;; BESCHRIFTUNG einfügen (vor Block-Erzeugung, damit sie im Block ist) + (kreisel-make-label kreisel-nummer abstand (if is-pin "PIN" "STANDARD") ) + + ;; Unsichtbare Attribut-Definitionen erzeugen + (ssg-attrib-make-defs *kreisel-attrib-defs* 50.0) + + ;; --- Neue Entities einsammeln --- + (setq ss (ssadd)) + + ;; Korrekte Behandlung wenn lastEnt nil ist (Zeichnung war leer) + (if (null lastEnt) + (setq e (entnext)) + (setq e (entnext lastEnt)) + ) + + (while e + (ssadd e ss) + (setq e (entnext e)) + ) + + ;; --- Block erzeugen (Entities werden aus Zeichnung entfernt) --- + (if (> (sslength ss) 0) + (command "_.-BLOCK" bname (list 0.0 0.0 0.0) ss "") + (princ "\nFehler: Keine Entities zum Block erstellen!") + ) + + (princ (strcat "\n-> Neue Blockdefinition: " bname)) + ) + (princ (strcat "\n-> Verwende bestehende Blockdefinition: " bname)) + ) + + ;; --- Block am Zielpunkt einfuegen (ohne Attribut-Dialog) --- + ;; ATTREQ/ATTDIA wurden bereits oben gesetzt + + ;; Einfügepunkt: X,Y aus basePoint, Z aus ermittelter Höhe + + (setq insertPoint (list (car basePoint) (cadr basePoint) z-hoehe)) + (command "_.INSERT" bname insertPoint 1 1 rotation) + + ;; --- Attribut-Werte durch direkte Datenbankänderung setzen --- + (setq block-ent (entlast)) + (setq att-entity (entnext block-ent)) + + (while att-entity + (setq att-data (entget att-entity)) + (if (= (cdr (assoc 0 att-data)) "ATTRIB") + (progn + (setq att-tag (cdr (assoc 2 att-data))) + (setq new-value (cdr (assoc att-tag attribs))) + (if new-value + (progn + (setq att-data (subst (cons 1 new-value) (assoc 1 att-data) att-data)) + (entmod att-data) + ) + ) + ) + ) + (setq att-entity (entnext att-entity)) + ) + (entupd block-ent) + (princ (strcat "\n-> Kreisel #" (itoa kreisel-nummer) " eingefügt: " bname + " (Höhe=" block-hoehe ")")) + (entlast) +) + + +;; ============================================================ +;; TEIL 4: BEFEHLE +;; ============================================================ + +;; -------------------------------------------- +;; KreiselInsert: Manuell Position + Parameter +;; -------------------------------------------- + +;; -------------------------------------------- +;; KreiselInsert: Manuell Position + Parameter +;; -------------------------------------------- +(defun c:KreiselInsert ( / pt abstand typ rotation rotStr hoehe + selectedEnt blockAttribs oldOsmode) + (ssg-start "Kreisel Modul einfuegen" '(("OSMODE") ("CECOLOR"))) + + ;; Temporär Osnap für Blockerkennung setzen + (setq oldOsmode (getvar "OSMODE")) + (setvar "OSMODE" (logior oldOsmode 512)) ;; 512 = INS (Block-Einfügepunkt) + + ;; 1. Einfuegepunkt + (setq pt (getpoint "\nBasispunkt (AN-Seite): ")) + (if (null pt) + (progn + (setvar "OSMODE" oldOsmode) + (ssg-end) + (princ "\nBefehl abgebrochen.") + (princ) + (return) + ) + ) + + ;; Osnap zurücksetzen auf den ursprünglichen Wert + (setvar "OSMODE" oldOsmode) + + ;; 2. Prüfen ob ein Block getroffen wurde + (setq selectedEnt (nentselp pt)) + + ;; --- HÖHE BESTIMMEN --- + (cond + ;; Fall 1: Auf einem Kreisel-Block geklickt + ((and selectedEnt + (setq selectedEnt (car selectedEnt)) + (setq blockAttribs (ssg-attrib-read selectedEnt)) + (assoc "HOEHE" blockAttribs)) + (setq hoehe (atof (cdr (assoc "HOEHE" blockAttribs)))) + (princ (strcat "\n-> Höhe von bestehendem Kreisel übernommen: " (rtos hoehe 2 0))) + ) + ;; Fall 2: Punkt hat Z-Koordinate > 0 + ((and (> (length pt) 2) (> (caddr pt) 0)) + (setq hoehe (caddr pt)) + (princ (strcat "\n-> Höhe aus 3D-Punkt übernommen: " (rtos hoehe 2 0))) + ) + ;; Fall 3: Sonst separat abfragen + (t + (setq hoehe (getreal (strcat "\nHöhe (Z-Koordinate) <" (rtos *kreisel-default-hoehe* 2 0) ">: "))) + (if (null hoehe) (setq hoehe *kreisel-default-hoehe*)) + ) + ) + + ;; 3. Abstand + (initget 6) + (setq abstand (getdist (list (car pt) (cadr pt)) + (strcat "\nAbstand (Tangentenlaenge) <" + (rtos *kreisel-default-laenge* 2 0) ">: "))) + (if (null abstand) (setq abstand *kreisel-default-laenge*)) + (princ (strcat "\n-> Abstand: " (rtos abstand 2 0) " mm")) + + ;; 4. Rotation + (setq rotStr (getstring "\nRotation in Grad <0>: ")) + (if (= rotStr "") + (setq rotation 0.0) + (setq rotation (atof rotStr)) + ) + + ;; 5. Kreiselart + (setq typ (kreisel-ask-typ)) + + (princ (strcat "\n-> Rotation: " (rtos rotation 2 1) + " Höhe: " (rtos hoehe 2 0) + " Kreiselart: " typ)) + + ;; 6. Modul einfuegen + (draw-module (list (car pt) (cadr pt) hoehe) abstand rotation + (list (cons "KREISELART" typ) + (cons "HOEHE" (rtos hoehe 2 0)))) + + ;; KEIN weiteres (setvar "OSMODE" ...) mehr nötig! + ;; ssg-end stellt nur CLAYER und CMDECHO wieder her, nicht OSMODE + + (princ "\nKreisel Modul eingefuegt.") + (ssg-end) +) + + +;; ----------------------------------------------- +;; KreiselConnect: Linie zeichnen fuer Kreisel-Platzierung +;; +;; Ablauf: +;; 1. Startpunkt anklicken -> aeusserster AN-Punkt (Antriebsstation) +;; 2. Endpunkt anklicken -> aeusserster SP-Punkt (Spannstation) +;; 3. Abstand = Distanz - Durchmesser, Rotation aus Winkel +;; 4. Hoehe aus Z-Koordinate des Startpunkts +;; 5. Nur Kreiselart (PIN/STANDARD) wird abgefragt +;; ----------------------------------------------- +(defun c:KreiselConnect ( / ptStart ptEnd dx dy dist abstand rotation typ hoehe) + + (ssg-start "Kreisel Smart Connect" '(("OSMODE") ("CECOLOR"))) + + (princ "\n--- Kreisel durch Linie definieren (AN -> SP) ---") + + ;; 1. Startpunkt (aeusserster Punkt AN-Seite) + (setq ptStart (getpoint "\nStartpunkt (AN-Seite aussen): ")) + (if (null ptStart) + (progn (ssg-end) (princ "\nAbgebrochen.") (princ) (exit)) + ) + + ;; 2. Endpunkt (aeusserster Punkt SP-Seite) mit Gummiband + (setq ptEnd (getpoint ptStart "\nEndpunkt (SP-Seite aussen): ")) + (if (null ptEnd) + (progn (ssg-end) (princ "\nAbgebrochen.") (princ) (exit)) + ) + + ;; 3. Geometrie berechnen + (setq dx (- (car ptEnd) (car ptStart)) + dy (- (cadr ptEnd) (cadr ptStart))) + (setq dist (sqrt (+ (* dx dx) (* dy dy)))) + (setq abstand (- dist *kreisel-durchmesser*)) + + (if (<= abstand 0.0) + (progn + (ssg-emsg (strcat "Distanz zu klein! (" + (rtos dist 2 0) " < " (rtos *kreisel-durchmesser* 2 0) ")")) + (ssg-end) + (exit) + ) + ) + + ;; 4. Rotation aus Winkel Start->End + (setq rotation (* (/ 180.0 pi) (atan dy dx))) + + ;; 5. Hoehe aus Z-Koordinate des Startpunkts + (if (and (> (length ptStart) 2) (caddr ptStart)) + (setq hoehe (caddr ptStart)) + (setq hoehe 0.0) + ) + (if (<= hoehe 0.0) + (progn + (setq hoehe (getreal (strcat "\nHoehe (Z-Koordinate) <" (rtos *kreisel-default-hoehe* 2 0) ">: "))) + (if (null hoehe) (setq hoehe *kreisel-default-hoehe*)) + ) + (princ (strcat "\n-> Hoehe aus Startpunkt uebernommen: " (rtos hoehe 2 0))) + ) + + ;; 6. Kreiselart abfragen + (setq typ (kreisel-ask-typ)) + + (princ (strcat "\n-> Abstand: " (rtos abstand 2 0) " mm" + " Rotation: " (rtos rotation 2 1) " Grad" + " Hoehe: " (rtos hoehe 2 0) + " Kreiselart: " typ)) + + ;; 7. Modul einfuegen + (draw-module (list (car ptStart) (cadr ptStart) hoehe) abstand rotation + (list (cons "KREISELART" typ) + (cons "HOEHE" (rtos hoehe 2 0)))) + + (princ "\nKreisel Connect erfolgreich!") + (ssg-end) +) + + +;; Neue Befehle für Beschriftungs-Einstellungen +(defun c:KreiselLabelPos ( / dx dy) + (setq dx (getreal (strcat "\nX-Abstand von AN8-Mitte <" (rtos *kreisel-beschriftung-abstand-x* 2 0) ">: "))) + (if dx (setq *kreisel-beschriftung-abstand-x* dx)) + (setq dy (getreal (strcat "\nY-Abstand von AN8-Mitte <" (rtos *kreisel-beschriftung-abstand-y* 2 0) ">: "))) + (if dy (setq *kreisel-beschriftung-abstand-y* dy)) + (princ (strcat "\nNeue Beschriftungsposition: X=" (rtos *kreisel-beschriftung-abstand-x* 2 0) + " Y=" (rtos *kreisel-beschriftung-abstand-y* 2 0))) + (princ) +) + +(defun c:KreiselLabelHoehe ( / h) + (setq h (getreal (strcat "\nTexthöhe <" (rtos *kreisel-beschriftung-hoehe* 2 0) ">: "))) + (if h (setq *kreisel-beschriftung-hoehe* h)) + (princ (strcat "\nNeue Texthöhe: " (rtos *kreisel-beschriftung-hoehe* 2 0))) + (princ) +) + +;; ----------------------------------------------- +;; KreiselRedraw: Bestehenden Kreisel neu zeichnen +;; +;; Liest Attribute aus dem bestehenden Block, +;; loescht ihn, und zeichnet ihn mit (optional +;; geaendertem) Abstand neu. Alle Attribute bleiben +;; erhalten. +;; ----------------------------------------------- +(defun c:KreiselRedraw ( / sel ent ed attribs basePoint rotation newAbstand) + + (ssg-start "Kreisel Neu Zeichnen" '(("CECOLOR"))) + + ;; 1. Bestehenden Kreisel-Block auswaehlen + (setq sel (entsel "\nKreisel-Block auswaehlen: ")) + (if (null sel) (exit)) + (setq ent (car sel)) + (setq ed (entget ent)) + + ;; Pruefen ob INSERT + (if (/= (cdr (assoc 0 ed)) "INSERT") + (progn (ssg-emsg "Kein Block ausgewaehlt!") (exit)) + ) + + ;; 2. Bestehende Werte auslesen + (setq attribs (ssg-attrib-read ent)) + (setq basePoint (cdr (assoc 10 ed))) + (setq rotation (* (/ 180.0 pi) (cdr (assoc 50 ed)))) + + ;; NEU - Höhe aus Attributen lesen und anzeigen: + (princ (strcat "\n-> Bestehend: Abstand=" (cdr (assoc "ABSTAND" attribs)) + " Drehung=" (cdr (assoc "DREHUNG" attribs)) + " Höhe=" (cdr (assoc "HOEHE" attribs)) ;; <-- NEU + " Art=" (cdr (assoc "KREISELART" attribs)))) + + ;; 3. Neuen Abstand abfragen (Enter = beibehalten) + (initget 6) + (setq newAbstand (getdist (strcat "\nNeuer Abstand <" (cdr (assoc "ABSTAND" attribs)) ">: "))) + (if (null newAbstand) + (setq newAbstand (atof (cdr (assoc "ABSTAND" attribs)))) + ) + ;; NEU - Neue Höhe abfragen: + (setq newHoehe (getreal (strcat "\nNeue Höhe <" (cdr (assoc "HOEHE" attribs)) ">: "))) + (if (null newHoehe) + (setq newHoehe (atof (cdr (assoc "HOEHE" attribs)))) + ) + ;; 4. Alten Block loeschen + (command "_.ERASE" ent "") + + ;; 5. Neu zeichnen mit bestehenden Attributen + neuem Abstand + (draw-module (list (car basePoint) (cadr basePoint) newHoehe) + newAbstand rotation attribs) + + (princ (strcat "\nKreisel neu gezeichnet. Abstand=" (rtos newAbstand 2 0))) + (ssg-end) +) + + +;; -------------------------------------------- +;; KreiselQuick: Schnell mit Defaults (horizontal) +;; -------------------------------------------- +(defun c:KreiselQuick ( / pt) + (ssg-start "Kreisel Schnell Einfuegen" '(("CECOLOR"))) + (setq pt (getpoint "\nBasispunkt (AN-Seite): ")) + ;; NEU - Höhe abfragen: + (setq hoehe (getreal (strcat "\nHöhe (Z-Koordinate) <0>: "))) + (if (null hoehe) (setq hoehe 0.0)) + (if pt + ;; NEU - Höhe im Aufruf übergeben: + (draw-module (list (car pt) (cadr pt) hoehe) *kreisel-default-laenge* 0.0 + (list (cons "HOEHE" (rtos hoehe 2 0)))) + ) + (princ "\nSchnell Einfuegen fertig.") + (ssg-end) +) + + +;; ============================================================ +;; TEIL 5: KREISEL BEARBEITEN (DCL-Dialog) +;; ============================================================ + +;; Ausrichtungs-Definitionen: ((Label Rotation) ...) +;; Rotation in Grad: 0=rechts, 90=oben, 180=links, 270=unten +(setq *kreisel-ausrichtungen* + '(("Horizontal MS" 0.0) + ("Horizontal SM" 180.0) + ("Vertikal MS" 90.0) + ("Vertikal SM" 270.0)) +) + +;; Rotation (Grad) -> Ausrichtungs-Index (fuer popup_list) +(defun kreisel-rotation-to-idx (rot / idx i entry diff) + (setq idx 0 i 0) + (foreach entry *kreisel-ausrichtungen* + (setq diff (abs (- (rem (+ rot 360.0) 360.0) + (rem (+ (cadr entry) 360.0) 360.0)))) + (if (< diff 1.0) (setq idx i)) + (setq i (1+ i)) + ) + idx +) + +;; Ausrichtungs-Index -> Rotation (Grad) +(defun kreisel-idx-to-rotation (idx) + (cadr (nth idx *kreisel-ausrichtungen*)) +) + +;; ----------------------------------------------- +;; KreiselEdit: Bestehenden Kreisel per Dialog bearbeiten +;; +;; Ablauf: +;; 1. Kreisel-Block auswaehlen (oder vorselektiert) +;; 2. DCL-Dialog mit aktuellen Werten oeffnen +;; 3. Bei OK: Block loeschen und mit neuen Werten neu zeichnen +;; ----------------------------------------------- +(defun c:KreiselEdit ( / sel ss ent ed attribs basePoint rotation + dcl-pfad dat ergebnis + dlg-name dlg-abstand dlg-hoehe dlg-ausrichtung + dlg-drehrichtung dlg-kreiselart + newAbstand newRotation ausrichtLabels) + + ;; Implied Selection VOR ssg-start pruefen (ssg-start hebt Selektion auf) + (setq ss (ssget "I")) + (if (and ss (= (sslength ss) 1) + (= (cdr (assoc 0 (entget (ssname ss 0)))) "INSERT")) + (setq ent (ssname ss 0)) + ) + + (ssg-start "Kreisel bearbeiten" '(("OSMODE") ("CECOLOR") ("ATTREQ") ("ATTDIA"))) + (setvar "OSMODE" 0) + + ;; 1. Block auswaehlen (falls nicht vorselektiert) + (if (null ent) + (progn + (setq sel (entsel "\nKreisel-Block auswaehlen: ")) + (if sel (setq ent (car sel))) + ) + ) + (if (null ent) (progn (ssg-end) (exit))) + + (setq ed (entget ent)) + (if (/= (cdr (assoc 0 ed)) "INSERT") + (progn (ssg-emsg "Kein Block ausgewaehlt!") (ssg-end) (exit)) + ) + + ;; 2. Bestehende Werte auslesen + (setq attribs (ssg-attrib-read ent)) + (setq basePoint (cdr (assoc 10 ed))) + (setq rotation (* (/ 180.0 pi) (cdr (assoc 50 ed)))) + + ;; Pruefen ob Block Kreisel-Attribute hat (mindestens ABSTAND) + (if (null (assoc "ABSTAND" attribs)) + (progn + (ssg-emsg "Kein Kreisel-Block! (Attribut ABSTAND fehlt)") + (ssg-end) + (exit) + ) + ) + + ;; Fehlende Attribute mit Defaults auffuellen + (foreach def *kreisel-attrib-defs* + (if (null (assoc (car def) attribs)) + (setq attribs (append attribs (list (cons (car def) (cadr def))))) + ) + ) + + ;; HOEHE immer aus Z-Koordinate des Einfuegepunkts befuellen + (setq attribs (subst (cons "HOEHE" (rtos (if (caddr basePoint) (caddr basePoint) 0.0) 2 1)) + (assoc "HOEHE" attribs) attribs)) + + (princ (strcat "\n-> Bestehend: Abstand=" (cdr (assoc "ABSTAND" attribs)) + " Drehung=" (rtos rotation 2 1) + " Art=" (cdr (assoc "KREISELART" attribs)))) + + ;; 3. DCL-Dialog laden + (setq dcl-pfad (strcat (getenv "DXFM_DCL") "/kreisel_edit.dcl")) + (setq dat (load_dialog dcl-pfad)) + (if (not (new_dialog "kreisel_edit" dat)) + (progn (alert (strcat "Dialog nicht verfuegbar: " dcl-pfad)) (ssg-end) (exit)) + ) + + ;; Ausrichtungs-Labels fuer popup_list aufbauen + (setq ausrichtLabels "") + (foreach entry *kreisel-ausrichtungen* + (if (= ausrichtLabels "") + (setq ausrichtLabels (car entry)) + (setq ausrichtLabels (strcat ausrichtLabels "\n" (car entry))) + ) + ) + + ;; Tiles initialisieren + (set_tile "name" (cdr (assoc "NAME" attribs))) + (set_tile "abstand" (cdr (assoc "ABSTAND" attribs))) + (set_tile "hoehe" (cdr (assoc "HOEHE" attribs))) + + (start_list "ausrichtung") + (foreach entry *kreisel-ausrichtungen* + (add_list (car entry)) + ) + (end_list) + (set_tile "ausrichtung" (itoa (kreisel-rotation-to-idx rotation))) + + (start_list "drehrichtung") + (add_list "UZS") + (add_list "GUZ") + (end_list) + (set_tile "drehrichtung" (if (equal (cdr (assoc "DREHRICHTUNG" attribs)) "GUZ") "1" "0")) + + (start_list "kreiselart") + (add_list "STANDARD") + (add_list "PIN") + (end_list) + (set_tile "kreiselart" (if (equal (cdr (assoc "KREISELART" attribs)) "PIN") "1" "0")) + + ;; Actions + (action_tile "accept" + (strcat + "(setq dlg-name (get_tile \"name\"))" + "(setq dlg-abstand (get_tile \"abstand\"))" + "(setq dlg-hoehe (get_tile \"hoehe\"))" + "(setq dlg-ausrichtung (get_tile \"ausrichtung\"))" + "(setq dlg-drehrichtung (get_tile \"drehrichtung\"))" + "(setq dlg-kreiselart (get_tile \"kreiselart\"))" + "(done_dialog 1)" + ) + ) + (action_tile "cancel" "(done_dialog 0)") + + (setq ergebnis (start_dialog)) + (unload_dialog dat) + + ;; 4. Bei OK: Block loeschen und neu zeichnen + (if (= ergebnis 1) + (progn + ;; Werte aufbereiten + (setq newAbstand (atof dlg-abstand)) + (setq newRotation (kreisel-idx-to-rotation (atoi dlg-ausrichtung))) + + ;; Attribute aktualisieren + (setq attribs (subst (cons "NAME" dlg-name) + (assoc "NAME" attribs) attribs)) + (setq attribs (subst (cons "HOEHE" dlg-hoehe) + (assoc "HOEHE" attribs) attribs)) + (setq attribs (subst (cons "KREISELART" + (if (= dlg-kreiselart "1") "PIN" "STANDARD")) + (assoc "KREISELART" attribs) attribs)) + (setq attribs (subst (cons "DREHRICHTUNG" + (if (= dlg-drehrichtung "1") "GUZ" "UZS")) + (assoc "DREHRICHTUNG" attribs) attribs)) + + ;; Alten Block loeschen + (command "_.ERASE" ent "") + + ;; Neu zeichnen mit Z-Koordinate aus Hoehe-Dialogwert + (draw-module (list (car basePoint) (cadr basePoint) (atof dlg-hoehe)) + newAbstand newRotation attribs) + + (princ (strcat "\nKreisel aktualisiert: " + "Name=" dlg-name + " Abstand=" (rtos newAbstand 2 0) + " Hoehe=" dlg-hoehe + " Rotation=" (rtos newRotation 2 1))) + ) + (princ "\nAbgebrochen.") + ) + + (ssg-end) +) + + +;; -------------------------------------------- +;; KreiselParams: Aktuelle Parameter anzeigen +;; -------------------------------------------- +(defun c:KreiselParams () + (princ "\n=== Kreisel Parameter ===") + (princ (strcat "\nKreiselart: " #Kreisel_Typ)) + (princ (strcat "\nDurchmesser: " (rtos *kreisel-durchmesser* 2 0))) + (princ (strcat "\nDefault-Laenge: " (rtos *kreisel-default-laenge* 2 0))) + ;; NEU - Default-Höhe anzeigen: + (princ (strcat "\nDefault-Höhe: " (rtos *kreisel-default-hoehe* 2 0))) + (princ "\nAttribute im Block:") + (foreach def *kreisel-attrib-defs* + (princ (strcat "\n " (car def) " = " (cadr def))) + ) + (princ "\n=========================\n") + (princ) +) + + +;; -------------------------------------------- +;; ILS_Eckrad: Befehl - fragt Eingaben ab und fuegt Eckrad ein +;; +;; Ablauf: +;; 1. Beruehrpunkt anklicken (wo der Kreis tangential anliegen soll) +;; 2. Richtungspunkt anklicken (bestimmt Versatzrichtung zum Kreismittelpunkt) +;; 3. Kreismittelpunkt = Beruehrpunkt + Radius in Richtung des 2. Klicks +;; 4. Hoehe aus Z-Koordinate oder manuell +;; -------------------------------------------- +(defun c:ILS_Eckrad ( / ptTangent ptDir dx dy dist ux uy radius + centerPt rotation hoehe) + (dbgf "c:ILS_Eckrad") + + ;; 1. Beruehrpunkt (Tangentenpunkt) + (setq ptTangent (getpoint "\nBeruehrpunkt Eckrad (Tangente): ")) + (if (null ptTangent) (progn (dbgreturn nil) (exit))) + (dbg 'ptTangent) + + ;; 2. Richtungspunkt (Gummiband vom Beruehrpunkt) + (setq ptDir (getpoint ptTangent "\nRichtung zum Kreismittelpunkt: ")) + (if (null ptDir) (progn (dbgreturn nil) (exit))) + (dbg 'ptDir) + + ;; 3. Winkel und Versatz berechnen + (setq dx (- (car ptDir) (car ptTangent)) + dy (- (cadr ptDir) (cadr ptTangent))) + (setq dist (sqrt (+ (* dx dx) (* dy dy)))) + + (if (<= dist 0.001) + (progn + (princ "\nFehler: Beruehr- und Richtungspunkt sind identisch!") + (dbgreturn nil) + (exit) + ) + ) + + ;; Einheitsvektor in Richtung Beruehrpunkt -> Richtungspunkt + (setq ux (/ dx dist) + uy (/ dy dist)) + + ;; Radius = halber Kreisdurchmesser + (setq radius (/ *kreisel-durchmesser* 2.0)) + + ;; Kreismittelpunkt = Beruehrpunkt + Radius * Richtung + (setq centerPt (list (+ (car ptTangent) (* radius ux)) + (+ (cadr ptTangent) (* radius uy)))) + (dbg 'centerPt) + + ;; Rotation = Winkel der Versatzrichtung + (setq rotation (* (/ 180.0 pi) (atan dy dx))) + (dbg 'rotation) + + ;; 4. Hoehe bestimmen + (if (and (> (length ptTangent) 2) (caddr ptTangent) (> (caddr ptTangent) 0)) + (progn + (setq hoehe (caddr ptTangent)) + (princ (strcat "\n-> Hoehe aus 3D-Punkt uebernommen: " (rtos hoehe 2 0))) + ) + (progn + (setq hoehe (getreal (strcat "\nHoehe (Z-Koordinate) <" (rtos *eckrad-default-hoehe* 2 0) ">: "))) + (if (null hoehe) (setq hoehe *eckrad-default-hoehe*)) + ) + ) + (dbg 'hoehe) + + ;; 5. Einfuegen (centerPt ist der Kreismittelpunkt) + (ils-eckrad-insert (list (car centerPt) (cadr centerPt) hoehe) rotation nil) + (dbgreturn nil) +) + +;; -------------------------------------------- +;; ils-eckrad-insert: Erzeugt Eckrad als Compound-Block mit Attributen +;; Parameter: +;; pt - Einfuegepunkt (Liste x y z) +;; rotation - Drehwinkel in Grad +;; attribs - alist mit Attribut-Ueberschreibungen (nil = Defaults) +;; Rueckgabe: Entity-Name des eingefuegten Blocks +;; -------------------------------------------- +(defun ils-eckrad-insert (pt rotation attribs / lastEnt ss e bname + eckrad-nummer block-exists + z-hoehe block-hoehe + insertPoint block-ent + att-entity att-data att-tag new-value) + (dbgf "ils-eckrad-insert") + (dbg 'pt) + (dbg 'rotation) + + (ssg-start "Eckrad einfuegen" '(("ATTREQ") ("ATTDIA") ("OSMODE") ("CECOLOR"))) + + ;; Attribute vorbereiten + (setq attribs (ssg-attrib-merge attribs *eckrad-attrib-defs*)) + (setq attribs (subst (cons "DREHUNG" (rtos rotation 2 1)) + (assoc "DREHUNG" attribs) attribs)) + (dbgp "Attribute nach merge vorbereitet") + + ;; Hoehe bestimmen + (if (and pt (caddr pt) (> (caddr pt) 0)) + (progn + (setq z-hoehe (caddr pt)) + (setq block-hoehe (rtos z-hoehe 2 0)) + ) + (progn + (setq block-hoehe (cdr (assoc "HOEHE" attribs))) + (if (or (null block-hoehe) (= block-hoehe "")) + (setq block-hoehe "0") + ) + (setq z-hoehe (atof block-hoehe)) + ) + ) + (setq attribs (subst (cons "HOEHE" block-hoehe) + (assoc "HOEHE" attribs) attribs)) + (dbg 'z-hoehe) + (dbg 'block-hoehe) + + ;; Automatische Nummer vergeben + (setq eckrad-nummer (eckrad-next-number)) + (setq attribs (subst (cons "NUMMER" (itoa eckrad-nummer)) + (assoc "NUMMER" attribs) attribs)) + (dbg 'eckrad-nummer) + + ;; Blockname: ECKRAD_1, ECKRAD_2, ... + (setq bname (strcat "ECKRAD_" (itoa eckrad-nummer))) + (dbg 'bname) + + ;; Pruefen ob Block bereits existiert + (setq block-exists (tblsearch "BLOCK" bname)) + (dbgp (strcat "block-exists=" (if block-exists "JA" "NEIN"))) + + ;; ATTREQ/ATTDIA und OSMODE setzen + (setvar "ATTREQ" 0) + (setvar "ATTDIA" 0) + (setvar "OSMODE" 0) + + ;; --- Geometrie NUR zeichnen, wenn Block noch nicht existiert --- + (if (not block-exists) + (progn + (dbgp "Erzeuge neue Blockdefinition...") + ;; Letzten Entity merken (mit SEQEND-Schutz wie bei draw-module) + (if (setq lastEnt (entlast)) + (progn + (dbgp (strcat "lastEnt Typ=" (cdr (assoc 0 (entget lastEnt))))) + (if (and (= (cdr (assoc 0 (entget lastEnt))) "INSERT") + (= (cdr (assoc 66 (entget lastEnt))) 1)) + (progn + (dbgp "lastEnt ist INSERT mit Attributen -> navigiere zu SEQEND") + (setq lastEnt (entnext lastEnt)) + (while (and lastEnt + (/= (cdr (assoc 0 (entget lastEnt))) "SEQEND")) + (setq lastEnt (entnext lastEnt)) + ) + (dbgp "SEQEND erreicht") + ) + ) + ) + (setq lastEnt nil) + ) + + ;; AN8 Block einfuegen bei (0,0) - Eckrad ist ein einzelner Kreis + (dbgp (strcat "INSERT Block: " *block-path* "AN8.dwg")) + (command "_.INSERT" (strcat *block-path* "AN8.dwg") (list 0.0 0.0 0.0) 1 1 0) + + ;; Unsichtbare Attribut-Definitionen erzeugen + (dbgp (strcat "Erzeuge " (itoa (length *eckrad-attrib-defs*)) " Attribut-Definitionen")) + (ssg-attrib-make-defs *eckrad-attrib-defs* 50.0) + + ;; Neue Entities einsammeln + (setq ss (ssadd)) + (if (null lastEnt) + (setq e (entnext)) + (setq e (entnext lastEnt)) + ) + (while e + (ssadd e ss) + (setq e (entnext e)) + ) + (dbgp (strcat "Entities eingesammelt: " (itoa (sslength ss)))) + + ;; Block erzeugen + (if (> (sslength ss) 0) + (progn + (command "_.-BLOCK" bname (list 0.0 0.0 0.0) ss "") + (dbgp (strcat "Blockdefinition erzeugt: " bname)) + ) + (progn + (princ "\nFehler: Keine Entities zum Block erstellen!") + (dbgp "FEHLER: Keine Entities fuer Block!") + ) + ) + (princ (strcat "\n-> Neue Blockdefinition: " bname)) + ) + (progn + (princ (strcat "\n-> Verwende bestehende Blockdefinition: " bname)) + (dbgp (strcat "Verwende bestehende Blockdefinition: " bname)) + ) + ) + + ;; Block am Zielpunkt einfuegen + (setq insertPoint (list (car pt) (cadr pt) z-hoehe)) + (dbg 'insertPoint) + (dbgp (strcat "INSERT " bname " bei " (rtos (car insertPoint) 2 1) + "," (rtos (cadr insertPoint) 2 1) + "," (rtos (caddr insertPoint) 2 1) + " Rotation=" (rtos rotation 2 1))) + (command "_.INSERT" bname insertPoint 1 1 rotation) + + ;; Attribut-Werte durch direkte Datenbankaenderung setzen + (setq block-ent (entlast)) + (setq att-entity (entnext block-ent)) + (dbgp "Setze Attribut-Werte:") + (while att-entity + (setq att-data (entget att-entity)) + (if (= (cdr (assoc 0 att-data)) "ATTRIB") + (progn + (setq att-tag (cdr (assoc 2 att-data))) + (setq new-value (cdr (assoc att-tag attribs))) + (if new-value + (progn + (dbgp (strcat " " att-tag "=" new-value)) + (setq att-data (subst (cons 1 new-value) (assoc 1 att-data) att-data)) + (entmod att-data) + ) + ) + ) + ) + (setq att-entity (entnext att-entity)) + ) + (entupd block-ent) + + (princ (strcat "\n-> Eckrad #" (itoa eckrad-nummer) " eingefuegt: " bname + " bei " (rtos (car pt) 2 1) "," (rtos (cadr pt) 2 1) + " Rotation=" (rtos rotation 2 1) + " Hoehe=" block-hoehe)) + (ssg-end) + (dbgreturn (entlast)) +) + +;; NEU: KreiselLabelSetup - Hier einfügen! +(defun c:KreiselLabelSetup ( / hoehe farbe abstand schriftart) + (setq hoehe (getreal (strcat "\nSchrifthöhe <" (rtos *kreisel-beschriftung-hoehe* 2 0) ">: "))) + (if hoehe (setq *kreisel-beschriftung-hoehe* hoehe)) + + (setq farbe (getint (strcat "\nSchriftfarbe (1=Rot,2=Gelb,3=Grün,4=Cyan,5=Blau,6=Magenta,7=Weiß) <" (itoa *kreisel-beschriftung-farbe*) ">: "))) + (if farbe (setq *kreisel-beschriftung-farbe* farbe)) + + (setq abstand (getreal (strcat "\nAbstand über Kreisel-Mitte <" (rtos *kreisel-beschriftung-abstand-oben* 2 0) ">: "))) + (if abstand (setq *kreisel-beschriftung-abstand-oben* abstand)) + + (princ (strcat "\nNeue Einstellungen: Höhe=" (rtos *kreisel-beschriftung-hoehe* 2 0) + ", Farbe=" (itoa *kreisel-beschriftung-farbe*) + ", Y-Versatz=" (rtos *kreisel-beschriftung-abstand-oben* 2 0) + ", Schriftart=Arial")) + (princ) +) + +(princ "\nKreiselInsert.lsp geladen (Version 7.0 - Auto-Nummerierung + Beschriftung + Attribute + Redraw + Eckrad)") +(princ "\nBefehle: KreiselInsert, KreiselConnect, KreiselRedraw, KreiselEdit, KreiselQuick, KreiselParams, ILS_Eckrad") +(princ) diff --git a/Lisp/OmniModulInsert.lsp b/Lisp/OmniModulInsert.lsp new file mode 100644 index 0000000..6c7be8d --- /dev/null +++ b/Lisp/OmniModulInsert.lsp @@ -0,0 +1,1137 @@ +;; ============================================================ +;; OMNIFLO JSON-DATEN LADEN UND ABFRAGEN +;; Liest omniflo_boegen.json und omniflo_weichen.json ein. +;; Daten werden als Listen von Assoziationslisten gespeichert. +;; +;; Globale Variablen: +;; *OMNI-BOEGEN* - Liste aller Boegen-Eintraege +;; *OMNI-WEICHEN* - Liste aller Weichen-Eintraege +;; +;; Funktionen: +;; (omni:load-data) - Beide JSON-Dateien laden +;; (omni:get-bogen sivasid) - Bogen-Info zu einer SivasId +;; (omni:get-weiche sivasid) - Weichen-Info zu einer SivasId +;; (omni:filter lst key wert) - Eintraege nach Key/Wert filtern +;; ============================================================ + + +;; --- Datei zeilenweise einlesen --- +(defun omni:read-file-lines (datei / f zeile ergebnis) + (setq f (open datei "r")) + (if (null f) + (progn + (princ (strcat "\n[OMNI] FEHLER: Datei nicht gefunden: " datei)) + nil + ) + (progn + (setq ergebnis nil) + (while (setq zeile (read-line f)) + (setq ergebnis (cons zeile ergebnis)) + ) + (close f) + (reverse ergebnis) + ) + ) +) + + +;; --- Whitespace und Komma am Ende einer Zeile entfernen --- +(defun omni:trim (s / len ch) + (setq s (vl-string-trim " \t\r\n" s)) + (setq len (strlen s)) + (if (and (> len 0) (= (substr s len 1) ",")) + (setq s (substr s 1 (1- len))) + ) + (vl-string-trim " \t\r\n" s) +) + + +;; --- JSON-Wert parsen (String, Zahl, null) --- +(defun omni:parse-value (val-str / len) + (setq val-str (omni:trim val-str)) + (cond + ((= val-str "null") nil) + ((= (substr val-str 1 1) "\"") + ;; String: Anfuehrungszeichen entfernen + (setq len (strlen val-str)) + (if (and (> len 1) (= (substr val-str len 1) "\"")) + (substr val-str 2 (- len 2)) + val-str + ) + ) + (T + ;; Zahl + (if (vl-string-search "." val-str) + (atof val-str) + (atoi val-str) + ) + ) + ) +) + + +;; --- Eine Key-Value-Zeile parsen -> dotted pair oder nil --- +(defun omni:parse-kv-line (zeile / pos key rest val) + (setq zeile (omni:trim zeile)) + ;; Muss mit " beginnen (Key) + (if (and (> (strlen zeile) 0) (= (substr zeile 1 1) "\"")) + (progn + ;; Key extrahieren: zweites Anfuehrungszeichen finden + ;; vl-string-search ist 0-basiert, substr ist 1-basiert + (setq pos (vl-string-search "\"" zeile 1)) + (if pos + (progn + (setq key (substr zeile 2 (1- pos))) + ;; Rest nach dem schliessenden " extrahieren + (setq rest (substr zeile (+ pos 2))) + ;; ":" im Rest finden + (setq pos (vl-string-search ":" rest)) + (if pos + (progn + (setq val (substr rest (+ pos 2))) + (cons key (omni:parse-value val)) + ) + ) + ) + ) + ) + ) +) + + +;; --- JSON-Array von flachen Objekten parsen --- +(defun omni:parse-json-array (zeilen / in-obj obj ergebnis zeile kv trimmed) + (setq in-obj nil + obj nil + ergebnis nil + ) + (foreach zeile zeilen + (setq trimmed (omni:trim zeile)) + (cond + ;; Objekt-Start + ((= trimmed "{") + (setq in-obj T + obj nil + ) + ) + ;; Objekt-Ende + ((or (= trimmed "}") (= trimmed "},")) + (if (and in-obj obj) + (setq ergebnis (cons (reverse obj) ergebnis)) + ) + (setq in-obj nil) + ) + ;; Key-Value-Zeile innerhalb eines Objekts + (in-obj + (setq kv (omni:parse-kv-line zeile)) + (if kv (setq obj (cons kv obj))) + ) + ) + ) + (reverse ergebnis) +) + + +;; --- JSON-Datei laden und als Liste von Alists zurueckgeben --- +(defun omni:load-json (datei / zeilen) + (setq zeilen (omni:read-file-lines datei)) + (if zeilen + (omni:parse-json-array zeilen) + ) +) + + +;; --- Beide Datensaetze laden --- +(defun omni:load-data ( / data-pfad f-boegen f-weichen) + (setq data-pfad (getenv "DXFM_DATA")) + (if (null data-pfad) + (progn + (princ "\n[OMNI] FEHLER: DXFM_DATA nicht gesetzt!") + nil + ) + (progn + ;; Boegen laden + (setq f-boegen (strcat data-pfad "/json/omniflo_boegen.json")) + (setq *OMNI-BOEGEN* (omni:load-json f-boegen)) + (if *OMNI-BOEGEN* + (princ (strcat "\n[OMNI] " (itoa (length *OMNI-BOEGEN*)) " Boegen geladen.")) + (princ (strcat "\n[OMNI] WARNUNG: Keine Boegen geladen aus " f-boegen)) + ) + ;; Weichen laden + (setq f-weichen (strcat data-pfad "/json/omniflo_weichen.json")) + (setq *OMNI-WEICHEN* (omni:load-json f-weichen)) + (if *OMNI-WEICHEN* + (princ (strcat "\n[OMNI] " (itoa (length *OMNI-WEICHEN*)) " Weichen geladen.")) + (princ (strcat "\n[OMNI] WARNUNG: Keine Weichen geladen aus " f-weichen)) + ) + T + ) + ) +) + + +;; --- SivasId zu String konvertieren (fuer Vergleich) --- +(defun omni:sivasid-to-str (id) + (cond + ((= (type id) 'STR) id) + ((= (type id) 'INT) (itoa id)) + ((= (type id) 'REAL) (itoa (fix id))) + (T "") + ) +) + + +;; --- Eintrag anhand SivasId in einer Liste suchen --- +(defun omni:get-by-sivasid (lst sivasid / such-str eintrag sivasnr gefunden) + (setq such-str (omni:sivasid-to-str sivasid)) + (setq gefunden nil) + (foreach eintrag lst + (if (null gefunden) + (progn + (setq sivasnr (cdr (assoc "Sivasnr" eintrag))) + (if (= (omni:sivasid-to-str sivasnr) such-str) + (setq gefunden eintrag) + ) + ) + ) + ) + gefunden +) + + +;; --- Bogen anhand SivasId abfragen --- +;; Rueckgabe: Assoziationsliste mit allen Eigenschaften oder nil +;; Beispiel: (omni:get-bogen 821104025) +;; -> (("Sivasnr" . 821104025) ("ProfilTyp" . "APB 110 R 550/22,5...") ...) +(defun omni:get-bogen (sivasid) + (if (null *OMNI-BOEGEN*) (omni:load-data)) + (omni:get-by-sivasid *OMNI-BOEGEN* sivasid) +) + + +;; --- Weiche anhand SivasId abfragen --- +;; Rueckgabe: Assoziationsliste mit allen Eigenschaften oder nil +;; Beispiel: (omni:get-weiche 834372001) +;; -> (("Sivasnr" . 834372001) ("ProfilTyp" . "WEICHE S 45...") ...) +(defun omni:get-weiche (sivasid) + (if (null *OMNI-WEICHEN*) (omni:load-data)) + (omni:get-by-sivasid *OMNI-WEICHEN* sivasid) +) + + +;; --- Eintraege nach beliebigem Key/Wert filtern --- +;; lst = *OMNI-BOEGEN* oder *OMNI-WEICHEN* +;; key = Schluesselname z.B. "KurvenWinkel" +;; wert = Gesuchter Wert z.B. 45 +;; Rueckgabe: Liste aller passenden Eintraege +;; +;; Beispiel: (omni:filter *OMNI-BOEGEN* "KurvenWinkel" 45) +;; -> Liste aller 45-Grad-Boegen +;; Beispiel: (omni:filter *OMNI-WEICHEN* "WeichenTyp" "Doppelweiche") +;; -> Liste aller Doppelweichen +(defun omni:filter (lst key wert / eintrag val ergebnis) + (setq ergebnis nil) + (foreach eintrag lst + (setq val (cdr (assoc key eintrag))) + (if (equal val wert) + (setq ergebnis (cons eintrag ergebnis)) + ) + ) + (reverse ergebnis) +) + + +;; --- Einzelnen Wert aus einem Eintrag lesen --- +;; eintrag = Assoziationsliste (Rueckgabe von omni:get-bogen etc.) +;; key = Schluesselname z.B. "Radius" +;; Beispiel: (omni:val (omni:get-bogen 821104025) "Radius") -> 550 +(defun omni:val (eintrag key) + (cdr (assoc key eintrag)) +) + + +;; --- SivasNummern aller Boegen fuer einen bestimmten Winkel --- +;; winkel = KurvenWinkel z.B. 90, 45, 22.5 +;; Rueckgabe: Liste von SivasIds (gemischt INT/STR) +;; Beispiel: (omni:boegen-ids 45) -> (821104021 821104026 "821104026+0_B10071" ...) +(defun omni:boegen-ids (winkel / lst eintrag ergebnis) + (if (null *OMNI-BOEGEN*) (omni:load-data)) + (setq ergebnis nil) + (foreach eintrag *OMNI-BOEGEN* + (if (equal (cdr (assoc "KurvenWinkel" eintrag)) winkel) + (setq ergebnis (cons (cdr (assoc "Sivasnr" eintrag)) ergebnis)) + ) + ) + (reverse ergebnis) +) + + +;; --- SivasNummern aller Boegen, gruppiert nach Winkel --- +;; Rueckgabe: Assoziationsliste ((180 . (id ...)) (90 . (id ...)) ...) +;; Beispiel: (omni:boegen-ids-alle) +;; -> ((180 821104043) (90 821104022 821104030 ...) (67.5 ...) (45 ...) (22.5 ...)) +(defun omni:boegen-ids-alle () + (list + (cons 180 (omni:boegen-ids 180)) + (cons 90 (omni:boegen-ids 90)) + (cons 67.5 (omni:boegen-ids 67.5)) + (cons 45 (omni:boegen-ids 45)) + (cons 22.5 (omni:boegen-ids 22.5)) + ) +) + + +;; --- SivasNummern von Weichen nach Winkel und WeichenTyp --- +;; winkel = KurvenWinkel z.B. 90, 45 +;; weichentyp = "Einzelweiche", "Doppelweiche", "Dreiwegeweiche" +;; Beispiel: (omni:weichen-ids 90 "Einzelweiche") +(defun omni:weichen-ids (winkel weichentyp / eintrag ergebnis) + (if (null *OMNI-WEICHEN*) (omni:load-data)) + (setq ergebnis nil) + (foreach eintrag *OMNI-WEICHEN* + (if (and (equal (cdr (assoc "KurvenWinkel" eintrag)) winkel) + (= (cdr (assoc "WeichenTyp" eintrag)) weichentyp) + ) + (setq ergebnis (cons (cdr (assoc "Sivasnr" eintrag)) ergebnis)) + ) + ) + (reverse ergebnis) +) + + +;; --- SivasNummern von Weichenkombinationen (Delta/Star) --- +;; typ = "DELTA" oder "STAR" +;; Filtert anhand ProfilTyp-Inhalt +(defun omni:weichen-kombi-ids (typ / eintrag ergebnis profil) + (if (null *OMNI-WEICHEN*) (omni:load-data)) + (setq ergebnis nil) + (foreach eintrag *OMNI-WEICHEN* + (setq profil (cdr (assoc "ProfilTyp" eintrag))) + (if (and profil (vl-string-search typ profil)) + (setq ergebnis (cons (cdr (assoc "Sivasnr" eintrag)) ergebnis)) + ) + ) + (reverse ergebnis) +) + + +;; --- Alle Weichen-SivasNummern gruppiert --- +;; Rueckgabe: Assoziationsliste nach Kategorie +;; Beispiel: (omni:weichen-ids-alle) +;; -> (("W90-Einfach" id1 id2 ...) +;; ("W90-Doppel" ...) +;; ... +;; ("WKomb-Delta" ...) +;; ("WKomb-Star" ...)) +(defun omni:weichen-ids-alle () + (list + ;; 90 Grad + (cons "W90-Einfach" (omni:weichen-ids 90 "Einzelweiche")) + (cons "W90-Doppel" (omni:weichen-ids 90 "Doppelweiche")) + (cons "W90-Dreiwege" (omni:weichen-ids 90 "Dreiwegeweiche")) + ;; 45 Grad + (cons "W45-Einfach" (omni:weichen-ids 45 "Einzelweiche")) + (cons "W45-Doppel" (omni:weichen-ids 45 "Doppelweiche")) + (cons "W45-Dreiwege" (omni:weichen-ids 45 "Dreiwegeweiche")) + ;; Parallel (KurvenWinkel = 0) + (cons "WP-Einfach" (omni:weichen-ids 0 "Einzelweiche")) + (cons "WP-Doppel" (omni:weichen-ids 0 "Doppelweiche")) + (cons "WP-Dreiwege" (omni:weichen-ids 0 "Dreiwegeweiche")) + ;; Weichenkoerper (KurvenWinkel = 22.5) + (cons "WK-Einfach" (omni:weichen-ids 22.5 "Einzelweiche")) + (cons "WK-Doppel" (omni:weichen-ids 22.5 "Doppelweiche")) + (cons "WK-Dreiwege" (omni:weichen-ids 22.5 "Dreiwegeweiche")) + ;; Weichenkombinationen + (cons "WKomb-Delta" (omni:weichen-kombi-ids "DELTA")) + (cons "WKomb-Star" (omni:weichen-kombi-ids "STAR")) + ) +) + + +;; --- BricsCAD-Befehl: Daten laden --- +(defun c:OMNI_LOAD () + (omni:load-data) + (princ) +) + + +;; --- BricsCAD-Befehl: Bogen-Info anzeigen --- +(defun c:OMNI_INFO_BOGEN ( / id eintrag) + (if (null *OMNI-BOEGEN*) (omni:load-data)) + (setq id (getstring T "\nSivasId des Bogens eingeben: ")) + (if (= id "") (princ "\nAbgebrochen.") + (progn + ;; Versuch als Zahl, dann als String + (setq eintrag (omni:get-bogen (if (/= (atoi id) 0) (atoi id) id))) + (if eintrag + (progn + (princ (strcat "\n ProfilTyp: " (omni:sivasid-to-str (omni:val eintrag "ProfilTyp")))) + (princ (strcat "\n Radius: " (itoa (fix (omni:val eintrag "Radius"))))) + (princ (strcat "\n KurvenWinkel: " (rtos (omni:val eintrag "KurvenWinkel") 2 1))) + (princ (strcat "\n Breite: " (itoa (fix (omni:val eintrag "Breite"))))) + (princ (strcat "\n Laenge: " (itoa (fix (omni:val eintrag "Länge"))))) + (princ (strcat "\n Antriebsart: " (itoa (fix (omni:val eintrag "Antriebsart"))))) + ) + (princ (strcat "\nKein Bogen mit SivasId '" id "' gefunden.")) + ) + ) + ) + (princ) +) + + +;; --- BricsCAD-Befehl: Weichen-Info anzeigen --- +(defun c:OMNI_INFO_WEICHE ( / id eintrag wkl) + (if (null *OMNI-WEICHEN*) (omni:load-data)) + (setq id (getstring T "\nSivasId der Weiche eingeben: ")) + (if (= id "") (princ "\nAbgebrochen.") + (progn + (setq eintrag (omni:get-weiche (if (/= (atoi id) 0) (atoi id) id))) + (if eintrag + (progn + (princ (strcat "\n ProfilTyp: " (omni:sivasid-to-str (omni:val eintrag "ProfilTyp")))) + (princ (strcat "\n WeichenTyp: " (omni:sivasid-to-str (omni:val eintrag "WeichenTyp")))) + (setq wkl (omni:val eintrag "KurvenWinkel")) + (princ (strcat "\n KurvenWinkel: " (if (= (type wkl) 'INT) (itoa wkl) (rtos wkl 2 1)))) + (princ (strcat "\n Schaltungstyp: " (omni:sivasid-to-str (omni:val eintrag "Schaltungstyp")))) + (princ (strcat "\n Breite: " (itoa (fix (omni:val eintrag "Breite"))))) + (princ (strcat "\n Laenge: " (itoa (fix (omni:val eintrag "Länge"))))) + (princ (strcat "\n KurvenRichtung: " (itoa (fix (omni:val eintrag "KurvenRichtung"))))) + (if (omni:val eintrag "WeichenkörperLänge") + (princ (strcat "\n WK-Laenge: " (rtos (omni:val eintrag "WeichenkörperLänge") 2 1))) + ) + ) + (princ (strcat "\nKeine Weiche mit SivasId '" id "' gefunden.")) + ) + ) + ) + (princ) +) + + +;; ============================================================ +;; OMNIFLO BOGEN-DIALOG +;; Generischer Dialog fuer Bogen-Auswahl nach Winkel +;; ============================================================ + + +;; --- Detail-Felder im Dialog aktualisieren --- +;; Wird bei Dropdown-Aenderung aufgerufen (action_tile callback) +(defun omni:bogen-dlg-update (idx-str / idx eintrag wkl) + (setq idx (atoi idx-str)) + (setq eintrag (nth idx *OMNI-DLG-BOEGEN*)) + (if eintrag + (progn + (set_tile "val_sivasnr" + (omni:sivasid-to-str (omni:val eintrag "Sivasnr"))) + (setq wkl (omni:val eintrag "KurvenWinkel")) + (set_tile "val_winkel" + (if (= (type wkl) 'INT) (strcat (itoa wkl) " Grad") + (strcat (rtos wkl 2 1) " Grad") + ) + ) + (set_tile "val_radius" + (itoa (fix (omni:val eintrag "Radius")))) + (set_tile "val_breite" + (itoa (fix (omni:val eintrag "Breite")))) + (set_tile "val_laenge" + (itoa (fix (omni:val eintrag "Länge")))) + ) + ) +) + + +;; --- Bogen-Auswahl-Dialog oeffnen --- +;; winkel = KurvenWinkel (90, 67.5, 45, 22.5, 180) +;; Rueckgabe: gewaehlter Bogen-Eintrag (alist) oder nil bei Abbruch +(defun omni:bogen-dialog (winkel / dcl-pfad dat boegen-liste + profil-liste ergebnis) + (if (null *OMNI-BOEGEN*) (omni:load-data)) + + ;; Boegen nach Winkel filtern + (setq boegen-liste (omni:filter *OMNI-BOEGEN* "KurvenWinkel" winkel)) + (if (null boegen-liste) + (progn + (alert (strcat "Keine Boegen fuer " + (if (= (type winkel) 'INT) (itoa winkel) (rtos winkel 2 1)) + " Grad gefunden.")) + nil + ) + (progn + ;; In globaler Variable fuer Dialog-Callbacks speichern + (setq *OMNI-DLG-BOEGEN* boegen-liste) + + ;; ProfilTyp-Liste fuer Dropdown aufbauen + (setq profil-liste + (mapcar '(lambda (e) (cdr (assoc "ProfilTyp" e))) boegen-liste)) + + ;; DCL laden + (setq dcl-pfad (strcat (getenv "DXFM_DCL") "/omniflo_boegen.dcl")) + (setq dat (load_dialog dcl-pfad)) + (if (not (new_dialog "omniflo_boegen" dat)) + (progn (alert "Bogen-Dialog konnte nicht geladen werden.") nil) + (progn + ;; Dropdown befuellen + (start_list "bogenart") + (mapcar 'add_list profil-liste) + (end_list) + (set_tile "bogenart" "0") + + ;; Startwerte anzeigen + (omni:bogen-dlg-update "0") + + ;; Callback bei Dropdown-Aenderung + (action_tile "bogenart" "(omni:bogen-dlg-update $value)") + + ;; OK/Abbrechen + (action_tile "accept" + "(setq ergebnis (atoi (get_tile \"bogenart\"))) (done_dialog 1)") + (action_tile "cancel" "(done_dialog 0)") + + (start_dialog) + (unload_dialog dat) + + ;; Gewaehlten Eintrag zurueckgeben + (if ergebnis + (nth ergebnis *OMNI-DLG-BOEGEN*) + nil + ) + ) + ) + ) + ) +) + + +;; ============================================================ +;; OMNIFLO MODUL-BEFEHLE +;; ============================================================ + +;; --- Omniflo / Boegen --- +(defun c:OMNI_APB_630_90 ( / eintrag) + (setq eintrag (omni:bogen-dialog 90)) + (if eintrag + (omni:insert-from-entry eintrag) + (princ "\n[BOGEN] Abgebrochen.") + ) + (princ) +) + +(defun c:OMNI_APB_550_675 ( / eintrag) + (setq eintrag (omni:bogen-dialog 67.5)) + (if eintrag + (omni:insert-from-entry eintrag) + (princ "\n[BOGEN] Abgebrochen.") + ) + (princ) +) + +(defun c:OMNI_APB_630_45 ( / eintrag) + (setq eintrag (omni:bogen-dialog 45)) + (if eintrag + (omni:insert-from-entry eintrag) + (princ "\n[BOGEN] Abgebrochen.") + ) + (princ) +) + +(defun c:OMNI_APB_550_225 ( / eintrag) + (setq eintrag (omni:bogen-dialog 22.5)) + (if eintrag + (omni:insert-from-entry eintrag) + (princ "\n[BOGEN] Abgebrochen.") + ) + (princ) +) + +(defun c:OMNI_APB_650_180 ( / eintrag) + (setq eintrag (omni:bogen-dialog 180)) + (if eintrag + (omni:insert-from-entry eintrag) + (princ "\n[BOGEN] Abgebrochen.") + ) + (princ) +) + +;; --- Omniflo / Aluprofil Gerade --- + +;; Aluprofil-Fahrstrecke einfuegen. +;; +;; Ablauf: +;; 1. Quell-Block (.dwg) temporaer einfuegen, Attribute lesen, loeschen +;; 2. Nutzer waehlt Einfuegepunkt -> Text "blockname" wird horizontal platziert +;; 3. Nutzer klickt Endpunkt -> Linie definiert Fahrstreckenlaenge und Richtung +;; 4. Laenge wird gegen laengemax geprueft (Fehlermeldung bei Ueberschreitung) +;; 5. Compound-Block aus Linie + ATTDEFs (mit Quell-Werten) wird erzeugt +;; Blockname: blockname_YYYYMMDDHHMMSS +;; 6. Text wird gedreht, oberhalb der Linie positioniert, Inhalt aktualisiert +;; z.B. "APG110 L=2879" +;; +;; blockname = Profiltyp (z.B. "AP60", "AP110", "APG110") +;; laengemax = Maximale Fahrstreckenlaenge in mm +(defun omni:insert-block (blockname laengemax / + pt pt2 laenge laengeStr + dx dy angle angleDeg + textEnt textHeight textGap + perpX perpY textPt ed + lastEnt ss e bname blockEnt + srcAttribs attribDefs attribs + ok) + + (setq textHeight 100.0) + (setq textGap 20.0) + + ;; 0. Attribute aus der Quell-.dwg lesen (vor ssg-start, da eigene INSERT/ERASE) + (setq srcAttribs (ssg-attrib-read-dwg (strcat *block-path* blockname ".dwg"))) + (if (null srcAttribs) + (progn (princ "\n[OMNI] Keine Attribute im Quell-Block gefunden.") nil) + (progn + ;; LAENGEMAX aus Quell-Attribut lesen (falls vorhanden), sonst Parameter + (if (and (assoc "LAENGEMAX" srcAttribs) + (> (strlen (cdr (assoc "LAENGEMAX" srcAttribs))) 0)) + (setq laengemax (atof (cdr (assoc "LAENGEMAX" srcAttribs)))) + ) + + (setq pt (getpoint "\nEinfuegepunkt waehlen: ")) + (if (null pt) + (progn (princ "\n[OMNI] Abgebrochen.") nil) + (progn + (ssg-start "OMNI Aluprofil" '(("OSMODE") ("ATTREQ") ("ATTDIA"))) + ;; ATTREQ/ATTDIA auf 0 setzen (werden durch ssg-end wiederhergestellt) + (setvar "ATTREQ" 0) + (setvar "ATTDIA" 0) + + ;; 1. Text horizontal am Einfuegepunkt erzeugen + (entmake (list '(0 . "TEXT") + (cons 8 (getvar "CLAYER")) + (cons 10 (list (car pt) (cadr pt) + (if (caddr pt) (caddr pt) 0.0))) + (cons 40 textHeight) + (cons 1 blockname) + '(50 . 0.0))) + (setq textEnt (entlast)) + + ;; 2. Endpunkt fuer Fahrstrecke abfragen (Schleife bei Ueberschreitung) + (setq ok nil) + (while (not ok) + (setq pt2 (getpoint pt "\nEndpunkt der Fahrstrecke waehlen: ")) + (if (null pt2) + (progn + ;; Abbruch: Text loeschen + (command "_.ERASE" textEnt "") + (princ "\n[OMNI] Abgebrochen.") + (setq ok T pt nil) + ) + (progn + (setq laenge (distance (list (car pt) (cadr pt)) + (list (car pt2) (cadr pt2)))) + (if (> laenge laengemax) + (alert (strcat "Die gewuenschte Fahrstreckenlaenge von " + (rtos laenge 2 0) " mm ueberschreitet die Maximallaenge von " + (rtos laengemax 2 0) " mm des Fahrstreckenprofils.\n" + "Bitte neu definieren!")) + (progn + (setq laengeStr (rtos laenge 2 0)) + (setq dx (- (car pt2) (car pt)) + dy (- (cadr pt2) (cadr pt))) + (setq angle (atan dy dx)) + (setq angleDeg (* (/ 180.0 pi) angle)) + + ;; 3. Compound-Block: Linie bei (0,0) + ATTDEFs aus Quell-Attributen + (setq lastEnt textEnt) + + ;; Linie von Ursprung bis (laenge, 0) + (command "_.LINE" (list 0.0 0.0) (list laenge 0.0) "") + + ;; ATTDEFs aus Quell-Attributen erzeugen + (setq attribDefs (ssg-attrib-alist-to-defs srcAttribs)) + (ssg-attrib-make-defs attribDefs 50.0) + + ;; Neue Entities einsammeln (alles nach textEnt) + (setq ss (ssadd)) + (setq e (entnext lastEnt)) + (while e (ssadd e ss) (setq e (entnext e))) + + ;; Block mit eindeutigem Zeitstempel-Namen erzeugen + (setq bname (strcat blockname "_" (ssg-timestamp))) + ;; Falls Name schon existiert, Suffix anhaengen + (if (tblsearch "BLOCK" bname) + (setq bname (strcat bname "_" (itoa (fix (* (getvar "CDATE") 1000000))))) + ) + (command "_.-BLOCK" bname (list 0.0 0.0 0.0) ss "") + + ;; Block einfuegen (ATTREQ/ATTDIA bereits auf 0) + (command "_.INSERT" bname pt 1 1 angleDeg) + + (setq blockEnt (entlast)) + + ;; 4. Attribute setzen: Quell-Werte + LAENGE/A aktualisieren + (setq attribs srcAttribs) + (if (assoc "LAENGE" attribs) + (setq attribs (subst (cons "LAENGE" laengeStr) + (assoc "LAENGE" attribs) attribs)) + (setq attribs (cons (cons "LAENGE" laengeStr) attribs)) + ) + (if (assoc "A" attribs) + (setq attribs (subst (cons "A" laengeStr) + (assoc "A" attribs) attribs)) + (setq attribs (cons (cons "A" laengeStr) attribs)) + ) + (ssg-attrib-set-on blockEnt attribs) + + ;; 5. Text aktualisieren: oberhalb der Linie positionieren, + ;; um Linienwinkel drehen, Inhalt mit Laenge ergaenzen + (setq perpX (* (- (sin angle)) textGap) + perpY (* (cos angle) textGap)) + (setq textPt (list (+ (car pt) perpX) + (+ (cadr pt) perpY) + (if (caddr pt) (caddr pt) 0.0))) + + (setq ed (entget textEnt)) + (setq ed (subst (cons 10 textPt) (assoc 10 ed) ed)) + (if (assoc 50 ed) + (setq ed (subst (cons 50 angle) (assoc 50 ed) ed)) + (setq ed (append ed (list (cons 50 angle)))) + ) + (setq ed (subst (cons 1 (strcat blockname " L=" laengeStr)) + (assoc 1 ed) ed)) + (entmod ed) + (entupd textEnt) + + (princ (strcat "\n[OMNI] " bname " eingefuegt. Laenge=" laengeStr " mm")) + (setq ok T) + ) + ) + ) + ) + ) + + (ssg-end) + pt + ) + ) + ) + ) +) + +(defun c:OMNI_AP60 () + (omni:insert-block "AP60" 7000.0) + (princ) +) +(defun c:OMNI_AP110 () + (omni:insert-block "AP110" 6000.0) + (princ) +) +(defun c:OMNI_APG110 () + (omni:insert-block "APG110" 6000.0) + (princ) +) + +;; ============================================================ +;; OMNIFLO WEICHEN-DIALOG +;; Generischer Dialog fuer Weichen-Auswahl nach Winkel/Typ +;; mit Filter fuer Schaltungstyp und Richtung +;; ============================================================ + + +;; --- Aktuelle Filterwerte aus Radio-Buttons lesen --- +(defun omni:weichen-get-filter ( / sch ri) + (setq sch "alle") + (if (= (get_tile "sch_m") "1") (setq sch "M")) + (if (= (get_tile "sch_p") "1") (setq sch "P")) + (setq ri "alle") + (if (= (get_tile "ri_links") "1") (setq ri "1")) + (if (= (get_tile "ri_rechts") "1") (setq ri "2")) + (list sch ri) +) + + +;; --- Gefilterte Weichen-Liste aufbauen --- +;; basis-liste = alle Weichen fuer den gewaehlten Winkel/Typ +;; sch-filter = "M", "P" oder "alle" +;; ri-filter = "1", "2" oder "alle" +(defun omni:weichen-filter-liste (basis-liste sch-filter ri-filter / eintrag sch kr ergebnis) + (setq ergebnis nil) + (foreach eintrag basis-liste + (setq sch (cdr (assoc "Schaltungstyp" eintrag))) + (setq kr (cdr (assoc "KurvenRichtung" eintrag))) + (if (and + (or (= sch-filter "alle") (= sch sch-filter)) + (or (= ri-filter "alle") + (= (omni:sivasid-to-str kr) ri-filter)) + ) + (setq ergebnis (cons eintrag ergebnis)) + ) + ) + (reverse ergebnis) +) + + +;; --- Dropdown mit gefilterter Liste neu befuellen --- +(defun omni:weichen-dlg-refresh ( / filter sch-f ri-f gefiltert profil-liste) + (setq filter (omni:weichen-get-filter)) + (setq sch-f (car filter)) + (setq ri-f (cadr filter)) + (setq gefiltert (omni:weichen-filter-liste *OMNI-DLG-WEICHEN-BASIS* sch-f ri-f)) + (setq *OMNI-DLG-WEICHEN* gefiltert) + + ;; Dropdown neu befuellen + (setq profil-liste + (mapcar '(lambda (e) (cdr (assoc "ProfilTyp" e))) gefiltert)) + (start_list "profiltyp") + (mapcar 'add_list profil-liste) + (end_list) + + ;; Ersten Eintrag anzeigen (falls vorhanden) + (if gefiltert + (progn + (set_tile "profiltyp" "0") + (omni:weichen-dlg-update "0") + ) + (progn + (set_tile "val_sivasnr" "---") + (set_tile "val_winkel" "---") + (set_tile "val_breite" "---") + (set_tile "val_laenge" "---") + ) + ) +) + + +;; --- Detail-Felder im Weichen-Dialog aktualisieren --- +(defun omni:weichen-dlg-update (idx-str / idx eintrag wkl) + (setq idx (atoi idx-str)) + (setq eintrag (nth idx *OMNI-DLG-WEICHEN*)) + (if eintrag + (progn + (set_tile "val_sivasnr" + (omni:sivasid-to-str (omni:val eintrag "Sivasnr"))) + (setq wkl (omni:val eintrag "KurvenWinkel")) + (set_tile "val_winkel" + (if (= (type wkl) 'INT) (strcat (itoa wkl) " Grad") + (strcat (rtos wkl 2 1) " Grad") + ) + ) + (set_tile "val_breite" + (itoa (fix (omni:val eintrag "Breite")))) + (set_tile "val_laenge" + (itoa (fix (omni:val eintrag "Länge")))) + ) + ) +) + + +;; --- Weichen-Auswahl-Dialog oeffnen --- +;; winkel = KurvenWinkel (90, 45, 0, 22.5) +;; weichentyp = "Einzelweiche", "Doppelweiche", "Dreiwegeweiche" oder nil fuer alle +;; Rueckgabe: gewaehlter Weichen-Eintrag (alist) oder nil bei Abbruch +(defun omni:weichen-dialog (winkel weichentyp / dcl-pfad dat basis-liste + profil-liste ergebnis) + (if (null *OMNI-WEICHEN*) (omni:load-data)) + + ;; Weichen nach Winkel filtern (nil = alle Winkel) + (if winkel + (setq basis-liste (omni:filter *OMNI-WEICHEN* "KurvenWinkel" winkel)) + (setq basis-liste *OMNI-WEICHEN*) + ) + + ;; Optional nach WeichenTyp filtern + (if weichentyp + (setq basis-liste + (vl-remove-if-not + '(lambda (e) (= (cdr (assoc "WeichenTyp" e)) weichentyp)) + basis-liste)) + ) + + (if (null basis-liste) + (progn + (alert (strcat "Keine Weichen fuer " + (cond + ((null winkel) "alle Winkel") + ((= (type winkel) 'INT) (strcat (itoa winkel) " Grad")) + (T (strcat (rtos winkel 2 1) " Grad")) + ) + (if weichentyp (strcat " / " weichentyp) "") + " gefunden.")) + nil + ) + (progn + ;; Basis-Liste und gefilterte Liste in globalen Variablen speichern + (setq *OMNI-DLG-WEICHEN-BASIS* basis-liste) + (setq *OMNI-DLG-WEICHEN* basis-liste) + + ;; ProfilTyp-Liste fuer Dropdown aufbauen + (setq profil-liste + (mapcar '(lambda (e) (cdr (assoc "ProfilTyp" e))) basis-liste)) + + ;; DCL laden + (setq dcl-pfad (strcat (getenv "DXFM_DCL") "/omniflo_weichen.dcl")) + (setq dat (load_dialog dcl-pfad)) + (if (not (new_dialog "omniflo_weichen" dat)) + (progn (alert "Weichen-Dialog konnte nicht geladen werden.") nil) + (progn + ;; Dropdown befuellen + (start_list "profiltyp") + (mapcar 'add_list profil-liste) + (end_list) + (set_tile "profiltyp" "0") + + ;; Startwerte anzeigen + (omni:weichen-dlg-update "0") + + ;; Callback bei Dropdown-Aenderung + (action_tile "profiltyp" "(omni:weichen-dlg-update $value)") + + ;; Callbacks fuer Filter-Radio-Buttons (alle loesen Refresh aus) + (action_tile "sch_alle" "(omni:weichen-dlg-refresh)") + (action_tile "sch_m" "(omni:weichen-dlg-refresh)") + (action_tile "sch_p" "(omni:weichen-dlg-refresh)") + (action_tile "ri_alle" "(omni:weichen-dlg-refresh)") + (action_tile "ri_links" "(omni:weichen-dlg-refresh)") + (action_tile "ri_rechts" "(omni:weichen-dlg-refresh)") + + ;; OK/Abbrechen + (action_tile "accept" + "(setq ergebnis (atoi (get_tile \"profiltyp\"))) (done_dialog 1)") + (action_tile "cancel" "(done_dialog 0)") + + (start_dialog) + (unload_dialog dat) + + ;; Gewaehlten Eintrag zurueckgeben + (if ergebnis + (nth ergebnis *OMNI-DLG-WEICHEN*) + nil + ) + ) + ) + ) + ) +) + + +;; ============================================================ +;; OMNIFLO DXF-BLOCK EINFUEGEN +;; Fuegt eine DXF-Datei aus data/omniflo/ als Block ein. +;; Der Benutzer waehlt den Einfuegepunkt und Drehwinkel. +;; ============================================================ + +;; --- DXF-Datei als Block einfuegen --- +;; sivasnr-str = SivasNr als String (Dateiname ohne .dxf) +;; Rueckgabe: Einfuegepunkt oder nil bei Abbruch +(defun omni:insert-dxf (sivasnr-str / dxf-pfad data-pfad pt) + (setq data-pfad (getenv "DXFM_DATA")) + (if (null data-pfad) + (progn + (princ "\n[OMNI] FEHLER: DXFM_DATA nicht gesetzt!") + nil + ) + (progn + (setq dxf-pfad (strcat data-pfad "/omniflo/" sivasnr-str ".dxf")) + (if (not (findfile dxf-pfad)) + (progn + (princ (strcat "\n[OMNI] FEHLER: DXF nicht gefunden: " dxf-pfad)) + nil + ) + (progn + (setq pt (getpoint "\nEinfuegepunkt waehlen: ")) + (if (null pt) + (progn (princ "\n[OMNI] Abgebrochen.") nil) + (progn + (ssg-start "OMNI DXF Insert" '(("OSMODE"))) + + ;; Block einfuegen mit Winkelabfrage (pause) + (command "_.INSERT" dxf-pfad pt "" "" pause) + + (princ (strcat "\n[OMNI] " sivasnr-str " eingefuegt.")) + (ssg-end) + pt + ) + ) + ) + ) + ) + ) +) + + +;; --- Eintrag aus Dialog-Ergebnis einfuegen --- +;; Nimmt einen Eintrag (alist) und fuegt die zugehoerige DXF ein. +(defun omni:insert-from-entry (eintrag / sivasnr-str) + (if eintrag + (progn + (setq sivasnr-str (omni:sivasid-to-str (omni:val eintrag "Sivasnr"))) + (princ (strcat "\n[OMNI] Einfuegen: " + (omni:val eintrag "ProfilTyp") " (" sivasnr-str ")")) + (omni:insert-dxf sivasnr-str) + ) + ) +) + + +;; ============================================================ +;; OMNIFLO WEICHEN-BEFEHLE +;; ============================================================ + +;; --- Omniflo / Weiche 90 Grad --- +(defun c:OMNI_W90_Einfach ( / eintrag) + (setq eintrag (omni:weichen-dialog 90 "Einzelweiche")) + (if eintrag + (omni:insert-from-entry eintrag) + (princ "\n[WEICHE] Abgebrochen.") + ) + (princ) +) + +(defun c:OMNI_W90_Doppel ( / eintrag) + (setq eintrag (omni:weichen-dialog 90 "Doppelweiche")) + (if eintrag + (omni:insert-from-entry eintrag) + (princ "\n[WEICHE] Abgebrochen.") + ) + (princ) +) + +(defun c:OMNI_W90_Dreiwege ( / eintrag) + (setq eintrag (omni:weichen-dialog 90 "Dreiwegeweiche")) + (if eintrag + (omni:insert-from-entry eintrag) + (princ "\n[WEICHE] Abgebrochen.") + ) + (princ) +) + +;; --- Omniflo / Weiche 45 Grad --- +(defun c:OMNI_W45_Einfach ( / eintrag) + (setq eintrag (omni:weichen-dialog 45 "Einzelweiche")) + (if eintrag + (omni:insert-from-entry eintrag) + (princ "\n[WEICHE] Abgebrochen.") + ) + (princ) +) + +(defun c:OMNI_W45_Doppel ( / eintrag) + (setq eintrag (omni:weichen-dialog 45 "Doppelweiche")) + (if eintrag + (omni:insert-from-entry eintrag) + (princ "\n[WEICHE] Abgebrochen.") + ) + (princ) +) + +(defun c:OMNI_W45_Dreiwege ( / eintrag) + (setq eintrag (omni:weichen-dialog 45 "Dreiwegeweiche")) + (if eintrag + (omni:insert-from-entry eintrag) + (princ "\n[WEICHE] Abgebrochen.") + ) + (princ) +) + +;; --- Omniflo / Weichen Parallel --- +(defun c:OMNI_WP_Einfach ( / eintrag) + (setq eintrag (omni:weichen-dialog 0 "Einzelweiche")) + (if eintrag + (omni:insert-from-entry eintrag) + (princ "\n[WEICHE] Abgebrochen.") + ) + (princ) +) + +(defun c:OMNI_WP_Doppel ( / eintrag) + (setq eintrag (omni:weichen-dialog 0 "Doppelweiche")) + (if eintrag + (omni:insert-from-entry eintrag) + (princ "\n[WEICHE] Abgebrochen.") + ) + (princ) +) + +(defun c:OMNI_WP_Dreiwege ( / eintrag) + (setq eintrag (omni:weichen-dialog 0 "Dreiwegeweiche")) + (if eintrag + (omni:insert-from-entry eintrag) + (princ "\n[WEICHE] Abgebrochen.") + ) + (princ) +) + +;; --- Omniflo / Weichenkoerper --- +(defun c:OMNI_WK_Einfach ( / eintrag) + (setq eintrag (omni:weichen-dialog 22.5 "Einzelweiche")) + (if eintrag + (omni:insert-from-entry eintrag) + (princ "\n[WEICHE] Abgebrochen.") + ) + (princ) +) + +(defun c:OMNI_WK_Doppel ( / eintrag) + (setq eintrag (omni:weichen-dialog 22.5 "Doppelweiche")) + (if eintrag + (omni:insert-from-entry eintrag) + (princ "\n[WEICHE] Abgebrochen.") + ) + (princ) +) + +(defun c:OMNI_WK_Dreiwege ( / eintrag) + (setq eintrag (omni:weichen-dialog 22.5 "Dreiwegeweiche")) + (if eintrag + (omni:insert-from-entry eintrag) + (princ "\n[WEICHE] Abgebrochen.") + ) + (princ) +) + +;; --- Omniflo / Weichenkombinationen --- +(defun c:OMNI_WKomb_Delta ( / eintrag) + (setq eintrag (omni:weichen-dialog nil "Deltaweiche")) + (if eintrag + (omni:insert-from-entry eintrag) + (princ "\n[WEICHE] Abgebrochen.") + ) + (princ) +) + +(defun c:OMNI_WKomb_Star ( / eintrag) + (setq eintrag (omni:weichen-dialog nil "Sternweiche")) + (if eintrag + (omni:insert-from-entry eintrag) + (princ "\n[WEICHE] Abgebrochen.") + ) + (princ) +) + +;; --- Omniflo / TEF Elemente --- +(defun c:OMNI_TEF_UmlenkR () + (princ "\n[DUMMY] Umlenkspannst. rechts fuer TEF links") + (princ) +) + +(defun c:OMNI_TEF_UmlenkL () + (princ "\n[DUMMY] Umlenkspannst. links fuer TEF rechts") + (princ) +) + +(defun c:OMNI_TEF_AntriebL () + (princ "\n[DUMMY] Antriebst. links fuer TEF links") + (princ) +) + +(defun c:OMNI_TEF_AntriebR () + (princ "\n[DUMMY] Antriebst. rechts fuer TEF rechts") + (princ) +) + +(defun c:OMNI_TEF_Gerade () + (princ "\n[DUMMY] TEF Gerade") + (princ) +) + +;; --- Omniflo / KettenFoerderer --- +(defun c:OMNI_KettenFoerderer () + (princ "\n[DUMMY] KettenFoerderer") + (princ) +) diff --git a/Lisp/ssg_dbg.lsp b/Lisp/ssg_dbg.lsp index 558519f..4281817 100644 --- a/Lisp/ssg_dbg.lsp +++ b/Lisp/ssg_dbg.lsp @@ -117,7 +117,6 @@ ) ) (setq fullpath (strcat dir filename)) - (prompt (strcat "\n[DBG] Oeffne: " fullpath)) ;; Datei mit "w" erstellen/leeren, Header schreiben, sofort schliessen (setq fh (open fullpath "w")) (if fh diff --git a/Lisp/ssg_load.lsp b/Lisp/ssg_load.lsp index e156e6f..47726d7 100644 --- a/Lisp/ssg_load.lsp +++ b/Lisp/ssg_load.lsp @@ -20,10 +20,6 @@ (strcat (getvar "DWGPREFIX")) ) ) - (load (strcat base-path "ssg_dbg.lsp") "ssg_dbg.lsp nicht gefunden") - (if (not *dbg-path*) - (dbgopen "debugfile.dbg" "DXFM_LOG") ; Fallback: direkt geladen ohne on_start.lsp - ) (load (strcat base-path "ssg_core.lsp") "ssg_core.lsp nicht gefunden") (load (strcat base-path "ssg_dialog.lsp") "ssg_dialog.lsp nicht gefunden") (load (strcat base-path "ssg_layer.lsp") "ssg_layer.lsp nicht gefunden") diff --git a/bin/on_start.lsp b/bin/on_start.lsp index 405a354..9fc0471 100644 --- a/bin/on_start.lsp +++ b/bin/on_start.lsp @@ -45,13 +45,117 @@ (dbgflush) ) +;; ------------------------------------------------------------ +;; SSG-LIB-LOAD-PYRX - PyRx BRX laden und Python-Module via PYLOAD starten +;; Aufruf: (ssg-lib-load-pyrx menu-pfad) +;; Deaktiviert wegen PyRx/BricsCAD V25.3 Inkompatibilitaet (cad-pyrx 2.2.58.5504) +;; Reaktivieren sobald kompatible Version verfuegbar ist. +;; ------------------------------------------------------------ +(defun ssg-lib-load-pyrx (menu-pfad / acadver-str ver-punkt ver-major pyrx-pfad brx-datei brx-result) + ;; BricsCAD-Version ermitteln + (setq acadver-str (getvar "ACADVER")) + (setq ver-punkt (vl-string-search "." acadver-str)) + (setq ver-major (if ver-punkt (substr acadver-str 1 ver-punkt) "25")) + ;; Pyrx-Pfad: .venv (primaer), dann System/User Python + (setq pyrx-pfad + (cond + ((findfile (strcat menu-pfad "/.venv/Lib/site-packages/pyrx/RxLoaderV" ver-major ".0.brx")) + (strcat menu-pfad "/.venv/Lib/site-packages/pyrx")) + ((and (getenv "PYTHONHOME") + (findfile (strcat (getenv "PYTHONHOME") "/Lib/site-packages/pyrx/RxLoaderV" ver-major ".0.brx"))) + (strcat (getenv "PYTHONHOME") "/Lib/site-packages/pyrx")) + ((and (getenv "APPDATA") + (findfile (strcat (getenv "APPDATA") "/Python/Python312/site-packages/pyrx/RxLoaderV" ver-major ".0.brx"))) + (strcat (getenv "APPDATA") "/Python/Python312/site-packages/pyrx")) + (t nil) + ) + ) + ;; BRX laden wenn PyRx noch nicht via Startup-Suite aktiv + (if (not (member (strcat "rxloaderv" ver-major ".0.brx") (arx))) + (if pyrx-pfad + (progn + (setq brx-datei (strcat pyrx-pfad "/RxLoaderV" ver-major ".0.brx")) + (setq brx-result (vl-catch-all-apply 'arxload (list brx-datei))) + (ssg-dbg-pyrx pyrx-pfad ver-major brx-datei brx-result) + (if (vl-catch-all-error-p brx-result) + (progn + (princ (strcat "\n[SSG_LIB] FEHLER: RxLoaderV" ver-major ".0.brx nicht geladen: " + (vl-catch-all-error-message brx-result))) + (princ "\n[SSG_LIB] HINWEIS: PyRx einmalig via APPLOAD -> Startup Suite einrichten.") + ) + (princ (strcat "\n[SSG_LIB] PyRx RxLoader geladen (V" ver-major "): " brx-datei)) + ) + ) + (princ (strcat "\n[SSG_LIB] WARNUNG: RxLoaderV" ver-major ".0.brx nicht gefunden." + "\n PYTHONHOME=" (if (getenv "PYTHONHOME") (getenv "PYTHONHOME") "nicht gesetzt"))) + ) + (progn + (dbgmsg "[PyRx] PyRx bereits via Startup-Suite aktiv") + (princ (strcat "\n[SSG_LIB] PyRx (V" ver-major ") via Startup-Suite aktiv.")) + ) + ) + ;; Python-Module laden - nur wenn PYLOAD verfuegbar + (dbgmsg "[PYLOAD] --- Python-Module ---") + (if (not (member "PYLOAD" (atoms-family 0))) + (progn + (dbgmsg "[PYLOAD] PYLOAD nicht verfuegbar - ueberspringe alle Module") + (princ "\n[SSG_LIB] WARNUNG: PYLOAD nicht verfuegbar (PyRx nicht geladen).") + (princ "\n[SSG_LIB] Python-Befehle (KreiselInsert etc.) nicht aktiv.") + ) + (foreach pymod '("eckrad" "kreisel" "dblclick" "omniflo" "omniflo_boegen" "omniflo_weichen") + (if (findfile (strcat menu-pfad "/lib/elemente/" pymod ".py")) + (progn + (dbgmsg (strcat "PYLOAD start: " pymod ".py")) + (command "PYLOAD" (strcat menu-pfad "/lib/elemente/" pymod ".py")) + (dbgmsg (strcat "PYLOAD done: " pymod ".py")) + (princ (strcat "\n[SSG_LIB] Python-Modul " pymod ".py geladen.")) + ) + (progn + (dbgmsg (strcat "PYLOAD skip: " pymod ".py -- nicht gefunden")) + (princ (strcat "\n[SSG_LIB] HINWEIS: " pymod ".py nicht gefunden.")) + ) + ) + ) + ) + (dbgflush) +) + +;; ------------------------------------------------------------ +;; SSG-LIB-REGISTER-CHECK - Verfuegbarkeit aller Befehle ins Debug-Log schreiben +;; ------------------------------------------------------------ +(defun ssg-lib-register-check () + (dbgmsg "[CHECK] --- AutoLISP Funktionen (atoms-family) ---") + (dbgmsg (strcat "ssg-start: " (ssg-dbg-fn "SSG-START"))) + (dbgmsg (strcat "ssg-end: " (ssg-dbg-fn "SSG-END"))) + (dbgmsg (strcat "ssg-make-layer: " (ssg-dbg-fn "SSG-MAKE-LAYER"))) + (dbgmsg (strcat "ssg-errhan: " (ssg-dbg-fn "SSG-ERRHAN"))) + (dbgmsg (strcat "ensure-block-loaded: " (ssg-dbg-fn "ENSURE-BLOCK-LOADED"))) + (dbgmsg "[CHECK] --- SSG_LIB_Commands (c:...) ---") + (dbgmsg (strcat "c:ILS_BTMT_Beladung: " (ssg-dbg-fn "C:ILS_BTMT_BELADUNG"))) + (dbgmsg (strcat "c:ILS_K90LA: " (ssg-dbg-fn "C:ILS_K90LA"))) + (dbgmsg (strcat "c:ILS_TEF_Strecke: " (ssg-dbg-fn "C:ILS_TEF_STRECKE"))) + (dbgmsg "[CHECK] --- PyRx Befehle (BRX-Ebene, nicht via atoms-family pruefbar) ---") + (dbgmsg (strcat "KreiselInsert: " (ssg-dbg-fn "C:KREISELINSERT"))) + (dbgmsg (strcat "KreiselEdit: " (ssg-dbg-fn "C:KREISELEDIT"))) + (dbgmsg (strcat "EckradEdit: " (ssg-dbg-fn "C:ECKRADEDIT"))) + (dbgmsg (strcat "SSG_BLOCKEDIT: " (ssg-dbg-fn "C:SSG_BLOCKEDIT"))) + (dbgmsg (strcat "OMNI_AP60: " (ssg-dbg-fn "C:OMNI_AP60"))) + (dbgmsg (strcat "OMNI_APB_630_90: " (ssg-dbg-fn "C:OMNI_APB_630_90"))) + (dbgmsg (strcat "OMNI_W90_Einfach: " (ssg-dbg-fn "C:OMNI_W90_EINFACH"))) + (dbgflush) +) + (defun ssg-lib-startup ( / lisp-pfad menu-pfad curr-srch menu-datei - pyrx-pfad acadver-str ver-punkt ver-major brx-datei brx-fallback brx-result) + acadver-str ver-punkt ver-major lsp-fb-pfad) ;; Pfade aus Umgebungsvariablen lesen (setq lisp-pfad (getenv "DXFM_LISP")) (setq menu-pfad (getenv "DXFMAKRO")) + ;; Pfadtrenner vereinheitlichen: Backslash -> Forward-Slash + (if lisp-pfad (setq lisp-pfad (vl-string-translate "\\" "/" lisp-pfad))) + (if menu-pfad (setq menu-pfad (vl-string-translate "\\" "/" menu-pfad))) + (if (null lisp-pfad) (progn (princ "\n[SSG_LIB] FEHLER: DXFM_LISP nicht gesetzt!") @@ -106,104 +210,32 @@ ;; DBLCLKEDIT deaktivieren (Block-Editor nicht bei Doppelklick oeffnen) (setvar "DBLCLKEDIT" 0) - ;; PyRx BRX-Plugin: wird via BricsCAD Startup-Suite geladen (nicht via arxload). - ;; Grund: PyRxV25.0.brx muss vor dem LISP-Startup aktiv sein. - ;; Einmalige Einrichtung: APPLOAD -> PyRxV25.0.brx -> "Startup Suite" hinzufuegen. - ;; - ;; Pyrx-Pfad: aus PYTHONHOME (system Python), nicht aus .venv - (if menu-pfad - (progn - (setq acadver-str (getvar "ACADVER")) - (setq ver-punkt (vl-string-search "." acadver-str)) - (setq ver-major (if ver-punkt (substr acadver-str 1 ver-punkt) "25")) - ;; Pyrx-Pfad: .venv (primaer, dort installiert), dann System/User Python - (setq pyrx-pfad - (cond - ((findfile (strcat menu-pfad "/.venv/Lib/site-packages/pyrx/RxLoaderV" ver-major ".0.brx")) - (strcat menu-pfad "/.venv/Lib/site-packages/pyrx")) - ((and (getenv "PYTHONHOME") - (findfile (strcat (getenv "PYTHONHOME") "/Lib/site-packages/pyrx/RxLoaderV" ver-major ".0.brx"))) - (strcat (getenv "PYTHONHOME") "/Lib/site-packages/pyrx")) - ((and (getenv "APPDATA") - (findfile (strcat (getenv "APPDATA") "/Python/Python312/site-packages/pyrx/RxLoaderV" ver-major ".0.brx"))) - (strcat (getenv "APPDATA") "/Python/Python312/site-packages/pyrx")) - (t nil) - ) - ) - ;; Wenn PyRx noch nicht aktiv (nicht via Startup Suite geladen): arxload versuchen - (if (not (member (strcat "rxloaderv" ver-major ".0.brx") (arx))) - (if pyrx-pfad - (progn - (setq brx-datei (strcat pyrx-pfad "/RxLoaderV" ver-major ".0.brx")) - (setq brx-result (vl-catch-all-apply 'arxload (list brx-datei))) - (ssg-dbg-pyrx pyrx-pfad ver-major brx-datei brx-result) - (if (vl-catch-all-error-p brx-result) - (progn - (princ (strcat "\n[SSG_LIB] FEHLER: RxLoaderV" ver-major ".0.brx nicht geladen: " - (vl-catch-all-error-message brx-result))) - (princ "\n[SSG_LIB] HINWEIS: PyRx einmalig via APPLOAD -> Startup Suite einrichten.") - ) - (princ (strcat "\n[SSG_LIB] PyRx RxLoader geladen (V" ver-major "): " brx-datei)) - ) - ) - (princ (strcat "\n[SSG_LIB] WARNUNG: PyRxV" ver-major ".0.brx nicht gefunden." - "\n PYTHONHOME=" (if (getenv "PYTHONHOME") (getenv "PYTHONHOME") "nicht gesetzt"))) - ) - (progn - (dbgmsg "[PyRx] PyRx bereits via Startup-Suite aktiv") - (princ (strcat "\n[SSG_LIB] PyRx (V" ver-major ") via Startup-Suite aktiv.")) - ) - ) - ) - ) + ;; (ssg-lib-load-pyrx menu-pfad) ;; deaktiviert - PyRx/BricsCAD V25.3 Inkompatibilitaet - ;; Python-Module laden (PyRx) - nur wenn PYLOAD verfuegbar - (dbgmsg "[PYLOAD] --- Python-Module ---") - (if (not (member "PYLOAD" (atoms-family 0))) + ;; Fallback: LSP-Routinen laden wenn PyRx nicht aktiv + (setq acadver-str (getvar "ACADVER")) + (setq ver-punkt (vl-string-search "." acadver-str)) + (setq ver-major (if ver-punkt (substr acadver-str 1 ver-punkt) "25")) + (if (not (member (strcat "rxloaderv" ver-major ".0.brx") (arx))) (progn - (dbgmsg "[PYLOAD] PYLOAD nicht verfuegbar - ueberspringe alle Module") - (princ "\n[SSG_LIB] WARNUNG: PYLOAD nicht verfuegbar (PyRx nicht geladen).") - (princ "\n[SSG_LIB] Python-Befehle (KreiselInsert etc.) nicht aktiv.") - ) - (if menu-pfad - (foreach pymod '("eckrad" "kreisel" "dblclick" "omniflo" "omniflo_boegen" "omniflo_weichen") - (if (findfile (strcat menu-pfad "/lib/elemente/" pymod ".py")) + (dbgmsg "[FALLBACK] PyRx nicht aktiv - lade LSP-Fallbacks") + (foreach lsp-fb (list "KreiselInsert" "OmniModulInsert") + (setq lsp-fb-pfad (strcat lisp-pfad "/" lsp-fb ".lsp")) + (if (findfile lsp-fb-pfad) (progn - (dbgmsg (strcat "PYLOAD start: " pymod ".py")) - (command "PYLOAD" (strcat menu-pfad "/lib/elemente/" pymod ".py")) - (dbgmsg (strcat "PYLOAD done: " pymod ".py")) - (princ (strcat "\n[SSG_LIB] Python-Modul " pymod ".py geladen.")) - ) - (progn - (dbgmsg (strcat "PYLOAD skip: " pymod ".py -- nicht gefunden")) - (princ (strcat "\n[SSG_LIB] HINWEIS: " pymod ".py nicht gefunden.")) + (ssg-lib-safe-load lsp-fb-pfad) + (dbgmsg (strcat "[FALLBACK] geladen: " lsp-fb ".lsp")) + (princ (strcat "\n[SSG_LIB] Fallback geladen: " lsp-fb ".lsp")) ) + (dbgmsg (strcat "[FALLBACK] nicht gefunden: " lsp-fb ".lsp")) ) ) ) + (dbgmsg "[FALLBACK] PyRx aktiv - kein LSP-Fallback noetig") ) (dbgflush) - ;; Verfuegbarkeits-Check aller erwarteten Funktionen - (dbgmsg "[CHECK] --- AutoLISP Funktionen (atoms-family) ---") - (dbgmsg (strcat "ssg-start: " (ssg-dbg-fn "SSG-START"))) - (dbgmsg (strcat "ssg-end: " (ssg-dbg-fn "SSG-END"))) - (dbgmsg (strcat "ssg-make-layer: " (ssg-dbg-fn "SSG-MAKE-LAYER"))) - (dbgmsg (strcat "ssg-errhan: " (ssg-dbg-fn "SSG-ERRHAN"))) - (dbgmsg (strcat "ensure-block-loaded: " (ssg-dbg-fn "ENSURE-BLOCK-LOADED"))) - (dbgmsg "[CHECK] --- SSG_LIB_Commands (c:...) ---") - (dbgmsg (strcat "c:ILS_BTMT_Beladung: " (ssg-dbg-fn "C:ILS_BTMT_BELADUNG"))) - (dbgmsg (strcat "c:ILS_K90LA: " (ssg-dbg-fn "C:ILS_K90LA"))) - (dbgmsg (strcat "c:ILS_TEF_Strecke: " (ssg-dbg-fn "C:ILS_TEF_STRECKE"))) - (dbgmsg "[CHECK] --- PyRx Befehle (BRX-Ebene, nicht via atoms-family pruefbar) ---") - (dbgmsg (strcat "KreiselInsert: " (ssg-dbg-fn "C:KREISELINSERT"))) - (dbgmsg (strcat "KreiselEdit: " (ssg-dbg-fn "C:KREISELEDIT"))) - (dbgmsg (strcat "EckradEdit: " (ssg-dbg-fn "C:ECKRADEDIT"))) - (dbgmsg (strcat "SSG_BLOCKEDIT: " (ssg-dbg-fn "C:SSG_BLOCKEDIT"))) - (dbgmsg (strcat "OMNI_AP60: " (ssg-dbg-fn "C:OMNI_AP60"))) - (dbgmsg (strcat "OMNI_APB_630_90: " (ssg-dbg-fn "C:OMNI_APB_630_90"))) - (dbgmsg (strcat "OMNI_W90_Einfach: " (ssg-dbg-fn "C:OMNI_W90_EINFACH"))) - (dbgflush) + (ssg-lib-register-check) (princ "\n[SSG_LIB] Startup abgeschlossen.") ) diff --git a/dcl/kreisel_edit.dcl b/dcl/kreisel_edit.dcl new file mode 100644 index 0000000..b715316 --- /dev/null +++ b/dcl/kreisel_edit.dcl @@ -0,0 +1,53 @@ +// ============================================================ +// kreisel_edit.dcl - Kreisel Parameter bearbeiten +// Erlaubt das Aendern von Abstand, Hoehe, Ausrichtung, +// Drehrichtung, Typ und Name eines bestehenden Kreisels. +// ============================================================ + +kreisel_edit : dialog { + label = "Kreisel bearbeiten"; + + : column { + + : edit_box { + key = "name"; + label = "Kreiselname:"; + edit_width = 30; + } + + : row { + : edit_box { + key = "abstand"; + label = "Abstand (mm):"; + edit_width = 10; + } + : edit_box { + key = "hoehe"; + label = "Hoehe (mm):"; + edit_width = 10; + } + } + + : popup_list { + key = "ausrichtung"; + label = "Ausrichtung:"; + width = 30; + } + + : row { + : popup_list { + key = "drehrichtung"; + label = "Motordrehrichtung:"; + width = 16; + } + : popup_list { + key = "kreiselart"; + label = "Typ:"; + width = 16; + } + } + + } + + ok_cancel; +} diff --git a/dcl/omniflo_boegen.dcl b/dcl/omniflo_boegen.dcl new file mode 100644 index 0000000..c4830b1 --- /dev/null +++ b/dcl/omniflo_boegen.dcl @@ -0,0 +1,54 @@ +// ============================================================ +// omniflo_boegen.dcl - Bogen-Auswahl Dialog fuer Omniflo +// Zeigt gefilterte Boegen nach Winkel mit Details an. +// ============================================================ + +omniflo_boegen : dialog { + label = "Omniflo Bogen Auswahl"; + + : row { + : popup_list { + key = "bogenart"; + label = "Bogenart:"; + width = 42; + } + : edit_box { + key = "val_sivasnr"; + label = "SivasNr:"; + width = 22; + is_enabled = false; + } + } + + : row { + : edit_box { + key = "val_winkel"; + label = "Winkel:"; + width = 16; + is_enabled = false; + } + : edit_box { + key = "val_radius"; + label = "Radius:"; + width = 16; + is_enabled = false; + } + } + + : row { + : edit_box { + key = "val_breite"; + label = "Breite:"; + width = 16; + is_enabled = false; + } + : edit_box { + key = "val_laenge"; + label = "Laenge:"; + width = 16; + is_enabled = false; + } + } + + ok_cancel; +} diff --git a/dcl/omniflo_weichen.dcl b/dcl/omniflo_weichen.dcl new file mode 100644 index 0000000..e629c70 --- /dev/null +++ b/dcl/omniflo_weichen.dcl @@ -0,0 +1,65 @@ +// ============================================================ +// omniflo_weichen.dcl - Weichen-Auswahl Dialog fuer Omniflo +// Zeigt gefilterte Weichen mit Details und Filteroptionen an. +// ============================================================ + +omniflo_weichen : dialog { + label = "Omniflo Weichen Auswahl"; + + : row { + : popup_list { + key = "profiltyp"; + label = "Profiltyp-Auswahl:"; + width = 50; + } + } + + : row { + : boxed_radio_column { + key = "schaltung"; + label = "Schaltungstyp"; + : radio_button { key = "sch_alle"; label = "Alle"; value = "1"; } + : radio_button { key = "sch_m"; label = "Mechanisch (M)"; } + : radio_button { key = "sch_p"; label = "Pneumatisch (P)"; } + } + : boxed_radio_column { + key = "richtung"; + label = "Richtung"; + : radio_button { key = "ri_alle"; label = "Alle"; value = "1"; } + : radio_button { key = "ri_links"; label = "Links"; } + : radio_button { key = "ri_rechts"; label = "Rechts"; } + } + } + + : row { + : edit_box { + key = "val_sivasnr"; + label = "SivasNr:"; + width = 22; + is_enabled = false; + } + : edit_box { + key = "val_winkel"; + label = "Winkel:"; + width = 12; + is_enabled = false; + } + } + + : row { + : edit_box { + key = "val_breite"; + label = "Breite:"; + width = 12; + is_enabled = false; + } + : edit_box { + key = "val_laenge"; + label = "Laenge:"; + width = 12; + is_enabled = false; + } + } + + ok_cancel; +}