diff --git a/CLAUDE.md b/CLAUDE.md index 3491fbd..f4144f9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -67,12 +67,12 @@ Die `start_briscad.bat` ruft `setenv.bat` auf und startet BricsCAD. |---|---|---| | Kreisel-Module | `KreiselInsert` | KreiselInsert, KreiselConnect, KreiselEdit, ILS_Eckrad | | Zusatzmodul/Foerderer/Kurven | `SSG_LIB_Commands` | ILS_BTMT_*, ILS_ETF_*, ILS_K*_*, ILS_GK*_* | -| VarioFoerderer | `VarioFoerderer` | FOERDERANLAGE | -| Gefaellestrecke | `Gefaellestrecke` | GEFAELLESTRECKE | +| VarioFoerderer | `VarioFoerderer` | FOERDERANLAGE, VARIOFOERDERER_EDIT | +| Gefaellestrecke | `Gefaellestrecke` | GEFAELLESTRECKE, GEFAELLESTRECKE_EDIT | | Omniflo (komplett) | `OmniModulInsert` | OMNI_APB_*, OMNI_W*_*, OMNI_AP*, OMNI_TEF_*, OMNI_TV_*, OMNI_EDIT | | Export | `export` | EXPORTSIVAS, EXPORTCSV, CALLPYTHON | | Konfiguration | `SSG_LIB_Commands` | SSG_DIM_SWITCH, SSG_SPRACHE | -| Doppelklick/Kontextmenue | `SSG_LIB_Commands` | SSG_BLOCKEDIT | +| Doppelklick/Kontextmenue | `SSG_LIB_Commands` | SSG_BLOCKEDIT (dispatcht Kreisel->KreiselEdit, Omniflo->OMNI_EDIT, GF_*->GEFAELLESTRECKE_EDIT, VF_*->VARIOFOERDERER_EDIT) | ### Entfernte Legacy-Dateien @@ -92,8 +92,8 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. | `ssg_dialog.lsp` | - | DCL-Dialog-Vorlagen und Hilfsfunktionen | | `ssg_layer.lsp` | - | Layer-Verwaltung | | `KreiselInsert.lsp` | KreiselInsert, KreiselConnect, KreiselRedraw, KreiselQuick, KreiselEdit, KreiselParams, KreiselLabelSetup, KreiselLabelPos, KreiselLabelHoehe, ILS_Eckrad | ILS Kreisel und Eckrad komplett in AutoLISP | -| `VarioFoerderer.lsp` | FOERDERANLAGE | Vario-Foerderanlagen Generator | -| `Gefaellestrecke.lsp` | GEFAELLESTRECKE | Gefaelle-Foerderanlage (AUS -> Staustrecke skaliert -> Separator -> EIN) | +| `VarioFoerderer.lsp` (Wrapper fuer `vf_core.lsp`/`vf_standard.lsp`/`vf_etage.lsp`/`vf_linienzug.lsp`) | FOERDERANLAGE, VARIOFOERDERER_EDIT | Vario-Foerderanlagen Generator (Typen Standard/Etage/Linienzug); Standardfall + Werteingabe per DCL-Dialog (`vfs-standard-dialog-ablauf` in vf_standard.lsp); Doppelklick auf VF_n-Block ruft VARIOFOERDERER_EDIT (nur fuer per Dialog erstellte Standard-Bloecke, erkannt an XDATA) | +| `Gefaellestrecke.lsp` | GEFAELLESTRECKE, GEFAELLESTRECKE_EDIT | Gefaelle-Foerderanlage (AUS -> Staustrecke skaliert -> Separator -> EIN); Modus 1 per DCL-Dialog (Einfuegehoehe, Element-Winkel 30/90); Doppelklick auf GF_n-Block ruft GEFAELLESTRECKE_EDIT (Dialog vorbelegt, Neuaufbau) | | `export.lsp` | EXPORTSIVAS, EXPORTCSV, OMNI_UPDATE_ATTRIBS | JSON-Sammlung und Python-Export (Omniflo-Merkmale/Sum-Zeile via lib/export_csv.py) | | `OmniModulInsert.lsp` | OMNI_LOAD, OMNI_APB_*, OMNI_W*_*, OMNI_AP60/AP110, OMNI_TEF_*, OMNI_TV_*, OMNI_APBW_*, OMNI_EDIT | Omniflo-Komponenten: Boegen, Weichen, Verbinder, Transferwagen, Edit-Dialog | | `SSG_LIB_Commands.lsp` | ILS_BTMT_*, ILS_ETF_*, ILS_K*_*, ILS_GK*_*, SSG_BLOCKEDIT, SSG_DIM_SWITCH, SSG_SPRACHE | Dummy-Befehle fuer Menue + Doppelklick/Kontextmenue-Dispatcher + Konfiguration (2D/3D, Sprache) | @@ -104,6 +104,8 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. | Datei | Verwendet von | |---|---| | `kreisel_edit.dcl` | KreiselEdit (KreiselInsert.lsp) | +| `gefaellestrecke.dcl` | GEFAELLESTRECKE Modus 1 (Gefaellestrecke.lsp, `gf-dialog-eingabe`) | +| `variofoerderer.dcl` | FOERDERANLAGE Standardfall + Werteingabe (vf_standard.lsp, `vfs-dialog-eingabe-basis`/`vfs-dialog-winkel-verteilung`) | | `omniflo_boegen.dcl` | OMNI_APB_* (OmniModulInsert.lsp) | | `omniflo_weichen.dcl` | OMNI_W*_* (OmniModulInsert.lsp) | | `sprache.dcl` | SSG_SPRACHE (SSG_LIB_Commands.lsp) | diff --git a/Lisp/Gefaellestrecke.lsp b/Lisp/Gefaellestrecke.lsp index 4f1f5e5..d64514f 100644 --- a/Lisp/Gefaellestrecke.lsp +++ b/Lisp/Gefaellestrecke.lsp @@ -1611,6 +1611,12 @@ startpunkt last-ent nach-aus-pt (float hz) (float L_stau) es-seite)) + ;; Edit-Metadaten (Fahrtrichtung, Gefaellewinkel, Element-Winkel) als XDATA + ;; auf das GF_N-INSERT schreiben, damit GEFAELLESTRECKE_EDIT die Strecke + ;; verlustfrei nachbauen kann. Nicht Teil des Sivas-Attributsatzes. + (gf-xdata-schreiben gf-insert hz winkel as-winkel es-winkel + (caddr startpunkt) deltaL-total) + (princ "\n\n=========================================") (princ (ssg-text "gf-status-erfolgreich-eingefuegt")) (princ "\n=========================================") @@ -1620,14 +1626,246 @@ (list gf-insert gf-deltaH (float deltaL-total)) ) +;; ============================================================ +;; TEIL 5b: DCL-DIALOG (Modus 1 - parametrische Eingabe) +;; ============================================================ + +;; Parametrische Eingabe fuer Modus 1 / Edit ueber DCL-Dialog +;; (dcl/gefaellestrecke.dcl). Analog zum Kreisel-Dialog, ergaenzt +;; um die Angabe der Einfuegehoehe (Z). +;; prefill: Assoziationsliste zur Vorbelegung (fuer GEFAELLESTRECKE_EDIT) mit +;; Schluesseln "deltaL" "winkel" "hz" "as-seite" "es-seite" "einfuegehoehe" +;; "as-winkel" "es-winkel" - oder nil fuer Neuanlage (Modus 1) mit Defaults. +;; Rueckgabe: (deltaL winkel hz-winkel as-seite es-seite einfuegehoehe +;; as-winkel es-winkel) +;; oder nil bei Abbruch / fehlendem Dialog. +(defun gf-dialog-eingabe ( prefill / dcl-pfad dat ergebnis + dlg-deltal dlg-hoehe dlg-winkel + dlg-richtung dlg-aus dlg-ein + dlg-aus-winkel dlg-ein-winkel + hz-winkel as-seite es-seite as-winkel es-winkel) + (setq dcl-pfad (strcat (getenv "DXFM_DCL") "/gefaellestrecke.dcl")) + (setq dat (load_dialog dcl-pfad)) + (if (not (new_dialog "gefaellestrecke" dat)) + (progn + (if (>= dat 0) (unload_dialog dat)) + (alert (ssg-textf "gf-alert-dialog-fehlt" (list dcl-pfad))) + nil + ) + (progn + ;; Vorbelegung: aus prefill (Edit) oder Defaults (Neuanlage) + (set_tile "deltal" + (if prefill (rtos (cdr (assoc "deltaL" prefill)) 2 0) + (rtos (ssg-cfg-or "gefaelle" "default_delta_l" 5000.0) 2 0))) + (set_tile "einfuegehoehe" + (if prefill (rtos (cdr (assoc "einfuegehoehe" prefill)) 2 1) "0")) + (set_tile "winkel" + (if prefill (rtos (cdr (assoc "winkel" prefill)) 2 1) + (rtos (ssg-cfg-or "gefaelle" "default_winkel" 3.0) 2 1))) + + ;; Fahrtrichtung + (start_list "fahrtrichtung") + (add_list (ssg-textf "gf-dlg-richtung-0" (list grad-zeichen))) + (add_list (ssg-textf "gf-dlg-richtung-90" (list grad-zeichen))) + (add_list (ssg-textf "gf-dlg-richtung-180" (list grad-zeichen))) + (add_list (ssg-textf "gf-dlg-richtung-270" (list grad-zeichen))) + (end_list) + (set_tile "fahrtrichtung" + (if prefill + (cond ((equal (cdr (assoc "hz" prefill)) 90.0 0.1) "1") + ((equal (cdr (assoc "hz" prefill)) 180.0 0.1) "2") + ((equal (cdr (assoc "hz" prefill)) 270.0 0.1) "3") + (t "0")) + "0")) + + ;; AUS-Element: Winkel (90/30) + Seite + (start_list "aus_winkel") + (add_list "90") + (add_list "30") + (end_list) + (set_tile "aus_winkel" + (if (and prefill (equal (cdr (assoc "as-winkel" prefill)) "30")) "1" "0")) + (start_list "aus_seite") + (add_list (ssg-text "gf-dlg-links")) + (add_list (ssg-text "gf-dlg-rechts")) + (end_list) + (set_tile "aus_seite" + (if (and prefill (equal (cdr (assoc "as-seite" prefill)) "rechts")) "1" "0")) + + ;; EIN-Element: Winkel (90/30) + Seite + (start_list "ein_winkel") + (add_list "90") + (add_list "30") + (end_list) + (set_tile "ein_winkel" + (if (and prefill (equal (cdr (assoc "es-winkel" prefill)) "30")) "1" "0")) + (start_list "ein_seite") + (add_list (ssg-text "gf-dlg-links")) + (add_list (ssg-text "gf-dlg-rechts")) + (end_list) + (set_tile "ein_seite" + (if (and prefill (equal (cdr (assoc "es-seite" prefill)) "rechts")) "1" "0")) + + ;; Actions + (action_tile "accept" + (strcat + "(setq dlg-deltal (get_tile \"deltal\"))" + "(setq dlg-hoehe (get_tile \"einfuegehoehe\"))" + "(setq dlg-winkel (get_tile \"winkel\"))" + "(setq dlg-richtung (get_tile \"fahrtrichtung\"))" + "(setq dlg-aus-winkel (get_tile \"aus_winkel\"))" + "(setq dlg-aus (get_tile \"aus_seite\"))" + "(setq dlg-ein-winkel (get_tile \"ein_winkel\"))" + "(setq dlg-ein (get_tile \"ein_seite\"))" + "(done_dialog 1)" + ) + ) + (action_tile "cancel" "(done_dialog 0)") + + (setq ergebnis (start_dialog)) + (unload_dialog dat) + + (if (= ergebnis 1) + (progn + (setq hz-winkel + (cond ((= dlg-richtung "1") 90.0) + ((= dlg-richtung "2") 180.0) + ((= dlg-richtung "3") 270.0) + (t 0.0))) + (setq as-seite (if (= dlg-aus "1") "rechts" "links")) + (setq es-seite (if (= dlg-ein "1") "rechts" "links")) + (setq as-winkel (if (= dlg-aus-winkel "1") "30" "90")) + (setq es-winkel (if (= dlg-ein-winkel "1") "30" "90")) + (list + (atof dlg-deltal) + (atof dlg-winkel) + hz-winkel + as-seite + es-seite + (atof dlg-hoehe) + as-winkel + es-winkel) + ) + nil + ) + ) + ) +) + +;; Gemeinsamer Abschluss fuer Modus 1 + 2: Laengenberechnung, +;; Zusammenfassung, Bestaetigung und Einfuegen. +;; startpunkt: Einfuegepunkt AUS-Element (inkl. Z aus Einfuegehoehe) +;; as-winkel/es-winkel: "30" oder "90" (Element-Variante) +(defun gf-modus12-abschluss (deltaL winkel hz-winkel as-seite es-seite startpunkt + as-winkel es-winkel / + rad sep-x L_stau antwort) + (if (null as-winkel) (setq as-winkel "90")) + (if (null es-winkel) (setq es-winkel "90")) + (setq winkel (float winkel)) + (setq rad (* winkel (/ pi 180.0))) + (princ (ssg-textf "gf-status-winkel" (list (rtos winkel 2 1) grad-zeichen))) + + ;; AS-/ES-Masse fuer die gewaehlte Winkel-/Seiten-Variante setzen + ;; (aktualisiert aus-dx/ein-dx vor der Laengenberechnung) + (vf-set-as-masse as-winkel as-seite) + (vf-set-es-masse es-winkel es-seite) + + ;; Laengenberechnung + ;; deltaL = aus_dx + L_stau*cos(rad) + sep*cos(rad) + ein_dx + (setq sep-x (* (ssg-cfg-or "gefaelle" "separator_breite" 300.0) (cos rad))) + (setq L_stau (/ (- deltaL aus-dx ein-dx sep-x) (cos rad))) + + ;; Validierung + (if (<= L_stau 0.1) + (progn + (alert (ssg-textf "gf-alert-staustrecke-ungueltig" (list (rtos L_stau 2 2)))) + (exit) + ) + ) + + ;; Zusammenfassung + (princ "\n\n=========================================") + (princ (ssg-textf "gf-status-fahrtrichtung" (list (rtos hz-winkel 2 1) grad-zeichen))) + (princ (ssg-textf "gf-status-zus2-winkel" (list (rtos winkel 2 1) grad-zeichen))) + (princ (ssg-textf "gf-status-zus2-aus-seite" (list as-seite))) + (princ (ssg-textf "gf-status-zus2-ein-seite" (list es-seite))) + (princ (ssg-textf "gf-status-zus2-lstau" (list (rtos L_stau 2 2)))) + (princ "\n=========================================") + + ;; Bestaetigung + (setq antwort (getstring (ssg-text "gf-prompt-einfuegen"))) + (if (not (= antwort "2")) + (gefaellestrecke-einfuegen L_stau (fix winkel) startpunkt as-seite es-seite hz-winkel deltaL as-winkel es-winkel) + (princ (ssg-text "gf-status-abgebrochen")) + ) +) + +;; Nicht-interaktiver Neuaufbau (fuer GEFAELLESTRECKE_EDIT): Element-Masse +;; setzen, L_stau berechnen und einfuegen - ohne Zusammenfassung/Rueckfrage. +;; Rueckgabe: (ename deltaH deltaL) von gefaellestrecke-einfuegen oder nil. +(defun gf-rebuild (deltaL winkel hz-winkel as-seite es-seite startpunkt + as-winkel es-winkel / + rad sep-x L_stau) + (if (null as-winkel) (setq as-winkel "90")) + (if (null es-winkel) (setq es-winkel "90")) + (setq winkel (float winkel)) + (setq rad (* winkel (/ pi 180.0))) + (vf-set-as-masse as-winkel as-seite) + (vf-set-es-masse es-winkel es-seite) + (setq sep-x (* (ssg-cfg-or "gefaelle" "separator_breite" 300.0) (cos rad))) + (setq L_stau (/ (- deltaL aus-dx ein-dx sep-x) (cos rad))) + (if (<= L_stau 0.1) + (progn + (alert (ssg-textf "gf-alert-staustrecke-ungueltig" (list (rtos L_stau 2 2)))) + nil + ) + (gefaellestrecke-einfuegen + L_stau (fix winkel) startpunkt as-seite es-seite hz-winkel deltaL as-winkel es-winkel) + ) +) + +;; ============================================================ +;; XDATA-Metadaten fuer den Edit-Nachbau (App "SSG_GF_EDIT"). +;; Bewusst NICHT im Sivas-Attributsatz, damit der Export unveraendert bleibt. +;; ============================================================ +(if (null *gf-xdata-app*) (setq *gf-xdata-app* "SSG_GF_EDIT")) + +;; Fahrtrichtung/Winkel/Element-Varianten als XDATA auf das GF_N-INSERT schreiben. +(defun gf-xdata-schreiben (ent hz winkel as-winkel es-winkel z-start deltaL /) + (regapp *gf-xdata-app*) + (entmod + (append (entget ent) + (list + (list -3 + (list *gf-xdata-app* + (cons 1000 (rtos (float hz) 2 4)) + (cons 1000 (rtos (float winkel) 2 4)) + (cons 1000 (if as-winkel as-winkel "90")) + (cons 1000 (if es-winkel es-winkel "90")) + (cons 1000 (rtos (float z-start) 2 4)) + (cons 1000 (rtos (float deltaL) 2 4))))))) + ent +) + +;; XDATA lesen -> (hz-str winkel-str as-winkel es-winkel z-str deltaL-str) oder nil. +(defun gf-xdata-lesen (ent / xd app-data) + (setq xd (entget ent (list *gf-xdata-app*))) + (setq app-data (cdr (assoc -3 xd))) + (if app-data + (mapcar 'cdr (cdr (car app-data))) + nil + ) +) + ;; ============================================================ ;; TEIL 6: HAUPTBEFEHL ;; ============================================================ -(defun c:GEFAELLESTRECKE ( / antwort eingabe-modus deltaL winkel rad L_stau sep-x +(defun c:GEFAELLESTRECKE ( / antwort deltaL winkel as-seite es-seite gf-as-winkel gf-es-winkel line-points startpunkt endpunkt differenz - deltaX deltaY startpunkt-fuer-einfuegen hz-winkel) + deltaX deltaY startpunkt-fuer-einfuegen hz-winkel + dlg-werte) (princ "\n=========================================") (princ (ssg-text "gf-banner-titel")) @@ -1655,95 +1893,52 @@ (gf-linienzug-modus) ) - ;; Modus 1+2: einfache Gefaellestrecke - (t - (if (= antwort "2") - (setq eingabe-modus "Linie") - (setq eingabe-modus "Manuell") + ;; Modus 2: 3D-Linie (Konsoleneingabe) + ((= antwort "2") + (princ (ssg-text "gf-modus2-header")) + (command "BKS" "W") + (princ (ssg-text "gf-status-bks-welt")) + (setq line-points + (get-line-start-end-points + (ssg-text "gf-prompt-3dlinie-richtung"))) + (if (null line-points) + (progn (alert (ssg-text "gf-alert-keine-linie")) (exit)) ) - - ;; Modus 1: Manuelle Eingabe - (if (= eingabe-modus "Manuell") - (progn - (princ (ssg-text "gf-modus1-header")) - (setq startpunkt-fuer-einfuegen - (getpoint (ssg-text "gf-prompt-startpunkt-aus"))) - (if (null startpunkt-fuer-einfuegen) - (setq startpunkt-fuer-einfuegen '(0 0 0))) - (setq deltaL (getreal (ssg-textf "gf-prompt-deltal-abstand" (list delta-sym)))) - (if (or (null deltaL) (<= deltaL 0)) - (setq deltaL (ssg-cfg-or "gefaelle" "default_delta_l" 5000.0))) - ) - ;; Modus 2: 3D-Linie - (progn - (princ (ssg-text "gf-modus2-header")) - (command "BKS" "W") - (princ (ssg-text "gf-status-bks-welt")) - (setq line-points - (get-line-start-end-points - (ssg-text "gf-prompt-3dlinie-richtung"))) - (if (null line-points) - (progn (alert (ssg-text "gf-alert-keine-linie")) (exit)) - ) - (setq startpunkt (car line-points) - endpunkt (cadr line-points)) - (setq differenz (punkt-differenz startpunkt endpunkt)) - (setq deltaX (car differenz) - deltaY (cadr differenz)) - ;; deltaL: horizontale 2D-Projektion entlang Fahrtrichtung - (setq deltaL (sqrt (+ (* deltaX deltaX) (* deltaY deltaY)))) - ;; hz-Winkel: Fahrtrichtung aus Linienpunkten (in Grad, 0=Ost) - (setq hz-winkel (* (angle '(0.0 0.0) (list deltaX deltaY)) (/ 180.0 pi))) - (princ (ssg-textf "gf-status-fahrtrichtung-linie" (list (rtos hz-winkel 2 1) grad-zeichen))) - (princ (ssg-textf "gf-status-deltal-mm" (list delta-sym (rtos deltaL 2 2)))) - ;; Startpunkt separat waehlen (unabhaengig von Linie) - (setq startpunkt-fuer-einfuegen - (getpoint (ssg-text "gf-prompt-startpunkt-aus"))) - (if (null startpunkt-fuer-einfuegen) - (progn (princ (ssg-text "gf-fehler-kein-startpunkt")) (exit)) - ) - ) + (setq startpunkt (car line-points) + endpunkt (cadr line-points)) + (setq differenz (punkt-differenz startpunkt endpunkt)) + (setq deltaX (car differenz) + deltaY (cadr differenz)) + ;; deltaL: horizontale 2D-Projektion entlang Fahrtrichtung + (setq deltaL (sqrt (+ (* deltaX deltaX) (* deltaY deltaY)))) + ;; hz-Winkel: Fahrtrichtung aus Linienpunkten (in Grad, 0=Ost) + (setq hz-winkel (* (angle '(0.0 0.0) (list deltaX deltaY)) (/ 180.0 pi))) + (princ (ssg-textf "gf-status-fahrtrichtung-linie" (list (rtos hz-winkel 2 1) grad-zeichen))) + (princ (ssg-textf "gf-status-deltal-mm" (list delta-sym (rtos deltaL 2 2)))) + ;; Startpunkt separat waehlen (unabhaengig von Linie) + (setq startpunkt-fuer-einfuegen + (getpoint (ssg-text "gf-prompt-startpunkt-aus"))) + (if (null startpunkt-fuer-einfuegen) + (progn (princ (ssg-text "gf-fehler-kein-startpunkt")) (exit)) ) (princ "\n\n=========================================") (princ (ssg-textf "gf-status-deltal-mm" (list delta-sym (rtos deltaL 2 2)))) (princ "\n=========================================") - ;; Winkelabfrage (beide Modi: manuell) + ;; Winkelabfrage (setq winkel (getreal (ssg-text "gf-prompt-gefaellewinkel-def3"))) (if (or (null winkel) (<= winkel 0)) (setq winkel (ssg-cfg-or "gefaelle" "default_winkel" 3.0))) (setq winkel (float winkel)) - (setq rad (* winkel (/ pi 180.0))) - (princ (ssg-textf "gf-status-winkel" (list (rtos winkel 2 1) grad-zeichen))) - ;; Fahrtrichtung waehlen (nur Modus 1; Modus 2 berechnet hz aus Linie) - (if (= eingabe-modus "Manuell") - (progn - (princ (ssg-text "vfc-fahrtrichtung-header")) - (princ (ssg-textf "vfc-fahrtrichtung-0" (list grad-zeichen))) - (princ (ssg-textf "vfc-fahrtrichtung-90" (list grad-zeichen))) - (princ (ssg-textf "vfc-fahrtrichtung-180" (list grad-zeichen))) - (princ (ssg-textf "vfc-fahrtrichtung-270" (list grad-zeichen))) - (setq antwort (getstring (ssg-text "prompt-wahl-1-2-3-4"))) - (cond - ((= antwort "2") (setq hz-winkel 90.0)) - ((= antwort "3") (setq hz-winkel 180.0)) - ((= antwort "4") (setq hz-winkel 270.0)) - (t (setq hz-winkel 0.0)) - ) - (princ (ssg-textf "gf-status-fahrtrichtung" (list (rtos hz-winkel 2 1) grad-zeichen))) - ) - ) - - ;; AUS-Element: 30/90 (vor Seite) + Seite, dann Masse fuer Variante setzen + ;; AUS-Element: 30/90 + Seite (setq gf-as-winkel (vf-frage-element-winkel "vf-winkel-aus-header")) (princ (ssg-text "gf-seite-aus-header")) (princ (ssg-text "gf-seite-links")) (princ (ssg-text "gf-seite-rechts")) (setq antwort (getstring (ssg-text "prompt-wahl-1-2"))) (setq as-seite (if (= antwort "2") "rechts" "links")) - (vf-set-as-masse gf-as-winkel as-seite) ;; EIN-Element: 30/90 + Seite (setq gf-es-winkel (vf-frage-element-winkel "vf-winkel-ein-header")) @@ -1752,41 +1947,148 @@ (princ (ssg-text "gf-seite-rechts")) (setq antwort (getstring (ssg-text "prompt-wahl-1-2"))) (setq es-seite (if (= antwort "2") "rechts" "links")) - (vf-set-es-masse gf-es-winkel es-seite) - ;; Laengenberechnung (aus-dx/ein-dx jetzt fuer die gewaehlte Variante) - ;; deltaL = aus_dx + L_stau*cos(rad) + sep*cos(rad) + ein_dx - (setq sep-x (* (ssg-cfg-or "gefaelle" "separator_breite" 300.0) (cos rad))) - (setq L_stau (/ (- deltaL aus-dx ein-dx sep-x) (cos rad))) + ;; Gemeinsamer Abschluss (Masse, Laenge, Zusammenfassung, Einfuegen) + (gf-modus12-abschluss deltaL winkel hz-winkel as-seite es-seite + startpunkt-fuer-einfuegen gf-as-winkel gf-es-winkel) + ) - ;; Validierung - (if (<= L_stau 0.1) - (progn - (alert (ssg-textf "gf-alert-staustrecke-ungueltig" (list (rtos L_stau 2 2)))) - (exit) - ) - ) - - ;; Zusammenfassung - (princ "\n\n=========================================") - (princ (ssg-textf "gf-status-fahrtrichtung" (list (rtos hz-winkel 2 1) grad-zeichen))) - (princ (ssg-textf "gf-status-zus2-winkel" (list (rtos winkel 2 1) grad-zeichen))) - (princ (ssg-textf "gf-status-zus2-aus-seite" (list as-seite))) - (princ (ssg-textf "gf-status-zus2-ein-seite" (list es-seite))) - (princ (ssg-textf "gf-status-zus2-lstau" (list (rtos L_stau 2 2)))) - (princ "\n=========================================") - - ;; Bestaetigung - (setq antwort (getstring (ssg-text "gf-prompt-einfuegen"))) - (if (not (= antwort "2")) - (gefaellestrecke-einfuegen L_stau (fix winkel) startpunkt-fuer-einfuegen as-seite es-seite hz-winkel deltaL gf-as-winkel gf-es-winkel) + ;; Modus 1: Manuelle Eingabe via DCL-Dialog + (t + (princ (ssg-text "gf-modus1-header")) + ;; Startpunkt (X/Y) in der Zeichnung waehlen; Z kommt aus dem Dialog + (setq startpunkt-fuer-einfuegen + (getpoint (ssg-text "gf-prompt-startpunkt-aus"))) + (if (null startpunkt-fuer-einfuegen) + (setq startpunkt-fuer-einfuegen '(0 0 0))) + (setq dlg-werte (gf-dialog-eingabe nil)) + (if (null dlg-werte) (princ (ssg-text "gf-status-abgebrochen")) + (progn + (setq deltaL (nth 0 dlg-werte) + winkel (nth 1 dlg-werte) + hz-winkel (nth 2 dlg-werte) + as-seite (nth 3 dlg-werte) + es-seite (nth 4 dlg-werte) + gf-as-winkel (nth 6 dlg-werte) + gf-es-winkel (nth 7 dlg-werte)) + ;; Einfuegehoehe (Z) aus Dialog auf gewaehlten Startpunkt anwenden + (setq startpunkt-fuer-einfuegen + (list (car startpunkt-fuer-einfuegen) + (cadr startpunkt-fuer-einfuegen) + (nth 5 dlg-werte))) + (if (or (null deltaL) (<= deltaL 0)) + (setq deltaL (ssg-cfg-or "gefaelle" "default_delta_l" 5000.0))) + (if (or (null winkel) (<= winkel 0)) + (setq winkel (ssg-cfg-or "gefaelle" "default_winkel" 3.0))) + (gf-modus12-abschluss deltaL winkel hz-winkel as-seite es-seite + startpunkt-fuer-einfuegen gf-as-winkel gf-es-winkel) + ) ) ) ) nil ) +;; ============================================================ +;; TEIL 7: GEFAELLESTRECKE_EDIT - Doppelklick/Kontextmenue-Bearbeitung +;; ============================================================ + +;; Bearbeitet eine bestehende Gefaellestrecke (GF_n-Block) ueber den +;; DCL-Dialog: liest die aktuellen Parameter (XDATA, sonst Attribute), +;; zeigt sie vorbelegt im Dialog und baut die Strecke bei OK am selben +;; Startpunkt neu auf. Wird vom Doppelklick-Dispatcher SSG_BLOCKEDIT +;; fuer Blocknamen "GF_*" aufgerufen. +(defun c:GEFAELLESTRECKE_EDIT ( / ss ent ed bname startpunkt attribs xd + hz winkel as-winkel es-winkel z-start deltaL + prefill dlg-werte) + ;; 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 "GEFAELLESTRECKE_EDIT" '(("OSMODE") ("ATTREQ") ("ATTDIA"))) + (setvar "OSMODE" 0) + + ;; Block auswaehlen (falls nicht vorselektiert) + (if (null ent) + (progn + (setq ss (ssget ":S" '((0 . "INSERT")))) + (if ss (setq ent (ssname ss 0))) + ) + ) + (if (null ent) (progn (ssg-end) (exit))) + + (setq ed (entget ent)) + (setq bname (cdr (assoc 2 ed))) + (if (not (wcmatch bname "GF_*")) + (progn (alert (ssg-textf "gf-edit-kein-gf" (list bname))) (ssg-end) (exit))) + + (setq startpunkt (cdr (assoc 10 ed))) + (setq attribs (ssg-attrib-read ent)) + + ;; Nur einfache Gefaellestrecken (TYP "Gefaellestrecke") lassen sich ueber den + ;; Dialog verlustfrei nachbauen. Streckengruppen (mit Bogen / Linienzug / VF) + ;; wuerden beim Neuaufbau ihre Bogengeometrie verlieren -> abbrechen. + (if (/= (cond ((cdr (assoc "TYP" attribs))) ("")) "Gefaellestrecke") + (progn + (alert (ssg-textf "gf-edit-nur-einfach" + (list (cond ((cdr (assoc "TYP" attribs))) ("?"))))) + (ssg-end) + (exit) + ) + ) + + ;; Parameter bestimmen: bevorzugt aus XDATA (verlustfrei), sonst aus Attributen. + ;; Aus Attributen sind Fahrtrichtung (hz) und Element-Winkel nicht ableitbar + ;; -> Default 0 Grad / 90 Grad; der Nutzer kann sie im Dialog korrigieren. + (setq xd (gf-xdata-lesen ent)) + (if xd + (setq hz (atof (nth 0 xd)) + winkel (atof (nth 1 xd)) + as-winkel (nth 2 xd) + es-winkel (nth 3 xd) + z-start (atof (nth 4 xd)) + deltaL (atof (nth 5 xd))) + (setq hz 0.0 + winkel (atof (cond ((cdr (assoc "GF_WINKEL" attribs))) ("3.0"))) + as-winkel "90" + es-winkel "90" + z-start (atof (cond ((cdr (assoc "HOEHE_VON_mm" attribs))) ("0"))) + deltaL (atof (cond ((cdr (assoc "DELTA_L_mm" attribs))) ("0")))) + ) + + (setq prefill + (list (cons "deltaL" deltaL) + (cons "winkel" winkel) + (cons "hz" hz) + (cons "as-seite" (cond ((cdr (assoc "SEITE_AS" attribs))) ("links"))) + (cons "es-seite" (cond ((cdr (assoc "SEITE_ES" attribs))) ("links"))) + (cons "einfuegehoehe" z-start) + (cons "as-winkel" as-winkel) + (cons "es-winkel" es-winkel))) + + (setq dlg-werte (gf-dialog-eingabe prefill)) + (if (null dlg-werte) + (princ (ssg-text "gf-status-abgebrochen")) + (progn + ;; Alten GF-Verbund loeschen und am selben Startpunkt (X/Y) mit der + ;; im Dialog gewaehlten Einfuegehoehe (Z) neu aufbauen. + (entdel ent) + (gf-rebuild + (nth 0 dlg-werte) (nth 1 dlg-werte) (nth 2 dlg-werte) + (nth 3 dlg-werte) (nth 4 dlg-werte) + (list (car startpunkt) (cadr startpunkt) (nth 5 dlg-werte)) + (nth 6 dlg-werte) (nth 7 dlg-werte)) + (princ (ssg-textf "gf-edit-neu-aufgebaut" (list bname))) + ) + ) + (ssg-end) + (princ) +) + ;; ============================================================ ;; START ;; ============================================================ diff --git a/Lisp/KreiselInsert.lsp b/Lisp/KreiselInsert.lsp index cb8c6a3..d4dde50 100644 --- a/Lisp/KreiselInsert.lsp +++ b/Lisp/KreiselInsert.lsp @@ -72,7 +72,7 @@ ;; Attribut-Definitionen: ((TAG DEFAULT) ...) (setq *kreisel-attrib-defs* - '(("NAME" "") + '(("Bezeichnung" "") ("DREHRICHTUNG" "UZS") ("ANZAHL_SEPARATOR" "2") ("KREISELART" "STANDARD") @@ -90,7 +90,7 @@ ;; Eckrad Attribut-Definitionen: ((TAG DEFAULT) ...) (setq *eckrad-attrib-defs* - '(("NAME" "") + '(("Bezeichnung" "") ("DREHRICHTUNG" "UZS") ("DREHUNG" "0") ("NUMMER" "0") @@ -325,9 +325,9 @@ ) ) - ;; NAME automatisch setzen: "KreiselN" - (setq attribs (subst (cons "NAME" (strcat "Kreisel" (itoa kreisel-nummer))) - (assoc "NAME" attribs) attribs)) + ;; Bezeichnung automatisch setzen: "KreiselN" + (setq attribs (subst (cons "Bezeichnung" (strcat "Kreisel" (itoa kreisel-nummer))) + (assoc "Bezeichnung" attribs) attribs)) ;; --- HÖHE BESTIMMEN --- ;; Priorität 1: Aus basePoint (wenn 3D Punkt mit Z > 0) @@ -928,7 +928,7 @@ ) ;; Tiles initialisieren - (set_tile "name" (cdr (assoc "NAME" attribs))) + (set_tile "name" (cdr (assoc "Bezeichnung" attribs))) (set_tile "abstand" (cdr (assoc "ABSTAND" attribs))) (set_tile "hoehe" (cdr (assoc "HOEHE" attribs))) @@ -976,8 +976,8 @@ (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 "Bezeichnung" dlg-name) + (assoc "Bezeichnung" attribs) attribs)) (setq attribs (subst (cons "HOEHE" dlg-hoehe) (assoc "HOEHE" attribs) attribs)) (setq attribs (subst (cons "KREISELART" diff --git a/Lisp/README.md b/Lisp/README.md index 1ff7d35..e70233f 100644 --- a/Lisp/README.md +++ b/Lisp/README.md @@ -233,9 +233,30 @@ Lädt alle Module in der richtigen Reihenfolge. Ermittelt den Pfad automatisch ### `VarioFoerderer.lsp` – Vario-Förderer -Parametrischer Generator für ILS Vario-Förderanlagen. Liest Block-Geometrie aus einer DWG-Bibliothek (`DXFM_BLOCKS`). Alle Konstanten (Abstände, Winkel, Skalierung) werden via `ssg-cfg-or` aus `component_defaults.json` (Sektion `vario`) gelesen. +Kompatibilitäts-Wrapper, der `vf_core.lsp` lädt (Plugin-Dispatcher-Architektur; lädt seinerseits `vf_standard.lsp`, `vf_etage.lsp`, `vf_linienzug.lsp`). Parametrischer Generator für ILS Vario-Förderanlagen. Liest Block-Geometrie aus einer DWG-Bibliothek (`DXFM_BLOCKS`). Alle Konstanten (Abstände, Winkel, Skalierung) werden via `ssg-cfg-or` aus `component_defaults.json` (Sektion `vario`) gelesen. -**Befehl:** `c:FOERDERANLAGE` +**Befehl:** `c:FOERDERANLAGE` / `c:VarioFoerderer` – wählt zuerst den Anlagen-Typ (Standard/Etage/Linienzug): + +- **Typ „standard“ + Werteingabe:** läuft über den DCL-Dialog + [`dcl/variofoerderer.dcl`](../dcl/variofoerderer.dcl) (zwei Dialoge, `vfs-standard-dialog-ablauf` + in `vf_standard.lsp`): Dialog 1 (`vfs-dialog-eingabe-basis`) erfasst deltaL, deltaH, + Förderrichtung (Auf/Ab), Einfügehöhe, Fahrtrichtung und Seite; anschließend berechnet + `berechne-standard` die gültigen Winkel-Varianten, und Dialog 2 + (`vfs-dialog-winkel-verteilung`) lässt Winkel und L_GF-Verteilung (vorne/hinten) wählen. + Startpunkt (X/Y) wird wie bei der Gefällestrecke vorher in der Zeichnung gepickt. +- **Typ „standard“ + 3D-Linie**, sowie **Typ „etage“** und **„linienzug“** bleiben + vollständig interaktiv (Kommandozeile), unverändert gegenüber dem bisherigen Ablauf. + +**Bearbeiten (`c:VARIOFOERDERER_EDIT`):** Doppelklick auf einen `VF_n`-Block – bzw. +Rechtsklick-Kontextmenü/`SSG_BLOCKEDIT` – öffnet dieselben Dialoge, vorbelegt mit den +aktuellen Parametern, und baut die Strecke bei OK am selben Startpunkt neu auf (neue +`VF_n`-Nummer). Da `VF_n`-Blöcke auch von Etage- und Linienzug-Anlagen erzeugt werden +(deren komplexere Geometrie ein einfacher Neuaufbau zerstören würde), markiert +`vfs-xdata-schreiben` nur per Standard-Dialog erstellte Blöcke mit XDATA (App +`SSG_VF_EDIT`, Fahrtrichtung `hz`); Blöcke ohne diese Markierung weist +`c:VARIOFOERDERER_EDIT` mit einer Meldung ab, statt sie zu verändern. Winkel und L_GF1 +werden aus den Sivas-Attributen (`VF_WINKEL`, `L_GF_m`) vorbelegt (Verteilung stets als +„Eigene Werte“ mit dem exakten aktuellen L_GF1). **Wichtige interne Funktionen** (werden auch von `Gefaellestrecke.lsp` genutzt): @@ -260,10 +281,36 @@ Setzt `VarioFoerderer.lsp` voraus (nutzt dessen `init-bibliothek`, `insert-block **Befehl:** `c:GEFAELLESTRECKE` -Zwei Modi: +Drei Modi: -- **Modus 1:** Startpunkt + ΔL (Horizontalabstand) interaktiv abfragen -- **Modus 2:** Bestehende 3D-Linie wählen (ΔL und Winkel werden daraus berechnet) +- **Modus 1:** Startpunkt (X/Y) picken, restliche Parameter über den DCL-Dialog + [`dcl/gefaellestrecke.dcl`](../dcl/gefaellestrecke.dcl) eingeben (ΔL, Einfügehöhe Z, + Gefällewinkel, Fahrtrichtung, AUS-/EIN-Element je Winkel 30/90 und Seite links/rechts). + Die Einfügehöhe aus dem Dialog setzt die Z-Koordinate des Startpunkts. +- **Modus 2:** Bestehende 3D-Linie wählen (ΔL und Fahrtrichtung werden daraus berechnet), + restliche Parameter interaktiv über die Kommandozeile. +- **Modus 3:** Linienzug aus LINE-/ARC-Objekten; ARC-Segmente werden durch + 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, +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 +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 +(`GF_n`) – bzw. Rechtsklick-Kontextmenü/`SSG_BLOCKEDIT` – öffnet denselben DCL-Dialog, +vorbelegt mit den aktuellen Parametern, und baut die Strecke bei OK am selben Startpunkt +neu auf. Damit Fahrtrichtung und Element-Winkel (30/90) verlustfrei rekonstruiert werden, +schreibt `gefaellestrecke-einfuegen` diese beim Erstellen als XDATA (App `SSG_GF_EDIT`, +Helfer `gf-xdata-schreiben`/`gf-xdata-lesen`) auf das `GF_n`-INSERT – bewusst **nicht** in +den Sivas-Attributsatz, damit der Export unverändert bleibt. Ältere Blöcke ohne XDATA +werden aus den Attributen vorbelegt (Fahrtrichtung 0°, Element-Winkel 90° als Vorgabe). +Der Neuaufbau läuft über `gf-rebuild` (nicht-interaktiv, ohne Konsolen-Rückfrage). --- diff --git a/Lisp/SSG_LIB_Commands.lsp b/Lisp/SSG_LIB_Commands.lsp index 8fa4d45..e71d7a2 100644 --- a/Lisp/SSG_LIB_Commands.lsp +++ b/Lisp/SSG_LIB_Commands.lsp @@ -15,6 +15,55 @@ (princ) ) +;; --- ILS / Zusatzmodul: Sensoren (Scanner / Separator) einfuegen --- + +;; Ermittelt den Pfad zu einer Sensor-Blockdatei. Die Sensor-Bloecke +;; werden fest aus data/ils/3D geladen (unabhaengig von der +;; 2D/3D-Umschaltung). +(defun ils-sensor-pfad (fname / p) + (setq p (strcat (getenv "DXFMAKRO") "\\data\\ils\\3D\\" fname ".dwg")) + (if (findfile p) p nil) +) + +;; Fuegt einen Sensor-Block wiederholt ein, bis der Benutzer mit +;; ENTER oder ESC abbricht. Rotation je Einfuegung interaktiv. +(defun ils-insert-sensor (fname / pfad pt oldattreq n res) + (setq pfad (ils-sensor-pfad fname)) + (if (null pfad) + (princ (strcat "\n>>> FEHLER: Blockdatei '" fname ".dwg' nicht gefunden." + " (in data/ils/3D pruefen)")) + (progn + (setq oldattreq (getvar "ATTREQ")) + (setvar "ATTREQ" 0) + (setq n 0) + ;; Punkt abfragen; ENTER liefert nil, ESC einen abgefangenen Fehler - + ;; beides beendet die Schleife sauber (ATTREQ wird wiederhergestellt). + (while + (progn + (setq res (vl-catch-all-apply + 'getpoint + (list (strcat "\nEinfuegepunkt fuer " fname " [ENTER=Ende]: ")))) + (and (not (vl-catch-all-error-p res)) res) + ) + (setq pt res) + (command "_.INSERT" pfad pt "" "" pause) + (setq n (1+ n)) + ) + (setvar "ATTREQ" oldattreq) + (princ (strcat "\n>>> " (itoa n) " x " fname " eingefuegt.")) + ) + ) + (princ) +) + +(defun c:ILS_SCANNER_INSERT () + (ils-insert-sensor "Scanner") +) + +(defun c:ILS_SEPARATOR_INSERT () + (ils-insert-sensor "Separator_SP") +) + ;; --- ILS / Foerderer --- (defun c:ILS_TEF_Strecke () (princ "\n[DUMMY] ILS_TEF_Strecke aufgerufen") @@ -219,6 +268,20 @@ (command "_.BEDIT" bname) ) + ;; Gefaellestrecke-Bloecke (GF_n) -> GEFAELLESTRECKE_EDIT (DCL-Dialog) + ((wcmatch bname "GF_*") + (princ (ssg-textf "cmd-gefaelle-bearbeiten" (list bname))) + (c:GEFAELLESTRECKE_EDIT) + ) + + ;; VarioFoerderer-Bloecke (VF_n) -> VARIOFOERDERER_EDIT (DCL-Dialog); + ;; weist Bloecke ohne SSG_VF_EDIT-XDATA (Etage/Linienzug/Altbestand) + ;; intern selbst ab, siehe c:VARIOFOERDERER_EDIT in vf_standard.lsp. + ((wcmatch bname "VF_*") + (princ (ssg-textf "cmd-variofoerderer-bearbeiten" (list bname))) + (c:VARIOFOERDERER_EDIT) + ) + ;; Omniflo-Bloecke -> OMNI_EDIT ;; Erkennung: TEILEART-Attribut vorhanden, AP110-Blockname oder rein numerisch ((progn diff --git a/Lisp/count_sep_scan.lsp b/Lisp/count_sep_scan.lsp index c5acbc0..f2e0d8c 100644 --- a/Lisp/count_sep_scan.lsp +++ b/Lisp/count_sep_scan.lsp @@ -6,11 +6,14 @@ ;;; Gefaellestrecke) und schreibt die Anzahlen in die Attribute ;;; des jeweiligen ILS-Blocks. Anschliessend QSAVE. ;;; -;;; Zuordnung eines Sensors zu einem ILS-Block: -;;; - Der geometrische Mittelpunkt (X/Y) des Sensors (Zentrum -;;; seiner eigenen Bounding-Box, unabhaengig vom $INSBASE) -;;; muss in der achsparallelen Bounding-Box des ILS-Blocks -;;; liegen (Z wird ignoriert). +;;; Zuordnung eines Sensors zu einem ILS-Block (Z wird ignoriert): +;;; - Scanner: der Einfuegepunkt (X/Y) muss in der Bounding-Box +;;; des ILS-Blocks liegen. Die 3D-Geometrie des Scanners kann +;;; weit vom Einfuegepunkt entfernt sein, daher zaehlt hier der +;;; Einfuegepunkt (dort klickt der Benutzer auf den Block). +;;; - Separator: der geometrische Mittelpunkt (Zentrum der eigenen +;;; Bounding-Box, unabhaengig vom $INSBASE) muss in der +;;; Bounding-Box des ILS-Blocks liegen. ;;; - Liegt der Punkt in mehreren Boxen (Ueberlappung), wird ;;; der ILS-Block mit dem naechstgelegenen Box-Zentrum gewaehlt. ;;; - Ein optionaler Toleranzrand (*senstol*) vergroessert die @@ -112,17 +115,23 @@ ) ;;; ------------------------------------------------------------ -;;; Referenzpunkt eines Sensors: geometrischer Mittelpunkt seiner -;;; eigenen Bounding-Box (X/Y). Unabhaengig vom $INSBASE der -;;; Sensor-DWG. Fallback auf den Einfuegepunkt, falls die Box -;;; nicht ermittelbar ist. +;;; Referenzpunkt eines Sensors (X/Y), je nach Typ: +;;; - Scanner : Einfuegepunkt (DXF-Gruppe 10). +;;; - Separator : geometrischer Mittelpunkt seiner eigenen +;;; Bounding-Box (unabhaengig vom $INSBASE), +;;; Fallback auf den Einfuegepunkt. ;;; ------------------------------------------------------------ -(defun cs-sensor-point (ent ed / bb) - (setq bb (cs-bbox ent)) - (if bb - (list (/ (+ (nth 0 bb) (nth 2 bb)) 2.0) - (/ (+ (nth 1 bb) (nth 3 bb)) 2.0)) +(defun cs-sensor-point (ent ed kind / bb) + (if (eq kind 'scanner) (cdr (assoc 10 ed)) + (progn + (setq bb (cs-bbox ent)) + (if bb + (list (/ (+ (nth 0 bb) (nth 2 bb)) 2.0) + (/ (+ (nth 1 bb) (nth 3 bb)) 2.0)) + (cdr (assoc 10 ed)) + ) + ) ) ) @@ -271,7 +280,7 @@ (setq kind (cs-sensor-kind nm)) (if kind (progn - (setq pt (cs-sensor-point ent ed)) + (setq pt (cs-sensor-point ent ed kind)) (if (eq kind 'scanner) (setq scanpts (cons pt scanpts)) (setq seppts (cons pt seppts))))) diff --git a/Lisp/vf_core.lsp b/Lisp/vf_core.lsp index c2570a5..3e59657 100644 --- a/Lisp/vf_core.lsp +++ b/Lisp/vf_core.lsp @@ -1151,8 +1151,9 @@ (if (car (atoms-family 1 '("SSG-ID-GENERATE"))) (ssg-id-generate vf-insert)) (princ (ssg-textf "vfc-block-erstellt-eingefuegt" (list vf-bname))) + vf-insert ) - (princ (ssg-text "vfc-fehler-keine-entities")) + (progn (princ (ssg-text "vfc-fehler-keine-entities")) nil) ) ) @@ -1247,10 +1248,10 @@ (princ "\n 3 - 3D-Objekte stueckweise (Vorwaerts-Nachbau, in Arbeit)") (setq wahl (getint "\nIhre Wahl (1/2/3) [1]: ")) ;; Konsolen-Nummer -> interne Funktion: - ;; 2 = fertiger Ziel-Hoehe-Modus (intern vf-linienzug-modus3) - ;; 3 = alter Vorwaerts-Nachbau (intern vf-linienzug-modus2, wird umgebaut) - (cond ((= wahl 2) (vf-linienzug-modus3)) - ((= wahl 3) (vf-linienzug-modus2)) + ;; 2 = fertiger Ziel-Hoehe-Modus (intern vf-linienzug-modus2) + ;; 3 = alter Vorwaerts-Nachbau (intern vf-linienzug-modus3, wird umgebaut) + (cond ((= wahl 2) (vf-linienzug-modus2)) + ((= wahl 3) (vf-linienzug-modus3)) (t (vf-linienzug-modus))) (exit) ) @@ -1260,6 +1261,26 @@ (setq vf-nummer (vf-next-number)) (princ (ssg-textf "vfc-naechste-vf-nummer" (list (itoa vf-nummer)))) + ;; 2b. Standardfall (anlage-typ "standard") + Werteingabe -> DCL-Dialog + ;; (dcl/variofoerderer.dcl, siehe vf_standard.lsp: vfs-standard-dialog-ablauf). + ;; 3D-Linie-Eingabe und alle anderen Anlagen-Typen (Etage, Linienzug) bleiben + ;; unveraendert interaktiv (fallen unten in den bestehenden Konsolen-Ablauf, + ;; der die Eingabemodus-Frage dabei erneut stellt - siehe vf-eingabe-abfragen). + (if (= anlage-typ "standard") + (progn + (princ (ssg-text "vfc-eingabemodus-header")) + (princ (ssg-text "vfc-eingabemodus-3dlinie")) + (princ (ssg-text "vfc-eingabemodus-werte")) + (setq antwort (getstring (ssg-text "vfc-prompt-wahl-1-2-ohne-default"))) + (if (= antwort "2") + (progn + (vfs-standard-dialog-ablauf vf-nummer) + (exit) + ) + ) + ) + ) + ;; 3. Gemeinsame Eingabe (deltaL, deltaH, richtung, startpunkt) - richtung ;; steht bei beiden Eingabemodi (Werteingabe UND 3D-Linie) bereits fest. (setq eingabe (vf-eingabe-abfragen)) diff --git a/Lisp/vf_linienzug.lsp b/Lisp/vf_linienzug.lsp index 442cb00..0829dd0 100644 --- a/Lisp/vf_linienzug.lsp +++ b/Lisp/vf_linienzug.lsp @@ -1386,7 +1386,7 @@ (foreach x liste (setq d (abs (- x w))) (if (< d bd) (setq bd d best x))) best) -(defun vf-linienzug-modus2 ( / ss k obj-liste startpunkt start-hoehe as-seite +(defun vf-linienzug-modus3 ( / ss k obj-liste startpunkt start-hoehe as-seite es-seite kette segmente n i seg typ hz laenge bwinkel bseite frame antwort winkel deltaL anzahl-gf anzahl-vf vfl-nummer lastEnt hoehe-bis @@ -1770,7 +1770,7 @@ (- (/ (- ep-na (* perp-es np-na)) dp-na) cc) 100.0)))) -(defun vf-linienzug-modus3 ( / ss k obj-liste startpunkt start-hoehe as-seite +(defun vf-linienzug-modus2 ( / ss k obj-liste startpunkt start-hoehe as-seite endpunkt end-hoehe es-seite kette segmente n i seg typ hz laenge bwinkel bseite antwort winkel klass plan e ecke-bad vf-start vf-ende dz z-front @@ -1791,57 +1791,60 @@ rad3v feste-vf dH-adj dir-x dir-y fill-D end-hz gf-total br-gf-mode br-gf2-exp filler-A-len filler-a-done) (princ "\n\n=========================================") - (princ "\n VF-LINIENZUG - Modus 2: Pfad + Ziel-Hoehe (fertig; Anker + Solver + Bau)") + (princ (ssg-text "vfl-m3-titel")) (princ "\n=========================================") ;; Abhaengigkeit Gefaellestrecke-Modul (if (null (car (atoms-family 1 '("GF-INSERT-HZ-INCL-SCALED")))) - (progn (alert "Gefaellestrecke-Modul nicht geladen!") (exit))) + (progn (alert (ssg-text "vfl-m3-alert-gf-modul")) (exit))) (if (or (not *lib-initialized*) (null bogen-auf)) (init-bibliothek)) ;; --- 1. Pfad-Objekte waehlen --- - (princ "\n\nPfad-Objekte waehlen (Linien/Boegen):") + (princ (ssg-text "vfl-m3-pfad-waehlen")) (setq ss (ssget '((0 . "LINE,ARC")))) - (if (null ss) (progn (princ "\nKeine Objekte gewaehlt - Abbruch.") (exit))) + (if (null ss) (progn (princ (ssg-text "vfl-m3-keine-objekte")) (exit))) (setq obj-liste '() k 0) (repeat (sslength ss) (setq obj-liste (cons (vlax-ename->vla-object (ssname ss k)) obj-liste)) (setq k (1+ k))) ;; --- 2. Startpunkt + Z + AS-Seite --- - (setq startpunkt (vfl-getpoint nil "\n\nStartpunkt der Kette (hoehere Seite) waehlen: ")) - (if (null startpunkt) (progn (princ "\nAbgebrochen.") (exit))) - (setq start-hoehe (getreal (strcat "\nHoehe (Z) des Startpunkts [" - (rtos (caddr startpunkt) 2 1) "]: "))) + (setq startpunkt (vfl-getpoint nil (ssg-text "vfl-m3-prompt-startpunkt"))) + (if (null startpunkt) (progn (princ (ssg-text "gf-status-abgebrochen")) (exit))) + (setq start-hoehe (getreal (ssg-textf "vfl-prompt-hoehe-startpunkt" + (list (rtos (caddr startpunkt) 2 1))))) (if (null start-hoehe) (setq start-hoehe (caddr startpunkt))) (setq startpunkt (list (car startpunkt) (cadr startpunkt) start-hoehe)) (setq *vfl-as-winkel* (vf-frage-element-winkel "vf-winkel-aus-header")) ; 30/90 vor Seite - (princ "\n\nAUS-Element - Seite waehlen:\n 1 - Links\n 2 - Rechts") - (setq as-seite (if (= (getstring "\nIhre Wahl (1/2) [1]: ") "2") "rechts" "links")) + (princ (ssg-text "gf-seite-aus-header")) + (princ (ssg-text "gf-seite-links")) + (princ (ssg-text "gf-seite-rechts")) + (setq as-seite (if (= (getstring (ssg-text "prompt-wahl-1-2")) "2") "rechts" "links")) (vf-set-as-masse *vfl-as-winkel* as-seite) ; Masse fuer Variante ;; --- 3. Endpunkt + Z + ES-Seite (NEU in Modus 3) --- - (setq endpunkt (vfl-getpoint nil "\n\nEndpunkt der Kette (Ziel) waehlen: ")) - (if (null endpunkt) (progn (princ "\nAbgebrochen.") (exit))) - (setq end-hoehe (getreal (strcat "\nZiel-Hoehe (Z) des Endpunkts [" - (rtos (caddr endpunkt) 2 1) "]: "))) + (setq endpunkt (vfl-getpoint nil (ssg-text "vfl-m3-prompt-endpunkt"))) + (if (null endpunkt) (progn (princ (ssg-text "gf-status-abgebrochen")) (exit))) + (setq end-hoehe (getreal (ssg-textf "vfl-m3-prompt-zielhoehe" + (list (rtos (caddr endpunkt) 2 1))))) (if (null end-hoehe) (setq end-hoehe (caddr endpunkt))) (setq endpunkt (list (car endpunkt) (cadr endpunkt) end-hoehe)) (setq *vfl-es-winkel* (vf-frage-element-winkel "vf-winkel-ein-header")) ; 30/90 vor Seite - (princ "\n\nEIN-Element (ES) - Seite waehlen:\n 1 - Links\n 2 - Rechts") - (setq es-seite (if (= (getstring "\nIhre Wahl (1/2) [1]: ") "2") "rechts" "links")) + (princ (ssg-text "gf-seite-ein-header")) + (princ (ssg-text "gf-seite-links")) + (princ (ssg-text "gf-seite-rechts")) + (setq es-seite (if (= (getstring (ssg-text "prompt-wahl-1-2")) "2") "rechts" "links")) (vf-set-es-masse *vfl-es-winkel* es-seite) ; Masse fuer Variante ;; --- 4. Sortieren + Analysieren + Eck-Vorpruefung --- (setq kette (gf-sortiere-objekte obj-liste startpunkt)) (if (null kette) - (progn (princ "\nFEHLER: Pfad nicht sortierbar (haengt er lueckenlos zusammen?).") (exit))) + (progn (princ (ssg-text "vfl-m3-fehler-nicht-sortierbar")) (exit))) (setq segmente (gf-analysiere-kette kette)) (setq ecke-bad (vfl2-pruefe-eckwinkel kette 5.0)) (if ecke-bad (progn - (alert (strcat "Kein passender Bogen: Eck-Winkel " (rtos ecke-bad 2 1) - " Grad ist nicht ~30/60/90.\nBitte die Winkel anpassen.")) + (alert (ssg-textf "vfl-m3-alert-eckwinkel" (list (rtos ecke-bad 2 1)))) (exit))) ;; --- 5. Klassifizierung (Phase A: nur speichern, nichts bauen) --- @@ -1852,36 +1855,36 @@ (setq seg (nth i segmente) typ (car seg) hz (cadr seg) laenge (caddr seg)) (cond ((= typ "Linie") - (princ (strcat "\n\nSegment " (itoa (1+ i)) "/" (itoa n) - ": Gerade L=" (rtos laenge 2 0) " mm hz=" (rtos hz 2 1))) + (princ (ssg-textf "vfl-m3-seg-gerade" + (list (itoa (1+ i)) (itoa n) (rtos laenge 2 0) (rtos hz 2 1)))) (cond ;; Direkt nach einer Vario-Kurve: automatisch VF (keine Abfrage) - ;; die Kurve sitzt mitten in der VF-Einheit, es MUSS VF folgen. (nach-kurve - (princ "\n (automatisch VF - Segment folgt direkt auf eine Vario-Kurve)") + (princ (ssg-text "vfl-m3-auto-vf")) (setq plan (cons (list "Linie" hz laenge "VF" nil) plan)) (setq nach-kurve nil)) (t - (princ "\n Typ? 1 = GF (Eingabe-Winkel) 2 = VF (Bruecke)") - (setq antwort (getstring "\nIhre Wahl (1/2) [1]: ")) + (princ (ssg-text "vfl-m3-typ-gerade")) + (setq antwort (getstring (ssg-text "prompt-wahl-1-2"))) (if (= antwort "2") (setq plan (cons (list "Linie" hz laenge "VF" nil) plan)) (progn - (setq winkel (getreal "\n GF-Neigung in Grad [3]: ")) + (setq winkel (getreal (ssg-text "vfl-m3-prompt-gf-neigung"))) (if (null winkel) (setq winkel 3.0)) (if (> winkel 3.0) - (progn (princ "\n Hinweis: GF max. 3 Grad - auf 3 begrenzt.") (setq winkel 3.0))) + (progn (princ (ssg-text "vfl-m3-hinweis-gf-max")) (setq winkel 3.0))) (setq plan (cons (list "Linie" hz laenge "GF" winkel) plan))))))) ((= typ "Bogen") (setq bwinkel (nth 3 seg) bseite (nth 4 seg)) - (princ (strcat "\n\nSegment " (itoa (1+ i)) "/" (itoa n) - ": Eck/Bogen " (itoa bwinkel) " Grad " bseite)) - (princ "\n Typ? 1 = GF-Bogen 2 = Vario-Kurve") - (setq antwort (getstring "\nIhre Wahl (1/2) [1]: ")) + (princ (ssg-textf "vfl-m3-seg-bogen" + (list (itoa (1+ i)) (itoa n) (itoa bwinkel) bseite))) + (princ (ssg-text "vfl-m3-typ-bogen")) + (setq antwort (getstring (ssg-text "prompt-wahl-1-2"))) (if (= antwort "2") (progn - (princ "\n Vario-Kurve - Variante? 1 = Aussen 2 = Innen") - (setq kv-variante (if (= (getstring "\nIhre Wahl (1/2) [2]: ") "1") "aussen" "innen")) + (princ (ssg-text "vfl-m3-variante-frage")) + (setq kv-variante (if (= (getstring (ssg-text "vfl-prompt-wahl-1-2-def2")) "1") "aussen" "innen")) (setq plan (cons (list "Bogen" hz laenge bwinkel bseite "Vario-Kurve" kv-variante) plan)) (setq nach-kurve t)) ; naechste Gerade automatisch VF (progn @@ -1905,9 +1908,9 @@ (if (/= vf-count 1) (progn - (princ (strcat "\n\n[M3a] Gefundene VF-Laeufe: " (itoa vf-count))) - (princ "\n[M3a] Genau EIN VF-Lauf noetig (GF...VF...GF; Vario-Kurven duerfen im Lauf liegen).") - (princ "\n[M3a] Mehrere/keine VF-Laeufe -> M3b spaeter.") + (princ (ssg-textf "vfl-m3-vf-laeufe" (list (itoa vf-count)))) + (princ (ssg-text "vfl-m3-vf-lauf-noetig")) + (princ (ssg-text "vfl-m3-vf-lauf-m3b")) (exit))) ;; Traeger-Stueck = laengste VF-Gerade im Lauf (traegt die ganze Hoehe). (setq carrier-idx -1 i vf-start) @@ -1918,7 +1921,7 @@ (setq carrier-idx i))) (setq i (1+ i))) (if (< carrier-idx 0) - (progn (princ "\n[M3a] VF-Lauf ohne VF-Gerade - Abbruch.") (exit))) + (progn (princ (ssg-text "vfl-m3-vf-lauf-ohne-gerade")) (exit))) ;; --- 7. Anker rechnen --- ;; Vorwaerts: Start-Z durch alle Front-Segmente (Index < vf-start). @@ -1947,31 +1950,30 @@ ;; --- 8. Anker-Report (noch kein Bauen) --- (princ "\n\n=========================================") - (princ "\n M3a ANKER-VORSCHAU (grob geschaetzt; exakte Werte beim Bau)") + (princ (ssg-text "vfl-m3-anker-vorschau-header")) (princ "\n=========================================") - (princ (strcat "\n Start-Hoehe Z: " (rtos (float start-hoehe) 2 1) " mm")) - (princ (strcat "\n Ziel-Hoehe Z: " (rtos (float end-hoehe) 2 1) " mm")) - (princ (strcat "\n delta-H gesamt: " (rtos dH-gesamt 2 1) " mm (positiv = Abfall)")) - (princ (strcat "\n VF-Lauf: Segment " (itoa (1+ vf-start)) ".." (itoa (1+ vf-ende)))) - (princ (strcat "\n Front-Anker Z: " (rtos z-front 2 1) " mm (vorwaerts von AS)")) - (princ (strcat "\n Junction-Anker Z: " (rtos z-junction 2 1) " mm (rueckwaerts von ES)")) + (princ (ssg-textf "vfl-m3-start-hoehe" (list (rtos (float start-hoehe) 2 1)))) + (princ (ssg-textf "vfl-m3-ziel-hoehe" (list (rtos (float end-hoehe) 2 1)))) + (princ (ssg-textf "vfl-m3-delta-h-gesamt" (list (rtos dH-gesamt 2 1)))) + (princ (ssg-textf "vfl-m3-vf-lauf-segmente" (list (itoa (1+ vf-start)) (itoa (1+ vf-ende))))) + (princ (ssg-textf "vfl-m3-front-anker-vorschau" (list (rtos z-front 2 1)))) + (princ (ssg-textf "vfl-m3-junction-anker-vorschau" (list (rtos z-junction 2 1)))) ;; Vorzeichen = Richtung (VF ist angetrieben, kann steigen UND fallen). - (setq richtn (cond ((< dH-bruecke -0.1) "Auf (steigt)") - ((> dH-bruecke 0.1) "Ab (faellt)") - (t "horizontal"))) + (setq richtn (cond ((< dH-bruecke -0.1) (ssg-text "vfl-m3-richtung-auf")) + ((> dH-bruecke 0.1) (ssg-text "vfl-m3-richtung-ab")) + (t (ssg-text "vfl-m3-richtung-horizontal")))) (setq req-w (if (> span-bruecke 1.0) (* (atan (/ (abs dH-bruecke) span-bruecke)) (/ 180.0 pi)) 0.0)) - (princ (strcat "\n --> Bruecke: delta-H = " (rtos dH-bruecke 2 1) - " mm ueber Spannweite " (rtos span-bruecke 2 0) " mm")) - (princ (strcat "\n Richtung: VF-" richtn)) - (princ "\n (VF ist angetrieben - kann STEIGEN und FALLEN; Vorzeichen = nur Auf/Ab)") - (princ (strcat "\n grobe mittlere Neigung ueber Spannweite: ~" (rtos req-w 2 1) " Grad")) + (princ (ssg-textf "vfl-m3-bruecke-dh" (list (rtos dH-bruecke 2 1) (rtos span-bruecke 2 0)))) + (princ (ssg-textf "vfl-m3-bruecke-richtung" (list richtn))) + (princ (ssg-text "vfl-m3-vf-angetrieben")) + (princ (ssg-textf "vfl-m3-mittlere-neigung" (list (rtos req-w 2 1)))) (if (> req-w 51.0) - (princ "\n WARNUNG: ~Neigung > 51 Grad -> zu steil fuer Vario (Magnitude infeasibel).") - (princ "\n -> innerhalb Vario-Bereich (3..51 Grad), grobe Orientierung.")) + (princ (ssg-text "vfl-m3-warnung-zu-steil")) + (princ (ssg-text "vfl-m3-vario-bereich-ok"))) - (princ "\n (Anker oben = grobe Vorschau; exakte Werte werden beim Bau GEMESSEN)") + (princ (ssg-text "vfl-m3-anker-hinweis")) (princ "\n=========================================") ;; ================= PHASE B: BAUEN (messen statt schaetzen) ================= @@ -1990,7 +1992,7 @@ (setq i (1+ i))) ;; --- B1: FRONT-Lauf bauen (Segmente 0 .. vf-start-1) -> Front-Anker MESSEN --- - (princ "\n\n>>> Phase B1: Front-Lauf (AS + GF) bauen ...") + (princ (ssg-text "vfl-m3-phase-b1")) (setq i 0) (while (< i vf-start) (setq seg (nth i plan) typ (car seg) hz (cadr seg)) @@ -2016,9 +2018,9 @@ (if (= klass "GF-Bogen") (progn (if (null frame) - (progn (alert "Kette beginnt mit einem Bogen - bitte erst eine Gerade.") (exit))) + (progn (alert (ssg-text "vfl-m3-alert-beginnt-bogen")) (exit))) (setq frame (vfl-insert-gf-bogen-block frame bwinkel bseite))) - (princ "\n >>> [M3a] Vario-Kurve im Front-Lauf - uebersprungen.")))) + (princ (ssg-text "vfl-m3-kurve-front-uebersprungen"))))) (setq i (1+ i))) ;; Front-Anker (gemessen). Falls die VF-Bruecke ganz vorne liegt: AS jetzt setzen. @@ -2066,11 +2068,11 @@ ;; Kletter-Segment als Standard-Vario loesen; GF wird BERECHNET (L_GF) und der ;; Winkel WAEHLBAR (mehrere gueltige -> Nutzer waehlt). feste = 800 (Umlenk+Sep; ;; Motor sitzt am Kettenende). Die flache Zone gleicht danach die Laenge aus. - (princ "\n\n --- STANDARD-VARIO (Kletter-Segment) + flache Zone ---") - (princ (strcat "\n Front-Anker (gemessen): " (rtos z-front 2 1) " mm")) - (princ (strcat "\n Junction (exakt): " (rtos z-junction 2 1) " mm")) - (princ (strcat "\n Kletterhoehe " (rtos target-climb 2 1) " mm | Kletterer " - (itoa n-climb) " | Kurven " (itoa nkurve) " | kurze VF " (itoa nonclimber-cnt))) + (princ (ssg-text "vfl-m3-standard-vario-header")) + (princ (ssg-textf "vfl-m3-front-anker-gemessen" (list (rtos z-front 2 1)))) + (princ (ssg-textf "vfl-m3-junction-exakt" (list (rtos z-junction 2 1)))) + (princ (ssg-textf "vfl-m3-kletter-info" + (list (rtos target-climb 2 1) (itoa n-climb) (itoa nkurve) (itoa nonclimber-cnt)))) ;; feste-Horizontal + Hoehen-Anpassung fuer den Solver: ;; - Mit flacher Zone: Motor sitzt am Kettenende (nicht im Kletter-Segment) -> ;; feste = 800 (Umlenk+Sep). berechne rechnet Motor-/Uebergangs-Abstieg NICHT, @@ -2083,24 +2085,28 @@ (setq feste-vf 1300.0 dH-adj dH-bruecke)) (setq wahl3 (vfl3-waehle-winkel climber-span dH-adj feste-vf)) (if (null wahl3) - (progn (princ "\n KEIN passender Vario-Winkel -> infeasibel (Front bereits gebaut).") + (progn (princ (ssg-text "vfl-m3-kein-winkel")) (princ) (exit))) (setq br-winkel (car wahl3) gf-total (cadr wahl3) br-lvf (caddr wahl3) br-richtn (cadddr wahl3)) ;; GF-Verteilung: 1 = alles am Einlauf (GF1); 2 = 1/2 GF1 + 1/2 GF2. Bei 1/2/1/2 ;; wird der im Kletter-Segment durch das halbe GF1 frei werdende Platz mit einem ;; horizontalen Fueller-A gefuellt; GF2 (~1/2 L_GF) sitzt hinter dem Motor, der ;; ES-Laengen-Abschluss zieht seinen Fussabdruck ab (Fueller-B wird kuerzer). - (princ "\n\n GF-Verteilung: 1 - alles am Einlauf (GF1) 2 - 1/2 GF1 + 1/2 GF2") - (setq br-gf-mode (if (= (getstring "\n Ihre Wahl (1/2) [1]: ") "2") 2 1)) + (princ (ssg-text "vfl-m3-gf-verteilung")) + (setq br-gf-mode (if (= (getstring (ssg-text "prompt-wahl-1-2")) "2") 2 1)) (if (= br-gf-mode 2) (setq br-gf1 (/ gf-total 2.0) br-gf2-exp (/ gf-total 2.0) filler-A-len (* (/ gf-total 2.0) (cos rad3v))) (setq br-gf1 gf-total br-gf2-exp 0.0 filler-A-len 0.0)) (setq filler-a-done nil) - (princ (strcat "\n -> Vario " (itoa br-winkel) " (" br-richtn "), L_VF " (rtos br-lvf 2 0) - " mm, GF gesamt " (rtos gf-total 2 0) " mm, Verteilung " - (if (= br-gf-mode 2) "1/2 GF1 + 1/2 GF2" "alles GF1") - " (GF2-Rest = Mess-Feinkorrektur)")) + (princ (ssg-textf "vfl-m3-vario-ergebnis" + (list (itoa br-winkel) + (if (= br-richtn "Auf") (ssg-text "vfl-m3-richtung-auf-kurz") + (ssg-text "vfl-m3-richtung-ab-kurz")) + (rtos br-lvf 2 0) + (rtos gf-total 2 0) + (if (= br-gf-mode 2) (ssg-text "vfl-m3-vert-halb") + (ssg-text "vfl-m3-vert-ganz"))))) ;; --- B3: Standard-Vario (Klettern, 3-Grad-Basis) + flache Zone (0 Grad) --- ;; Die flache Zone (Vario-Kurve + horizontaler Fueller) haengt EINMAL ueber auf_3 @@ -2171,13 +2177,12 @@ (setq gf2-drop (- z-aftermotor z-junction)) (if (< gf2-drop 0.0) (progn - (princ (strcat "\n WARNUNG: Koerper klettert zu wenig - GF2<0 (fehlen " - (rtos (- gf2-drop) 2 1) " mm). Winkel zu flach; dZ nicht exakt.")) + (princ (ssg-textf "vfl-m3-warnung-gf2-negativ" (list (rtos (- gf2-drop) 2 1)))) (setq gf2-drop 0.0))) (setq gf2-planar (/ gf2-drop (/ (sin (* 3.0 (/ pi 180.0))) (cos (* 3.0 (/ pi 180.0)))))) (if (> gf2-planar 0.1) (progn - (princ (strcat "\n GF2 (gemessener Ausgleich): L=" (rtos gf2-planar 2 1) " mm")) + (princ (ssg-textf "vfl-m3-gf2-ausgleich" (list (rtos gf2-planar 2 1)))) (setq frame (vfl-insert-gf-segment pt letzt-koerper-hz gf2-planar 3)) (vfl-acc-gf-seg (/ gf2-planar (cos (* 3.0 (/ pi 180.0)))) 3)) (setq frame (vfl-frame-3grad pt letzt-koerper-hz))) @@ -2199,11 +2204,11 @@ (setq bwinkel (nth 3 seg) bseite (nth 4 seg) klass (nth 5 seg)) (if (= klass "GF-Bogen") (setq frame (vfl-insert-gf-bogen-block frame bwinkel bseite)) - (princ "\n >>> [M3a] Vario-Kurve im Back-Lauf - uebersprungen.")))) + (princ (ssg-text "vfl-m3-kurve-back-uebersprungen"))))) (setq i (1+ i))) ;; --- B5: Kettenende Separator + ES --- - (if (null frame) (progn (princ "\nNichts gebaut - Abbruch.") (exit))) + (if (null frame) (progn (princ (ssg-text "vfl-m3-nichts-gebaut")) (exit))) (setq frame (vfl-insert-es-element "GF" frame (car (frame->hz-winkel frame)) (if letzt-winkel letzt-winkel 3.0) (caddr (car frame)) es-seite)) @@ -2213,25 +2218,25 @@ (vfl-planar-dist startpunkt (car frame)) as-seite es-seite startpunkt lastEnt) (setq soll-ende endpunkt ist-ende (car frame)) (princ "\n\n=========================================") - (princ "\n>>> VF-Linienzug (Modus 3, M3a) gebaut! <<<") - (princ (strcat "\n Ziel (Soll): X=" (rtos (car soll-ende) 2 1) - " Y=" (rtos (cadr soll-ende) 2 1) " Z=" (rtos (caddr soll-ende) 2 1))) - (princ (strcat "\n ES (Ist): X=" (rtos (car ist-ende) 2 1) - " Y=" (rtos (cadr ist-ende) 2 1) " Z=" (rtos (caddr ist-ende) 2 1))) - (princ (strcat "\n Abweichung: dX=" (rtos (- (car ist-ende) (car soll-ende)) 2 1) - " dY=" (rtos (- (cadr ist-ende) (cadr soll-ende)) 2 1) - " dZ=" (rtos (- (caddr ist-ende) (caddr soll-ende)) 2 1) " mm")) + (princ (ssg-text "vfl-m3-fertig-header")) + (princ (ssg-textf "vfl-m3-ziel-soll" + (list (rtos (car soll-ende) 2 1) (rtos (cadr soll-ende) 2 1) (rtos (caddr soll-ende) 2 1)))) + (princ (ssg-textf "vfl-m3-es-ist" + (list (rtos (car ist-ende) 2 1) (rtos (cadr ist-ende) 2 1) (rtos (caddr ist-ende) 2 1)))) + (princ (ssg-textf "vfl-m3-abweichung" + (list (rtos (- (car ist-ende) (car soll-ende)) 2 1) + (rtos (- (cadr ist-ende) (cadr soll-ende)) 2 1) + (rtos (- (caddr ist-ende) (caddr soll-ende)) 2 1)))) ;; Zerlegung bezogen auf die ES-KS_AUS-ACHSE: Quer (senkrecht zur Achse) soll ;; ~0 sein (Endpunkt liegt auf der KS_AUS-Achse), Laengs = ES-Ausladung. (setq end-hz (car (frame->hz-winkel frame))) ; KS_AUS-Achsrichtung (setq dir-x (cos (* end-hz (/ pi 180.0))) dir-y (sin (* end-hz (/ pi 180.0)))) - (princ (strcat "\n Laengs KS_AUS-Achse: " - (rtos (+ (* (- (car ist-ende) (car soll-ende)) dir-x) + (princ (ssg-textf "vfl-m3-laengs-quer" + (list (rtos (+ (* (- (car ist-ende) (car soll-ende)) dir-x) (* (- (cadr ist-ende) (cadr soll-ende)) dir-y)) 2 1) - " mm | Quer zur Achse (soll ~0): " (rtos (+ (* (- (car ist-ende) (car soll-ende)) (- dir-y)) - (* (- (cadr ist-ende) (cadr soll-ende)) dir-x)) 2 1) " mm")) - (princ "\n (dZ=Ziel-Hoehe; Quer zur KS_AUS-Achse ~0 => Endpunkt liegt auf der Achse)") + (* (- (cadr ist-ende) (cadr soll-ende)) dir-x)) 2 1)))) + (princ (ssg-text "vfl-m3-achse-hinweis")) (princ "\n=========================================") (princ) ) diff --git a/Lisp/vf_standard.lsp b/Lisp/vf_standard.lsp index 6f046c3..c5b330b 100644 --- a/Lisp/vf_standard.lsp +++ b/Lisp/vf_standard.lsp @@ -699,6 +699,427 @@ endpunkt ) +;; ============================================================ +;; DCL-DIALOG (Standardfall) - dcl/variofoerderer.dcl +;; Ersetzt die interaktive Werteingabe aus vf-eingabe-abfragen +;; (Konsolen-Modus "Werteingabe") fuer anlage-typ "standard" durch +;; zwei DCL-Dialoge: Basis-Eingabe und Winkel/Verteilung. Die +;; 3D-Linie-Eingabe sowie die Typen "etage"/"linienzug" bleiben +;; unveraendert interaktiv (siehe Verzweigung in c:VarioFoerderer). +;; ============================================================ + +;; Basis-Eingabe (Dialog 1): deltaL, deltaH, Richtung, Einfuegehoehe, +;; Fahrtrichtung, Seite. +;; prefill: Assoziationsliste zur Vorbelegung (fuer VARIOFOERDERER_EDIT) mit +;; Schluesseln "deltaL" "deltaH" "richtung" "einfuegehoehe" "hz" "seite" +;; - oder nil fuer Neuanlage mit Defaults. +;; Rueckgabe: (deltaL deltaH richtung einfuegehoehe hz seite) oder nil bei Abbruch. +(defun vfs-dialog-eingabe-basis (prefill / dcl-pfad dat ergebnis + dlg-deltal dlg-deltah dlg-richtung dlg-hoehe + dlg-fahrtrichtung dlg-seite + deltaL deltaH richtung hz seite z-start) + (setq dcl-pfad (strcat (getenv "DXFM_DCL") "/variofoerderer.dcl")) + (setq dat (load_dialog dcl-pfad)) + (if (not (new_dialog "variofoerderer_basis" dat)) + (progn + (if (>= dat 0) (unload_dialog dat)) + (alert (ssg-textf "gf-alert-dialog-fehlt" (list dcl-pfad))) + nil + ) + (progn + ;; Vorbelegung: aus prefill (Edit) oder Defaults (Neuanlage) + (set_tile "deltal" + (if prefill (rtos (cdr (assoc "deltaL" prefill)) 2 0) "15000")) + (set_tile "deltah" + (if prefill (rtos (cdr (assoc "deltaH" prefill)) 2 0) "3000")) + (set_tile "einfuegehoehe" + (if prefill (rtos (cdr (assoc "einfuegehoehe" prefill)) 2 1) "0")) + + (start_list "richtung") + (add_list (ssg-text "vfs-dlg-richtung-auf")) + (add_list (ssg-text "vfs-dlg-richtung-ab")) + (end_list) + (set_tile "richtung" + (if (and prefill (equal (cdr (assoc "richtung" prefill)) "Ab")) "1" "0")) + + (start_list "fahrtrichtung") + (add_list (ssg-textf "gf-dlg-richtung-0" (list grad-zeichen))) + (add_list (ssg-textf "gf-dlg-richtung-90" (list grad-zeichen))) + (add_list (ssg-textf "gf-dlg-richtung-180" (list grad-zeichen))) + (add_list (ssg-textf "gf-dlg-richtung-270" (list grad-zeichen))) + (end_list) + (set_tile "fahrtrichtung" + (if prefill + (cond ((equal (cdr (assoc "hz" prefill)) 90.0 0.1) "1") + ((equal (cdr (assoc "hz" prefill)) 180.0 0.1) "2") + ((equal (cdr (assoc "hz" prefill)) 270.0 0.1) "3") + (t "0")) + "0")) + + (start_list "seite") + (add_list (ssg-text "gf-dlg-rechts")) + (add_list (ssg-text "gf-dlg-links")) + (end_list) + (set_tile "seite" + (if (and prefill (equal (cdr (assoc "seite" prefill)) "links")) "1" "0")) + + ;; Actions + (action_tile "accept" + (strcat + "(setq dlg-deltal (get_tile \"deltal\"))" + "(setq dlg-deltah (get_tile \"deltah\"))" + "(setq dlg-richtung (get_tile \"richtung\"))" + "(setq dlg-hoehe (get_tile \"einfuegehoehe\"))" + "(setq dlg-fahrtrichtung (get_tile \"fahrtrichtung\"))" + "(setq dlg-seite (get_tile \"seite\"))" + "(done_dialog 1)" + ) + ) + (action_tile "cancel" "(done_dialog 0)") + + (setq ergebnis (start_dialog)) + (unload_dialog dat) + + (if (= ergebnis 1) + (progn + (setq deltaL (atof dlg-deltal)) + (setq deltaH (atof dlg-deltah)) + (setq richtung (if (= dlg-richtung "1") "Ab" "Auf")) + (setq z-start (atof dlg-hoehe)) + (setq hz + (cond ((= dlg-fahrtrichtung "1") 90.0) + ((= dlg-fahrtrichtung "2") 180.0) + ((= dlg-fahrtrichtung "3") 270.0) + (t 0.0))) + (setq seite (if (= dlg-seite "1") "links" "rechts")) + (list deltaL deltaH richtung z-start hz seite) + ) + nil + ) + ) + ) +) + +;; Winkel/Verteilung-Eingabe (Dialog 2): Winkel-Popup aus den vorher +;; berechneten gueltigen Varianten (gueltige-winkel/ergebnis-liste, siehe +;; berechne-alle-winkel), plus L_GF-Verteilung vorne/hinten (analog Schritt +;; 8+9 in c:VarioFoerderer). +;; prefill: Assoziationsliste ("winkel" . best-winkel) ("verteilung-idx" . "0".."3") +;; ("lgf1" . mm) - oder nil fuer Vorbelegung mit dem kleinsten gueltigen Winkel. +;; Rueckgabe: (best-winkel L_GF L_VF L_GF1 L_GF2 verteilung-modus) oder nil bei Abbruch. +(defun vfs-dialog-winkel-verteilung (gueltige-winkel ergebnis-liste staustrecke-basis prefill / + dcl-pfad dat ergebnis w eintrag idx sel-idx init-verteilung + dlg-winkel dlg-verteilung dlg-lgf1 + best-winkel L_GF L_VF verteilung-modus L_GF1 L_GF2) + (setq dcl-pfad (strcat (getenv "DXFM_DCL") "/variofoerderer.dcl")) + (setq dat (load_dialog dcl-pfad)) + (if (not (new_dialog "variofoerderer_winkel" dat)) + (progn + (if (>= dat 0) (unload_dialog dat)) + (alert (ssg-textf "gf-alert-dialog-fehlt" (list dcl-pfad))) + nil + ) + (progn + ;; Winkel-Popup aus den gueltigen Varianten aufbauen + (start_list "winkel") + (foreach w gueltige-winkel + (setq eintrag (assoc w ergebnis-liste)) + (if (= w 0) + (add_list (ssg-textf "vfs-dlg-winkel-horizontal" + (list (rtos (nth 1 eintrag) 2 1) (rtos (nth 2 eintrag) 2 1)))) + (add_list (ssg-textf "vfs-dlg-winkel-option" + (list (itoa w) grad-zeichen (rtos (nth 1 eintrag) 2 1) (rtos (nth 2 eintrag) 2 1)))) + ) + ) + (end_list) + ;; Vorbelegung: Winkel aus prefill (falls noch gueltig), sonst erster + ;; (kleinster) gueltiger Winkel - analog der automatischen Konsolen-Wahl. + (setq sel-idx 0 idx 0) + (if prefill + (foreach w gueltige-winkel + (if (equal w (cdr (assoc "winkel" prefill))) (setq sel-idx idx)) + (setq idx (1+ idx)) + ) + ) + (set_tile "winkel" (itoa sel-idx)) + + ;; Verteilung: Popup + manuelles L_GF1-Feld (nur bei "Eigene Werte" aktiv) + (start_list "verteilung") + (add_list (ssg-text "vfs-dlg-verteilung-1")) + (add_list (ssg-text "vfs-dlg-verteilung-2")) + (add_list (ssg-text "vfs-dlg-verteilung-3")) + (add_list (ssg-text "vfs-dlg-verteilung-4")) + (end_list) + (setq init-verteilung (if prefill (cdr (assoc "verteilung-idx" prefill)) "0")) + (set_tile "verteilung" init-verteilung) + (set_tile "lgf1_manuell" + (if (and prefill (cdr (assoc "lgf1" prefill))) + (rtos (cdr (assoc "lgf1" prefill)) 2 1) "0")) + (mode_tile "lgf1_manuell" (if (= init-verteilung "3") 0 1)) + + (action_tile "verteilung" + "(mode_tile \"lgf1_manuell\" (if (= (get_tile \"verteilung\") \"3\") 0 1))") + + (action_tile "accept" + (strcat + "(setq dlg-winkel (get_tile \"winkel\"))" + "(setq dlg-verteilung (get_tile \"verteilung\"))" + "(setq dlg-lgf1 (get_tile \"lgf1_manuell\"))" + "(done_dialog 1)" + ) + ) + (action_tile "cancel" "(done_dialog 0)") + + (setq ergebnis (start_dialog)) + (unload_dialog dat) + + (if (= ergebnis 1) + (progn + (setq best-winkel (nth (atoi dlg-winkel) gueltige-winkel)) + (setq eintrag (assoc best-winkel ergebnis-liste)) + (setq L_GF (nth 1 eintrag) L_VF (nth 2 eintrag)) + (setq verteilung-modus dlg-verteilung) + (cond + ((= verteilung-modus "0") + (setq L_GF1 (/ L_GF 2.0) L_GF2 (/ L_GF 2.0))) + ((= verteilung-modus "1") + (setq L_GF1 (float staustrecke-basis)) + (setq L_GF2 (max 0.0 (- L_GF (float staustrecke-basis))))) + ((= verteilung-modus "2") + (setq L_GF2 (float staustrecke-basis)) + (setq L_GF1 (max 0.0 (- L_GF (float staustrecke-basis))))) + ((= verteilung-modus "3") + (setq L_GF1 (atof dlg-lgf1)) + (if (or (null L_GF1) (< L_GF1 0)) (setq L_GF1 (/ L_GF 2.0))) + (if (> L_GF1 L_GF) (setq L_GF1 L_GF)) + (setq L_GF2 (max 0.0 (- L_GF L_GF1)))) + (t (setq L_GF1 (/ L_GF 2.0) L_GF2 (/ L_GF 2.0))) + ) + (list best-winkel L_GF L_VF L_GF1 L_GF2 verteilung-modus) + ) + nil + ) + ) + ) +) + +;; ============================================================ +;; XDATA-Metadaten fuer den Edit-Nachbau (App "SSG_VF_EDIT"). +;; Markiert ein VF_n-INSERT als "mit dem Standard-Dialog erstellt" und +;; speichert die Fahrtrichtung (hz) - der einzige Wert, der sich nicht aus +;; den Sivas-Attributen rekonstruieren laesst (ANTRIEBFAHRTRICHTUNG, SEITE_AS, +;; VF_WINKEL, L_GF_m stehen dort bereits). Bewusst NICHT im Sivas-Attributsatz. +;; Ohne diese Markierung (z.B. Etage-, Linienzug- oder Altbestand-Bloecke) +;; verweigert c:VARIOFOERDERER_EDIT die Bearbeitung, um deren komplexere +;; Geometrie nicht versehentlich durch einen einfachen Neuaufbau zu ersetzen. +;; ============================================================ +(if (null *vf-xdata-app*) (setq *vf-xdata-app* "SSG_VF_EDIT")) + +(defun vfs-xdata-schreiben (ent hz /) + (regapp *vf-xdata-app*) + (entmod + (append (entget ent) + (list + (list -3 + (list *vf-xdata-app* + (cons 1000 "standard") + (cons 1000 (rtos (float hz) 2 4))))))) + ent +) + +;; XDATA lesen -> (typ-marker hz-str) oder nil. +(defun vfs-xdata-lesen (ent / xd app-data) + (setq xd (entget ent (list *vf-xdata-app*))) + (setq app-data (cdr (assoc -3 xd))) + (if app-data + (mapcar 'cdr (cdr (car app-data))) + nil + ) +) + +;; ============================================================ +;; Gemeinsame Berechnung + Winkel/Verteilung-Dialog + Einfuegung. +;; Wird sowohl von der Neuanlage (vfs-standard-dialog-ablauf) als auch vom +;; Edit-Befehl (c:VARIOFOERDERER_EDIT) verwendet. +;; winkel-prefill: Vorbelegung fuer vfs-dialog-winkel-verteilung oder nil. +;; ============================================================ +(defun vfs-standard-dialog-berechnen-einfuegen (vf-nummer deltaL deltaH richtung startpunkt hz seite + winkel-prefill / + ergebnis ergebnis-liste gueltige-winkel horizontal-info + winkelwahl best-winkel L_GF L_VF L_GF1 L_GF2 verteilung-modus + n-scanner hoehe-von hoehe-bis lastEnt vf-insert staustrecke-basis) + (setq ergebnis (berechne-standard deltaL deltaH richtung seite)) + (setq ergebnis-liste (cadddr ergebnis)) + (setq staustrecke-basis (ssg-cfg-or "vario" "staustrecke_basis" 1000)) + + ;; Horizontale Zwischenstrecke als Zusatzoption (nur bei "Ab" erreichbar, + ;; siehe Kommentar in c:VarioFoerderer Schritt 5b). + (setq horizontal-info nil) + (if (= richtung "Ab") + (progn + (setq horizontal-info (berechne-horizontale-mitte deltaL deltaH "Ab")) + (if (and horizontal-info (caddr horizontal-info)) + (setq ergebnis-liste + (append ergebnis-liste (list (list 0 (car horizontal-info) (cadr horizontal-info) T)))) + (setq horizontal-info nil) + ) + ) + ) + + (setq gueltige-winkel + (mapcar 'car + (vl-remove-if-not + (function (lambda (e) (and (nth 3 e) (numberp (nth 1 e)) (numberp (nth 2 e)) + (>= (nth 1 e) 0) (>= (nth 2 e) 0)))) + ergebnis-liste))) + + (if (null gueltige-winkel) + (alert (ssg-textf "vfc-alert-kein-winkel" + (list (chr 916) (rtos deltaL 2 0) (rtos deltaH 2 0) richtung))) + (progn + (setq winkelwahl (vfs-dialog-winkel-verteilung gueltige-winkel ergebnis-liste staustrecke-basis winkel-prefill)) + (if (null winkelwahl) + (princ (ssg-text "vfc-vorgang-abgebrochen")) + (progn + (setq best-winkel (nth 0 winkelwahl) + L_GF (nth 1 winkelwahl) + L_VF (nth 2 winkelwahl) + L_GF1 (nth 3 winkelwahl) + L_GF2 (nth 4 winkelwahl) + verteilung-modus (nth 5 winkelwahl)) + (setq n-scanner 0) + (setq hoehe-von (caddr startpunkt)) + (setq hoehe-bis + (cond ((= richtung "Auf") (+ hoehe-von deltaH)) + ((= richtung "Ab") (- hoehe-von deltaH)) + (t hoehe-von))) + (setq lastEnt (vf-lastent-ohne-attribute)) + + (variofoerderer-einfuegen deltaL deltaH richtung best-winkel L_GF1 L_GF2 L_VF startpunkt seite hz) + + (setq vf-insert + (vf-block-erstellen "standard" seite vf-nummer n-scanner + hoehe-von hoehe-bis deltaH deltaL L_VF L_GF1 L_GF2 + richtung best-winkel startpunkt lastEnt hz)) + (if vf-insert (vfs-xdata-schreiben vf-insert hz)) + (princ "\n=========================================") + ) + ) + ) + ) +) + +;; Neuanlage (Menue/Konsole -> Dialog): Startpunkt (X/Y) picken, Basis-Dialog, +;; dann gemeinsame Berechnung/Winkel-Dialog/Einfuegung. +(defun vfs-standard-dialog-ablauf (vf-nummer / eingabe deltaL deltaH richtung + z-start hz seite startpunkt startpunkt-xy) + (setq startpunkt-xy (getpoint (ssg-text "vfc-prompt-startpunkt-aus"))) + (if (null startpunkt-xy) (setq startpunkt-xy '(0 0 0))) + + (setq eingabe (vfs-dialog-eingabe-basis nil)) + (if (null eingabe) + (princ (ssg-text "vfc-vorgang-abgebrochen")) + (progn + (setq deltaL (nth 0 eingabe) + deltaH (nth 1 eingabe) + richtung (nth 2 eingabe) + z-start (nth 3 eingabe) + hz (nth 4 eingabe) + seite (nth 5 eingabe)) + (setq startpunkt (list (car startpunkt-xy) (cadr startpunkt-xy) z-start)) + (vfs-standard-dialog-berechnen-einfuegen vf-nummer deltaL deltaH richtung startpunkt hz seite nil) + ) + ) +) + +;; ============================================================ +;; VARIOFOERDERER_EDIT - Doppelklick/Kontextmenue-Bearbeitung +;; ============================================================ + +;; Bearbeitet einen bestehenden Standard-VarioFoerderer (VF_n-Block, mit +;; SSG_VF_EDIT-XDATA) ueber die DCL-Dialoge: liest die aktuellen Parameter, +;; zeigt sie vorbelegt und baut die Strecke bei OK am selben Startpunkt neu +;; auf. Wird vom Doppelklick-Dispatcher SSG_BLOCKEDIT fuer Blocknamen "VF_*" +;; aufgerufen. Bloecke ohne SSG_VF_EDIT-XDATA (Etage, Linienzug, Altbestand) +;; werden abgewiesen, da ihre Geometrie sich nicht verlustfrei aus dem +;; einfachen Standard-Schema rekonstruieren laesst. +(defun c:VARIOFOERDERER_EDIT ( / ss ent ed bname startpunkt attribs xd + deltaL deltaH richtung z-start hz seite + eingabe vf-nummer best-winkel-attr L_GF_m-teile + prefill-basis prefill-winkel) + ;; 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 "VARIOFOERDERER_EDIT" '(("OSMODE") ("ATTREQ") ("ATTDIA"))) + (setvar "OSMODE" 0) + + (if (null ent) + (progn + (setq ss (ssget ":S" '((0 . "INSERT")))) + (if ss (setq ent (ssname ss 0))) + ) + ) + (if (null ent) (progn (ssg-end) (exit))) + + (setq ed (entget ent)) + (setq bname (cdr (assoc 2 ed))) + (if (not (wcmatch bname "VF_*")) + (progn (alert (ssg-textf "vfs-edit-kein-vf" (list bname))) (ssg-end) (exit))) + + (setq xd (vfs-xdata-lesen ent)) + (if (or (null xd) (/= (car xd) "standard")) + (progn (alert (ssg-textf "vfs-edit-keine-xdata" (list bname))) (ssg-end) (exit))) + + (setq startpunkt (cdr (assoc 10 ed))) + (setq attribs (ssg-attrib-read ent)) + (setq hz (atof (nth 1 xd))) + (setq deltaL (atof (cond ((cdr (assoc "DELTA_L_mm" attribs))) ("15000")))) + (setq deltaH (atof (cond ((cdr (assoc "DELTA_H_mm" attribs))) ("3000")))) + (setq richtung (cond ((cdr (assoc "ANTRIEBFAHRTRICHTUNG" attribs))) ("Auf"))) + (setq seite (cond ((cdr (assoc "SEITE_AS" attribs))) ("rechts"))) + (setq z-start (caddr startpunkt)) + + (setq prefill-basis + (list (cons "deltaL" deltaL) (cons "deltaH" deltaH) (cons "richtung" richtung) + (cons "einfuegehoehe" z-start) (cons "hz" hz) (cons "seite" seite))) + + (setq eingabe (vfs-dialog-eingabe-basis prefill-basis)) + (if (null eingabe) + (princ (ssg-text "vfc-vorgang-abgebrochen")) + (progn + (setq deltaL (nth 0 eingabe) + deltaH (nth 1 eingabe) + richtung (nth 2 eingabe) + z-start (nth 3 eingabe) + hz (nth 4 eingabe) + seite (nth 5 eingabe)) + (setq startpunkt (list (car startpunkt) (cadr startpunkt) z-start)) + + ;; Vorbelegung Winkel/Verteilung: bestehenden Winkel vorschlagen, L_GF- + ;; Verteilung als "Eigene Werte" mit dem aktuellen L_GF1 (aus L_GF_m) - + ;; das ist unabhaengig vom urspruenglichen Verteilungsmodus immer exakt. + (setq best-winkel-attr (atoi (cond ((cdr (assoc "VF_WINKEL" attribs))) ("0")))) + (setq L_GF_m-teile (ssg-cfg-split-comma (cond ((cdr (assoc "L_GF_m" attribs))) ("0.0,0.0")))) + (setq prefill-winkel + (list (cons "winkel" best-winkel-attr) + (cons "verteilung-idx" "3") + (cons "lgf1" (* 1000.0 (atof (car L_GF_m-teile)))))) + + (entdel ent) + (setq vf-nummer (vf-next-number)) + (vfs-standard-dialog-berechnen-einfuegen vf-nummer deltaL deltaH richtung + startpunkt hz seite prefill-winkel) + (princ (ssg-textf "vfs-edit-neu-aufgebaut" (list bname))) + ) + ) + (ssg-end) + (princ) +) + ;; ============================================================ ;; REGISTRIERUNG ;; ============================================================ diff --git a/data/dxf/834372115_symbol.dwg b/data/dxf/834372115_symbol.dwg deleted file mode 100644 index 2f563dd..0000000 Binary files a/data/dxf/834372115_symbol.dwg and /dev/null differ diff --git a/data/ils/3D/AS_Element_30_links.dwg b/data/ils/3D/AS_Element_30_links.dwg index 3dccb8f..72dfcff 100644 Binary files a/data/ils/3D/AS_Element_30_links.dwg and b/data/ils/3D/AS_Element_30_links.dwg differ diff --git a/data/ils/3D/AS_Element_30_rechts.dwg b/data/ils/3D/AS_Element_30_rechts.dwg index b7960d3..63a63e8 100644 Binary files a/data/ils/3D/AS_Element_30_rechts.dwg and b/data/ils/3D/AS_Element_30_rechts.dwg differ diff --git a/dcl/gefaellestrecke.dcl b/dcl/gefaellestrecke.dcl new file mode 100644 index 0000000..e406e6d --- /dev/null +++ b/dcl/gefaellestrecke.dcl @@ -0,0 +1,82 @@ +// ============================================================ +// gefaellestrecke.dcl - Gefaellestrecke Parameter-Eingabe +// Parametrische Eingabe fuer die einfache Gefaellestrecke +// (Modus 1 - Manuell) analog zum Kreisel-Dialog, ergaenzt um +// die Angabe der Einfuegehoehe. +// Eingaben entsprechen dem interaktiven Skript Gefaellestrecke.lsp: +// Abstand deltaL, Gefaellewinkel, Fahrtrichtung, +// Seite AUS-Element, Seite EIN-Element. +// ============================================================ + +gefaellestrecke : dialog { + label = "Gefaellestrecke erstellen"; + + : column { + + : boxed_column { + label = "Geometrie"; + + : row { + : edit_box { + key = "deltal"; + label = "Abstand deltaL (mm):"; + edit_width = 10; + } + : edit_box { + key = "einfuegehoehe"; + label = "Einfuegehoehe (mm):"; + edit_width = 10; + } + } + + : edit_box { + key = "winkel"; + label = "Gefaellewinkel (Grad):"; + edit_width = 10; + } + } + + : boxed_column { + label = "Ausrichtung"; + + : popup_list { + key = "fahrtrichtung"; + label = "Fahrtrichtung:"; + width = 30; + } + } + + : boxed_row { + label = "AUS-Element"; + + : popup_list { + key = "aus_winkel"; + label = "Winkel:"; + width = 12; + } + : popup_list { + key = "aus_seite"; + label = "Seite:"; + width = 14; + } + } + + : boxed_row { + label = "EIN-Element"; + + : popup_list { + key = "ein_winkel"; + label = "Winkel:"; + width = 12; + } + : popup_list { + key = "ein_seite"; + label = "Seite:"; + width = 14; + } + } + + } + + ok_cancel; +} diff --git a/dcl/variofoerderer.dcl b/dcl/variofoerderer.dcl new file mode 100644 index 0000000..86b213f --- /dev/null +++ b/dcl/variofoerderer.dcl @@ -0,0 +1,99 @@ +// ============================================================ +// variofoerderer.dcl - Standard-VarioFoerderer Parameter-Eingabe +// Zwei Dialoge fuer den Standardfall (anlage-typ "standard") von +// c:VarioFoerderer, ersetzen die interaktive Werteingabe (Modus +// "Werteingabe") aus vf-eingabe-abfragen / vf_core.lsp: +// Dialog 1 (variofoerderer_basis): deltaL, deltaH, Foerderrichtung, +// Einfuegehoehe, Fahrtrichtung, Seite. +// Dialog 2 (variofoerderer_winkel): Winkel (dynamisch berechnete +// gueltige Varianten), Verteilung der Gefaellestrecken vorne/hinten. +// Die 3D-Linie-Eingabe (Modus "3D-Linie") und andere Anlagen-Typen +// (Etage, Linienzug) bleiben interaktiv (Kommandozeile). +// ============================================================ + +variofoerderer_basis : dialog { + label = "VarioFoerderer (Standard) - Eingabe"; + + : column { + + : boxed_column { + label = "Geometrie"; + + : row { + : edit_box { + key = "deltal"; + label = "Horizontale Distanz deltaL (mm):"; + edit_width = 10; + } + : edit_box { + key = "deltah"; + label = "Hoehenunterschied deltaH (mm):"; + edit_width = 10; + } + } + + : row { + : popup_list { + key = "richtung"; + label = "Foerderrichtung:"; + width = 16; + } + : edit_box { + key = "einfuegehoehe"; + label = "Einfuegehoehe (mm):"; + edit_width = 10; + } + } + } + + : boxed_column { + label = "Ausrichtung"; + + : popup_list { + key = "fahrtrichtung"; + label = "Fahrtrichtung:"; + width = 30; + } + : popup_list { + key = "seite"; + label = "Seite:"; + width = 16; + } + } + + } + + ok_cancel; +} + +variofoerderer_winkel : dialog { + label = "VarioFoerderer (Standard) - Winkel / Verteilung"; + + : column { + + : popup_list { + key = "winkel"; + label = "Winkel:"; + width = 45; + } + + : boxed_column { + label = "Verteilung Gefaellestrecken (vorne/hinten)"; + + : popup_list { + key = "verteilung"; + label = "Modus:"; + width = 35; + } + : edit_box { + key = "lgf1_manuell"; + label = "L_GF1 vorne (mm):"; + edit_width = 10; + is_enabled = false; + } + } + + } + + ok_cancel; +} diff --git a/lang/de_DE.json b/lang/de_DE.json index 5edfcba..f2d5599 100644 --- a/lang/de_DE.json +++ b/lang/de_DE.json @@ -33,6 +33,69 @@ "vfl-soll-xyz": "\n Soll: X=%1 Y=%2 Z=%3", "vfl-ist-xyz": "\n Ist : X=%1 Y=%2 Z=%3", "vfl-abweichung-xyz": "\n Abweichung: dX=%1 dY=%2 dZ=%3 mm", + "vfl-m3-titel": "\n VF-LINIENZUG - Modus 2: Pfad + Ziel-Hoehe (fertig; Anker + Solver + Bau)", + "vfl-m3-alert-gf-modul": "Gefaellestrecke-Modul nicht geladen!", + "vfl-m3-pfad-waehlen": "\n\nPfad-Objekte waehlen (Linien/Boegen):", + "vfl-m3-keine-objekte": "\nKeine Objekte gewaehlt - Abbruch.", + "vfl-m3-prompt-startpunkt": "\n\nStartpunkt der Kette (hoehere Seite) waehlen: ", + "vfl-prompt-hoehe-startpunkt": "\nHoehe (Z) des Startpunkts [%1]: ", + "vfl-m3-prompt-endpunkt": "\n\nEndpunkt der Kette (Ziel) waehlen: ", + "vfl-m3-prompt-zielhoehe": "\nZiel-Hoehe (Z) des Endpunkts [%1]: ", + "vfl-m3-fehler-nicht-sortierbar": "\nFEHLER: Pfad nicht sortierbar (haengt er lueckenlos zusammen?).", + "vfl-m3-alert-eckwinkel": "Kein passender Bogen: Eck-Winkel %1 Grad ist nicht ~30/60/90.\nBitte die Winkel anpassen.", + "vfl-m3-seg-gerade": "\n\nSegment %1/%2: Gerade L=%3 mm hz=%4", + "vfl-m3-auto-vf": "\n (automatisch VF - Segment folgt direkt auf eine Vario-Kurve)", + "vfl-m3-typ-gerade": "\n Typ? 1 = GF (Eingabe-Winkel) 2 = VF (Bruecke)", + "vfl-m3-prompt-gf-neigung": "\n GF-Neigung in Grad [3]: ", + "vfl-m3-hinweis-gf-max": "\n Hinweis: GF max. 3 Grad - auf 3 begrenzt.", + "vfl-m3-seg-bogen": "\n\nSegment %1/%2: Eck/Bogen %3 Grad %4", + "vfl-m3-typ-bogen": "\n Typ? 1 = GF-Bogen 2 = Vario-Kurve", + "vfl-m3-variante-frage": "\n Vario-Kurve - Variante? 1 = Aussen 2 = Innen", + "vfl-m3-vf-laeufe": "\n\n[M3a] Gefundene VF-Laeufe: %1", + "vfl-m3-vf-lauf-noetig": "\n[M3a] Genau EIN VF-Lauf noetig (GF...VF...GF; Vario-Kurven duerfen im Lauf liegen).", + "vfl-m3-vf-lauf-m3b": "\n[M3a] Mehrere/keine VF-Laeufe -> M3b spaeter.", + "vfl-m3-vf-lauf-ohne-gerade": "\n[M3a] VF-Lauf ohne VF-Gerade - Abbruch.", + "vfl-m3-anker-vorschau-header": "\n M3a ANKER-VORSCHAU (grob geschaetzt; exakte Werte beim Bau)", + "vfl-m3-start-hoehe": "\n Start-Hoehe Z: %1 mm", + "vfl-m3-ziel-hoehe": "\n Ziel-Hoehe Z: %1 mm", + "vfl-m3-delta-h-gesamt": "\n delta-H gesamt: %1 mm (positiv = Abfall)", + "vfl-m3-vf-lauf-segmente": "\n VF-Lauf: Segment %1..%2", + "vfl-m3-front-anker-vorschau": "\n Front-Anker Z: %1 mm (vorwaerts von AS)", + "vfl-m3-junction-anker-vorschau": "\n Junction-Anker Z: %1 mm (rueckwaerts von ES)", + "vfl-m3-richtung-auf": "Auf (steigt)", + "vfl-m3-richtung-ab": "Ab (faellt)", + "vfl-m3-richtung-horizontal": "horizontal", + "vfl-m3-richtung-auf-kurz": "Auf", + "vfl-m3-richtung-ab-kurz": "Ab", + "vfl-m3-bruecke-dh": "\n --> Bruecke: delta-H = %1 mm ueber Spannweite %2 mm", + "vfl-m3-bruecke-richtung": "\n Richtung: VF-%1", + "vfl-m3-vf-angetrieben": "\n (VF ist angetrieben - kann STEIGEN und FALLEN; Vorzeichen = nur Auf/Ab)", + "vfl-m3-mittlere-neigung": "\n grobe mittlere Neigung ueber Spannweite: ~%1 Grad", + "vfl-m3-warnung-zu-steil": "\n WARNUNG: ~Neigung > 51 Grad -> zu steil fuer Vario (Magnitude infeasibel).", + "vfl-m3-vario-bereich-ok": "\n -> innerhalb Vario-Bereich (3..51 Grad), grobe Orientierung.", + "vfl-m3-anker-hinweis": "\n (Anker oben = grobe Vorschau; exakte Werte werden beim Bau GEMESSEN)", + "vfl-m3-phase-b1": "\n\n>>> Phase B1: Front-Lauf (AS + GF) bauen ...", + "vfl-m3-alert-beginnt-bogen": "Kette beginnt mit einem Bogen - bitte erst eine Gerade.", + "vfl-m3-kurve-front-uebersprungen": "\n >>> [M3a] Vario-Kurve im Front-Lauf - uebersprungen.", + "vfl-m3-standard-vario-header": "\n\n --- STANDARD-VARIO (Kletter-Segment) + flache Zone ---", + "vfl-m3-front-anker-gemessen": "\n Front-Anker (gemessen): %1 mm", + "vfl-m3-junction-exakt": "\n Junction (exakt): %1 mm", + "vfl-m3-kletter-info": "\n Kletterhoehe %1 mm | Kletterer %2 | Kurven %3 | kurze VF %4", + "vfl-m3-kein-winkel": "\n KEIN passender Vario-Winkel -> infeasibel (Front bereits gebaut).", + "vfl-m3-gf-verteilung": "\n\n GF-Verteilung: 1 - alles am Einlauf (GF1) 2 - 1/2 GF1 + 1/2 GF2", + "vfl-m3-vert-halb": "1/2 GF1 + 1/2 GF2", + "vfl-m3-vert-ganz": "alles GF1", + "vfl-m3-vario-ergebnis": "\n -> Vario %1 (%2), L_VF %3 mm, GF gesamt %4 mm, Verteilung %5 (GF2-Rest = Mess-Feinkorrektur)", + "vfl-m3-warnung-gf2-negativ": "\n WARNUNG: Koerper klettert zu wenig - GF2<0 (fehlen %1 mm). Winkel zu flach; dZ nicht exakt.", + "vfl-m3-gf2-ausgleich": "\n GF2 (gemessener Ausgleich): L=%1 mm", + "vfl-m3-kurve-back-uebersprungen": "\n >>> [M3a] Vario-Kurve im Back-Lauf - uebersprungen.", + "vfl-m3-nichts-gebaut": "\nNichts gebaut - Abbruch.", + "vfl-m3-fertig-header": "\n>>> VF-Linienzug (Modus 2) gebaut! <<<", + "vfl-m3-ziel-soll": "\n Ziel (Soll): X=%1 Y=%2 Z=%3", + "vfl-m3-es-ist": "\n ES (Ist): X=%1 Y=%2 Z=%3", + "vfl-m3-abweichung": "\n Abweichung: dX=%1 dY=%2 dZ=%3 mm", + "vfl-m3-laengs-quer": "\n Laengs KS_AUS-Achse: %1 mm | Quer zur Achse (soll ~0): %2 mm", + "vfl-m3-achse-hinweis": "\n (dZ=Ziel-Hoehe; Quer zur KS_AUS-Achse ~0 => Endpunkt liegt auf der Achse)", "gf-fehler-block-fehlt": "\n FEHLER: Block '%1' fehlt", "gf-fehler-block-fehlt-ausruf": "\n FEHLER: Block '%1' fehlt!", "gf-fehler-blockdatei-fehlt": "\n FEHLER: Block-Datei nicht gefunden: %1", @@ -298,6 +361,17 @@ "vfc-einfuegen-frage": "\n\nMoechten Sie die Foerderanlage einfuegen?", "vfc-einfuegen-optionen": "\n 1 - Ja, Module einfuegen\n 2 - Nein, abbrechen", "vfc-vorgang-abgebrochen": "\nVorgang abgebrochen.", + "vfs-dlg-richtung-auf": "Auf", + "vfs-dlg-richtung-ab": "Ab", + "vfs-dlg-winkel-horizontal": "Horizontal (GF=%1 mm, VF=%2 mm)", + "vfs-dlg-winkel-option": "%1%2 (GF=%3 mm, VF=%4 mm)", + "vfs-dlg-verteilung-1": "Gleichmaessig (L_GF1 = L_GF2 = L_GF/2)", + "vfs-dlg-verteilung-2": "Vorne Minimum, hinten Rest", + "vfs-dlg-verteilung-3": "Hinten Minimum, vorne Rest", + "vfs-dlg-verteilung-4": "Eigene Werte eingeben", + "vfs-edit-kein-vf": "Block %1 ist keine VarioFoerderer-Strecke.", + "vfs-edit-keine-xdata": "VarioFoerderer %1 wurde nicht mit diesem Dialog erstellt (Etage/Linienzug/Altbestand) und kann hier nicht bearbeitet werden.", + "vfs-edit-neu-aufgebaut": "\nVarioFoerderer %1 neu aufgebaut.", "vfe-alert-bib-nicht-init": "Etage-Bibliothek nicht initialisiert!", "vfe-berechnung-header": "\n ETAGE-BERECHNUNG FUER ALLE WINKEL", "vfe-bib-bereits-init": "\n Etage-Bibliothek bereits initialisiert.", @@ -376,6 +450,11 @@ "cmd-kein-block-ausgewaehlt": "\nKein Block ausgewaehlt.", "cmd-kreisel-bearbeiten": "\nKreisel bearbeiten: %1", "cmd-eckrad-bearbeiten": "\nEckrad bearbeiten: %1", + "cmd-gefaelle-bearbeiten": "\nGefaellestrecke bearbeiten: %1", + "cmd-variofoerderer-bearbeiten": "\nVarioFoerderer bearbeiten: %1", + "gf-edit-kein-gf": "Block %1 ist keine Gefaellestrecke.", + "gf-edit-nur-einfach": "Nur einfache Gefaellestrecken (ohne Bogen) koennen ueber den Dialog bearbeitet werden.\nTYP: %1", + "gf-edit-neu-aufgebaut": "\nGefaellestrecke %1 neu aufgebaut.", "cmd-omniflo-bearbeiten": "\nOmniflo Element bearbeiten: %1", "cmd-attribute-bearbeiten": "\nAttribute bearbeiten: %1", "layer-prompt-ziel-layer": "\nObjekt auf dem Ziel-Layer waehlen: ", @@ -499,6 +578,13 @@ "gf-status-z-hoehe-ks-aus": "\n Z-Hoehe KS_AUS: %1 mm", "gf-status-fertig": "\n>>> Fertig! <<<", "gf-status-abgebrochen": "\nAbgebrochen.", + "gf-alert-dialog-fehlt": "Dialog-Datei nicht gefunden:\n%1", + "gf-dlg-richtung-0": "0%1 (X+, Ost)", + "gf-dlg-richtung-90": "90%1 (Y+, Nord)", + "gf-dlg-richtung-180": "180%1 (X-, West)", + "gf-dlg-richtung-270": "270%1 (Y-, Sued)", + "gf-dlg-links": "Links", + "gf-dlg-rechts": "Rechts", "gf-status-gf-block-erstellt": "\n>>> GF-Block erstellt: %1 (%2)", "gf-status-schritt1-aus": "\n\n1/4: %1 Fahrtrichtung=%2%3 KS_EIN-hz=%4%5 v=%6%7", "gf-status-schritt2-staustrecke": "\n\n2/4: Staustrecke L=%1 mm hz=%2%3 v=%4%5", diff --git a/lang/en_GB.json b/lang/en_GB.json index 482cacd..aba8584 100644 --- a/lang/en_GB.json +++ b/lang/en_GB.json @@ -33,6 +33,69 @@ "vfl-soll-xyz": "\n Target: X=%1 Y=%2 Z=%3", "vfl-ist-xyz": "\n Actual: X=%1 Y=%2 Z=%3", "vfl-abweichung-xyz": "\n Deviation: dX=%1 dY=%2 dZ=%3 mm", + "vfl-m3-titel": "\n VF LINE PATH - Mode 2: path + target height (finished; anchors + solver + build)", + "vfl-m3-alert-gf-modul": "Gefaellestrecke module not loaded!", + "vfl-m3-pfad-waehlen": "\n\nSelect path objects (lines/arcs):", + "vfl-m3-keine-objekte": "\nNo objects selected - aborting.", + "vfl-m3-prompt-startpunkt": "\n\nSelect chain start point (higher side): ", + "vfl-prompt-hoehe-startpunkt": "\nHeight (Z) of the start point [%1]: ", + "vfl-m3-prompt-endpunkt": "\n\nSelect chain end point (target): ", + "vfl-m3-prompt-zielhoehe": "\nTarget height (Z) of the end point [%1]: ", + "vfl-m3-fehler-nicht-sortierbar": "\nERROR: path cannot be sorted (is it connected without gaps?).", + "vfl-m3-alert-eckwinkel": "No matching arc: corner angle %1 deg is not ~30/60/90.\nPlease adjust the angles.", + "vfl-m3-seg-gerade": "\n\nSegment %1/%2: straight L=%3 mm hz=%4", + "vfl-m3-auto-vf": "\n (automatic VF - segment follows directly after a Vario curve)", + "vfl-m3-typ-gerade": "\n Type? 1 = GF (input angle) 2 = VF (bridge)", + "vfl-m3-prompt-gf-neigung": "\n GF slope in degrees [3]: ", + "vfl-m3-hinweis-gf-max": "\n Note: GF max. 3 deg - limited to 3.", + "vfl-m3-seg-bogen": "\n\nSegment %1/%2: corner/arc %3 deg %4", + "vfl-m3-typ-bogen": "\n Type? 1 = GF arc 2 = Vario curve", + "vfl-m3-variante-frage": "\n Vario curve - variant? 1 = Outer 2 = Inner", + "vfl-m3-vf-laeufe": "\n\n[M3a] VF runs found: %1", + "vfl-m3-vf-lauf-noetig": "\n[M3a] Exactly ONE VF run required (GF...VF...GF; Vario curves may lie within the run).", + "vfl-m3-vf-lauf-m3b": "\n[M3a] Several/no VF runs -> M3b later.", + "vfl-m3-vf-lauf-ohne-gerade": "\n[M3a] VF run without a VF straight - aborting.", + "vfl-m3-anker-vorschau-header": "\n M3a ANCHOR PREVIEW (rough estimate; exact values during build)", + "vfl-m3-start-hoehe": "\n Start height Z: %1 mm", + "vfl-m3-ziel-hoehe": "\n Target height Z: %1 mm", + "vfl-m3-delta-h-gesamt": "\n delta-H total: %1 mm (positive = descent)", + "vfl-m3-vf-lauf-segmente": "\n VF run: segment %1..%2", + "vfl-m3-front-anker-vorschau": "\n Front anchor Z: %1 mm (forward from AS)", + "vfl-m3-junction-anker-vorschau": "\n Junction anchor Z: %1 mm (backward from ES)", + "vfl-m3-richtung-auf": "up (rising)", + "vfl-m3-richtung-ab": "down (falling)", + "vfl-m3-richtung-horizontal": "horizontal", + "vfl-m3-richtung-auf-kurz": "Up", + "vfl-m3-richtung-ab-kurz": "Down", + "vfl-m3-bruecke-dh": "\n --> Bridge: delta-H = %1 mm over span %2 mm", + "vfl-m3-bruecke-richtung": "\n Direction: VF-%1", + "vfl-m3-vf-angetrieben": "\n (VF is powered - can RISE and FALL; sign = up/down only)", + "vfl-m3-mittlere-neigung": "\n rough mean slope over span: ~%1 deg", + "vfl-m3-warnung-zu-steil": "\n WARNING: ~slope > 51 deg -> too steep for Vario (magnitude infeasible).", + "vfl-m3-vario-bereich-ok": "\n -> within Vario range (3..51 deg), rough orientation.", + "vfl-m3-anker-hinweis": "\n (anchors above = rough preview; exact values are MEASURED during build)", + "vfl-m3-phase-b1": "\n\n>>> Phase B1: building front run (AS + GF) ...", + "vfl-m3-alert-beginnt-bogen": "Chain starts with an arc - please begin with a straight.", + "vfl-m3-kurve-front-uebersprungen": "\n >>> [M3a] Vario curve in front run - skipped.", + "vfl-m3-standard-vario-header": "\n\n --- STANDARD VARIO (climbing segment) + flat zone ---", + "vfl-m3-front-anker-gemessen": "\n Front anchor (measured): %1 mm", + "vfl-m3-junction-exakt": "\n Junction (exact): %1 mm", + "vfl-m3-kletter-info": "\n Climb height %1 mm | climbers %2 | curves %3 | short VF %4", + "vfl-m3-kein-winkel": "\n NO matching Vario angle -> infeasible (front already built).", + "vfl-m3-gf-verteilung": "\n\n GF distribution: 1 - all at inlet (GF1) 2 - 1/2 GF1 + 1/2 GF2", + "vfl-m3-vert-halb": "1/2 GF1 + 1/2 GF2", + "vfl-m3-vert-ganz": "all GF1", + "vfl-m3-vario-ergebnis": "\n -> Vario %1 (%2), L_VF %3 mm, GF total %4 mm, distribution %5 (GF2 remainder = measured fine correction)", + "vfl-m3-warnung-gf2-negativ": "\n WARNING: body climbs too little - GF2<0 (missing %1 mm). Angle too shallow; dZ not exact.", + "vfl-m3-gf2-ausgleich": "\n GF2 (measured compensation): L=%1 mm", + "vfl-m3-kurve-back-uebersprungen": "\n >>> [M3a] Vario curve in back run - skipped.", + "vfl-m3-nichts-gebaut": "\nNothing built - aborting.", + "vfl-m3-fertig-header": "\n>>> VF line path (mode 2) built! <<<", + "vfl-m3-ziel-soll": "\n Target (nominal): X=%1 Y=%2 Z=%3", + "vfl-m3-es-ist": "\n ES (actual): X=%1 Y=%2 Z=%3", + "vfl-m3-abweichung": "\n Deviation: dX=%1 dY=%2 dZ=%3 mm", + "vfl-m3-laengs-quer": "\n Along KS_AUS axis: %1 mm | across axis (should be ~0): %2 mm", + "vfl-m3-achse-hinweis": "\n (dZ=target height; across KS_AUS axis ~0 => end point lies on the axis)", "gf-fehler-block-fehlt": "\n ERROR: block '%1' missing", "gf-fehler-block-fehlt-ausruf": "\n ERROR: block '%1' missing!", "gf-fehler-blockdatei-fehlt": "\n ERROR: block file not found: %1", @@ -298,6 +361,17 @@ "vfc-einfuegen-frage": "\n\nDo you want to insert the conveyor system?", "vfc-einfuegen-optionen": "\n 1 - Yes, insert modules\n 2 - No, cancel", "vfc-vorgang-abgebrochen": "\nProcess cancelled.", + "vfs-dlg-richtung-auf": "Up", + "vfs-dlg-richtung-ab": "Down", + "vfs-dlg-winkel-horizontal": "Horizontal (GF=%1 mm, VF=%2 mm)", + "vfs-dlg-winkel-option": "%1%2 (GF=%3 mm, VF=%4 mm)", + "vfs-dlg-verteilung-1": "Even (L_GF1 = L_GF2 = L_GF/2)", + "vfs-dlg-verteilung-2": "Front minimum, rear remainder", + "vfs-dlg-verteilung-3": "Rear minimum, front remainder", + "vfs-dlg-verteilung-4": "Enter custom values", + "vfs-edit-kein-vf": "Block %1 is not a VarioFoerderer conveyor.", + "vfs-edit-keine-xdata": "VarioFoerderer %1 was not created with this dialog (Etage/Linienzug/legacy) and cannot be edited here.", + "vfs-edit-neu-aufgebaut": "\nVarioFoerderer %1 rebuilt.", "vfe-alert-bib-nicht-init": "Etage library not initialised!", "vfe-berechnung-header": "\n ETAGE CALCULATION FOR ALL ANGLES", "vfe-bib-bereits-init": "\n Etage library already initialised.", @@ -376,6 +450,11 @@ "cmd-kein-block-ausgewaehlt": "\nNo block selected.", "cmd-kreisel-bearbeiten": "\nEdit Kreisel: %1", "cmd-eckrad-bearbeiten": "\nEdit Eckrad: %1", + "cmd-gefaelle-bearbeiten": "\nEdit Gefaellestrecke: %1", + "cmd-variofoerderer-bearbeiten": "\nEdit VarioFoerderer: %1", + "gf-edit-kein-gf": "Block %1 is not a Gefaellestrecke.", + "gf-edit-nur-einfach": "Only simple Gefaellestrecken (without arcs) can be edited via the dialog.\nTYP: %1", + "gf-edit-neu-aufgebaut": "\nGefaellestrecke %1 rebuilt.", "cmd-omniflo-bearbeiten": "\nEdit Omniflo element: %1", "cmd-attribute-bearbeiten": "\nEdit attributes: %1", "layer-prompt-ziel-layer": "\nSelect object on the target layer: ", @@ -499,6 +578,13 @@ "gf-status-z-hoehe-ks-aus": "\n Z height KS_AUS: %1 mm", "gf-status-fertig": "\n>>> Done! <<<", "gf-status-abgebrochen": "\nCancelled.", + "gf-alert-dialog-fehlt": "Dialog file not found:\n%1", + "gf-dlg-richtung-0": "0%1 (X+, East)", + "gf-dlg-richtung-90": "90%1 (Y+, North)", + "gf-dlg-richtung-180": "180%1 (X-, West)", + "gf-dlg-richtung-270": "270%1 (Y-, South)", + "gf-dlg-links": "Left", + "gf-dlg-rechts": "Right", "gf-status-gf-block-erstellt": "\n>>> GF block created: %1 (%2)", "gf-status-schritt1-aus": "\n\n1/4: %1 travel dir=%2%3 KS_EIN-hz=%4%5 v=%6%7", "gf-status-schritt2-staustrecke": "\n\n2/4: Buffer section L=%1 mm hz=%2%3 v=%4%5", diff --git a/lib/export_csv.py b/lib/export_csv.py index e416c54..4865dce 100644 --- a/lib/export_csv.py +++ b/lib/export_csv.py @@ -214,7 +214,7 @@ def build_kreisel_merkmale(block): "Höhe in m": hoehe_m, "Drehrichtung": attribs.get("DREHRICHTUNG", "UZS"), "Drehung": block.get("rotation", 0.0), - "Name": attribs.get("NAME", ""), + "Name": attribs.get("Bezeichnung", ""), } diff --git a/lib/export_sivas.py b/lib/export_sivas.py index 288fbc4..b01fefc 100644 --- a/lib/export_sivas.py +++ b/lib/export_sivas.py @@ -4,7 +4,12 @@ export_sivas.py - Erzeugt Sivas-Export-CSV mit gruppierten Zeilen und Summierungszeilen. Neues CSV-Format: - Nr;TeileArt;SivasNummer;Dispogruppe;Anzahl;Laenge[mm];Hoehe[m];details + Nr;TeileArt;SivasNummer;Bezeichnung;Dispogruppe;Anzahl;Laenge[mm];Hoehe[m];details + + - Bezeichnung: Wert des Attributs "Bezeichnung" (Kreisel/Eckrad/VF/GF/Strecke). + Bei gruppierten Zeilen (mehrere Bloecke je Zeile) kommasepariert. + Bei Omniflo-Zeilen (Bogen/Weiche/Gerade) und der Automation-Summenzeile + bleibt das Feld leer, da es sich um Sammlungen gleichartiger Objekte handelt. - Omniflo Bogen/Weiche: gruppiert nach SivasNummer, Anzahl summiert - Omniflo Gerade: gruppiert nach ARTINR-Attribut, Laenge[mm] summiert @@ -271,7 +276,9 @@ def process_blocks(blocks, lookup): gerade_groups = {} kreisel_list = [] # Liste von blocks eckrad_ids = [] # IDs aller Eckrad-Bloecke + eckrad_bezeichnungen = [] # Bezeichnung-Attribut aller Eckrad-Bloecke strecke_ids = [] # IDs loser Strecke-Elemente (Vario/Staustrecke ausserhalb VF_N) + strecke_bezeichnungen = [] # Bezeichnung-Attribut loser Strecke-Elemente vario_list = [] # Liste von VarioFoerderer-Compound-Bloecken (VF_N), je einer Zeile gefaelle_list = [] # Liste von Gefaellestrecke-Bloecken (GF_*), je einer Zeile @@ -372,6 +379,7 @@ def process_blocks(blocks, lookup): if matches_any(bname, BLOCKPATTERNS.get("pattern_eckrad", [])): counters["anzahl_eckraeder"] += 1 eckrad_ids.append(get_id(block)) + eckrad_bezeichnungen.append(block.get("attribs", {}).get("Bezeichnung", "")) continue # --- ILS Kreisel --- @@ -443,6 +451,7 @@ def process_blocks(blocks, lookup): if matches_any(bname, BLOCKPATTERNS.get("pattern_strecke_module", [])): counters["anzahl_variofoerderer"] += 1 strecke_ids.append(get_id(block)) + strecke_bezeichnungen.append(block.get("attribs", {}).get("Bezeichnung", "")) # --- Zeilen aufbauen --- items = [] @@ -454,6 +463,7 @@ def process_blocks(blocks, lookup): "teileart": "Omniflo Bogen", "sivasnr": sivasnr, "sivasnr_quoted": False, + "bezeichnung": "", "dispgruppe": 10, "anzahl": g["anzahl"], "laenge_mm": "", @@ -468,6 +478,7 @@ def process_blocks(blocks, lookup): "teileart": "Omniflo Weiche", "sivasnr": sivasnr, "sivasnr_quoted": False, + "bezeichnung": "", "dispgruppe": 10, "anzahl": g["anzahl"], "laenge_mm": "", @@ -482,6 +493,7 @@ def process_blocks(blocks, lookup): "teileart": "Omniflo Gerade", "sivasnr": g["artinr"], "sivasnr_quoted": True, + "bezeichnung": "", "dispgruppe": 10, "anzahl": g["anzahl"], "laenge_mm": int(g["laenge_mm"]), @@ -499,6 +511,7 @@ def process_blocks(blocks, lookup): "teileart": teileart, "sivasnr": sivasnr, "sivasnr_quoted": True, + "bezeichnung": block.get("attribs", {}).get("Bezeichnung", ""), "dispgruppe": 20, "anzahl": 1, "laenge_mm": "", @@ -514,6 +527,7 @@ def process_blocks(blocks, lookup): "teileart": teileart, "sivasnr": sivasnr, "sivasnr_quoted": True, + "bezeichnung": ", ".join(b for b in eckrad_bezeichnungen if b), "dispgruppe": 20, "anzahl": counters["anzahl_eckraeder"], "laenge_mm": "", @@ -532,6 +546,7 @@ def process_blocks(blocks, lookup): "teileart": teileart, "sivasnr": sivasnr, "sivasnr_quoted": True, + "bezeichnung": ", ".join(b for b in strecke_bezeichnungen if b), "dispgruppe": 20, "anzahl": len(strecke_ids), "laenge_mm": "", @@ -549,6 +564,7 @@ def process_blocks(blocks, lookup): "teileart": teileart, "sivasnr": sivasnr, "sivasnr_quoted": True, + "bezeichnung": block.get("attribs", {}).get("Bezeichnung", ""), "dispgruppe": 20, "anzahl": 1, "laenge_mm": "", @@ -578,6 +594,7 @@ def process_blocks(blocks, lookup): "teileart": teileart, "sivasnr": sivasnr, "sivasnr_quoted": True, + "bezeichnung": ", ".join(b for b in group["bezeichnungen"] if b), "dispgruppe": 20, "anzahl": len(group["ids"]), "laenge_mm": "", @@ -620,6 +637,7 @@ def process_blocks(blocks, lookup): "teileart": auto_teileart, "sivasnr": auto_sivasnr, "sivasnr_quoted": True, + "bezeichnung": "", "dispgruppe": 20, "anzahl": 1, "laenge_mm": "", @@ -638,6 +656,7 @@ def format_csv_line(item): f'{item["nr"]}' f';"{item["teileart"]}"' f';{sivasnr}' + f';"{item["bezeichnung"]}"' f';{item["dispgruppe"]}' f';{item["anzahl"]}' f';{item["laenge_mm"]}' @@ -669,7 +688,7 @@ def main(): items, _ = process_blocks(blocks, lookup) - header = "Nr;TeileArt;SivasNummer;Dispogruppe;Anzahl;Laenge[mm];Hoehe[m];details" + header = "Nr;TeileArt;SivasNummer;Bezeichnung;Dispogruppe;Anzahl;Laenge[mm];Hoehe[m];details" with open(output_csv, "w", encoding="utf-8") as f: f.write(header + "\n") for item in items: diff --git a/menu/SSG_LIB.mnu b/menu/SSG_LIB.mnu index 95eed41..e2810ce 100644 --- a/menu/SSG_LIB.mnu +++ b/menu/SSG_LIB.mnu @@ -10,7 +10,10 @@ [<-Eckrad]^C^C(ssg-ensure "KreiselInsert") ILS_Eckrad [->Zusatzmodul] [~BTMT-Beladung]^C^C(ssg-ensure "SSG_LIB_Commands") ILS_BTMT_Beladung -[<-~BTMT-Entladung]^C^C(ssg-ensure "SSG_LIB_Commands") ILS_BTMT_Entladung +[~BTMT-Entladung]^C^C(ssg-ensure "SSG_LIB_Commands") ILS_BTMT_Entladung +[--] +[Scanner einfuegen]^C^C(ssg-ensure "SSG_LIB_Commands") ILS_SCANNER_INSERT +[<-Separator einfuegen]^C^C(ssg-ensure "SSG_LIB_Commands") ILS_SEPARATOR_INSERT [->Foerderer] [~Durch TEF angetriebene Strecke]^C^C(ssg-ensure "SSG_LIB_Commands") ILS_TEF_Strecke [VarioFoerderer]^C^CVarioFoerderer @@ -121,7 +124,7 @@ [<-~APBW 110 R550/67,5 58x497]^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R550_675_58 [<-Element bearbeiten]^C^C(ssg-ensure "OmniModulInsert") OMNI_EDIT [->Export] -[Export Sivas]^C^C(ssg-ensure "export") EXPORTSIVAS +[Export Sivas]^C^C(ssg-ensure "count_sep_scan") ZAEHLE_SEP_SCAN (ssg-ensure "export") EXPORTSIVAS [<-Export CSV]^C^C(ssg-ensure "export") EXPORTCSV [->Konfiguration] [Umschalten 2D und 3D]^C^C(ssg-ensure "SSG_LIB_Commands") SSG_DIM_SWITCH @@ -149,5 +152,7 @@ [SSG_LIB Edit Context] [Kreisel bearbeiten](ssg-ensure "KreiselInsert") KreiselEdit [Omniflo Element bearbeiten](ssg-ensure "OmniModulInsert") OMNI_EDIT +[Gefaellestrecke bearbeiten](ssg-ensure "Gefaellestrecke") GEFAELLESTRECKE_EDIT +[VarioFoerderer bearbeiten](ssg-ensure "VarioFoerderer") VARIOFOERDERER_EDIT [--] [SSG Bearbeiten (Auto)](ssg-ensure "SSG_LIB_Commands") SSG_BLOCKEDIT diff --git a/tests/reference/kreisel_results.json b/tests/reference/kreisel_results.json index 0b5ada1..e32a8c7 100644 --- a/tests/reference/kreisel_results.json +++ b/tests/reference/kreisel_results.json @@ -6,7 +6,7 @@ "block_handle": "11A", "insert_point": [500, 500, 2500], "actual_attributes": { - "NAME": "Kreisel1", + "Bezeichnung": "Kreisel1", "DREHRICHTUNG": "UZS", "N_SEPARATOREN": "2", "KREISELART": "STANDARD", @@ -27,7 +27,7 @@ "block_handle": "14A", "insert_point": [-500, 500, 2500], "actual_attributes": { - "NAME": "Kreisel2", + "Bezeichnung": "Kreisel2", "DREHRICHTUNG": "UZS", "N_SEPARATOREN": "2", "KREISELART": "STANDARD", @@ -48,7 +48,7 @@ "block_handle": "17A", "insert_point": [-500, -500, 2500], "actual_attributes": { - "NAME": "Kreisel3", + "Bezeichnung": "Kreisel3", "DREHRICHTUNG": "UZS", "N_SEPARATOREN": "2", "KREISELART": "STANDARD", @@ -69,7 +69,7 @@ "block_handle": "1AA", "insert_point": [500, -500, 2500], "actual_attributes": { - "NAME": "Kreisel4", + "Bezeichnung": "Kreisel4", "DREHRICHTUNG": "UZS", "N_SEPARATOREN": "2", "KREISELART": "STANDARD", @@ -90,7 +90,7 @@ "block_handle": "1DA", "insert_point": [3000, 3000, 3000], "actual_attributes": { - "NAME": "Kreisel5", + "Bezeichnung": "Kreisel5", "DREHRICHTUNG": "UZS", "N_SEPARATOREN": "2", "KREISELART": "STANDARD", @@ -111,7 +111,7 @@ "block_handle": "20F", "insert_point": [500, 6000, 1500], "actual_attributes": { - "NAME": "Kreisel6", + "Bezeichnung": "Kreisel6", "DREHRICHTUNG": "UZS", "N_SEPARATOREN": "2", "KREISELART": "PIN", @@ -132,7 +132,7 @@ "block_handle": "243", "insert_point": [-500, 6500, 1500], "actual_attributes": { - "NAME": "Kreisel7", + "Bezeichnung": "Kreisel7", "DREHRICHTUNG": "UZS", "N_SEPARATOREN": "2", "KREISELART": "PIN", @@ -153,7 +153,7 @@ "block_handle": "277", "insert_point": [3000, 8000, 1500], "actual_attributes": { - "NAME": "Kreisel8", + "Bezeichnung": "Kreisel8", "DREHRICHTUNG": "UZS", "N_SEPARATOREN": "2", "KREISELART": "PIN", diff --git a/tests/test_foerderer.py b/tests/test_foerderer.py index 29a28de..7515323 100644 --- a/tests/test_foerderer.py +++ b/tests/test_foerderer.py @@ -289,7 +289,7 @@ class TestFoerdererExportSivas: def test_header_felder(self): """Sivas-CSV-Header muss korrekte Spalten haben.""" - expected = ["Nr", "TeileArt", "SivasNummer", + expected = ["Nr", "TeileArt", "SivasNummer", "Bezeichnung", "Dispogruppe", "Anzahl", "Laenge[mm]", "Hoehe[m]", "details"] for i, name in enumerate(expected): assert self.header[i] == name, ( @@ -317,10 +317,10 @@ class TestFoerdererExportSivas: def test_details_sind_valides_json(self): """details-Spalte muss valides JSON enthalten.""" for i, row in enumerate(self.rows): - if len(row) < 8: + if len(row) < 9: continue try: - json.loads(row[7]) + json.loads(row[8]) except json.JSONDecodeError as e: pytest.fail(f"Zeile {i + 2}: details ist kein valides JSON: {e}") @@ -330,10 +330,10 @@ class TestFoerdererExportSivas: "Laengen aller Variofoerderer", "Anzahl aller Separatoren"} for row in self.rows: - if len(row) < 8: + if len(row) < 9: continue if row[1].strip('"') == "ILS 2.0 Automation und Pneumatik - Gesamtanlage": - details = json.loads(row[7]) + details = json.loads(row[8]) missing = required - set(details.keys()) assert not missing, ( f"Automation-details: fehlende Felder: {missing}" diff --git a/tests/test_gefaellestrecke.lsp b/tests/test_gefaellestrecke.lsp index 7818e6b..d0dc5fc 100644 --- a/tests/test_gefaellestrecke.lsp +++ b/tests/test_gefaellestrecke.lsp @@ -25,8 +25,12 @@ ;; --- Ergebnis eines Testfalls als JSON-String erzeugen --- -(defun gefaellestrecke:test-json (test-id modus hz deltaL winkel h-von h-bis d-h status / +;; as-winkel/es-winkel: "30" oder "90" (Element-Variante); default "90" +(defun gefaellestrecke:test-json (test-id modus hz deltaL winkel h-von h-bis d-h status + as-winkel es-winkel / json) + (if (null as-winkel) (setq as-winkel "90")) + (if (null es-winkel) (setq es-winkel "90")) (setq json (strcat " {\n" " \"test_id\": \"" test-id "\",\n" @@ -34,6 +38,8 @@ " \"hz_grad\": " (rtos (float hz) 2 1) ",\n" " \"deltaL_mm\": " (rtos (float deltaL) 2 0) ",\n" " \"winkel_grad\": " (rtos (float winkel) 2 3) ",\n" + " \"as_winkel\": \"" as-winkel "\",\n" + " \"es_winkel\": \"" es-winkel "\",\n" " \"hoehe_von_mm\": " (rtos (float h-von) 2 0) ",\n" " \"hoehe_bis_mm\": " (rtos (float h-bis) 2 0) ",\n" " \"delta_h_mm\": " (rtos (float d-h) 2 0) ",\n" @@ -296,6 +302,7 @@ m2-start m2-deltaH m2-deltaL m3-start m3-end m3-line-vla m3b-start m3b-end m3b-e1 m3b-e2 m3b-e3 m3b-objliste + w30-rad w30-sepx w30-lstau lbl-layer lbl-h lbl-h2) ;; Block-Bibliothek initialisieren (setzt aus-dx, ein-dx, aus-dz, ein-dz usw.) @@ -376,7 +383,7 @@ (setq gf-ins (car (gefaellestrecke-einfuegen test-L_stau test-winkel (list 0 0 test-z-start) - "links" "links" 0.0 test-deltaL))) + "links" "links" 0.0 test-deltaL "90" "90"))) (if gf-ins (progn (setq attribs (ssg-attrib-read gf-ins)) @@ -388,13 +395,13 @@ " dH=" (itoa d-h) " mm W=" w-str " OK")) (setq results-list (cons (gefaellestrecke:test-json "M1_hz000" 1 0.0 test-deltaL - (atof w-str) h-von h-bis d-h "GEBAUT") + (atof w-str) h-von h-bis d-h "GEBAUT" "90" "90") results-list))) (progn (princ " FEHLER") (setq results-list (cons (gefaellestrecke:test-json "M1_hz000" 1 0.0 test-deltaL - 0.0 0 0 0 "FEHLER") + 0.0 0 0 0 "FEHLER" "90" "90") results-list)))) ;; --- M1: hz=90 Grad (Nord), Start (15000, 0, 5000) --- @@ -408,7 +415,7 @@ (setq gf-ins (car (gefaellestrecke-einfuegen test-L_stau test-winkel (list 15000 0 test-z-start) - "links" "links" 90.0 test-deltaL))) + "links" "links" 90.0 test-deltaL "90" "90"))) (if gf-ins (progn (setq attribs (ssg-attrib-read gf-ins)) @@ -420,13 +427,13 @@ " dH=" (itoa d-h) " mm W=" w-str " OK")) (setq results-list (cons (gefaellestrecke:test-json "M1_hz090" 1 90.0 test-deltaL - (atof w-str) h-von h-bis d-h "GEBAUT") + (atof w-str) h-von h-bis d-h "GEBAUT" "90" "90") results-list))) (progn (princ " FEHLER") (setq results-list (cons (gefaellestrecke:test-json "M1_hz090" 1 90.0 test-deltaL - 0.0 0 0 0 "FEHLER") + 0.0 0 0 0 "FEHLER" "90" "90") results-list)))) ;; --- M1: hz=180 Grad (West), Start (0, -15000, 5000) --- @@ -440,7 +447,7 @@ (setq gf-ins (car (gefaellestrecke-einfuegen test-L_stau test-winkel (list 0 -15000 test-z-start) - "links" "links" 180.0 test-deltaL))) + "links" "links" 180.0 test-deltaL "90" "90"))) (if gf-ins (progn (setq attribs (ssg-attrib-read gf-ins)) @@ -452,13 +459,13 @@ " dH=" (itoa d-h) " mm W=" w-str " OK")) (setq results-list (cons (gefaellestrecke:test-json "M1_hz180" 1 180.0 test-deltaL - (atof w-str) h-von h-bis d-h "GEBAUT") + (atof w-str) h-von h-bis d-h "GEBAUT" "90" "90") results-list))) (progn (princ " FEHLER") (setq results-list (cons (gefaellestrecke:test-json "M1_hz180" 1 180.0 test-deltaL - 0.0 0 0 0 "FEHLER") + 0.0 0 0 0 "FEHLER" "90" "90") results-list)))) ;; --- M1: hz=270 Grad (Sued), Start (15000, -15000, 5000) --- @@ -472,7 +479,7 @@ (setq gf-ins (car (gefaellestrecke-einfuegen test-L_stau test-winkel (list 15000 -15000 test-z-start) - "links" "links" 270.0 test-deltaL))) + "links" "links" 270.0 test-deltaL "90" "90"))) (if gf-ins (progn (setq attribs (ssg-attrib-read gf-ins)) @@ -484,13 +491,13 @@ " dH=" (itoa d-h) " mm W=" w-str " OK")) (setq results-list (cons (gefaellestrecke:test-json "M1_hz270" 1 270.0 test-deltaL - (atof w-str) h-von h-bis d-h "GEBAUT") + (atof w-str) h-von h-bis d-h "GEBAUT" "90" "90") results-list))) (progn (princ " FEHLER") (setq results-list (cons (gefaellestrecke:test-json "M1_hz270" 1 270.0 test-deltaL - 0.0 0 0 0 "FEHLER") + 0.0 0 0 0 "FEHLER" "90" "90") results-list)))) ;; ============================================================ @@ -522,7 +529,7 @@ (princ (strcat "\n\n M2_hz000: Start=(0,-35000," (rtos test-z-start 2 0) ") ...")) (setq ergebnis (gefaellestrecke-einfuegen - test-L_stau test-winkel m2-start "links" "links" 0.0 test-deltaL)) + test-L_stau test-winkel m2-start "links" "links" 0.0 test-deltaL "90" "90")) (setq gf-ins (car ergebnis)) (if gf-ins (progn @@ -541,7 +548,7 @@ " mm W=" w-str " OK")) (setq results-list (cons (gefaellestrecke:test-json "M2_hz000" 2 0.0 test-deltaL - (atof w-str) h-von h-bis m2-deltaH "GEBAUT") + (atof w-str) h-von h-bis m2-deltaH "GEBAUT" "90" "90") results-list))) (progn ;; Fallback: sin(3deg) * 10000 ≈ 523mm @@ -550,7 +557,7 @@ (princ (strcat " FEHLER (Fallback " delta-sym "H=" (rtos m2-deltaH 2 3) ")")) (setq results-list (cons (gefaellestrecke:test-json "M2_hz000" 2 0.0 test-deltaL - 0.0 0 0 0 "FEHLER") + 0.0 0 0 0 "FEHLER" "90" "90") results-list)))) ;; ============================================================ @@ -618,20 +625,20 @@ " W=" w-str " OK")) (setq results-list (cons (gefaellestrecke:test-json "M3_hz270" 3 270.0 test-deltaL - (atof w-str) h-von h-bis d-h "GEBAUT") + (atof w-str) h-von h-bis d-h "GEBAUT" "90" "90") results-list))) (progn (princ "\n -> FEHLER (modus3-einfuegen)") (setq results-list (cons (gefaellestrecke:test-json "M3_hz270" 3 270.0 test-deltaL - 0.0 0 0 0 "FEHLER") + 0.0 0 0 0 "FEHLER" "90" "90") results-list))))) ;; 3D-Linie konnte nicht erzeugt werden (progn (princ "\n FEHLER: 3D-Linie nicht erzeugbar!") (setq results-list (cons (gefaellestrecke:test-json "M3_hz270" 3 270.0 test-deltaL - 0.0 0 0 0 "FEHLER_LINIE") + 0.0 0 0 0 "FEHLER_LINIE" "90" "90") results-list)))) ;; ============================================================ @@ -688,15 +695,71 @@ " " delta-sym "H-Soll=200 mm W=" w-str " OK")) (setq results-list (cons (gefaellestrecke:test-json "M3_Bogen" 3 0.0 14785.0 - (atof w-str) h-von h-bis d-h "GEBAUT") + (atof w-str) h-von h-bis d-h "GEBAUT" "90" "90") results-list))) (progn (princ "\n -> FEHLER (modus3-einfuegen mit Bogen)") (setq results-list (cons (gefaellestrecke:test-json "M3_Bogen" 3 0.0 14785.0 - 0.0 0 0 0 "FEHLER") + 0.0 0 0 0 "FEHLER" "90" "90") results-list)))) + ;; ============================================================ + ;; MODUS 1 - 30-Grad AUS-/EIN-Elemente (statt 90 Grad) + ;; Prueft die per DCL-Dialog waehlbare Element-Variante 30 Grad. + ;; hz=0, Start (30000, 0, 5000). Eigene L_stau-Berechnung, da die + ;; 30-Grad-Elemente andere aus-dx/ein-dx-Masse besitzen. + ;; ============================================================ + (princ "\n\n================================================================") + (princ "\n MODUS 1 - 30-Grad Elemente (M1_w30)") + (princ "\n================================================================") + + (entmake (list '(0 . "TEXT") + (cons 10 (list 30000 1200.0 test-z-start)) + (cons 11 (list 30000 1200.0 test-z-start)) + (cons 40 lbl-h) + (cons 1 (strcat "M1 | hz=0" grad-zeichen " | AS/ES=30" grad-zeichen + " | " delta-sym "L=10000 | W=3" grad-zeichen)) + '(7 . "Standard") (cons 8 lbl-layer) '(72 . 1) '(73 . 2))) + + ;; 30-Grad-Element-Masse setzen und L_stau dafuer berechnen + (vf-set-as-masse "30" "links") + (vf-set-es-masse "30" "links") + (setq w30-rad (* test-winkel (/ pi 180.0))) + (setq w30-sepx (* 300.0 (cos w30-rad))) + (setq w30-lstau + (/ (- test-deltaL (float aus-dx) (float ein-dx) w30-sepx) (cos w30-rad))) + (princ (strcat "\n\n M1_w30: AS/ES=30 Grad, aus-dx=" (rtos (float aus-dx) 2 1) + " ein-dx=" (rtos (float ein-dx) 2 1) + " L_stau=" (rtos w30-lstau 2 1) " ...")) + (setq gf-ins + (car (gefaellestrecke-einfuegen + w30-lstau test-winkel (list 30000 0 test-z-start) + "links" "links" 0.0 test-deltaL "30" "30"))) + (if gf-ins + (progn + (setq attribs (ssg-attrib-read gf-ins)) + (setq h-von (atoi (cdr (assoc "HOEHE_VON_mm" attribs)))) + (setq h-bis (atoi (cdr (assoc "HOEHE_BIS_mm" attribs)))) + (setq d-h (abs (- h-von h-bis))) + (setq w-str (cdr (assoc "GF_WINKEL" attribs))) + (princ (strcat " von=" (itoa h-von) " bis=" (itoa h-bis) + " dH=" (itoa d-h) " mm W=" w-str " OK")) + (setq results-list + (cons (gefaellestrecke:test-json "M1_w30" 1 0.0 test-deltaL + (atof w-str) h-von h-bis d-h "GEBAUT" "30" "30") + results-list))) + (progn + (princ " FEHLER") + (setq results-list + (cons (gefaellestrecke:test-json "M1_w30" 1 0.0 test-deltaL + 0.0 0 0 0 "FEHLER" "30" "30") + results-list)))) + + ;; Element-Masse wieder auf 90 Grad zuruecksetzen (fuer Folgelaeufe) + (vf-set-as-masse "90" "links") + (vf-set-es-masse "90" "links") + ;; ============================================================ ;; Zusammenfassung und Export ;; ============================================================ diff --git a/tests/test_gefaellestrecke.py b/tests/test_gefaellestrecke.py index b2357b6..59fb4d5 100644 --- a/tests/test_gefaellestrecke.py +++ b/tests/test_gefaellestrecke.py @@ -82,14 +82,30 @@ class TestGefaellestreckeStatus: ) def test_alle_modus1_gebaut(self): - """Alle vier Modus-1-Richtungen (hz=0/90/180/270) muessen GEBAUT sein.""" + """Alle Modus-1-Testfaelle (Richtungs-Sweep + 30-Grad-Variante) muessen GEBAUT sein.""" + erwartet = [t["test_id"] for t in self.tests if t["modus"] == 1] modus1 = [r for r in self.results if r["modus"] == 1] - assert len(modus1) == 4, f"Erwartet 4 Modus-1-Testfaelle, gefunden {len(modus1)}" + assert len(modus1) == len(erwartet), ( + f"Erwartet {len(erwartet)} Modus-1-Testfaelle, gefunden {len(modus1)}" + ) for r in modus1: assert r["status"] == "GEBAUT", ( f'{r["test_id"]}: erwartet GEBAUT, ist "{r["status"]}"' ) + def test_modus1_30grad_gebaut(self): + """Die per Dialog waehlbare 30-Grad-Element-Variante (M1_w30) muss GEBAUT sein.""" + r = self.results_by_id.get("M1_w30") + if r is None: + pytest.skip("M1_w30 nicht in Ergebnissen (aeltere Testdaten?)") + assert r["status"] == "GEBAUT", ( + f'M1_w30: erwartet GEBAUT, ist "{r["status"]}"' + ) + assert r.get("as_winkel") == "30" and r.get("es_winkel") == "30", ( + f'M1_w30: Element-Winkel sollten 30 sein, sind ' + f'AS={r.get("as_winkel")} ES={r.get("es_winkel")}' + ) + def test_modus2_und_modus3_gebaut(self): """Modus 2 und Modus 3 muessen GEBAUT sein.""" for test_id in ("M2_hz000", "M3_hz270"): @@ -179,10 +195,12 @@ class TestGefaellestreckeModusKonsistenz: self.tests_by_id = {t["test_id"]: t for t in self.testdata if "test_id" in t} def test_modus1_richtungsunabhaengig(self): - """Alle vier Modus-1-Richtungen muessen dieselbe Hoehe/Winkel liefern, - da nur die Fahrtrichtung (hz), nicht die Geometrie variiert.""" + """Die vier Modus-1-Richtungen (90-Grad-Elemente) muessen dieselbe Hoehe/Winkel + liefern, da nur die Fahrtrichtung (hz), nicht die Geometrie variiert. Die + 30-Grad-Variante (M1_w30) ist bewusst ausgenommen (andere Element-Masse).""" modus1 = [r for r in self.results - if r["modus"] == 1 and r["status"] == "GEBAUT"] + if r["modus"] == 1 and r["status"] == "GEBAUT" + and r.get("as_winkel", "90") == "90"] assert len(modus1) >= 2, "Zu wenige Modus-1-Ergebnisse fuer Vergleich" referenz = modus1[0] for r in modus1[1:]: diff --git a/tests/testdata/gefaellestrecke_tests.json b/tests/testdata/gefaellestrecke_tests.json index 2451942..74f9328 100644 --- a/tests/testdata/gefaellestrecke_tests.json +++ b/tests/testdata/gefaellestrecke_tests.json @@ -10,7 +10,9 @@ "hz_grad": 0.0, "start_mm": [0, 0, 5000], "as_seite": "links", - "es_seite": "links" + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90" }, { "test_id": "M1_hz090", @@ -18,7 +20,9 @@ "hz_grad": 90.0, "start_mm": [15000, 0, 5000], "as_seite": "links", - "es_seite": "links" + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90" }, { "test_id": "M1_hz180", @@ -26,7 +30,9 @@ "hz_grad": 180.0, "start_mm": [0, -15000, 5000], "as_seite": "links", - "es_seite": "links" + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90" }, { "test_id": "M1_hz270", @@ -34,7 +40,20 @@ "hz_grad": 270.0, "start_mm": [15000, -15000, 5000], "as_seite": "links", - "es_seite": "links" + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90" + }, + { + "test_id": "M1_w30", + "modus": 1, + "hz_grad": 0.0, + "start_mm": [30000, 0, 5000], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "30", + "es_winkel": "30", + "beschreibung": "Modus 1 mit 30-Grad AUS-/EIN-Elementen (statt 90 Grad)" }, { "test_id": "M2_hz000", @@ -44,7 +63,9 @@ "linie_start_mm": [0, -35000, 0], "linie_ende_mm": [10000, -35000, 0], "as_seite": "links", - "es_seite": "links" + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90" }, { "test_id": "M3_hz270", @@ -54,7 +75,9 @@ "deltaH_quelle": "M2_hz000", "deltaL_quelle": "M2_hz000", "as_seite": "links", - "es_seite": "links" + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90" }, { "test_id": "M3_Bogen", @@ -64,6 +87,8 @@ "ende_mm": [38500, -43500, 1800], "bogen": {"winkel_grad": 90, "radius_mm": 500, "seite": "links"}, "as_seite": "links", - "es_seite": "links" + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90" } ]