- Symbole erzeugen (HW_SYMBOLE, Einzelbefehle HW_SYM_*): Bauteile nach cfg/io_regeln.json (reduzierte Kopie aus kabellaengen), Symbole aus cfg/hw_symbole.json katalog-identisch nachgebaut (lib/hw_symbole.py), REALE_POSITION mit x auf dem Bauteil, Paare uebereinander, Ausweichen in y ohne Ueberlappung - Symbole nummerieren (HW_NUMMERIEREN): lib/create_numbers.py samt error_collector.py und cfg/enumerate.cfg aus kabellaengen uebernommen - Ausgabeziel per Dialog dcl/hw_ausgabe.dcl: aktuelle Zeichnung, bestehende Datei ergaenzen oder neue Datei - Materialfluss mit XDATA SSG_HW_MF, ergaenzt vorhandene Datei - Doku doc/hw_planung.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
610 lines
26 KiB
Common Lisp
610 lines
26 KiB
Common Lisp
;; ============================================================
|
|
;; HwPlanung.lsp - Hardware-Planung (Menue "HW Planung")
|
|
;;
|
|
;; Ziel der Ausgabe: vor jedem Erzeugungsbefehl fragt der Dialog
|
|
;; dcl/hw_ausgabe.dcl (hw-ausgabe-waehlen), wohin:
|
|
;; - aktuelle Zeichnung: Python schreibt eine einheitenlose Zwischendatei
|
|
;; <dwg>_HW_tmp.dxf, die als Block bei 0,0 eingefuegt und aufgeloest wird
|
|
;; (hw-in-aktuelle-zeichnung); die fruehere Ausgabe (XDATA SSG_HW_MF bzw.
|
|
;; SSG_HW_SYM) wird danach entfernt
|
|
;; - bestehende Datei ergaenzen (Dateiauswahl)
|
|
;; - neue Datei (Name, Ordner DXFM_RESULTS)
|
|
;; In einer Datei ersetzt jeder Befehl nur seinen eigenen Anteil - was der
|
|
;; Anwender dort ergaenzt (Renamer-Rahmen, Polylinien), bleibt erhalten.
|
|
;;
|
|
;; HW_MATERIALFLUSS ("Materialfluss erzeugen", in der Ursprungszeichnung):
|
|
;; EXPORTCSV -> lib/hw_materialfluss.py zeichnet Kreisel-Rechtecke in
|
|
;; Drehrichtung, Strecken-Polylinien AS -> Separatoren -> ES, Weichen und
|
|
;; Be-/Entladungen auf die HW_*-Layer der _HW.dxf.
|
|
;;
|
|
;; HW_SYMBOLE ("Symbole erzeugen", in der Ursprungszeichnung): sucht die
|
|
;; Mechanik-Bauteile nach cfg/io_regeln.json (auch verschachtelt in
|
|
;; VF_n/GF_n/KREISEL_n), schreibt den Symbolplan als JSON und laesst
|
|
;; lib/hw_symbole.py die Symbole in die _HW.dxf setzen - deren Aussehen und
|
|
;; Attribute stehen in cfg/hw_symbole.json (keine Symbol-Bibliothek). Die Geraete-ID ist noch eine VORLAGE (z.B. MB1@@@) -
|
|
;; nummeriert wird erst mit HW_NUMMERIEREN, entlang der Rahmen/Polylinien,
|
|
;; die der Anwender in der _HW.dxf zieht. Einzelbefehle HW_SYM_VENTILE usw.
|
|
;;
|
|
;; HW_NUMMERIEREN ("Symbole nummerieren", in der geoeffneten _HW.dxf):
|
|
;; speichert die Zeichnung, laesst lib/create_numbers.py (Renamer-Bereiche,
|
|
;; cfg/enumerate.cfg) die Nummern berechnen und traegt sie in die offene
|
|
;; Zeichnung ein.
|
|
;;
|
|
;; Setzt export.lsp voraus (laedt die MNL vor).
|
|
;; ============================================================
|
|
|
|
(setq *hw-skript* "hw_materialfluss.py")
|
|
(setq *hw-sym-skript* "hw_symbole.py")
|
|
(setq *hw-num-skript* "create_numbers.py")
|
|
|
|
;; XDATA der erzeugten Objekte (gesetzt von lib/hw_materialfluss.py bzw.
|
|
;; lib/hw_symbole.py) - daran erkennt hw-alte-ausgabe die fruehere Ausgabe
|
|
(setq *hw-mf-app* "SSG_HW_MF")
|
|
(setq *hw-sym-app* "SSG_HW_SYM")
|
|
|
|
;; Letzte Wahl im Ausgabe-Dialog (modus datei name), je Sitzung
|
|
(if (not (boundp '*hw-ausgabe-letzt*)) (setq *hw-ausgabe-letzt* nil))
|
|
|
|
;; Geraeteart -> Praefix (Einzelbefehle unten, noch nicht im Menue)
|
|
(setq *hw-sym-arten*
|
|
'(("ventile" "MB") ("sensoren" "BG") ("motoren" "MA")
|
|
("motorschutz" "FC") ("encoder" "GF") ("scanner" "BX")))
|
|
|
|
;; ------------------------------------------------------------
|
|
;; Reine Kerne (tests/test_unit.lsp, tu-tests-hw)
|
|
;; ------------------------------------------------------------
|
|
|
|
;; Name der Ausgabedatei aus dem Zeichnungsnamen: "Mubea.dwg" -> "Mubea_HW.dxf"
|
|
(defun hw-dxf-name (dwgname)
|
|
(strcat (vl-filename-base dwgname) "_HW.dxf")
|
|
)
|
|
|
|
;; Zahl fuer JSON, unabhaengig von DIMZIN/LUPREC (rtos wuerde bei DIMZIN-
|
|
;; Unterdrueckung der fuehrenden Null ".5" liefern - kein gueltiges JSON).
|
|
;; Auf 0.001 gerundet: (hw-json-zahl -12.5) -> "-12.500"
|
|
(defun hw-json-zahl (x / n r s)
|
|
(setq n (fix (+ (* (abs x) 1000.0) 0.5))
|
|
r (itoa (rem n 1000)))
|
|
(while (< (strlen r) 3) (setq r (strcat "0" r)))
|
|
(setq s (strcat (itoa (/ n 1000)) "." r))
|
|
(if (and (< x 0.0) (> n 0)) (strcat "-" s) s)
|
|
)
|
|
|
|
(defun hw-json-text (s)
|
|
(strcat "\"" (ssg-json-escape s) "\"")
|
|
)
|
|
|
|
;; Rollen-Objekt zum Rollennamen
|
|
(defun hw-sym-rolle (regeln name / erg)
|
|
(foreach r (ssg-json-get regeln "rollen")
|
|
(if (and (null erg) (= (ssg-json-get r "rolle") name)) (setq erg r)))
|
|
erg
|
|
)
|
|
|
|
;; Rollennamen eines Bauteils - je Eintrag in "benoetigt" die erste Alternative
|
|
(defun hw-sym-bauteil-rollen (bauteil)
|
|
(mapcar 'car (ssg-json-get bauteil "benoetigt"))
|
|
)
|
|
|
|
;; wcmatch-Muster aller Mechanik-Bloecke (gross, kommagetrennt)
|
|
(defun hw-sym-muster (regeln / muster)
|
|
(foreach b (ssg-json-get regeln "bauteile")
|
|
(setq muster (append muster (ssg-json-get b "bloecke"))))
|
|
(strcase (ssg-join muster ","))
|
|
)
|
|
|
|
;; Bauteil-Objekt zum Blocknamen (erster Treffer) oder nil
|
|
(defun hw-sym-bauteil-fuer-block (regeln blockname / erg)
|
|
(foreach b (ssg-json-get regeln "bauteile")
|
|
(if (and (null erg)
|
|
(wcmatch (strcase blockname)
|
|
(strcase (ssg-join (ssg-json-get b "bloecke") ","))))
|
|
(setq erg b)))
|
|
erg
|
|
)
|
|
|
|
;; Symbol (Blockname) einer Rolle, ggf. abhaengig vom Blocknamen des Bauteils
|
|
;; (block_nach_name, z.B. Vario-Motorstation rechts -> Motor VARIO rechts)
|
|
(defun hw-sym-block-fuer (rolle bauteil-blockname / erg)
|
|
(foreach v (ssg-json-get rolle "block_nach_name")
|
|
(if (and (null erg)
|
|
(wcmatch (strcase bauteil-blockname) (strcase (ssg-json-get v "muster"))))
|
|
(setq erg (ssg-json-get v "block"))))
|
|
(cond (erg) ((ssg-json-get rolle "block")))
|
|
)
|
|
|
|
;; IO-Vorlage eines Symbols: Praefix + io_vorlage, z.B. "MB" + "1@@@" -> "MB1@@@"
|
|
(defun hw-sym-io-vorlage (regeln praefix)
|
|
(strcat praefix (cond ((ssg-json-get regeln "io_vorlage")) ("1@@@")))
|
|
)
|
|
|
|
;; Zielpunkt eines Bauteils in der _HW.dxf: flach (Z = 0) - die _HW.dxf ist
|
|
;; ein Grundriss, die Nummerierung arbeitet in XY.
|
|
(defun hw-sym-ziel (pt)
|
|
(list (car pt) (cadr pt) 0.0)
|
|
)
|
|
|
|
;; Plan aus Bauteil-Instanzen. instanz = (bauteil blockname pt key).
|
|
;; Rueckgabe: Liste von Records, je Rolle in der Reihenfolge von "benoetigt"
|
|
;; (= Stapelfolge der Symbole am Bauteil, erstes oben):
|
|
;; (praefix io-vorlage symbolblock zielpunkt rolle key bauteilname)
|
|
;; Den Einfuegepunkt rechnet lib/hw_symbole.py aus dem Zielpunkt und der
|
|
;; Symbolgeometrie (Marke REALE_POSITION auf dem Ziel, ohne Ueberlappung).
|
|
(defun hw-sym-plan (regeln instanzen / erg rolle)
|
|
(foreach ins instanzen
|
|
(foreach name (hw-sym-bauteil-rollen (car ins))
|
|
(if (setq rolle (hw-sym-rolle regeln name))
|
|
(setq erg (cons (list (ssg-json-get rolle "praefix")
|
|
(hw-sym-io-vorlage regeln (ssg-json-get rolle "praefix"))
|
|
(hw-sym-block-fuer rolle (nth 1 ins))
|
|
(hw-sym-ziel (nth 2 ins))
|
|
name
|
|
(nth 3 ins)
|
|
(ssg-json-get (car ins) "bauteil"))
|
|
erg)))))
|
|
(reverse erg)
|
|
)
|
|
|
|
;; Sortierung der Instanzen: Bauteil-Reihenfolge im Regelwerk, dann x, dann y
|
|
(defun hw-sym-instanzen-sortieren (regeln instanzen / bauteile)
|
|
(setq bauteile (mapcar '(lambda (b) (ssg-json-get b "bauteil"))
|
|
(ssg-json-get regeln "bauteile")))
|
|
;; Rang vorab anhaengen (rang . instanz), sortieren, wieder abnehmen
|
|
(mapcar 'cdr
|
|
(vl-sort
|
|
(mapcar '(lambda (ins)
|
|
(cons (vl-position (ssg-json-get (car ins) "bauteil") bauteile) ins))
|
|
instanzen)
|
|
'(lambda (a b)
|
|
(cond ((/= (car a) (car b)) (< (car a) (car b)))
|
|
((not (equal (car (nth 3 a)) (car (nth 3 b)) 0.5))
|
|
(< (car (nth 3 a)) (car (nth 3 b))))
|
|
(t (< (cadr (nth 3 a)) (cadr (nth 3 b))))))))
|
|
)
|
|
|
|
;; Symbolplan als JSON-Zeilen fuer lib/hw_symbole.py. praefixe = die
|
|
;; Geraetearten, die dieser Lauf einfuegt bzw. ersetzt; der Plan selbst ist
|
|
;; immer vollstaendig, damit die Lage nicht davon abhaengt.
|
|
(defun hw-sym-plan->json (praefixe plan / zeilen)
|
|
(setq zeilen
|
|
(mapcar
|
|
'(lambda (r)
|
|
(strcat " {\"praefix\": " (hw-json-text (nth 0 r))
|
|
", \"io\": " (hw-json-text (nth 1 r))
|
|
", \"block\": " (hw-json-text (nth 2 r))
|
|
", \"x\": " (hw-json-zahl (car (nth 3 r)))
|
|
", \"y\": " (hw-json-zahl (cadr (nth 3 r)))
|
|
", \"rolle\": " (hw-json-text (nth 4 r))
|
|
", \"key\": " (hw-json-text (nth 5 r))
|
|
", \"bauteil\": " (hw-json-text (nth 6 r)) "}"))
|
|
plan))
|
|
(append
|
|
(list "{"
|
|
(strcat " \"praefixe\": [" (ssg-join (mapcar 'hw-json-text praefixe) ", ") "],")
|
|
" \"symbole\": [")
|
|
(if zeilen
|
|
(append (mapcar '(lambda (z) (strcat z ",")) (reverse (cdr (reverse zeilen))))
|
|
(list (last zeilen))))
|
|
(list " ]" "}"))
|
|
)
|
|
|
|
;; Name einer neuen Ausgabedatei: Leerzeichen am Rand und eine Endung .dxf
|
|
;; werden entfernt (" Anlage_HW.DXF " -> "Anlage_HW")
|
|
(defun hw-name-ohne-dxf (name / n)
|
|
(setq n (vl-string-trim " " (cond (name) (""))))
|
|
(if (wcmatch (strcase n) "*.DXF")
|
|
(substr n 1 (- (strlen n) 4))
|
|
n)
|
|
)
|
|
|
|
;; Gueltiger Dateiname: nicht leer, keine Pfad- oder Sonderzeichen
|
|
(defun hw-name-gueltig-p (name / n)
|
|
(setq n (hw-name-ohne-dxf name))
|
|
(and (> (strlen n) 0)
|
|
(not (wcmatch n "*[\\/:`*?\"<>|]*")))
|
|
)
|
|
|
|
(defun hw-neu-pfad (ordner name)
|
|
(strcat ordner "/" (hw-name-ohne-dxf name) ".dxf")
|
|
)
|
|
|
|
;; Eingaben des Ausgabe-Dialogs pruefen. datei-da / neu-da = ob die gewaehlte
|
|
;; bzw. die neue Datei schon existiert. Rueckgabe: nil oder ssg-text-Key.
|
|
(defun hw-ausgabe-pruefen (modus datei-da name neu-da)
|
|
(cond
|
|
((= modus "ergaenzen") (if datei-da nil "hw-aus-datei-fehlt"))
|
|
((= modus "neu")
|
|
(cond ((not (hw-name-gueltig-p name)) "hw-aus-name-ungueltig")
|
|
(neu-da "hw-aus-name-existiert")))
|
|
((= modus "aktuell") nil)
|
|
(t "hw-aus-datei-fehlt"))
|
|
)
|
|
|
|
;; Nummerierung uebertragen: passt ein Eintrag aus der create_numbers-Info
|
|
;; (old_value + Einfuegepunkt) auf ein Attribut? pos/wert aus der Zeichnung.
|
|
(defun hw-num-eintrag-p (eintrag wert pos / p)
|
|
(setq p (ssg-json-get eintrag "position"))
|
|
(and (= (ssg-json-get eintrag "old_value") wert)
|
|
(equal (ssg-json-get p "x") (car pos) 0.01)
|
|
(equal (ssg-json-get p "y") (cadr pos) 0.01))
|
|
)
|
|
|
|
;; ------------------------------------------------------------
|
|
;; Gemeinsam: Ausgabeordner und Python-Aufruf
|
|
;; ------------------------------------------------------------
|
|
|
|
;; DXFM_RESULTS, ausser waehrend TEST_EXPORT_ALL (*export-test-override*)
|
|
(defun hw-ausgabe-ordner ( / d)
|
|
(setq d (if *export-test-override* *export-test-override* (getenv "DXFM_RESULTS")))
|
|
(if (and d (not (vl-file-directory-p d))) (vl-mkdir d))
|
|
d
|
|
)
|
|
|
|
;; Python-Skript aus DXFM_LIB synchron ausfuehren, Log nach DXFM_LOG.
|
|
;; Rueckgabe: Exitcode (0 = ok) oder nil, wenn gar nicht gestartet.
|
|
;; ok-codes = Exitcodes, die KEIN Python-Fehler sind (create_numbers endet
|
|
;; mit 1, wenn es Planungsfehler meldet - die stehen in seiner Fehlerdatei).
|
|
(defun hw-python (label skript args log-name ok-codes / log-pfad rc)
|
|
(setq log-pfad (strcat (cond ((getenv "DXFM_LOG")) ((hw-ausgabe-ordner))) "/" log-name))
|
|
(setq rc (export:run-python (export:python-exe)
|
|
(strcat (getenv "DXFM_LIB") "/" skript) args log-pfad))
|
|
(if (null rc) (princ (ssg-textf "exp-python-call-failed" (list label))))
|
|
(export:log-ausgeben log-pfad 15)
|
|
(if (and rc (not (member rc (cons 0 ok-codes))))
|
|
(princ (ssg-textf "exp-python-error" (list label rc log-pfad))))
|
|
rc
|
|
)
|
|
|
|
(defun hw-umgebung-ok-p (label)
|
|
(if (getenv "DXFM_LIB")
|
|
T
|
|
(progn (princ (ssg-textf "exp-dxfm-lib-missing" (list label))) nil))
|
|
)
|
|
|
|
;; ------------------------------------------------------------
|
|
;; Ausgabeziel: Dialog dcl/hw_ausgabe.dcl
|
|
;; ------------------------------------------------------------
|
|
|
|
(defun hw-ausgabe-modus-tiles (modus)
|
|
(mode_tile "datei" (if (= modus "ergaenzen") 0 1))
|
|
(mode_tile "waehlen" (if (= modus "ergaenzen") 0 1))
|
|
(mode_tile "name" (if (= modus "neu") 0 1))
|
|
)
|
|
|
|
;; OK-Knopf: Eingaben pruefen, bei Fehler im Dialog bleiben. Arbeitet auf den
|
|
;; Variablen von hw-ausgabe-waehlen (modus datei name ordner pfad - AutoLISP
|
|
;; bindet dynamisch, der Rueckruf laeuft waehrend dessen start_dialog).
|
|
(defun hw-ausgabe-ok ( / fehler)
|
|
(setq modus (get_tile "modus")
|
|
datei (get_tile "datei")
|
|
name (get_tile "name"))
|
|
(setq fehler (hw-ausgabe-pruefen modus
|
|
(if (and (/= datei "") (findfile datei)) T)
|
|
name
|
|
(if (findfile (hw-neu-pfad ordner name)) T)))
|
|
(if fehler
|
|
(set_tile "error" (ssg-text fehler))
|
|
(progn
|
|
(setq pfad (cond ((= modus "aktuell")
|
|
(strcat ordner "/" (vl-filename-base (getvar "DWGNAME")) "_HW_tmp.dxf"))
|
|
((= modus "ergaenzen") datei)
|
|
(t (hw-neu-pfad ordner name))))
|
|
(done_dialog 1)))
|
|
)
|
|
|
|
;; Ziel der Ausgabe erfragen. aktion = Text oben im Dialog.
|
|
;; Rueckgabe: (modus pfad) mit modus "aktuell"/"ergaenzen"/"neu" - bei
|
|
;; "aktuell" ist pfad die Zwischendatei - oder nil bei Abbruch. Ohne GUI
|
|
;; (automatische Tests): Standarddatei <dwg>_HW.dxf, anlegen oder ergaenzen.
|
|
(defun hw-ausgabe-waehlen (aktion / ordner modus datei name pfad dcl dat r f erg weiter)
|
|
(setq ordner (hw-ausgabe-ordner))
|
|
(cond
|
|
((not (ssg-gui-p))
|
|
(list "ergaenzen" (strcat ordner "/" (hw-dxf-name (getvar "DWGNAME")))))
|
|
((or (null (getenv "DXFM_DCL"))
|
|
(not (findfile (setq dcl (strcat (getenv "DXFM_DCL") "/hw_ausgabe.dcl"))))
|
|
(< (setq dat (load_dialog dcl)) 0))
|
|
(princ (ssg-textf "hw-aus-dcl-fehlt" (list (cond (dcl) ("hw_ausgabe.dcl")))))
|
|
nil)
|
|
(t
|
|
(setq modus (cond ((car *hw-ausgabe-letzt*)) ("neu"))
|
|
datei (cond ((cadr *hw-ausgabe-letzt*))
|
|
((strcat ordner "/" (hw-dxf-name (getvar "DWGNAME")))))
|
|
name (cond ((caddr *hw-ausgabe-letzt*))
|
|
((vl-filename-base (hw-dxf-name (getvar "DWGNAME")))))
|
|
weiter T)
|
|
(while weiter
|
|
(if (not (new_dialog "hw_ausgabe" dat))
|
|
(setq weiter nil)
|
|
(progn
|
|
(set_tile "aktion" aktion)
|
|
(set_tile "modus" modus)
|
|
(set_tile "datei" datei)
|
|
(set_tile "name" name)
|
|
(set_tile "ordner" (ssg-textf "hw-aus-ordner" (list ordner)))
|
|
(hw-ausgabe-modus-tiles modus)
|
|
(action_tile "modus" "(setq modus $value) (hw-ausgabe-modus-tiles modus) (set_tile \"error\" \"\")")
|
|
;; getfiled geht nicht aus einem Rueckruf: Dialog schliessen,
|
|
;; waehlen, Dialog neu zeigen
|
|
(action_tile "waehlen"
|
|
"(setq datei (get_tile \"datei\") name (get_tile \"name\")) (done_dialog 2)")
|
|
(action_tile "accept" "(hw-ausgabe-ok)")
|
|
(action_tile "cancel" "(done_dialog 0)")
|
|
(setq r (start_dialog))
|
|
(cond
|
|
((= r 2)
|
|
(if (setq f (getfiled (ssg-text "hw-aus-waehlen")
|
|
(if (and (/= datei "") (findfile datei)) datei (strcat ordner "/"))
|
|
"dxf" 0))
|
|
(setq datei f modus "ergaenzen")))
|
|
((= r 1) (setq weiter nil erg (list modus pfad)))
|
|
(t (setq weiter nil))))))
|
|
(unload_dialog dat)
|
|
(if erg (setq *hw-ausgabe-letzt* (list modus datei name)))
|
|
erg))
|
|
)
|
|
|
|
;; Zieldatei fuer Python vorbereiten: die Zwischendatei der aktuellen
|
|
;; Zeichnung wird jedesmal frisch angelegt. Rueckgabe: Pfad.
|
|
(defun hw-ziel-pfad (ziel)
|
|
(if (and (= (car ziel) "aktuell") (findfile (cadr ziel)))
|
|
(vl-file-delete (cadr ziel)))
|
|
(cadr ziel)
|
|
)
|
|
|
|
;; Zusatzargumente fuer Python: Zwischendatei ohne Einheit (sonst skaliert
|
|
;; BricsCAD sie beim Einfuegen in eine Zeichnung mit anderer Einheit)
|
|
(defun hw-zusatz-args (ziel)
|
|
(if (= (car ziel) "aktuell") '("--einheitenlos"))
|
|
)
|
|
|
|
;; Fruehere Ausgabe in der aktuellen Zeichnung: alle Objekte mit XDATA app,
|
|
;; bei praefixe nur die, deren erster 1000er-Wert (Praefix) darin steht.
|
|
(defun hw-alte-ausgabe (app praefixe / ss i e xd erg)
|
|
(if (setq ss (ssget "_X" (list (list -3 (list app)))))
|
|
(progn
|
|
(setq i 0)
|
|
(while (setq e (ssname ss i))
|
|
(setq xd (cdr (assoc app (cdr (assoc -3 (entget e (list app)))))))
|
|
(if (or (null praefixe) (member (cdr (assoc 1000 xd)) praefixe))
|
|
(setq erg (cons e erg)))
|
|
(setq i (1+ i)))))
|
|
erg
|
|
)
|
|
|
|
;; Zwischendatei als Block bei 0,0 einfuegen und aufloesen; erst wenn das
|
|
;; geklappt hat, die fruehere Ausgabe (alte) loeschen. Rueckgabe: T/nil.
|
|
(defun hw-in-aktuelle-zeichnung (pfad alte / doc obj teile blk leer)
|
|
(setq doc (vla-get-ActiveDocument (vlax-get-acad-object)))
|
|
(setq obj (vl-catch-all-apply 'vla-InsertBlock
|
|
(list (vla-get-ModelSpace doc) (vlax-3D-point '(0 0 0)) pfad 1.0 1.0 1.0 0.0)))
|
|
(if (vl-catch-all-error-p obj)
|
|
nil
|
|
(progn
|
|
;; Leere Zwischendatei (HW_SYM_LOESCHEN, keine Bauteile): nichts
|
|
;; aufzuloesen - ein Explode wuerde scheitern, gilt aber als Erfolg
|
|
(setq blk (vl-catch-all-apply 'vla-Item (list (vla-get-Blocks doc) (vl-filename-base pfad))))
|
|
(setq leer (and (not (vl-catch-all-error-p blk)) (= (vla-get-Count blk) 0)))
|
|
(if (not leer) (setq teile (vl-catch-all-apply 'vla-Explode (list obj))))
|
|
(vla-Delete obj)
|
|
(if (not (vl-catch-all-error-p blk)) (vl-catch-all-apply 'vla-Delete (list blk)))
|
|
(if (vl-catch-all-error-p teile)
|
|
nil
|
|
(progn
|
|
(foreach e alte (if (entget e) (entdel e)))
|
|
(vl-file-delete pfad)
|
|
T))))
|
|
)
|
|
|
|
;; Ergebnis eines erfolgreichen Python-Laufs melden bzw. in die aktuelle
|
|
;; Zeichnung uebernehmen. app/praefixe: welche fruehere Ausgabe ersetzt wird.
|
|
(defun hw-ergebnis-uebernehmen (ziel app praefixe meldung / alte)
|
|
(if (= (car ziel) "aktuell")
|
|
(progn
|
|
(setq alte (hw-alte-ausgabe app praefixe))
|
|
(if (hw-in-aktuelle-zeichnung (cadr ziel) alte)
|
|
(princ (ssg-textf "hw-fertig-aktuell" (list (itoa (length alte)))))
|
|
(princ (ssg-textf "hw-aktuell-fehler" (list (cadr ziel))))))
|
|
(princ (ssg-textf meldung (list (cadr ziel)))))
|
|
)
|
|
|
|
;; ------------------------------------------------------------
|
|
;; MATERIALFLUSS
|
|
;; ------------------------------------------------------------
|
|
|
|
(defun c:HW_MATERIALFLUSS ( / label ziel out-dir csv-pfad dxf-pfad)
|
|
(setq label "HW_MATERIALFLUSS")
|
|
(if (and (hw-umgebung-ok-p label)
|
|
(setq ziel (hw-ausgabe-waehlen (ssg-text "hw-aus-materialfluss"))))
|
|
(progn
|
|
(setq out-dir (hw-ausgabe-ordner))
|
|
(setq csv-pfad (strcat out-dir "/" (export:dwg-praefix)
|
|
(export:filename "csv_csv")))
|
|
(setq dxf-pfad (hw-ziel-pfad ziel))
|
|
;; Alte CSV entfernen - sonst wuerde nach einem gescheiterten Export
|
|
;; still die Skizze aus dem vorigen Stand gezeichnet.
|
|
(if (findfile csv-pfad) (vl-file-delete csv-pfad))
|
|
|
|
(c:EXPORTCSV)
|
|
|
|
(if (not (findfile csv-pfad))
|
|
(princ (ssg-textf "hw-csv-fehlt" (list csv-pfad)))
|
|
(if (equal 0 (hw-python label *hw-skript*
|
|
(append (list csv-pfad dxf-pfad) (hw-zusatz-args ziel))
|
|
"hw_materialfluss.log" nil))
|
|
(hw-ergebnis-uebernehmen ziel *hw-mf-app* nil "hw-fertig")))))
|
|
(princ)
|
|
)
|
|
|
|
;; ------------------------------------------------------------
|
|
;; SYMBOLE ERZEUGEN (HW_SYMBOLE + Einzelbefehle je Geraeteart)
|
|
;; ------------------------------------------------------------
|
|
|
|
(defun hw-sym-regeln-laden ( / pfad regeln)
|
|
(setq pfad (strcat (cond ((getenv "DXFM_CFG")) ("")) "/io_regeln.json"))
|
|
(setq regeln (if (findfile pfad) (ssg-json-laden pfad)))
|
|
(if (null regeln) (princ (ssg-textf "hw-sym-regeln-fehlt" (list pfad))))
|
|
regeln
|
|
)
|
|
|
|
;; Alle Bauteile der Ursprungszeichnung: top-level INSERTs und in VF_n/GF_n/
|
|
;; KREISEL_n verschachtelte Mechanik-Bloecke (Weltlage ueber
|
|
;; csv:wrapper-welt-records, export.lsp). Katalogsymbole (ILS_*) werden
|
|
;; nicht durchsucht. Rueckgabe: sortierte Liste (bauteil blockname pt key).
|
|
(defun hw-sym-bauteile-sammeln (regeln / muster ss i ename ed name bt erg)
|
|
(setq muster (hw-sym-muster regeln))
|
|
(if (setq ss (ssget "_X" '((0 . "INSERT") (410 . "Model"))))
|
|
(progn
|
|
(setq i 0)
|
|
(while (setq ename (ssname ss i))
|
|
(setq ed (entget ename)
|
|
name (cdr (assoc 2 ed)))
|
|
(cond
|
|
((wcmatch (strcase name) muster)
|
|
(if (setq bt (hw-sym-bauteil-fuer-block regeln name))
|
|
(setq erg (cons (list bt name (trans (cdr (assoc 10 ed)) ename 0)
|
|
(cdr (assoc 5 ed)))
|
|
erg))))
|
|
((not (wcmatch (strcase name) "ILS_*,`**"))
|
|
(foreach rec (csv:wrapper-welt-records ename muster)
|
|
(if (setq bt (hw-sym-bauteil-fuer-block regeln (nth 2 rec)))
|
|
(setq erg (cons (list bt (nth 2 rec) (nth 3 rec)
|
|
(strcat (cdr (assoc 5 ed)) "/"
|
|
(cdr (assoc 5 (entget (nth 1 rec))))))
|
|
erg))))))
|
|
(setq i (1+ i)))))
|
|
(hw-sym-instanzen-sortieren regeln erg)
|
|
)
|
|
|
|
(defun hw-sym-zaehlen (schluessel alist / alt)
|
|
(setq alt (assoc schluessel alist))
|
|
(if alt
|
|
(subst (cons schluessel (1+ (cdr alt))) alt alist)
|
|
(cons (cons schluessel 1) alist))
|
|
)
|
|
|
|
;; Symbolplan als JSON schreiben und hw_symbole.py die Symbole der
|
|
;; angegebenen Praefixe ins gewaehlte Ziel setzen lassen (nil = alle Praefixe
|
|
;; des Regelwerks). mit-bauteilen = nil -> leerer Plan (nur entfernen).
|
|
(defun hw-sym-erzeugen (praefixe mit-bauteilen / label regeln instanzen plan out-dir
|
|
json-pfad dxf-pfad sym-pfad fh bt-zahl ziel)
|
|
(setq label "HW_SYMBOLE")
|
|
(if (and (hw-umgebung-ok-p label)
|
|
(setq regeln (hw-sym-regeln-laden))
|
|
(setq ziel (hw-ausgabe-waehlen (ssg-text "hw-aus-symbole"))))
|
|
(progn
|
|
(if (null praefixe)
|
|
(foreach r (ssg-json-get regeln "rollen")
|
|
(if (not (member (ssg-json-get r "praefix") praefixe))
|
|
(setq praefixe (append praefixe (list (ssg-json-get r "praefix")))))))
|
|
(if mit-bauteilen
|
|
(progn
|
|
(setq instanzen (hw-sym-bauteile-sammeln regeln))
|
|
(if (null instanzen) (princ (ssg-text "hw-sym-keine-bauteile")))
|
|
(foreach ins instanzen
|
|
(setq bt-zahl (hw-sym-zaehlen (ssg-json-get (car ins) "bauteil") bt-zahl)))
|
|
(foreach z (reverse bt-zahl)
|
|
(princ (ssg-textf "hw-sym-bauteile" (list (car z) (itoa (cdr z))))))
|
|
(setq plan (hw-sym-plan regeln instanzen))))
|
|
(setq out-dir (hw-ausgabe-ordner)
|
|
json-pfad (strcat out-dir "/" (vl-filename-base (getvar "DWGNAME")) "_hw_symbole.json")
|
|
dxf-pfad (hw-ziel-pfad ziel)
|
|
sym-pfad (strcat (cond ((getenv "DXFM_CFG")) ("")) "/hw_symbole.json"))
|
|
(if (not (setq fh (open json-pfad "w")))
|
|
(princ (ssg-textf "exp-file-open-error" (list label json-pfad)))
|
|
(progn
|
|
(foreach z (hw-sym-plan->json praefixe plan) (write-line z fh))
|
|
(close fh)
|
|
(if (equal 0 (hw-python label *hw-sym-skript*
|
|
(append (list json-pfad dxf-pfad "--symbole" sym-pfad)
|
|
(hw-zusatz-args ziel))
|
|
"hw_symbole.log" nil))
|
|
(hw-ergebnis-uebernehmen ziel *hw-sym-app* praefixe "hw-fertig-symbole"))))))
|
|
(princ)
|
|
)
|
|
|
|
(defun hw-sym-art (art)
|
|
(hw-sym-erzeugen (cdr (assoc art *hw-sym-arten*)) T)
|
|
)
|
|
|
|
;; Menue: HW Planung -> Symbole erzeugen
|
|
(defun c:HW_SYMBOLE () (hw-sym-erzeugen nil T))
|
|
|
|
;; Einzelbefehle je Geraeteart - noch nicht im Menue, zum schrittweisen
|
|
;; Erzeugen und Pruefen. Jeder ersetzt in der _HW.dxf nur die Symbole
|
|
;; seiner Art.
|
|
(defun c:HW_SYM_VENTILE () (hw-sym-art "ventile"))
|
|
(defun c:HW_SYM_SENSOREN () (hw-sym-art "sensoren"))
|
|
(defun c:HW_SYM_MOTOREN () (hw-sym-art "motoren"))
|
|
(defun c:HW_SYM_MOTORSCHUTZ () (hw-sym-art "motorschutz"))
|
|
(defun c:HW_SYM_ENCODER () (hw-sym-art "encoder"))
|
|
(defun c:HW_SYM_SCANNER () (hw-sym-art "scanner"))
|
|
|
|
;; Alle erzeugten Symbole aus dem gewaehlten Ziel entfernen
|
|
(defun c:HW_SYM_LOESCHEN () (hw-sym-erzeugen nil nil))
|
|
|
|
;; ------------------------------------------------------------
|
|
;; NUMMERIEREN (in der geoeffneten _HW.dxf)
|
|
;; ------------------------------------------------------------
|
|
|
|
;; Nummern aus der create_numbers-Info in die offene Zeichnung eintragen:
|
|
;; jedes Attribut mit '@', dessen Wert und Einfuegepunkt zu einem Eintrag
|
|
;; passen, bekommt new_value. Rueckgabe: Anzahl geaenderter Attribute.
|
|
(defun hw-num-anwenden (eintraege / ss i e pos obj ed wert treffer n)
|
|
(setq n 0)
|
|
(if (setq ss (ssget "_X" '((0 . "INSERT") (66 . 1) (410 . "Model"))))
|
|
(progn
|
|
(setq i 0)
|
|
(while (setq e (ssname ss i))
|
|
(setq pos (cdr (assoc 10 (entget e))))
|
|
(setq obj (entnext e))
|
|
(while (and obj (= (cdr (assoc 0 (setq ed (entget obj)))) "ATTRIB"))
|
|
(setq wert (cdr (assoc 1 ed)))
|
|
(if (vl-string-search "@" wert)
|
|
(progn
|
|
(setq treffer nil)
|
|
(foreach z eintraege
|
|
(if (and (null treffer) (hw-num-eintrag-p z wert pos)) (setq treffer z)))
|
|
(if treffer
|
|
(progn
|
|
(entmod (subst (cons 1 (ssg-json-get treffer "new_value")) (assoc 1 ed) ed))
|
|
(setq n (1+ n))))))
|
|
(setq obj (entnext obj)))
|
|
(entupd e)
|
|
(setq i (1+ i)))))
|
|
n
|
|
)
|
|
|
|
(defun c:HW_NUMMERIEREN ( / label pfad basis info-pfad fehler-pfad rc info n)
|
|
(setq label "HW_NUMMERIEREN")
|
|
(setq pfad (strcat (getvar "DWGPREFIX") (getvar "DWGNAME")))
|
|
(cond
|
|
((not (hw-umgebung-ok-p label)))
|
|
((or (= (getvar "DWGTITLED") 0)
|
|
(/= (strcase (vl-filename-extension pfad)) ".DXF"))
|
|
(princ (ssg-textf "hw-num-kein-dxf" (list (getvar "DWGNAME")))))
|
|
(t
|
|
;; create_numbers liest die Datei von der Platte - erst speichern
|
|
(command "_.QSAVE")
|
|
(setq basis (strcat (getvar "DWGPREFIX") (vl-filename-base pfad))
|
|
info-pfad (strcat basis "_nummern.json")
|
|
fehler-pfad (strcat basis "_nummern_fehler.json"))
|
|
(foreach f (list info-pfad fehler-pfad) (if (findfile f) (vl-file-delete f)))
|
|
;; --dryrun: create_numbers schreibt keine DXF, nur die Info - die
|
|
;; Nummern werden hier in die OFFENE Zeichnung eingetragen.
|
|
(setq rc (hw-python label *hw-num-skript*
|
|
(list "--filename" pfad "--dryrun"
|
|
"--info" info-pfad "--errorfile" fehler-pfad)
|
|
"hw_nummerieren.log" '(1)))
|
|
(if (and rc (setq info (if (findfile info-pfad) (ssg-json-laden info-pfad))))
|
|
(progn
|
|
(setq n (hw-num-anwenden (ssg-json-get info "renamed_symbols")))
|
|
(princ (ssg-textf "hw-num-ergebnis" (list (itoa n))))))
|
|
(if (findfile fehler-pfad)
|
|
(princ (ssg-textf "hw-num-fehler" (list fehler-pfad))))))
|
|
(princ)
|
|
)
|
|
|
|
(princ "\n>>> HwPlanung.lsp geladen")
|
|
(princ)
|