diff --git a/Lisp/README.md b/Lisp/README.md index 9f5428a..95e1db4 100644 --- a/Lisp/README.md +++ b/Lisp/README.md @@ -293,13 +293,15 @@ Drei Modi: Gefällebogen-Blöcke ersetzt, Winkel aus ΔH und Geometrie berechnet. **Dialog-Hilfsfunktionen:** `gf-dialog-eingabe` (lädt/liest den DCL-Dialog, liefert -`(deltaL winkel hz-winkel as-seite es-seite einfuegehoehe as-winkel es-winkel)` oder `nil` -bei Abbruch) und `gf-modus12-abschluss` (gemeinsamer Abschluss für Modus 1+2: setzt die -Element-Masse per `vf-set-as-masse`/`vf-set-es-masse`, berechnet die Staustreckenlänge, +`(deltaL winkel hz-winkel as-seite es-seite einfuegehoehe as-winkel es-winkel dim +geruest-einzelmodul geruest-typ)` oder `nil` bei Abbruch) und `gf-modus12-abschluss` +(gemeinsamer Abschluss für Modus 1+2: setzt die Element-Masse per +`vf-set-as-masse`/`vf-set-es-masse`, berechnet die Staustreckenlänge, zeigt die Zusammenfassung und ruft `gefaellestrecke-einfuegen`). Die AUS-/EIN-Element-Varianten (30/90 Grad, links/rechts) liegen als DWG-Blöcke -`AS_Element_<30|90>_` bzw. `ES_Element_…` in `data/ils/2D|3D/`; ihre Maße +`AS_Element_<30|90>_` bzw. `ES_Element_…` flach in `data/ils/` (Dimension +im Dateinamen als Suffix `_2D`/`_3D`, aufgelöst über `ssg-ils-block-datei`); ihre Maße werden direkt aus dem Block gemessen (`vf-element-masse`), es gibt dafür keine JSON-Tabelle. **Bearbeiten (`c:GEFAELLESTRECKE_EDIT`):** Doppelklick auf einen Gefällestrecken-Block @@ -367,7 +369,16 @@ Verzeichnisstruktur: [`../tests/README.md`](../tests/README.md)): Standardfunktionen direkt in AutoLISP, ohne Zeichnung. 2. **Zeichnungsbasierte Integrationstests** (`tests/test_*.lsp` + `tests/test_*.py`) – erzeugen Blöcke in BricsCAD und validieren das - Ergebnis anschließend mit pytest/ezdxf. + Ergebnis anschließend mit pytest/ezdxf. Module: `test_kreisel`, + `test_foerderer`, `test_linienzug`, `test_gefaellestrecke`, `test_omniflo`, + `test_omniflo_strecke` und `test_mubea` (Gesamtmodell: Kreisel + Vario + + Gefällestrecken + Separatoren aus `tests/testdata/mubea.json` in einer + Zeichnung; über `SSG_RUN_ALL_TESTS` bzw. Menü „Tests → Mubea Gesamtmodell"). + +Welche JSON-Angaben pro Element-Typ nötig sind (abgeleitet aus den +Produktions-Routinen, nicht aus den Test-Wrappern), dokumentiert +[`../tests/testdata/object_data.md`](../tests/testdata/object_data.md) – +inkl. der Unterscheidung scriptbar vs. nur-interaktiv. ### LISP-Unit-Tests (`test_unit.lsp`) @@ -465,11 +476,21 @@ AutoLISP-Implementierung fuer alle Omniflo-Komponenten: Boegen, Weichen, Verbind --- -### `SSG_LIB_Commands.lsp` – Dummy-Befehle und SSG_BLOCKEDIT +### `SSG_LIB_Commands.lsp` – Dummy-Befehle, Sensoren, Konfiguration und SSG_BLOCKEDIT -Platzhalter-Definitionen fuer noch nicht implementierte Menueintraege. Gibt beim Aufruf eine Meldung aus. -Alle zugehoerigen Menueintraege sind in `menu/SSG_LIB.mnu` mit `~` ausgegraut (siehe -Abschnitt ["Status: noch offene Menueintraege"](#status-noch-offene-menueintraege-im-menue-ausgegraut)). +Sammeldatei fuer Menue-Befehle: teils Platzhalter fuer noch nicht implementierte +Eintraege, teils bereits **echte** Funktionalitaet (Sensoren, Konfiguration, +Doppelklick-Dispatcher). Alle noch offenen Dummy-Menueintraege sind in +`menu/SSG_LIB.mnu` mit `~` ausgegraut (siehe Abschnitt +["Status: noch offene Menueintraege"](#status-noch-offene-menueintraege-im-menue-ausgegraut)). + +**Sensoren einfuegen** (real, ueber `ils-insert-sensor` → wiederholtes `_.INSERT` +mit interaktivem Einfuegepunkt/Rotation, Blockdatei via `ssg-ils-block-datei`): + +| Befehl | Block | Beschreibung | +| --- | --- | --- | +| `ILS_SCANNER_INSERT` | `Scanner` | Scanner wiederholt einfuegen (ENTER/ESC beendet) | +| `ILS_SEPARATOR_INSERT` | `Separator_SP` | Separator wiederholt einfuegen (Menue „Separator einfuegen") | Registrierte Dummy-Befehle: diff --git a/tests/test_mubea.lsp b/tests/test_mubea.lsp index c5371e9..05d098c 100644 --- a/tests/test_mubea.lsp +++ b/tests/test_mubea.lsp @@ -175,91 +175,52 @@ ) ) -;; --- Gefaellestrecke: L_stau <-> Ziel-Hoehendifferenz kalibrieren --------- -;; Bei festem Element-Winkel (3 Grad) ist deltaH linear in L_stau (nur die -;; Staustrecke ist skalierbar). Statt die Formel aus test_gefaellestrecke.lsp -;; zu uebernehmen (die L_stau aus einer ZIEL-LAENGE ableitet, nicht aus einer -;; ZIEL-HOEHE - beides ist bei festem Winkel nicht unabhaengig waehlbar), -;; wird die reale Steigung/Achsenabschnitt per zwei Probe-Bauten gemessen -;; (gefaellestrecke-einfuegen liefert deltaH exakt zurueck) und die Probe- -;; Inserts danach wieder geloescht. Rueckgabe: (steigung . achsenabschnitt). -(defun mubea:gf-calibrate (as-seite es-seite as-winkel es-winkel hz / - probe-pt l1 l2 e1 e2 dz1 dz2 steigung achsenabschnitt) - (mubea:ensure-gf-init) - (setq probe-pt (list 0.0 -500000.0 0.0)) ;; Schrott-Punkt, wird geloescht - (setq l1 3000.0 l2 8000.0) - (setq e1 (gefaellestrecke-einfuegen l1 3.0 probe-pt as-seite es-seite hz - l1 as-winkel es-winkel "0" "Schoenenberger Geruest")) - (setq e2 (gefaellestrecke-einfuegen l2 3.0 probe-pt as-seite es-seite hz - l2 as-winkel es-winkel "0" "Schoenenberger Geruest")) - (setq dz1 (cadr e1) dz2 (cadr e2)) - (setq steigung (/ (- dz2 dz1) (- l2 l1))) - (setq achsenabschnitt (- dz1 (* steigung l1))) - ;; Probe-Bloecke wieder entfernen (nur das INSERT - Blockdefinition bleibt - ;; ungenutzt in der Blocktabelle, erscheint nicht im Modelspace/Zaehlungen) - (if (car e1) (entdel (car e1))) - (if (car e2) (entdel (car e2))) - (princ (strcat "\n [GF-Kalibrierung] L_stau=" (rtos l1 2 0) "->dz=" (rtos dz1 2 1) - " L_stau=" (rtos l2 2 0) "->dz=" (rtos dz2 2 1) - " Steigung=" (rtos steigung 2 6) " Achsenabschnitt=" (rtos achsenabschnitt 2 2))) - (cons steigung achsenabschnitt) -) - - ;; --- Eine einzelne Gefaellestrecke bauen (Modus 1) --- -;; L_stau wird aus der ZIEL-HOEHENDIFFERENZ (start_mm.z - ende_mm.z) ueber die -;; kalibrierte lineare Beziehung berechnet (siehe mubea:gf-calibrate) - NICHT -;; aus der XY-Distanz (bei festem 3-Grad-Winkel legen Laenge und -;; Hoehendifferenz sich gegenseitig fest, beides gleichzeitig aus den realen -;; Koordinaten zu uebernehmen ist geometrisch inkonsistent). +;; Aufbau AUSSCHLIESSLICH aus Anfangspunkt (start-mm) und horizontaler +;; Gesamtlaenge deltaL - KEIN Endpunkt (wie Produktion/gefaellestrecke.dcl +;; Modus 1, siehe object_data.md 2.1). L_stau wird aus deltaL abgeleitet +;; (identische Formel wie test_gefaellestrecke.lsp): +;; L_stau = (deltaL - aus-dx - ein-dx - sep_x) / cos(v) +;; sep_x = 300 * cos(v), v = fester Element-Winkel 3 Grad +;; Die Zielhoehe ergibt sich aus L_stau/Winkel (kein Ziel-Hoehen-Parameter). ;; Rueckgabe: Ergebnis-JSON-String. -(defun mubea:build-gf-one (tid start-mm ende-mm hz as-seite es-seite as-winkel es-winkel / - ziel-dz kalib steigung achsenabschnitt test-L_stau - real-deltaL dx dy ent) - ;; Kalibrierung einmalig pro (as-seite/es-seite/as-winkel/es-winkel/hz)- - ;; Kombination; fuer alle Kopien mit denselben Parametern wiederverwendet. - (if (null *mubea-gf-kalib-cache*) (setq *mubea-gf-kalib-cache* '())) - (setq kalib (cdr (assoc (list as-seite es-seite as-winkel es-winkel hz) *mubea-gf-kalib-cache*))) - (if (null kalib) - (progn - (setq kalib (mubea:gf-calibrate as-seite es-seite as-winkel es-winkel hz)) - (setq *mubea-gf-kalib-cache* - (cons (cons (list as-seite es-seite as-winkel es-winkel hz) kalib) *mubea-gf-kalib-cache*)) - ) - ) - (setq steigung (car kalib) achsenabschnitt (cdr kalib)) - - (setq ziel-dz (- (caddr start-mm) (caddr ende-mm))) - (setq test-L_stau (/ (- ziel-dz achsenabschnitt) steigung)) - - ;; Nur zu Log-/Attributzwecken: reale XY-Distanz start_mm->ende_mm - (setq dx (- (car ende-mm) (car start-mm)) - dy (- (cadr ende-mm) (cadr start-mm))) - (setq real-deltaL (sqrt (+ (* dx dx) (* dy dy)))) +(defun mubea:build-gf-one (tid start-mm deltaL hz as-seite es-seite as-winkel es-winkel / + rad sep-x test-L_stau ent) + (mubea:ensure-gf-init) + ;; Element-Masse fuer die gewaehlte AS/ES-Variante setzen, damit aus-dx/ein-dx + ;; zur Variante (90/30 Grad) passen. Danach wieder auf 90 zuruecksetzen. + (vf-set-as-masse as-winkel as-seite) + (vf-set-es-masse es-winkel es-seite) + (setq rad (* 3.0 (/ pi 180.0))) + (setq sep-x (* 300.0 (cos rad))) + (setq test-L_stau + (/ (- deltaL (float aus-dx) (float ein-dx) sep-x) (cos rad))) (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) " Ziel-dz=" (rtos ziel-dz 2 1) + ") hz=" (rtos hz 2 0) " deltaL=" (rtos deltaL 2 0) " L_stau=" (rtos test-L_stau 2 1))) (setq ent (car (gefaellestrecke-einfuegen test-L_stau 3.0 start-mm as-seite es-seite hz - real-deltaL as-winkel es-winkel "0" "Schoenenberger Geruest"))) + deltaL as-winkel es-winkel "0" "Schoenenberger Geruest"))) + (vf-set-as-masse "90" as-seite) + (vf-set-es-masse "90" es-seite) (mubea:ent-json tid "gefaellestrecke" ent) ) ;; --- Gefaellestrecke(n) aus einem Template-Eintrag bauen --- ;; Ein einziger JSON-Eintrag beschreibt per "anzahl" + "delta_y"/"delta_x" eine ;; ganze Reihe identischer Gefaellestrecken (statt 20 Einzeleintraege). Element i -;; (1..anzahl) wird um (i-1)*delta in Y bzw. X versetzt (start_mm UND ende_mm -;; gemeinsam). Fehlen anzahl/delta -> genau eine Strecke am angegebenen Ort. -;; Aus JSON: start_mm, ende_mm, hz_grad, as_seite, es_seite, as_winkel, +;; (1..anzahl) wird um (i-1)*delta in Y bzw. X versetzt (nur start_mm - es gibt +;; keinen Endpunkt). Fehlen anzahl/delta -> genau eine Strecke am angegebenen Ort. +;; Aus JSON: start_mm, deltaL_mm, hz_grad, as_seite, es_seite, as_winkel, ;; es_winkel, anzahl (Default 1), delta_y (Default 0), delta_x (Default 0). ;; Rueckgabe: LISTE von Ergebnis-JSON-Strings (eine je Kopie). -(defun mubea:build-gf (e / tid0 start0 ende0 hz as-seite es-seite as-winkel es-winkel - anzahl dy dx i off nr tid s-mm e-mm ergebnisse) +(defun mubea:build-gf (e / tid0 start0 deltaL hz as-seite es-seite as-winkel es-winkel + anzahl dy dx i off nr tid s-mm ergebnisse) (setq tid0 (ssg-val e "test_id") start0 (mapcar 'float (ssg-val e "start_mm")) - ende0 (mapcar 'float (ssg-val e "ende_mm")) + deltaL (float (ssg-val e "deltaL_mm")) hz (float (ssg-val e "hz_grad")) as-seite (ssg-val e "as_seite") es-seite (ssg-val e "es_seite") @@ -287,9 +248,8 @@ (strcat tid0 "_" (if (< nr 10) (strcat "0" (itoa nr)) (itoa nr))) tid0)) (setq s-mm (list (+ (car start0) (* dx off)) (+ (cadr start0) (* dy off)) (caddr start0))) - (setq e-mm (list (+ (car ende0) (* dx off)) (+ (cadr ende0) (* dy off)) (caddr ende0))) (setq ergebnisse - (cons (mubea:build-gf-one tid s-mm e-mm hz as-seite es-seite as-winkel es-winkel) + (cons (mubea:build-gf-one tid s-mm deltaL hz as-seite es-seite as-winkel es-winkel) ergebnisse)) (setq i (1+ i)) ) @@ -373,10 +333,9 @@ (if (or (not *lib-initialized*) (null bogen-auf)) (init-bibliothek)) - ;; Caches fuer GF-Init-Workaround und Hoehenkalibrierung pro Lauf zuruecksetzen - ;; (siehe mubea:ensure-gf-init / mubea:gf-calibrate weiter oben) + ;; Cache fuer GF-Init-Workaround pro Lauf zuruecksetzen + ;; (siehe mubea:ensure-gf-init weiter oben) (setq *mubea-gf-init-done* nil) - (setq *mubea-gf-kalib-cache* nil) ;; Testdaten laden (setq json-datei (strcat (getenv "DXFMAKRO") "/tests/testdata/mubea.json")) diff --git a/tests/testdata/mubea.json b/tests/testdata/mubea.json index 20a6dda..b5f5a59 100644 --- a/tests/testdata/mubea.json +++ b/tests/testdata/mubea.json @@ -88,27 +88,27 @@ "winkel": 21, "gf_verteilung": "manuell", "L_GF1": 500, - "L_GF2": 4230, + "L_GF2": 8610, "seite": "rechts", "hz": 0.0, "x": 410, - "y": 3860, + "y": 13137, "z": 1475, - "comment": "Foerdererwinkel 21 (naechster verfuegbarer Bogenwinkel); Gefaellestrecke vorn L_GF1=500 / hinten L_GF2=4230 (gesamt L_GF=4730); deltaL und L_VF werden beim Bauen fuer winkel=21 und deltaH=553 geloest (L_GF ist linear in deltaL)" + "comment": "Foerdererwinkel 21 (naechster verfuegbarer Bogenwinkel); Gefaellestrecke vorn L_GF1=500 unveraendert, hinten L_GF2=8610 (gesamt L_GF=9110, angeglichen an deltaL_mm der GF_Mubea-Gefaellestrecken); deltaL und L_VF werden beim Bauen fuer winkel=21 und deltaH=553 geloest (L_GF ist linear in deltaL)" }, { "test_id": "GF_Mubea", "modus": 1, - "hz_grad": 0.0, - "start_mm": [399, 11526, 1941], - "ende_mm": [9510, 12314, 1467], - "as_seite": "rechts", - "es_seite": "rechts", + "deltaL_mm": 9110, + "hz_grad": 180.0, + "start_mm": [9510, 11526, 1941], + "as_seite": "links", + "es_seite": "links", "as_winkel": "90", "es_winkel": "90", "anzahl": 20, "delta_y": -800, - "comment": "Template fuer alle Gefaellestrecken: 'anzahl' identische Kopien, je um 'delta_y' (mm) in Y versetzt (start_mm und ende_mm gemeinsam). Erzeugt GF_1..GF_anzahl. x/z aus DXF (EE-R Start hoch=1941, AE DS Ende niedrig=1467); realer DXF-Versatz -799..-800 auf nominal -800 vereinheitlicht." + "comment": "Template fuer alle Gefaellestrecken (Modus 1): 'anzahl' identische Kopien, je um 'delta_y' (mm) in Y versetzt (nur start_mm). Erzeugt GF_Mubea_01..GF_Mubea_anzahl. Aufbau ausschliesslich aus Anfangspunkt start_mm und der horizontalen Gesamtlaenge deltaL_mm - KEIN Endpunkt (wie Produktion/gefaellestrecke.dcl Modus 1). Winkel fest 3 Grad, Zielhoehe ergibt sich daraus. start_mm.x/z aus DXF (EE-R Start hoch z=1941); deltaL_mm ~ reale XY-Distanz Start->AE-DS im DXF." }, { "comment": "Separator S-LP #1 Y-Abgleich mit Gefaellestrecken (Sep-Y=14158, GF_Mubea_01-Y=11526, diff=2632mm, naechstgelegene Reihe, kein enger Treffer)",