Files
dxfmakros/tests/test_dematic_arvato.lsp
T

418 lines
20 KiB
Common Lisp

;; ============================================================
;; test_dematic_arvato.lsp - Nachbau des Abschnitts Flowpuffer/Kreisel der
;; Anlage Dematic/Arvato.
;;
;; Datenquelle: tests/testdata/dematic_arvato.json. Entstehung in zwei
;; Stufen:
;; 1. Vorlage aus der Fremdzeichnung (Scanner, raet vieles):
;; python lib/dxf_scan_components.py \
;; C:/develop/sps_skel/data/Dematic_arvato_reduced.dxf data \
;; tests/testdata/dematic_arvato.json --projekt Arvato \
;; --fenster -2534 -4549 49466 29451 --ohne-hoehen \
;; --kreisel-hoehe 35860.37 12519.72 2437 \
;; --kreisel-hoehe 36661.24 24878.8 1826
;; 2. Vorlage mit diesem Treiber bauen, in BricsCAD von Hand korrigieren
;; und ergaenzen (VF-Ketten, Hoehen, Sensoren aufgeraeumt), als DXF
;; speichern und daraus die Testdaten neu schreiben - AKTUELLER STAND:
;; python lib/dxf_anlage_export.py \
;; C:/develop/sps_skel/data/Dematic_TST.dxf \
;; tests/testdata/dematic_arvato.json --projekt Arvato
;;
;; Eintragsarten:
;; "function": "insert" ohne "block" -> Kreisel (hundm05:bau-kreisel ->
;; kreisel-insert-script; x/y = Einfuegepunkt,
;; abstand = Mittenabstand AN8-SP8)
;; "function": "insert" + "block" -> Einzelblock (hundm05:bau-sensor)
;; "typ": "standard"/"etage" + "test_id"
;; -> VarioFoerderer ueber mubea:vario-bauen
;; (mubea-Schema: deltaL, deltaH, richtung,
;; winkel, L_GF1, seite, hz, x/y/z), optional
;; "motorseite"
;; "typ": "linienzug_journal"
;; -> Linienzug-Kette: das aufgezeichnete Eingabe-
;; Journal (SSG_VF_EDIT) wird 1:1 abgespielt
;; (vsp-bau-journal) - keine Spec, weil der
;; Dialog neuer ist als die Spec-Grammatik
;; "modus": 1 -> Gefaellestrecke ueber mubea:gf-bauen
;; (start_mm + deltaL_mm, kein Endpunkt). Mit
;; hoehe_ende_mm (Hoehe des Kreisels am Ende)
;; rechnet dematic_arvato:gf-geometrie Winkel
;; und Staustreckenlaenge (gf-bauen-exakt),
;; sonst gilt winkel_grad.
;; "typ": "gerade" -> waagrechter Foerderer aus der Scanner-Vorlage -
;; kein Bau-Pfad, wird gemeldet und uebersprungen
;;
;; Reihenfolge wie mubea.json (VF vor GF): gf-init-bibliothek setzt die
;; globalen AS/ES-Masse um, siehe mubea:ensure-gf-init.
;;
;; Keine eigene Bau-Logik: hundm05:bau-kreisel/-sensor aus
;; tests/test_hundm05.lsp und mubea:gf-bauen/-vario-bauen aus
;; tests/test_mubea.lsp werden mitgeladen (beide Dateien definieren nur
;; Funktionen), Linienzug-Ketten laufen ueber vsp-bau-journal (vf_spec.lsp).
;;
;; Aufruf in BricsCAD:
;; (load (strcat (getenv "DXFMAKRO") "/tests/test_dematic_arvato.lsp"))
;; TEST_DEMATIC_ARVATO
;; ============================================================
(if (not (boundp '*dematic-arvato-records*)) (setq *dematic-arvato-records* nil))
;; Module und die Bau-Funktionen aus test_hundm05.lsp beim LADEN dieser Datei
;; holen, nicht erst in c:TEST_DEMATIC_ARVATO: in BricsCAD werden per load
;; definierte Funktionen erst nach Rueckkehr zum Top-Level sichtbar (siehe
;; tests/test_unit.scr).
(ssg-ensure "KreiselInsert")
(ssg-ensure "VarioFoerderer")
(ssg-ensure "SSG_LIB_Commands")
(ssg-ensure "Gefaellestrecke")
(if (null (car (atoms-family 1 '("HUNDM05:BAU-SENSOR"))))
(load (strcat (getenv "DXFMAKRO") "/tests/test_hundm05.lsp")))
(if (null (car (atoms-family 1 '("MUBEA:VARIO-BAUEN"))))
(load (strcat (getenv "DXFMAKRO") "/tests/test_mubea.lsp")))
(defun dematic_arvato:datei ()
(strcat (getenv "DXFMAKRO") "/tests/testdata/dematic_arvato.json"))
;; Record um den gebauten Block ergaenzen (oder als Abbruch markieren).
(defun dematic_arvato:rec-block (rec ent fehlertext / ed)
(if (and ent (= (type ent) 'ENAME))
(progn
(setq ed (entget ent))
(princ (strcat " -> Block " (cdr (assoc 2 ed))))
(setq rec (vsp-set rec "block_name" (cdr (assoc 2 ed))))
(setq rec (vsp-set rec "block_handle" (cdr (assoc 5 ed))))
(setq rec (vsp-set rec "insert_point" (cdr (assoc 10 ed))))
(setq rec (vsp-set rec "attribs" (ssg-attrib-read ent)))
(vsp-set rec "status" "executed"))
(progn
(princ (strcat " FEHLER: " fehlertext))
(vsp-set (vsp-set rec "status" "abbruch") "fehler_text" fehlertext))))
;; Foerderer "gerade": noch kein Bau-Pfad - nur melden.
(defun dematic_arvato:gerade-melden (obj / tid rec)
(setq tid (ssg-val obj "test_id"))
(princ (strcat "\n [GERADE] " (if tid tid "?")
" uebersprungen - waagrechter Foerderer noch nicht unterstuetzt"))
(setq rec (vsp-rec-neu (if tid tid "(ohne id)")))
(setq rec (vsp-set rec "kind" "gerade"))
(vsp-set (vsp-set rec "status" "uebersprungen") "fehler_text"
"kein Bau-Pfad fuer typ gerade"))
;; ES-Element bei Einlaufneigung w (Grad, bergab) in Fahrtrichtung hz
;; vermessen: horizontale Laenge entlang hz und Abfall von KS_EIN bis KS_AUS.
;; Wie gf-messe-dz-block (Gefaellestrecke.lsp), liefert aber zusaetzlich die
;; Laenge - beide aendern sich mit der Neigung (90-Grad-ES flach ~436 mm
;; lang, bei 43 Grad nur noch ~292 mm).
;; Rueckgabe: (dx dz), dz positiv = nach unten.
(defun dematic_arvato:es-mass (blockname hz w / rad-h rad-v frame-aus ent-vor ent-nach p)
(setq rad-h (* hz (/ pi 180.0))
rad-v (* w (/ pi 180.0)))
(setq ent-vor (entlast))
(setq frame-aus
(insert-block-ks-to-ks blockname
(make-frame-from-dir '(0 0 0)
(list (* (cos rad-h) (cos rad-v)) (* (sin rad-h) (cos rad-v))
(- (sin rad-v))))))
(setq ent-nach (entlast))
(if (and ent-nach (not (eq ent-nach ent-vor))) (entdel ent-nach))
(setq p (car frame-aus))
(list (+ (* (car p) (cos rad-h)) (* (cadr p) (sin rad-h)))
(- 0.0 (caddr p))))
;; Winkel UND Staustreckenlaenge einer GF (Modus 1) aus Start- und Endhoehe,
;; so dass der ES-Auslauf genau auf Hoehe UND Kette des unteren Kreisels
;; liegt. deltaL reicht von AS-KS_EIN bis ES-KS_AUS (horizontal).
;;
;; H = deltaL - aus-dx - es_dx(w) horizontale Laenge der Schraege
;; tan(w) = (dH - aus-dz - es_dz(w)) / H Schraege = Staustrecke + Separator
;; L_stau = H / cos(w) - 300
;;
;; es_dx/es_dz werden beim aktuellen Winkel gemessen (dematic_arvato:es-mass)
;; und iteriert; das AS liegt flach, aus-dx/aus-dz sind fest.
;;
;; Warum nicht mubea:gf-bauen / gf-winkel-berechnen:
;; - gf-winkel-berechnen rechnet asin(dH / L), also mit SCHRAEGER Laenge
;; (Modus 3); Modus 1 haelt aber die horizontale Laenge fest. Bei 2-3 Grad
;; (Dematic) gleich, bei den steilen Showroom-GF (1860 mm auf 2405 mm)
;; ~50 statt ~43 Grad - die GF endete weit unter dem Kreisel.
;; - mubea:gf-bauen zieht die FLACH gemessene ES-Laenge ein-dx ab. Bei 43
;; Grad ist das ES horizontal ~144 mm kuerzer, die GF hoerte so 144 mm
;; vor der Kette des unteren Kreisels auf (Hoehe stimmte).
;; VORZEICHEN: vf-set-as-masse misst aus-dz als KS_AUS.z - KS_EIN.z
;; (negativ) - darum der Betrag (Dematic: sonst HOEHE_BIS 1568 statt 1826).
;; Rueckgabe: (winkel L_stau)
(defun dematic_arvato:gf-geometrie (deltaL hz as-seite es-seite as-winkel es-winkel
z-start z-ende / es-block dH es H winkel vorher
iter dx-as dz-as)
(mubea:ensure-gf-init)
(vf-set-as-masse as-winkel as-seite)
(vf-set-es-masse es-winkel es-seite)
(setq es-block (strcat "ES_Element_" es-winkel "_" es-seite)
dx-as (float aus-dx)
dz-as (abs (float aus-dz))
dH (- z-start z-ende)
es (list (float ein-dx) (abs (float ein-dz)))
vorher -999.0
iter 0)
(setq H (- deltaL dx-as (car es))
winkel (* (atan (- dH dz-as (cadr es)) H) (/ 180.0 pi)))
(while (and (< iter 8) (> (abs (- winkel vorher)) 0.0005))
(setq vorher winkel
es (dematic_arvato:es-mass es-block hz winkel)
H (- deltaL dx-as (car es))
winkel (* (atan (- dH dz-as (cadr es)) H) (/ 180.0 pi))
iter (1+ iter)))
(vf-set-as-masse "90" as-seite)
(vf-set-es-masse "90" es-seite)
(list winkel (- (/ H (cos (* winkel (/ pi 180.0)))) 300.0)))
;; GF mit vorgegebener Staustreckenlaenge einfuegen (wie mubea:gf-bauen, aber
;; L_stau kommt aus dematic_arvato:gf-geometrie statt aus der flachen
;; ES-Laenge).
(defun dematic_arvato:gf-bauen-exakt (tid start-mm deltaL hz as-seite es-seite
as-winkel es-winkel winkel L_stau / ent)
(mubea:ensure-gf-init)
;; Element-Masse der Variante wie in mubea:gf-bauen, danach zurueck auf 90
(vf-set-as-masse as-winkel as-seite)
(vf-set-es-masse es-winkel es-seite)
(princ (strcat "\n [GF] " tid " -> Start=(" (rtos (car start-mm) 2 0)
"," (rtos (cadr start-mm) 2 0) "," (rtos (caddr start-mm) 2 0)
") hz=" (rtos hz 2 0) " deltaL=" (rtos deltaL 2 0)
" winkel=" (rtos winkel 2 3) " L_stau=" (rtos L_stau 2 1)))
(setq ent (car (gefaellestrecke-einfuegen
L_stau winkel start-mm as-seite es-seite hz
deltaL as-winkel es-winkel "0" "Schoenenberger Geruest")))
(vf-set-as-masse "90" as-seite)
(vf-set-es-masse "90" es-seite)
ent)
;; Gefaellestrecke (Modus 1) bauen - Felder wie mubea:build-gf, ohne dessen
;; anzahl/delta-Vervielfaeltigung (jede GF steht einzeln in der Datei).
;; Mit "hoehe_ende_mm" (Hoehe des Kreisels am Ende) wird der Winkel daraus
;; gerechnet, sonst gilt "winkel_grad" (Default 3.0).
(defun dematic_arvato:bau-gf (obj / tid start deltaL hz winkel z-ende geo
as-seite es-seite as-winkel es-winkel rec)
(setq tid (ssg-val obj "test_id")
start (ssg-val obj "start_mm")
deltaL (ssg-val obj "deltaL_mm")
hz (ssg-val obj "hz_grad")
winkel (ssg-val obj "winkel_grad")
z-ende (ssg-val obj "hoehe_ende_mm")
as-seite (cond ((ssg-val obj "as_seite")) ("links"))
es-seite (cond ((ssg-val obj "es_seite")) ("links"))
as-winkel (cond ((ssg-val obj "as_winkel")) ("90"))
es-winkel (cond ((ssg-val obj "es_winkel")) ("90")))
(setq rec (vsp-rec-neu (if tid tid "(ohne id)")))
(setq rec (vsp-set rec "kind" "gefaellestrecke"))
(setq rec (vsp-set rec "dimension" (vsp-dim-text)))
(cond
((not (and (= (type start) 'LIST) (= (length start) 3)
(numberp deltaL) (numberp hz)))
(princ (strcat "\n [GF] " (if tid tid "?")
" - FEHLER: start_mm, deltaL_mm und hz_grad muessen gesetzt sein"))
(vsp-set (vsp-set rec "status" "spec-fehler") "fehler_text"
"start_mm, deltaL_mm oder hz_grad fehlt bzw. ist ungueltig"))
((and (numberp z-ende) (>= z-ende (caddr start)))
(princ (strcat "\n [GF] " (if tid tid "?")
" - FEHLER: hoehe_ende_mm liegt nicht unter der Starthoehe"))
(vsp-set (vsp-set rec "status" "spec-fehler") "fehler_text"
"hoehe_ende_mm >= start_mm.z - kein Gefaelle"))
(T
;; Mit Endhoehe: Winkel + Staustreckenlaenge exakt (gf-geometrie),
;; sonst fester Winkel ueber mubea:gf-bauen.
(setq geo (if (numberp z-ende)
(dematic_arvato:gf-geometrie (float deltaL) (float hz)
as-seite es-seite as-winkel es-winkel
(float (caddr start)) (float z-ende))))
(setq winkel
(cond
(geo (car geo))
((numberp winkel) (float winkel))
(T 3.0)))
;; Winkel und Soll-Endhoehe als Meldung (das Record-Schema aus vf_spec
;; kennt dafuer kein Feld); die Ist-Endhoehe steht in attribs HOEHE_BIS.
(setq rec (vsp-set rec "meldungen"
(list (strcat "winkel_grad " (rtos winkel 2 3)
(if (numberp z-ende)
(strcat " aus Hoehe " (rtos (caddr start) 2 1)
" -> " (rtos z-ende 2 1))
"")))))
(setq rec
(dematic_arvato:rec-block rec
(if geo
(dematic_arvato:gf-bauen-exakt tid (mapcar 'float start) (float deltaL)
(float hz) as-seite es-seite as-winkel
es-winkel winkel (cadr geo))
(mubea:gf-bauen tid (mapcar 'float start) (float deltaL) (float hz)
as-seite es-seite as-winkel es-winkel winkel))
"gefaellestrecke-einfuegen lieferte keinen GF-Block"))
;; Ist-Endhoehe gegen den Kreisel am Ende pruefen
(dematic_arvato:gf-endhoehe-pruefen rec z-ende))))
;; HOEHE_BIS_mm des gebauten GF-Blocks mit der Soll-Endhoehe vergleichen;
;; mehr als 5 mm daneben -> status "warnung" + Meldung (die GF trifft den
;; unteren Kreisel nicht).
(defun dematic_arvato:gf-endhoehe-pruefen (rec z-ende / ist diff)
(setq ist (cdr (assoc "HOEHE_BIS_mm" (ssg-val rec "attribs"))))
(cond
((not (and (numberp z-ende) ist (= (ssg-val rec "status") "executed"))) rec)
(T
(setq diff (- (atof ist) z-ende))
(setq rec (vsp-set rec "meldungen"
(append (ssg-val rec "meldungen")
(list (strcat "HOEHE_BIS " ist " (Soll "
(rtos z-ende 2 0) ", Abweichung "
(rtos diff 2 0) " mm)")))))
(if (> (abs diff) 5.0)
(progn
(princ (strcat "\n WARNUNG: GF endet bei " ist " statt "
(rtos z-ende 2 0)))
(vsp-set rec "status" "warnung"))
rec))))
;; VarioFoerderer "standard"/"etage" - mubea-Schema, Bau ueber
;; mubea:vario-bauen. "motorseite" wirkt wie im Edit-Dialog ueber den
;; Override *vf-motorseite* (vf-block-erstellen liest ihn).
(defun dematic_arvato:bau-vf (obj / tid typ rec ent)
(setq tid (ssg-val obj "test_id")
typ (cond ((ssg-val obj "typ")) ("standard")))
(setq rec (vsp-rec-neu (if tid tid "(ohne id)")))
(setq rec (vsp-set rec "kind" "vario"))
(setq rec (vsp-set rec "dimension" (vsp-dim-text)))
(setq *vf-motorseite* (ssg-val obj "motorseite"))
(setq ent
(vl-catch-all-apply 'mubea:vario-bauen
(list tid typ (ssg-val obj "richtung")
(float (ssg-val obj "deltaL")) (float (ssg-val obj "deltaH"))
(ssg-val obj "winkel") (float (cond ((ssg-val obj "L_GF1")) (0.0)))
(ssg-val obj "seite") (ssg-val obj "hz")
(list (float (ssg-val obj "x")) (float (ssg-val obj "y"))
(float (ssg-val obj "z"))))))
(setq *vf-motorseite* nil)
(if (vl-catch-all-error-p ent)
(vsp-set (vsp-set rec "status" "abbruch") "fehler_text"
(vl-catch-all-error-message ent))
(dematic_arvato:rec-block rec ent
"kein VF-Block (deltaL beim gewuenschten Winkel nicht loesbar?)")))
;; Linienzug-Kette: aufgezeichnetes Journal ("ART:wert"-Tokens, wie in der
;; SSG_VF_EDIT-XDATA) 1:1 abspielen. Headless-Rahmen wie vsp-bau-datei; er
;; MUSS auch nach einem Fehler zurueck, sonst bleiben getstring/getpoint der
;; Sitzung ersetzt.
(defun dematic_arvato:bau-journal (obj / tid journal res)
(setq tid (cond ((ssg-val obj "test_id")) ("(ohne id)")))
(setq journal (mapcar 'vfl-string->entry (ssg-val obj "journal")))
(vsp-headless-an)
(setq res (vl-catch-all-apply 'vsp-bau-journal
(list tid journal nil
(if journal nil (list "Feld \"journal\" fehlt oder ist leer")))))
(vsp-headless-aus)
(if (vl-catch-all-error-p res)
(vsp-set (vsp-set (vsp-rec-neu tid) "status" "abbruch") "fehler_text"
(vl-catch-all-error-message res))
res))
(defun dematic_arvato:bau-eintrag (obj / kind res typ)
(setq typ (ssg-val obj "typ"))
(cond
((ssg-val obj "modus")
(setq kind "gefaellestrecke")
(setq res (vl-catch-all-apply 'dematic_arvato:bau-gf (list obj))))
((= typ "linienzug_journal")
(setq kind "linienzug")
(setq res (dematic_arvato:bau-journal obj)))
((and (member typ '("standard" "etage")) (ssg-val obj "test_id"))
(setq kind "vario")
(setq res (dematic_arvato:bau-vf obj)))
((and (= (ssg-val obj "function") "insert") (ssg-val obj "block"))
(setq kind "sensor")
(setq res (vl-catch-all-apply 'hundm05:bau-sensor (list obj))))
((= (ssg-val obj "function") "insert")
(setq kind "kreisel")
(setq res (vl-catch-all-apply 'hundm05:bau-kreisel (list obj))))
((= typ "gerade")
(setq kind "gerade")
(setq res (dematic_arvato:gerade-melden obj)))
(T
(setq kind "unbekannt")
(princ "\n WARNUNG: unbekannter Eintrag uebersprungen")
(setq res (vsp-set (vsp-rec-neu "(unbekannt)") "status" "uebersprungen"))))
(if (vl-catch-all-error-p res)
(progn
(princ (strcat "\n [" (strcase kind) "] Ausnahme: "
(vl-catch-all-error-message res)))
(vsp-set (vsp-set (vsp-set (vsp-rec-neu (cond ((ssg-val obj "id"))
((ssg-val obj "test_id"))
((ssg-val obj "block"))
("?")))
"kind" kind) "status" "abbruch")
"fehler_text" (vl-catch-all-error-message res)))
res))
;; Alle Eintraege einer Nachbau-Datei bauen und die Records zurueckgeben
;; (nil bei Fehler vor dem Bau). Gemeinsamer Lauf fuer jeden Treiber mit
;; diesem Eintragsschema - auch tests/test_showroom_ils.lsp.
;; befehl = Name fuer Meldungen/ssg-start, titel = Kopfzeile, datei = JSON
(defun dematic_arvato:bau-datei (befehl titel datei / daten out records zaehler st)
(princ "\n\n================================================================")
(princ (strcat "\n " befehl " - " titel))
(princ (strcat "\n " datei))
(princ "\n================================================================")
(cond
((null (car (atoms-family 1 '("VSP-BAU-JOURNAL"))))
(princ (strcat "\n[" befehl "] FEHLER: vf_spec.lsp nicht geladen"
" (VarioFoerderer laden)."))
nil)
((null (findfile datei))
(princ (strcat "\n[" befehl "] FEHLER: " datei " nicht gefunden!"))
nil)
(T
(setq daten (ssg-json-laden datei))
(princ (strcat "\n " (itoa (length daten)) " Eintraege geladen"))
(ssg-start befehl '(("OSMODE") ("CECOLOR") ("ATTREQ") ("ATTDIA")))
(setvar "OSMODE" 0)
(setvar "ATTREQ" 0)
(setvar "ATTDIA" 0)
;; Vario-Bibliothek (Bogen-/AS-/ES-Masse) wie C:TEST_MUBEA, und die
;; GF-Elementmasse in jeder Zeichnung neu ermitteln.
(if (vsp-lib-noetig-p) (init-bibliothek))
(setq *mubea-gf-init-done* nil)
(setq out '())
(foreach obj daten
(setq out (cons (dematic_arvato:bau-eintrag obj) out)))
(ssg-end)
(setq records (reverse out))
;; Zusammenfassung je Status
(setq zaehler '())
(foreach r records
(setq st (cond ((ssg-val r "status")) ("?")))
(if (assoc st zaehler)
(setq zaehler (subst (cons st (1+ (cdr (assoc st zaehler))))
(assoc st zaehler) zaehler))
(setq zaehler (cons (cons st 1) zaehler))))
(princ "\n================================================================")
(foreach z (reverse zaehler)
(princ (strcat "\n " (car z) ": " (itoa (cdr z)))))
(princ "\n================================================================")
(command "_.ZOOM" "_E")
records)))
(defun c:TEST_DEMATIC_ARVATO ()
(setq *dematic-arvato-records*
(dematic_arvato:bau-datei "TEST_DEMATIC_ARVATO" "Abschnitt Flowpuffer/Kreisel"
(dematic_arvato:datei)))
(princ))
;; Ergebnis-Export (Konvention <name>:export-results fuer test_run_all.lsp)
(defun dematic_arvato:export-results (out-dir / pfad)
(if (null *dematic-arvato-records*)
(princ "\n Keine Dematic/Arvato-Ergebnisse vorhanden.")
(progn
(vl-mkdir out-dir)
(setq pfad (strcat out-dir "/dematic_arvato_results.json"))
(vsp-results-schreiben *dematic-arvato-records* pfad)))
(princ))
(princ "\nTEST_DEMATIC_ARVATO geladen. Aufruf: TEST_DEMATIC_ARVATO")
(princ)