;; ============================================================ ;; 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 :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)