feat: AS-Zufuehrungsachse fuer beide Winkel + GF-Option "Parallel zum Kreisel"
Die AS-Praeambel in Modus 1 fragt jetzt Winkel, Seite UND eine optionale Zufuehrungsachse (2. Punkt) - im Assistenten alles in einem Fenster (vflw_as_achse). Beide Angaben zusammen legen das AS vollstaendig fest: der 2. Punkt gibt die KS_EIN-Achse (Zufuehrung/Fahrtrichtung), links/rechts die AS-Variante und damit die KS_AUS-Richtung der Kette. Bisher galt die Achse nur beim 30-Grad-Element und ERSETZTE dort die Seitenfrage. Darauf setzt die neue 5. Option der gf-laenge-modus-Frage auf, intern "parallel" (vfl-gf-parallel-kreisel): AS -> GF-Stueck -> GF-Bogen aus EINEM Abstandswert, gemessen senkrecht zur Zufuehrungsachse von AS-KS_EIN bis Bogen-KS_AUS. Kein Separator dazwischen, damit der Abstand exakt getroffen wird; die Kettenende-Frage stellt der Zweig selbst NACH dem Bau. Waehlbar nur am Kettenanfang mit AS UND Achse. Der Bogen ist nicht verdrahtet: gewaehlt wird der, der den gemessenen Grundriss-Schwenk des AS-Blocks aufhebt (vf-element-plan-turn) - mit den vorhandenen Bausteinen AS 30 -> 30-Grad-Bogen, AS 90 -> 90-Grad-Bogen, immer zur Gegenseite. Querversatz von AS und Bogen wird gemessen statt gerechnet; die Bogen-Probe laeuft dabei auf dem IDEALISIERTEN 3-Grad-Rahmen, auf dem der echte Bogen spaeter sitzt (auf dem AS-Rahmen gemessen lag der Abstand im BricsCAD-Test um 0.5 mm daneben). Journal: [STR winkel][STR seite][PT p2 | NIL]. Welche Fragen gestellt wurden, wird nicht journalisiert, sondern beim Replay an der Eintragsart erkannt - alte Ketten bleiben ohne Sonderbehandlung editierbar. Die Journal-Werkzeuge (vf_linienzug_grammatik.py, vf_spec_export.py, vf_journal_export.py, vf_spec.lsp, test_hm_recformat.lsp) kennen das optionale Achsen-Token. Tests: 11 neue Unit-Tests fuer die reinen Kerne vfl-par-bogen-waehlen und vfl-par-gf-laenge (tu-tests-vfl-parallel), TEST_UNIT 701/701 gruen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+506
-141
@@ -853,57 +853,144 @@
|
||||
;; im Aufrufer-Code) - beides braucht daher keinen eigenen Parameter.
|
||||
;; Original-Reihenfolge/-Journal: vfl-in-string (Ja/Nein), dann bei Ja
|
||||
;; vfl-in-value (Winkel) + vfl-in-string (Seite) - bleibt unveraendert.
|
||||
(defun vflw-gruppe-as-impl (kopf-key / dat dcl-pfad ergebnis gsetzen gwinkel gseite)
|
||||
(setq dat (load_dialog (vflw-dcl-pfad)))
|
||||
(if (not (new_dialog "vflw_as" dat))
|
||||
(if (and dat (>= dat 0)) (unload_dialog dat))
|
||||
(progn
|
||||
(set_tile "kopf" (vflw-clean (ssg-text kopf-key)))
|
||||
(set_tile "setzen" "1")
|
||||
(set_tile "winkel_90" "1")
|
||||
(set_tile "seite_links" "1")
|
||||
;; Seitenauswahl ist nur beim 90-Grad-Element wirksam: beim 30-Grad-
|
||||
;; Element folgt die Seite aus der Zufuehrungsachse, die direkt nach
|
||||
;; diesem Dialog ueber einen zweiten Punkt abgefragt wird (Nutzer-Vorgabe
|
||||
;; 2026-10-14). Sie wird darum ausgegraut - und unten auch NICHT in die
|
||||
;; Pending-Queue gelegt, sonst zoege die Punktfrage sie als vermeintlichen
|
||||
;; Punkt heraus und erschiene gar nicht.
|
||||
(action_tile "setzen"
|
||||
"(mode_tile \"winkel_90\" (if (= (get_tile \"setzen\") \"1\") 0 1))
|
||||
(mode_tile \"winkel_30\" (if (= (get_tile \"setzen\") \"1\") 0 1))
|
||||
(mode_tile \"seite_links\" (if (and (= (get_tile \"setzen\") \"1\") (/= (get_tile \"winkel_30\") \"1\")) 0 1))
|
||||
(mode_tile \"seite_rechts\" (if (and (= (get_tile \"setzen\") \"1\") (/= (get_tile \"winkel_30\") \"1\")) 0 1))")
|
||||
(action_tile "winkel_30"
|
||||
"(mode_tile \"seite_links\" 1)
|
||||
(mode_tile \"seite_rechts\" 1)")
|
||||
(action_tile "winkel_90"
|
||||
"(mode_tile \"seite_links\" (if (= (get_tile \"setzen\") \"1\") 0 1))
|
||||
(mode_tile \"seite_rechts\" (if (= (get_tile \"setzen\") \"1\") 0 1))")
|
||||
(action_tile "accept"
|
||||
"(setq gsetzen (get_tile \"setzen\"))
|
||||
(setq gwinkel (if (= (get_tile \"winkel_30\") \"1\") \"30\" \"90\"))
|
||||
(setq gseite (if (= (get_tile \"seite_rechts\") \"1\") \"2\" \"1\"))
|
||||
(done_dialog 1)")
|
||||
(action_tile "cancel" "(done_dialog 0)")
|
||||
(action_tile "back" "(done_dialog 2)")
|
||||
(setq ergebnis (start_dialog))
|
||||
(unload_dialog dat)
|
||||
(cond
|
||||
((= ergebnis 1)
|
||||
(if (= gsetzen "1")
|
||||
;; Winkel-Slot wird von vfl-in-value (AS-Winkel, ueber
|
||||
;; vf-frage-element-winkel) konsumiert - der erwartet direkt
|
||||
;; "30"/"90", NICHT den Auswahl-Index wie beim Seite-Slot.
|
||||
;; Beim 30-Grad-Element wird die Seite NICHT mitgegeben: sie ist im
|
||||
;; Dialog ausgegraut und folgt aus der Zufuehrungsachse. Ein hier
|
||||
;; abgelegter Wert wuerde von der nachfolgenden Punktfrage
|
||||
;; faelschlich als Punkt konsumiert.
|
||||
(if (= gwinkel "30")
|
||||
(vflw-pending-push-all (list "1" gwinkel))
|
||||
(vflw-pending-push-all (list "1" gwinkel gseite)))
|
||||
(vflw-pending-push-all (list "2"))))
|
||||
((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck"))
|
||||
(t (setq *vfl-wizard-abbruch-grund* "abbrechen"))
|
||||
;;
|
||||
;; achse-basis (NUR das AS-Element am Kettenanfang von Modus 1, Nutzer-Vorgabe
|
||||
;; 2026-10-21; nil = wie bisher, sonst der Kettenstartpunkt): zeigt
|
||||
;; zusaetzlich die Zufuehrungsachse (2. Punkt) im SELBEN
|
||||
;; Bildschirm (Dialog vflw_as_achse) und legt deren Punkt als VIERTEN Wert in
|
||||
;; die Pending-Queue - Reihenfolge wie im Bau-Ablauf: ja/nein, Winkel, Seite,
|
||||
;; Achsen-Punkt. Beide Angaben zusammen legen das AS vollstaendig fest: der
|
||||
;; 2. Punkt gibt die KS_EIN-Achse (Zufuehrung/Fahrtrichtung), links/rechts die
|
||||
;; AS-Variante und damit die KS_AUS-Richtung der Kette. Wird KEIN Punkt
|
||||
;; gewaehlt, geht ein nil in die Queue (Journal-Eintrag "NIL") und die Kette
|
||||
;; laeuft wie bisher ueber die Richtung des naechsten Klicks.
|
||||
;; Ohne achse-basis (ES-Element, Modi 2/3) bleibt alles unveraendert -
|
||||
;; inklusive der ausgegrauten Seite beim 30-Grad-Element.
|
||||
;;
|
||||
;; Der Punkt-Button schliesst den Dialog (done_dialog 2) - (getpoint) direkt
|
||||
;; aus einem action_tile-Callback funktioniert in BricsCAD nicht (siehe
|
||||
;; vflw-g-punkt-str). Picken laeuft danach auf der Kommandozeile, und MIT
|
||||
;; Punkt ist der Dialog fertig: er wird NICHT erneut gezeigt (Nutzer-Wunsch
|
||||
;; 2026-10-22), anders als bei vflw-gruppe-punkt-hoehe-impl, wo nach dem Punkt
|
||||
;; noch ein Zahlenfeld zu fuellen ist. Nur ein mit ESC abgebrochener Pick
|
||||
;; zeigt den Dialog wieder. Fuer genau diesen Fall liest schon der Pick-Button
|
||||
;; die Auswahl aus und der Dialog stellt sie beim Neuaufbau wieder her -
|
||||
;; new_dialog setzt sonst alle Kacheln auf die DCL-Vorgaben (90/Links) zurueck.
|
||||
(defun vflw-gruppe-as-impl (kopf-key achse-basis /
|
||||
mit-achse dat dlg-name ergebnis
|
||||
gsetzen gwinkel gseite gpunkt fertig)
|
||||
;; achse-basis traegt BEIDES: nil = kein Achsen-Dialog (ES, Modi 2/3), sonst
|
||||
;; der Kettenstartpunkt als Basis fuers Gummiband der Punktwahl - genau der
|
||||
;; Punkt, von dem aus die Zufuehrungsachse gemessen wird.
|
||||
(setq mit-achse (if achse-basis t nil))
|
||||
(setq dlg-name (if mit-achse "vflw_as_achse" "vflw_as"))
|
||||
(setq gsetzen "1" gwinkel "90" gseite "1" gpunkt nil fertig nil)
|
||||
(while (not fertig)
|
||||
(setq dat (load_dialog (vflw-dcl-pfad)))
|
||||
(if (not (new_dialog dlg-name dat))
|
||||
(progn (if (and dat (>= dat 0)) (unload_dialog dat)) (setq fertig t))
|
||||
(progn
|
||||
(set_tile "kopf" (vflw-clean (ssg-text kopf-key)))
|
||||
(set_tile "setzen" gsetzen)
|
||||
(set_tile (if (= gwinkel "30") "winkel_30" "winkel_90") "1")
|
||||
(set_tile (if (= gseite "2") "seite_rechts" "seite_links") "1")
|
||||
;; Startpunkt IMMER zeigen - er ist der Ausgangspunkt der Achse und
|
||||
;; haengt waehrend der Punktwahl am Gummiband. Der 2. Punkt samt
|
||||
;; daraus entstehender Achsrichtung erscheint nur, wenn der Dialog
|
||||
;; ueberhaupt noch einmal kommt (abgebrochene Punktwahl, s.u.); nach
|
||||
;; einem erfolgreichen Pick schliesst der Dialog direkt, die Richtung
|
||||
;; meldet dann vfl-frage-as-winkel-seite-oder-achse auf der Konsole.
|
||||
(if mit-achse
|
||||
(progn
|
||||
(set_tile "start_anzeige"
|
||||
(strcat "Startpunkt: " (vflw-g-punkt-str achse-basis)))
|
||||
(if gpunkt
|
||||
(set_tile "pt_anzeige"
|
||||
(strcat (vflw-g-punkt-str gpunkt)
|
||||
" -> Achse "
|
||||
(rtos (vfl-planar-hz achse-basis gpunkt) 2 1)
|
||||
" Grad")))))
|
||||
;; Seitenauswahl ist OHNE Achsen-Dialog nur beim 90-Grad-Element
|
||||
;; wirksam: dort folgt die Seite beim 30-Grad-Element aus der
|
||||
;; Zufuehrungsachse (Nutzer-Vorgabe 2026-10-14). Sie wird darum
|
||||
;; ausgegraut - und unten auch NICHT in die Pending-Queue gelegt, sonst
|
||||
;; zoege die Punktfrage sie als vermeintlichen Punkt heraus und
|
||||
;; erschiene gar nicht. MIT Achsen-Dialog wird die Seite dagegen immer
|
||||
;; gebraucht (sie ist die AS-Variante, nicht mehr aus der Achse
|
||||
;; ableitbar) und bleibt daher auch bei 30 Grad waehlbar.
|
||||
(action_tile "setzen"
|
||||
(if mit-achse
|
||||
"(mode_tile \"winkel_90\" (if (= (get_tile \"setzen\") \"1\") 0 1))
|
||||
(mode_tile \"winkel_30\" (if (= (get_tile \"setzen\") \"1\") 0 1))
|
||||
(mode_tile \"seite_links\" (if (= (get_tile \"setzen\") \"1\") 0 1))
|
||||
(mode_tile \"seite_rechts\" (if (= (get_tile \"setzen\") \"1\") 0 1))
|
||||
(mode_tile \"pick\" (if (= (get_tile \"setzen\") \"1\") 0 1))"
|
||||
"(mode_tile \"winkel_90\" (if (= (get_tile \"setzen\") \"1\") 0 1))
|
||||
(mode_tile \"winkel_30\" (if (= (get_tile \"setzen\") \"1\") 0 1))
|
||||
(mode_tile \"seite_links\" (if (and (= (get_tile \"setzen\") \"1\") (/= (get_tile \"winkel_30\") \"1\")) 0 1))
|
||||
(mode_tile \"seite_rechts\" (if (and (= (get_tile \"setzen\") \"1\") (/= (get_tile \"winkel_30\") \"1\")) 0 1))"))
|
||||
(if (not mit-achse)
|
||||
(progn
|
||||
(action_tile "winkel_30"
|
||||
"(mode_tile \"seite_links\" 1)
|
||||
(mode_tile \"seite_rechts\" 1)")
|
||||
(action_tile "winkel_90"
|
||||
"(mode_tile \"seite_links\" (if (= (get_tile \"setzen\") \"1\") 0 1))
|
||||
(mode_tile \"seite_rechts\" (if (= (get_tile \"setzen\") \"1\") 0 1))")))
|
||||
(if mit-achse
|
||||
(action_tile "pick"
|
||||
"(setq gsetzen (get_tile \"setzen\"))
|
||||
(setq gwinkel (if (= (get_tile \"winkel_30\") \"1\") \"30\" \"90\"))
|
||||
(setq gseite (if (= (get_tile \"seite_rechts\") \"1\") \"2\" \"1\"))
|
||||
(done_dialog 2)"))
|
||||
(action_tile "accept"
|
||||
"(setq gsetzen (get_tile \"setzen\"))
|
||||
(setq gwinkel (if (= (get_tile \"winkel_30\") \"1\") \"30\" \"90\"))
|
||||
(setq gseite (if (= (get_tile \"seite_rechts\") \"1\") \"2\" \"1\"))
|
||||
(done_dialog 1)")
|
||||
(action_tile "cancel" "(done_dialog 0)")
|
||||
;; MIT Punkt-Button ist Code 2 belegt -> "Zurueck" nutzt 3 (wie in
|
||||
;; vflw_punkt_zahl/vflw-gruppe-punkt-hoehe-impl).
|
||||
(action_tile "back" (if mit-achse "(done_dialog 3)" "(done_dialog 2)"))
|
||||
(setq ergebnis (start_dialog))
|
||||
(unload_dialog dat)
|
||||
;; Punkt-Button: Dialog ist zu, die Zeichnung hat den Fokus, getpoint
|
||||
;; laeuft normal. MIT Punkt ist danach alles beisammen - der Ablauf
|
||||
;; geht direkt in den "Ok Weiter"-Zweig, der Dialog wird NICHT noch
|
||||
;; einmal gezeigt (Nutzer-Wunsch 2026-10-22: er stand vorher zweimal
|
||||
;; da, einmal vor und einmal nach der Punktwahl - alle uebrigen
|
||||
;; Angaben stehen beim Druck auf den Button ja schon fest, der Punkt
|
||||
;; ist die letzte offene). OHNE Punkt (Abbruch mit ESC) wird der
|
||||
;; Dialog dagegen erneut gezeigt, sonst waere nach einem Fehlklick
|
||||
;; die ganze Eingabe weg.
|
||||
(if (and mit-achse (= ergebnis 2))
|
||||
(progn
|
||||
(setq gpunkt (vfl-getpoint achse-basis (ssg-text "vfl-prompt-as-achse-p2")))
|
||||
(if gpunkt (setq ergebnis 1))))
|
||||
(cond
|
||||
((= ergebnis 1)
|
||||
(setq fertig t)
|
||||
(if (= gsetzen "1")
|
||||
;; Winkel-Slot wird von vfl-in-value (AS-Winkel, ueber
|
||||
;; vf-frage-element-winkel) konsumiert - der erwartet direkt
|
||||
;; "30"/"90", NICHT den Auswahl-Index wie beim Seite-Slot.
|
||||
(if mit-achse
|
||||
(vflw-pending-push-all (list "1" gwinkel gseite gpunkt))
|
||||
;; Ohne Achsen-Dialog beim 30-Grad-Element KEINE Seite
|
||||
;; mitgeben (siehe Kommentar oben).
|
||||
(if (= gwinkel "30")
|
||||
(vflw-pending-push-all (list "1" gwinkel))
|
||||
(vflw-pending-push-all (list "1" gwinkel gseite))))
|
||||
(vflw-pending-push-all (list "2"))))
|
||||
((= ergebnis (if mit-achse 3 2))
|
||||
(setq fertig t) (setq *vfl-wizard-abbruch-grund* "zurueck"))
|
||||
;; Code 2 steht hier NUR noch fuer "Punktwahl mit ESC abgebrochen"
|
||||
;; (mit Punkt ist ergebnis oben auf 1 gesetzt worden): fertig bleibt
|
||||
;; nil, die Schleife zeigt den Dialog mit den gemerkten Werten
|
||||
;; erneut - das ist KEIN Abbruch der ganzen Kette.
|
||||
((and mit-achse (= ergebnis 2)) nil)
|
||||
(t (setq fertig t) (setq *vfl-wizard-abbruch-grund* "abbrechen"))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -1110,16 +1197,22 @@
|
||||
;; separaten Dialog (vflw-gruppe-gf-steigend-untermodus-impl, weiter unten) -
|
||||
;; der 3-Optionen-Dialog hier waere dort irrefuehrend (dritte Kachel
|
||||
;; "Steigend" existiert in diesem Kontext gar nicht mehr).
|
||||
(defun vflw-gruppe-gf-laenge-modus-impl ( / dat ergebnis gwahl)
|
||||
;; mit-parallel: T, wenn "Parallel zum Kreisel" hier ueberhaupt baubar ist
|
||||
;; (Kettenanfang MIT AS-Element UND festgelegter Zufuehrungsachse - ohne
|
||||
;; Bezugsachse gibt es keinen Abstand). Sonst wird die Kachel deaktiviert,
|
||||
;; statt sie anzubieten und die Antwort hinterher abzulehnen.
|
||||
(defun vflw-gruppe-gf-laenge-modus-impl (mit-parallel / dat ergebnis gwahl)
|
||||
(setq dat (load_dialog (vflw-dcl-pfad)))
|
||||
(if (not (new_dialog "vflw_gf_laenge_modus" dat))
|
||||
(if (and dat (>= dat 0)) (unload_dialog dat))
|
||||
(progn
|
||||
(set_tile "kopf" (vflw-clean (ssg-text "vfl-gf-laenge-modus-header")))
|
||||
(if (not mit-parallel) (mode_tile "modus_parallel" 1))
|
||||
(action_tile "accept"
|
||||
"(setq gwahl (cond ((= (get_tile \"modus_hoehe\") \"1\") \"2\")
|
||||
((= (get_tile \"modus_steigend\") \"1\") \"3\")
|
||||
((= (get_tile \"modus_qc\") \"1\") \"4\")
|
||||
((= (get_tile \"modus_parallel\") \"1\") \"5\")
|
||||
(t \"1\")))
|
||||
(done_dialog 1)")
|
||||
(action_tile "cancel" "(done_dialog 0)")
|
||||
@@ -4717,6 +4810,227 @@
|
||||
)
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------------
|
||||
;; "Parallel zum Kreisel weiterbauen" (5. Option der gf-laenge-modus-Frage,
|
||||
;; intern "parallel"; Nutzer-Vorgabe 2026-10-21): der Regelfall an einer
|
||||
;; Kreisel-Ausschleusung. Gebaut wird AS -> kurzes GF-Stueck (Standard-
|
||||
;; Gefaelle) -> GF-Bogen, sodass die Kette danach PARALLEL zur
|
||||
;; Zufuehrungsachse (= Kreisel-Laufrichtung) weiterlaeuft.
|
||||
;;
|
||||
;; EINZIGE Eingabe ist der ABSTAND, gemessen SENKRECHT zur Zufuehrungsachse
|
||||
;; von KS_EIN des AS-Elements bis KS_AUS des Bogens. AS- und Bogen-Queranteil
|
||||
;; sind durch die Bausteine fest; die Laenge des GF-Stuecks dazwischen ist die
|
||||
;; einzige Unbekannte und folgt aus dem Abstand:
|
||||
;; abstand = quer(AS) + L * sin(hz0 - hz_achse) + quer(Bogen)
|
||||
;; (L = horizontale Laenge des GF-Stuecks wie bei vfl-insert-gf-segment).
|
||||
;;
|
||||
;; Warum hier KEIN Endpunkt geklickt wird: Zufuehrungsachse (2. Punkt) UND
|
||||
;; AS-Seite stehen seit 2026-10-21 beide schon aus dem AS-Dialog fest (siehe
|
||||
;; vfl-frage-as-winkel-seite-oder-achse) - die Achse gibt die KS_EIN-Richtung,
|
||||
;; die Seite die AS-Variante und damit die KS_AUS-Richtung. Die Fahrtrichtung
|
||||
;; nach dem AS ist dadurch bekannt, bevor irgendetwas gebaut ist.
|
||||
;;
|
||||
;; Bogenwahl NICHT fest verdrahtet: gesucht ist der Bogen, der den real
|
||||
;; gemessenen Grundriss-Schwenk des AS-Blocks GENAU aufhebt
|
||||
;; (as-turn + bogen-turn = 0, vf-element-plan-turn wie in vfl-qc-linie-mit-gf),
|
||||
;; immer zur GEGENSEITE der AS-Seite. Mit den vorhandenen Bausteinen ergibt
|
||||
;; das genau die Vorgabe-Tabelle: AS 30 Grad -> 30-Grad-Bogen, AS 90 Grad ->
|
||||
;; 90-Grad-Bogen (AS links -> Bogen rechts und umgekehrt). Genau DARUM wird
|
||||
;; gemessen statt eine Tabelle gepflegt: die Zuordnung folgt den Bloecken,
|
||||
;; auch wenn ein Element anders vermessen ist als erwartet. Passt kein Bogen
|
||||
;; in die Toleranz, wird das gemeldet statt schief gebaut.
|
||||
;;
|
||||
;; Quer-Anteile werden GEMESSEN, nicht gerechnet: AS ueber sein echtes KS_EIN
|
||||
;; (der Klickpunkt ist der Block-URSPRUNG, KS_EIN liegt beim Drehteller-
|
||||
;; Anschluss seitlich versetzt - siehe vfl-block-ks-punkt), der Bogen ueber
|
||||
;; einen Probe-Bau, der danach wieder geloescht wird (dasselbe Prinzip und
|
||||
;; derselbe Grund wie in vfl-qc-linie-mit-gf: die Bogen-Bausteine haengen an
|
||||
;; einem bereits geneigten Rahmen, Messen ist zuverlaessiger als eine weitere
|
||||
;; Rotationsformel). Der Probe-Bau haengt nur an der ANKUNFTS-Orientierung,
|
||||
;; nicht an der Position - er liefert daher denselben Versatz wie der spaetere
|
||||
;; echte Bau hinter dem GF-Stueck.
|
||||
;;
|
||||
;; KEIN Separator zwischen GF-Stueck und Bogen (Nutzer-Entscheidung
|
||||
;; 2026-10-21) - der Abstand wird dadurch exakt getroffen.
|
||||
;;
|
||||
;; Die Kettenende-Frage stellt dieser Zweig SELBST, und zwar NACH dem Bau
|
||||
;; (anders als die Zweige A/B/C, die sie vorab brauchen, um den ES-Fussabdruck
|
||||
;; von der gepickten Laenge abzuziehen): hier gibt es keine gepickte Laenge,
|
||||
;; von der etwas abzuziehen waere, und erst nach dem Bogen steht fest, wo die
|
||||
;; Kette weiterlaeuft.
|
||||
;;
|
||||
;; Nutzt - wie vfl-qc-linie-mit-gf - die dynamisch sichtbaren Lokalvariablen
|
||||
;; des Aufrufers vf-linienzug-modus (frame, p-aktuell, as-seite, as-vorhanden,
|
||||
;; kettenanfang, fertig, es-seite, anzahl-gf, letzter-typ,
|
||||
;; gf-kettenende-antwort).
|
||||
;;
|
||||
;; Die beiden Rechenkerne stehen bewusst als eigene, zeichnungsfreie
|
||||
;; Funktionen davor (vfl-par-bogen-waehlen / vfl-par-gf-laenge) - so sind sie
|
||||
;; in tests/test_unit.lsp ohne Zeichnung pruefbar (tu-tests-vfl-parallel).
|
||||
|
||||
;; Welcher Bogen hebt den AS-Schwenk auf? kandidaten ist eine Liste
|
||||
;; (winkel . plan-turn) der real vorhandenen Bogen-Varianten EINER Seite;
|
||||
;; gesucht ist der mit dem kleinsten |as-turn + plan-turn| innerhalb von tol.
|
||||
;; Rueckgabe: Winkel (Int) oder nil, wenn keiner passt.
|
||||
(defun vfl-par-bogen-waehlen (as-turn kandidaten tol / best best-diff diff kand)
|
||||
(setq best nil best-diff nil)
|
||||
(foreach kand kandidaten
|
||||
(setq diff (abs (+ as-turn (cdr kand))))
|
||||
(if (or (null best-diff) (< diff best-diff))
|
||||
(setq best-diff diff best (car kand))))
|
||||
(if (and best (<= best-diff tol)) best nil))
|
||||
|
||||
;; Horizontale Laenge des GF-Stuecks zwischen AS und Bogen.
|
||||
;; abstand = gewuenschter Abstand (Betrag, senkrecht zur Zufuehrungsachse)
|
||||
;; perp-as = Querversatz AS-KS_EIN -> AS-KS_AUS (vorzeichenbehaftet)
|
||||
;; perp-bog = Querversatz des Bogens (KS_EIN -> KS_AUS, vorzeichenbehaftet)
|
||||
;; k = sin(hz0 - hz-achse), Querversatz je Laengeneinheit GF
|
||||
;; Die Seite steht ueber die AS-Variante schon fest - sie steckt im Vorzeichen
|
||||
;; von k. Der Nutzer tippt deshalb einen reinen Betrag, das Ziel-Vorzeichen
|
||||
;; wird daraus abgeleitet. Rueckgabe: Laenge (kann <= 0 sein, wenn der Abstand
|
||||
;; kleiner ist als der feste Anteil von AS + Bogen) oder nil, wenn das AS gar
|
||||
;; nicht aus der Achse schwenkt (k ~ 0, keine Loesung).
|
||||
(defun vfl-par-gf-laenge (abstand perp-as perp-bog k / s)
|
||||
(if (< (abs k) 1e-6)
|
||||
nil
|
||||
(progn
|
||||
(setq s (if (> k 0.0) 1.0 -1.0))
|
||||
(/ (- (* (abs abstand) s) perp-as perp-bog) k))))
|
||||
|
||||
(defun vfl-gf-parallel-kreisel ( / as-w as-turn bogen-seite bogen-winkel
|
||||
kandidaten tol w
|
||||
abstand abstand-min
|
||||
checkpoint as-ent p-ein hz-a rad-a nx ny hz0 k
|
||||
perp-as perp-bogen l-gf perp-ist rad3
|
||||
acc-gfbogen-save acc-sep-save basis-frame
|
||||
probe-checkpoint probe-frame dxp dyp
|
||||
hz-nach erg-bogen)
|
||||
(if (or (not kettenanfang) (not as-vorhanden) (null *vfl-as-basis-hz*))
|
||||
(vfl-meldung (ssg-text "vfl-par-nur-kettenanfang"))
|
||||
(progn
|
||||
(setq as-w (vfl-as-winkel))
|
||||
(setq as-turn (vf-element-plan-turn (strcat "AS_Element_" as-w "_" as-seite)))
|
||||
;; Bogen zur Gegenseite der AS-Seite; Winkel aus den real vorhandenen
|
||||
;; Varianten, der den AS-Schwenk am besten aufhebt.
|
||||
(setq bogen-seite (if (= as-seite "rechts") "links" "rechts"))
|
||||
(setq kandidaten '())
|
||||
(foreach w *vfk-gf-bogen-winkel*
|
||||
(setq kandidaten
|
||||
(cons (cons w (vf-element-plan-turn (gf-bogen-blockname w bogen-seite)))
|
||||
kandidaten)))
|
||||
(setq tol 2.0) ; gleiche Toleranz wie in vfl-qc-linie-mit-gf
|
||||
(setq bogen-winkel (vfl-par-bogen-waehlen as-turn (reverse kandidaten) tol))
|
||||
(if (null bogen-winkel)
|
||||
(vfl-meldung (ssg-textf "vfl-par-kein-bogen"
|
||||
(list (rtos as-turn 2 1) bogen-seite)))
|
||||
(progn
|
||||
;; --- Abstand abfragen (VOR dem Bau: ein Abbruch laesst dann
|
||||
;; garantiert nichts Halbfertiges stehen) ---
|
||||
(setq abstand (vfl-in-real (ssg-text "vfl-par-prompt-abstand")))
|
||||
(if (or (null abstand) (<= (abs abstand) 0.0))
|
||||
(princ (ssg-text "vfl-abgebrochen"))
|
||||
(progn
|
||||
(setq checkpoint (ssg-lastent-ohne-attribute))
|
||||
;; --- AS bauen: KS_EIN-Achse auf die Zufuehrungsachse ---
|
||||
(setq frame (vfl-insert-as-element-auf-achse "GF" p-aktuell
|
||||
*vfl-as-basis-hz* as-seite))
|
||||
(setq as-ent (entlast))
|
||||
(setq p-ein (if as-ent
|
||||
(vfl-block-ks-punkt (vlax-ename->vla-object as-ent) "KS_EIN")
|
||||
nil))
|
||||
(if (null p-ein) (setq p-ein p-aktuell))
|
||||
(setq hz-a *vfl-as-basis-hz*)
|
||||
(setq rad-a (* (float hz-a) (/ pi 180.0)))
|
||||
(setq nx (- (sin rad-a)) ny (cos rad-a)) ; Normale zur Zufuehrungsachse
|
||||
(setq hz0 (car (frame->hz-winkel frame))) ; Fahrtrichtung nach dem AS
|
||||
(setq perp-as (+ (* (- (car (car frame)) (car p-ein)) nx)
|
||||
(* (- (cadr (car frame)) (cadr p-ein)) ny)))
|
||||
;; --- Bogen probeweise bauen, Querversatz messen, wieder weg ---
|
||||
;; WICHTIG - die Probe muss auf GENAU dem Rahmen sitzen, auf dem
|
||||
;; der echte Bogen spaeter steht, sonst misst sie eine andere
|
||||
;; Lage. Das ist NICHT der Ausgangsrahmen des AS-Elements: der
|
||||
;; traegt die reale Neigung des AS-KS_AUS, waehrend der Bogen
|
||||
;; hinter dem GF-Stueck auf dessen IDEALISIERTEM Rahmen sitzt
|
||||
;; (make-frame-from-dir + hz-winkel->xu mit genau hz0 und dem
|
||||
;; Standard-Gefaellewinkel, siehe vfl-insert-gf-segment). Realer
|
||||
;; Befund 2026-10-22 (BricsCAD): auf dem AS-Rahmen gemessen fiel
|
||||
;; der Probe-Bogen 31.3 mm statt 22.6 mm - die daraus falsche
|
||||
;; Verdrehung liess den Abstand um 0.5 mm danebenliegen. Mit dem
|
||||
;; idealisierten Rahmen sind Probe und echter Bau per
|
||||
;; Konstruktion identisch.
|
||||
;; vfl-insert-gf-bogen-block zaehlt intern mit (GF_Bogen_L/R_xx) -
|
||||
;; die Probe darf diese Zaehler nicht verfaelschen.
|
||||
(setq basis-frame
|
||||
(make-frame-from-dir (car frame)
|
||||
(hz-winkel->xu hz0 (fix *vfk-gefaelle-winkel*))))
|
||||
(setq acc-gfbogen-save *vfl-acc-gfbogen* acc-sep-save *vfl-acc-separator*)
|
||||
(setq probe-checkpoint (ssg-lastent-ohne-attribute))
|
||||
(setq probe-frame (vfl-insert-gf-bogen-block basis-frame bogen-winkel bogen-seite))
|
||||
(setq dxp (- (car (car probe-frame)) (car (car basis-frame))))
|
||||
(setq dyp (- (cadr (car probe-frame)) (cadr (car basis-frame))))
|
||||
(vfl-loesche-seit probe-checkpoint)
|
||||
(setq *vfl-acc-gfbogen* acc-gfbogen-save *vfl-acc-separator* acc-sep-save)
|
||||
(setq perp-bogen (+ (* dxp nx) (* dyp ny)))
|
||||
;; --- GF-Laenge aus dem Abstand loesen (reiner Kern) ---
|
||||
(setq k (sin (* (- hz0 hz-a) (/ pi 180.0))))
|
||||
(setq l-gf (vfl-par-gf-laenge abstand perp-as perp-bogen k))
|
||||
(if (null l-gf)
|
||||
(progn
|
||||
(vfl-meldung (ssg-text "vfl-par-kein-versatz"))
|
||||
(vfl-loesche-seit checkpoint))
|
||||
(progn
|
||||
;; Kleinster erreichbarer Abstand = der von AS und Bogen
|
||||
;; allein (GF-Stueck = 0).
|
||||
(setq abstand-min (abs (+ perp-as perp-bogen)))
|
||||
(if (< l-gf 1.0)
|
||||
(progn
|
||||
(vfl-meldung (ssg-textf "vfl-par-zu-klein"
|
||||
(list (rtos (abs abstand) 2 1) (rtos abstand-min 2 1))))
|
||||
(vfl-loesche-seit checkpoint))
|
||||
(progn
|
||||
(setq rad3 (* (float (fix *vfk-gefaelle-winkel*)) (/ pi 180.0)))
|
||||
(setq frame (vfl-insert-gf-segment (car frame) hz0 l-gf
|
||||
(fix *vfk-gefaelle-winkel*)))
|
||||
(vfl-acc-gf-seg (/ l-gf (cos rad3)) (fix *vfk-gefaelle-winkel*))
|
||||
(setq anzahl-gf (1+ anzahl-gf))
|
||||
(setq frame (vfl-insert-gf-bogen-block frame bogen-winkel bogen-seite))
|
||||
(setq p-aktuell (car frame))
|
||||
(setq letzter-typ "GF")
|
||||
(setq perp-ist (abs (+ (* (- (car p-aktuell) (car p-ein)) nx)
|
||||
(* (- (cadr p-aktuell) (cadr p-ein)) ny))))
|
||||
(princ (ssg-textf "vfl-par-erfolg"
|
||||
(list (rtos l-gf 2 1) (itoa bogen-winkel) bogen-seite
|
||||
(rtos perp-ist 2 1))))
|
||||
;; --- Kettenende/ES (siehe Kopfkommentar: hier NACH dem Bau) ---
|
||||
(setq hz-nach (car (frame->hz-winkel frame)))
|
||||
(setq gf-kettenende-antwort (vfl-frage-ist-kettenende))
|
||||
(cond
|
||||
((= gf-kettenende-antwort "1")
|
||||
(setq es-seite (vfl-frage-es-seite nil))
|
||||
;; Uebergangsbogen pruefen (No-Op, wenn die Kette hier
|
||||
;; ohnehin auf der Fallend-Basis ankommt) - dieselbe
|
||||
;; Absicherung wie im gemeinsamen Abschluss der Zweige
|
||||
;; A/B/C.
|
||||
(setq erg-bogen (vfl-gf-bogen-uebergang frame *vfk-gefaelle-winkel*))
|
||||
(setq frame (car erg-bogen))
|
||||
(setq frame (vfl-insert-es-element "GF" frame hz-nach
|
||||
*vfk-gefaelle-winkel* (caddr (car frame)) es-seite))
|
||||
(setq p-aktuell (car frame))
|
||||
(setq fertig t))
|
||||
((= gf-kettenende-antwort "2") (setq fertig t))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------------
|
||||
;; "QC Linie mit GF und U-Form" (Option 5 der gf-laenge-modus-Frage,
|
||||
;; Nutzer-Vorgabe 2026-09-13, nach mehreren Praezisierungsrunden - inkl. echter
|
||||
@@ -5227,7 +5541,7 @@
|
||||
(princ (ssg-text "vfl-ja"))
|
||||
(princ (ssg-text "vfl-es-nein-zielpunkt"))
|
||||
(if (vfl-wizard-aktiv)
|
||||
(vl-catch-all-apply 'vflw-gruppe-as-impl (list "vfl-es-setzen-frage")))
|
||||
(vl-catch-all-apply 'vflw-gruppe-as-impl (list "vfl-es-setzen-frage" nil)))
|
||||
(setq es-antwort (vfl-menu (ssg-text "prompt-wahl-1-2")
|
||||
(list (ssg-text "vfl-ja") (ssg-text "vfl-es-nein-zielpunkt")) 1
|
||||
"vfl-es-setzen-frage"))
|
||||
@@ -6589,25 +6903,33 @@
|
||||
(progn
|
||||
;; BASISLINIEN-Modus: das AS gehoert mit seinem KS_EIN auf die
|
||||
;; Zufuehrungsachse (*vfl-as-basis-hz*), nicht mit dem KS_AUS auf die
|
||||
;; Kettenrichtung. Die Seite ergibt sich aus der Lage des naechsten
|
||||
;; Kettenpunkts zur Basislinie (Nutzer-Vorgabe 2026-10-14): der liegt in
|
||||
;; Richtung hz-neu, deltaL entfernt.
|
||||
;; Kettenrichtung.
|
||||
;;
|
||||
;; Die Seite kommt seit 2026-10-21 normalerweise AUS DEM DIALOG
|
||||
;; (*vfl-as-seite-explizit*) - sie ist die AS-Variante und darf dann
|
||||
;; nicht mehr ueberschrieben werden. Nur beim Replay eines
|
||||
;; Alt-Achsen-Journals (30 Grad, 2026-10-14..10-20) wurde sie gar nicht
|
||||
;; gefragt; dort ergibt sie sich wie bisher aus der Lage des naechsten
|
||||
;; Kettenpunkts zur Basislinie: der liegt in Richtung hz-neu, deltaL
|
||||
;; entfernt.
|
||||
(if *vfl-as-basis-hz*
|
||||
(progn
|
||||
(setq rad (* (float hz-neu) (/ pi 180.0)))
|
||||
(setq ziel (list (+ (car p-aktuell) (* deltaL (cos rad)))
|
||||
(+ (cadr p-aktuell) (* deltaL (sin rad)))
|
||||
(caddr p-aktuell)))
|
||||
(setq as-seite (vfl-seite-aus-lage *vfl-as-basis-p1*
|
||||
(list (+ (car *vfl-as-basis-p1*)
|
||||
(cos (* *vfl-as-basis-hz* (/ pi 180.0))))
|
||||
(+ (cadr *vfl-as-basis-p1*)
|
||||
(sin (* *vfl-as-basis-hz* (/ pi 180.0))))
|
||||
0.0)
|
||||
ziel))
|
||||
;; Masse auf die jetzt bekannte Seite umstellen (Winkel steht schon).
|
||||
(vf-set-as-masse (vfl-as-winkel) as-seite)
|
||||
(princ (ssg-textf "vfl-as-seite-ermittelt" (list as-seite)))
|
||||
(if (not *vfl-as-seite-explizit*)
|
||||
(progn
|
||||
(setq rad (* (float hz-neu) (/ pi 180.0)))
|
||||
(setq ziel (list (+ (car p-aktuell) (* deltaL (cos rad)))
|
||||
(+ (cadr p-aktuell) (* deltaL (sin rad)))
|
||||
(caddr p-aktuell)))
|
||||
(setq as-seite (vfl-seite-aus-lage *vfl-as-basis-p1*
|
||||
(list (+ (car *vfl-as-basis-p1*)
|
||||
(cos (* *vfl-as-basis-hz* (/ pi 180.0))))
|
||||
(+ (cadr *vfl-as-basis-p1*)
|
||||
(sin (* *vfl-as-basis-hz* (/ pi 180.0))))
|
||||
0.0)
|
||||
ziel))
|
||||
;; Masse auf die jetzt bekannte Seite umstellen (Winkel steht schon).
|
||||
(vf-set-as-masse (vfl-as-winkel) as-seite)
|
||||
(princ (ssg-textf "vfl-as-seite-ermittelt" (list as-seite)))))
|
||||
;; KS_EIN auf die Zufuehrungsachse legen - NICHT KS_AUS auf hz-neu.
|
||||
(setq frame (vfl-insert-as-element-auf-achse "GF" p-aktuell
|
||||
*vfl-as-basis-hz* as-seite)))
|
||||
@@ -6695,72 +7017,57 @@
|
||||
(vf-set-as-masse *vfl-as-winkel* as-seite) ; Masse fuer Variante
|
||||
as-seite)
|
||||
|
||||
;; AS-Winkel abfragen und danach ENTWEDER die Seite ODER - nur beim 30-Grad-
|
||||
;; Element - eine Zufuehrungsachse (Nutzer-Vorgabe 2026-10-14: "bitte erstmal
|
||||
;; nur fuer 30 Grad").
|
||||
;; AS-Winkel abfragen, danach die Seite UND - fuer BEIDE Winkel - eine
|
||||
;; optionale Zufuehrungsachse (Nutzer-Vorgabe 2026-10-21; bis dahin galt die
|
||||
;; Achse nur fuer das 30-Grad-Element und ERSETZTE dort die Seitenfrage).
|
||||
;;
|
||||
;; Warum erst NACH dem Winkel: die Achsenfrage gilt nur fuer AS_Element_30, der
|
||||
;; Winkel muss also schon feststehen. Der Kettenstartpunkt bleibt davon
|
||||
;; unberuehrt - er ist und bleibt der echte Sitz des AS-Elements; die Achse
|
||||
;; entsteht aus ihm plus EINEM weiteren Punkt, der nur die Richtung gibt.
|
||||
;; Warum beides und warum in dieser Reihenfolge: die zwei Angaben beschreiben
|
||||
;; verschiedene Dinge und legen das AS erst ZUSAMMEN vollstaendig fest -
|
||||
;; 2. Punkt -> Richtung der KS_EIN-Achse (die Zufuehrung, z.B. die
|
||||
;; Kreisel-Laufrichtung); der Startpunkt bleibt der Sitz des
|
||||
;; AS-Elements, der zweite Punkt gibt nur die Richtung.
|
||||
;; links/rechts -> AS-Variante und damit die KS_AUS-Richtung, also wohin die
|
||||
;; Kette nach dem Ausschleusen laeuft.
|
||||
;; Damit steht die Kettenrichtung schon vor dem ersten Streckenklick fest -
|
||||
;; Voraussetzung fuer "Parallel zum Kreisel" (vfl-gf-parallel-kreisel), das
|
||||
;; gar keinen Endpunkt mehr klickt, sondern nur noch einen Abstand bekommt.
|
||||
;; Die Achse ist optional: ohne Punkt laeuft alles wie frueher ueber die
|
||||
;; Richtung des naechsten Klicks.
|
||||
;;
|
||||
;; JOURNAL - deswegen ist die Reihenfolge so gewaehlt:
|
||||
;; 90 Grad : [STR winkel] [STR seite] <- Eintrag fuer Eintrag wie bisher
|
||||
;; 30 + Seite : [STR winkel] [STR seite] <- ebenfalls wie bisher
|
||||
;; 30 + Achse : [STR winkel] [PT p2]
|
||||
;; Die Modus-Wahl selbst wird BEWUSST NICHT journalisiert: sie ist aus der Art
|
||||
;; des naechsten Eintrags eindeutig rekonstruierbar (PT = Achse, STR = Seite).
|
||||
;; Dadurch bleiben alle aelteren Ketten ohne Sonderbehandlung editierbar.
|
||||
;; JOURNAL - Eintragsfolge an dieser Stelle:
|
||||
;; neu : [STR winkel] [STR seite] [PT p2] (ohne Achse: [NIL])
|
||||
;; 30 + Achse alt : [STR winkel] [PT p2] (2026-10-14..10-20)
|
||||
;; ganz alt : [STR winkel] [STR seite]
|
||||
;; Welche Fragen gestellt werden, wird BEWUSST NICHT journalisiert: es ist aus
|
||||
;; der Art des jeweils naechsten Eintrags eindeutig rekonstruierbar (PT direkt
|
||||
;; nach dem Winkel = Alt-Achse ohne Seite; PT/NIL nach der Seite = neue Achse;
|
||||
;; alles andere = Altbestand ohne Achse). Dadurch bleiben alle aelteren Ketten
|
||||
;; ohne Sonderbehandlung editierbar. Ein neues Glied beginnt immer mit seiner
|
||||
;; Menue-Antwort (STR) bzw. - im erzwungenen QC-Modus - mit einer Richtung
|
||||
;; (REAL); ein PT/NIL an dieser Stelle kann daher nur die Achse sein.
|
||||
;;
|
||||
;; Setzt *vfl-as-basis-hz*/-p1 (nil, wenn keine Achse gewaehlt wurde).
|
||||
;; Rueckgabe: Seite. Im Achsen-Modus vorlaeufig "links" - die endgueltige Seite
|
||||
;; folgt aus der Lage des naechsten Kettenpunkts und wird in
|
||||
;; vfl-kettenanfang-baustein gesetzt (Laengsverbrauch ist seitengleich, nur das
|
||||
;; Vorzeichen des Querversatzes dreht).
|
||||
;; Setzt *vfl-as-basis-hz*/-p1 (nil, wenn keine Achse gewaehlt wurde) und
|
||||
;; *vfl-as-seite-explizit* (T, wenn die Seite wirklich gefragt wurde - nur
|
||||
;; dann darf vfl-kettenanfang-baustein sie NICHT mehr aus der Lage des
|
||||
;; naechsten Punkts ueberschreiben).
|
||||
;; Rueckgabe: Seite. Beim Alt-Achsen-Journal vorlaeufig "links" - die
|
||||
;; endgueltige Seite folgt dort aus der Lage des naechsten Kettenpunkts
|
||||
;; (Laengsverbrauch ist seitengleich, nur das Vorzeichen des Querversatzes
|
||||
;; dreht).
|
||||
(defun vfl-frage-as-winkel-seite-oder-achse (seiten-headerkey startpunkt
|
||||
/ antwort as-seite modus p2)
|
||||
(setq *vfl-as-basis-hz* nil *vfl-as-basis-p1* nil)
|
||||
/ antwort as-seite p2 mit-seite mit-achse)
|
||||
(setq *vfl-as-basis-hz* nil *vfl-as-basis-p1* nil *vfl-as-seite-explizit* nil)
|
||||
(princ (ssg-text "vf-winkel-aus-header"))
|
||||
(princ (ssg-text "vf-winkel-90"))
|
||||
(princ (ssg-text "vf-winkel-30"))
|
||||
(setq *vfl-as-winkel*
|
||||
(vfl-in-value "STR"
|
||||
(function (lambda () (vf-frage-element-winkel "vf-winkel-aus-header")))))
|
||||
;; Beim 30-Grad-Element wird die Seite NICHT gefragt (im Gruppendialog
|
||||
;; ausgegraut) - stattdessen direkt die Zufuehrungsachse ueber einen zweiten
|
||||
;; Punkt. Es gibt also keine Modus-Frage: 30 Grad = Achse, 90 Grad = Seite.
|
||||
;;
|
||||
;; AUSNAHME Replay: aeltere 30-Grad-Ketten wurden noch MIT Seitenfrage
|
||||
;; gebaut, ihr Journal hat an dieser Stelle ein "STR" statt eines "PT".
|
||||
;; Steht dort ein STR, ist es ein Altbestand und es wird wie frueher die
|
||||
;; Seite gelesen - sonst liefe die Queue aus dem Takt.
|
||||
(setq modus (if (= *vfl-as-winkel* "30") "1" "2"))
|
||||
(if (and (= modus "1") *vfl-replay-queue* (/= (vfl-replay-peek-art) "PT"))
|
||||
(setq modus "2"))
|
||||
(if (= modus "1")
|
||||
(progn
|
||||
;; Der AS-Gruppendialog legt beim 30-Grad-Element bewusst KEINE Seite in
|
||||
;; die Pending-Queue (siehe vflw-gruppe-as-impl) - die Queue ist hier
|
||||
;; also leer und der folgende vfl-in-point fragt wirklich nach dem Punkt.
|
||||
;; Zweiter Punkt gibt NUR die Richtung der Zufuehrung; der Startpunkt
|
||||
;; bleibt der Sitz des AS-Elements.
|
||||
(setq p2 (vfl-in-point startpunkt (ssg-text "vfl-prompt-as-achse-p2")))
|
||||
(if (or (null p2)
|
||||
(and (< (abs (- (car p2) (car startpunkt))) 1e-9)
|
||||
(< (abs (- (cadr p2) (cadr startpunkt))) 1e-9)))
|
||||
(progn
|
||||
;; Keine brauchbare Richtung -> auf die Seitenfrage zurueckfallen.
|
||||
;; (Der PT-Eintrag steht dann trotzdem im Journal und wird beim
|
||||
;; Replay wieder als "Achse" gelesen - deshalb hier KEIN stiller
|
||||
;; Rueckfall, sondern Abbruch.)
|
||||
(princ (ssg-text "vfl-basislinie-punkte-gleich"))
|
||||
(exit))
|
||||
(progn
|
||||
(setq *vfl-as-basis-p1* startpunkt)
|
||||
(setq *vfl-as-basis-hz* (vfl-planar-hz startpunkt p2))
|
||||
(princ (ssg-textf "vfl-basislinie-info" (list (rtos *vfl-as-basis-hz* 2 1))))
|
||||
(setq as-seite "links"))) ; vorlaeufig, s.o.
|
||||
)
|
||||
;; --- Seite (links/rechts) ---
|
||||
;; Uebersprungen NUR beim Replay eines Alt-Achsen-Journals (30 Grad,
|
||||
;; 2026-10-14..10-20): dort steht direkt hinter dem Winkel der Achsenpunkt.
|
||||
(setq mit-seite (not (and *vfl-replay-queue* (= (vfl-replay-peek-art) "PT"))))
|
||||
(if mit-seite
|
||||
(progn
|
||||
(princ (ssg-text seiten-headerkey))
|
||||
(princ (ssg-text "gf-seite-links"))
|
||||
@@ -6768,7 +7075,34 @@
|
||||
(setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2")
|
||||
(list (ssg-text "gf-seite-links") (ssg-text "gf-seite-rechts")) 1
|
||||
seiten-headerkey))
|
||||
(setq as-seite (if (= antwort "2") "rechts" "links"))))
|
||||
(setq as-seite (if (= antwort "2") "rechts" "links"))
|
||||
(setq *vfl-as-seite-explizit* t))
|
||||
(setq as-seite "links")) ; vorlaeufig, s.o.
|
||||
;; --- Zufuehrungsachse (2. Punkt, optional) ---
|
||||
;; Beim Replay nur lesen, wenn an dieser Stelle wirklich ein Achsen-Eintrag
|
||||
;; steht (PT = Punkt, NIL = bewusst ohne Achse gebaut) - sonst ist es ein
|
||||
;; Altbestand ohne diese Frage und der naechste Eintrag gehoert schon zum
|
||||
;; ersten Glied.
|
||||
(setq mit-achse
|
||||
(if *vfl-replay-queue*
|
||||
(if (member (vfl-replay-peek-art) '("PT" "NIL")) t nil)
|
||||
t))
|
||||
(if mit-achse
|
||||
(progn
|
||||
(setq p2 (vfl-in-point startpunkt (ssg-text "vfl-prompt-as-achse-p2")))
|
||||
(if (and p2
|
||||
(or (> (abs (- (car p2) (car startpunkt))) 1e-9)
|
||||
(> (abs (- (cadr p2) (cadr startpunkt))) 1e-9)))
|
||||
(progn
|
||||
(setq *vfl-as-basis-p1* startpunkt)
|
||||
(setq *vfl-as-basis-hz* (vfl-planar-hz startpunkt p2))
|
||||
(princ (ssg-textf "vfl-basislinie-info" (list (rtos *vfl-as-basis-hz* 2 1)))))
|
||||
;; Kein (brauchbarer) Punkt -> keine Achse. KEIN Abbruch mehr: die
|
||||
;; Achse ist seit 2026-10-21 optional, die Kette laeuft dann wie
|
||||
;; frueher ueber die Richtung des naechsten Klicks. Der Journal-
|
||||
;; Eintrag (PT bzw. NIL) steht trotzdem und wird beim Replay wieder
|
||||
;; genauso gelesen.
|
||||
(princ (ssg-text "vfl-basislinie-ohne")))))
|
||||
(vf-set-as-masse *vfl-as-winkel* as-seite)
|
||||
as-seite)
|
||||
|
||||
@@ -7062,7 +7396,7 @@
|
||||
startpunkt-familie gf-kettenende-antwort
|
||||
vorab-antwort vorab-es-gewuenscht vorab-es-seite
|
||||
save-eindx-vorab save-eindz-vorab erg-es vorab-ziel-punkt
|
||||
rad3-sep sep-eindx-add sep-eindz-add)
|
||||
rad3-sep sep-eindx-add sep-eindz-add gf-parallel-moeglich)
|
||||
;; "Zurueck"/"Abbrechen"-Flag ganz am Anfang zuruecksetzen (auch schon vor
|
||||
;; der ersten Praeambel-Frage) - sonst wuerde ein von einem VORHERIGEN Lauf
|
||||
;; noch gesetztes Flag (z.B. nach "Abbrechen") den allerersten vfl-in-*-
|
||||
@@ -7162,7 +7496,10 @@
|
||||
(setq as-vorhanden nil))
|
||||
(progn
|
||||
(if (vfl-wizard-aktiv)
|
||||
(vl-catch-all-apply 'vflw-gruppe-as-impl (list "vfl-as-setzen-frage")))
|
||||
;; startpunkt = Zufuehrungsachse (2. Punkt) gehoert hier in DENSELBEN
|
||||
;; Dialog wie Winkel/Seite (Nutzer-Vorgabe 2026-10-21); der Punkt ist
|
||||
;; zugleich die Gummiband-Basis der Punktwahl.
|
||||
(vl-catch-all-apply 'vflw-gruppe-as-impl (list "vfl-as-setzen-frage" startpunkt)))
|
||||
(princ (ssg-text "vfl-as-setzen-frage"))
|
||||
(princ (ssg-text "vfl-ja"))
|
||||
(princ (ssg-text "vfl-as-nein"))
|
||||
@@ -7175,10 +7512,13 @@
|
||||
;; werden - sonst wuerde ein WINKEL_AS-Attribut den Wert der VORHERIGEN Kette
|
||||
;; tragen, wenn diesmal kein AS gewaehlt wird.
|
||||
(setq *vfl-as-winkel* nil *vfl-es-winkel* nil)
|
||||
;; Winkel, dann Seite ODER (nur bei 30 Grad) eine Zufuehrungsachse - siehe
|
||||
;; vfl-frage-as-winkel-seite-oder-achse. Im Achsen-Modus entfaellt die
|
||||
;; Seitenfrage; die Seite folgt aus der Lage des naechsten Kettenpunkts und
|
||||
;; wird in vfl-kettenanfang-baustein bestimmt.
|
||||
;; Gilt genauso fuer die Achsen-Globals: ohne AS-Element bleibt sonst die
|
||||
;; Zufuehrungsachse der VORHERIGEN Kette stehen.
|
||||
(setq *vfl-as-basis-hz* nil *vfl-as-basis-p1* nil *vfl-as-seite-explizit* nil)
|
||||
;; Winkel, dann Seite UND eine optionale Zufuehrungsachse (2. Punkt) - siehe
|
||||
;; vfl-frage-as-winkel-seite-oder-achse. Beide zusammen legen AS-Lage und
|
||||
;; Kettenrichtung fest; ohne Achse laeuft alles wie frueher ueber die
|
||||
;; Richtung des naechsten Klicks.
|
||||
(if as-vorhanden
|
||||
(setq as-seite (vfl-frage-as-winkel-seite-oder-achse "vfl-aus-seite-header" startpunkt)))
|
||||
;; ES-Seite wird erst am Kettenende abgefragt (siehe vfl-frage-es-seite),
|
||||
@@ -7474,18 +7814,38 @@
|
||||
(setq *vfl-forciere-qc-modus* nil)
|
||||
)
|
||||
(progn
|
||||
(if (vfl-wizard-aktiv) (vl-catch-all-apply 'vflw-gruppe-gf-laenge-modus-impl nil))
|
||||
;; "Parallel zum Kreisel" braucht AS-Element UND Zufuehrungsachse
|
||||
;; als Bezug - sonst gibt es keinen Abstand, zu dem parallel
|
||||
;; gebaut werden koennte.
|
||||
(setq gf-parallel-moeglich
|
||||
(and kettenanfang as-vorhanden *vfl-as-basis-hz*))
|
||||
(if (vfl-wizard-aktiv)
|
||||
(vl-catch-all-apply 'vflw-gruppe-gf-laenge-modus-impl (list gf-parallel-moeglich)))
|
||||
(princ (ssg-text "vfl-gf-laenge-modus-header"))
|
||||
(princ (ssg-text "vfl-gf-laenge-modus-opt-endpunkt"))
|
||||
(princ (ssg-text "vfl-gf-laenge-modus-opt-hoehe"))
|
||||
(princ (ssg-text "vfl-gf-laenge-modus-opt-steigend"))
|
||||
(princ (ssg-text "vfl-gf-laenge-modus-opt-qc"))
|
||||
(if gf-parallel-moeglich (princ (ssg-text "vfl-gf-laenge-modus-opt-parallel")))
|
||||
(setq gf-laenge-modus (vfl-menu (ssg-text "prompt-wahl-1-2")
|
||||
(list (ssg-text "vfl-gf-laenge-modus-opt-endpunkt")
|
||||
(ssg-text "vfl-gf-laenge-modus-opt-hoehe")
|
||||
(ssg-text "vfl-gf-laenge-modus-opt-steigend")
|
||||
(ssg-text "vfl-gf-laenge-modus-opt-qc")) 1
|
||||
(if gf-parallel-moeglich
|
||||
(list (ssg-text "vfl-gf-laenge-modus-opt-endpunkt")
|
||||
(ssg-text "vfl-gf-laenge-modus-opt-hoehe")
|
||||
(ssg-text "vfl-gf-laenge-modus-opt-steigend")
|
||||
(ssg-text "vfl-gf-laenge-modus-opt-qc")
|
||||
(ssg-text "vfl-gf-laenge-modus-opt-parallel"))
|
||||
(list (ssg-text "vfl-gf-laenge-modus-opt-endpunkt")
|
||||
(ssg-text "vfl-gf-laenge-modus-opt-hoehe")
|
||||
(ssg-text "vfl-gf-laenge-modus-opt-steigend")
|
||||
(ssg-text "vfl-gf-laenge-modus-opt-qc"))) 1
|
||||
"vfl-gf-laenge-modus-header"))
|
||||
;; Menue-Antwort "5" (die neue 5. Option) auf einen SPRECHENDEN
|
||||
;; internen Wert abbilden: "5" ist intern bereits durch die
|
||||
;; erzwungene U-Form belegt (*vfl-forciere-qc-modus*, Linienzug-
|
||||
;; Modus 5), die diese Frage ueberspringt und daher nie eine "5"
|
||||
;; ins Journal schreibt. Journalisiert wird weiterhin die rohe
|
||||
;; Menue-Antwort; die Abbildung passiert beim Replay identisch.
|
||||
(if (= gf-laenge-modus "5") (setq gf-laenge-modus "parallel"))
|
||||
)
|
||||
)
|
||||
;; Option 4 ("QC Linie mit GF"): eigenstaendiger, vollstaendig
|
||||
@@ -7500,6 +7860,11 @@
|
||||
(cond
|
||||
((= gf-laenge-modus "4") (vfl-qc-linie-mit-gf))
|
||||
((= gf-laenge-modus "5") (vfl-qc-linie-mit-gf-uform))
|
||||
;; "Parallel zum Kreisel": ebenfalls eigenstaendig - baut AS + GF +
|
||||
;; Bogen aus EINEM Abstandswert und stellt die Kettenende-Frage
|
||||
;; selbst (sie kommt hier NACH dem Bau, nicht davor: erst nach dem
|
||||
;; Bogen steht fest, wo die Kette weiterlaeuft).
|
||||
((= gf-laenge-modus "parallel") (vfl-gf-parallel-kreisel))
|
||||
(t
|
||||
(progn
|
||||
;; NEU: Kettenende/ES JETZT fragen - VOR der Laengen-/Gefaelle-
|
||||
@@ -8250,7 +8615,7 @@
|
||||
(princ (ssg-text "vfl-ja"))
|
||||
(princ (ssg-text "vfl-es-nein-zielpunkt"))
|
||||
(if (vfl-wizard-aktiv)
|
||||
(vl-catch-all-apply 'vflw-gruppe-as-impl (list "vfl-es-setzen-frage")))
|
||||
(vl-catch-all-apply 'vflw-gruppe-as-impl (list "vfl-es-setzen-frage" nil)))
|
||||
(setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2")
|
||||
(list (ssg-text "vfl-ja") (ssg-text "vfl-es-nein-zielpunkt")) 1
|
||||
"vfl-es-setzen-frage"))
|
||||
@@ -10236,7 +10601,7 @@
|
||||
"vfl-prompt-hoehe-startpunkt" "gf-status-abgebrochen" "Starthoehe (Z, mm):"))
|
||||
(setq start-hoehe (caddr startpunkt))
|
||||
(if (vfl-wizard-aktiv)
|
||||
(vl-catch-all-apply 'vflw-gruppe-as-impl (list "vfl-as-setzen-frage")))
|
||||
(vl-catch-all-apply 'vflw-gruppe-as-impl (list "vfl-as-setzen-frage" nil)))
|
||||
(princ (ssg-text "vfl-as-setzen-frage"))
|
||||
(princ (ssg-text "vfl-ja"))
|
||||
(princ (ssg-text "vfl-m3-as-nein"))
|
||||
@@ -10257,7 +10622,7 @@
|
||||
"vfl-m3-prompt-zielhoehe" "gf-status-abgebrochen" "Zielhoehe (Z, mm):"))
|
||||
(setq end-hoehe (caddr endpunkt))
|
||||
(if (vfl-wizard-aktiv)
|
||||
(vl-catch-all-apply 'vflw-gruppe-as-impl (list "vfl-es-setzen-frage")))
|
||||
(vl-catch-all-apply 'vflw-gruppe-as-impl (list "vfl-es-setzen-frage" nil)))
|
||||
(princ (ssg-text "vfl-es-setzen-frage"))
|
||||
(princ (ssg-text "vfl-ja"))
|
||||
(princ (ssg-text "vfl-es-nein-zielpunkt"))
|
||||
|
||||
+19
-2
@@ -274,7 +274,18 @@
|
||||
((and (= (type v) 'STR) (= (strcase v) "AUTO")) (vsp-raus "NIL" nil))
|
||||
(T (vsp-zahl "REAL" v "eingang_hoehe"))))
|
||||
|
||||
(defun vsp-praeambel (kopf / punkt)
|
||||
;; Praeambel-Tokens: PT(Startpunkt) REAL(Starthoehe) STR(AS ja/nein)
|
||||
;; [STR(Winkel) STR(Seite) (PT|NIL)(Zufuehrungsachse)].
|
||||
;;
|
||||
;; Das Achsen-Feld "as_achse" ist OPTIONAL (Gegenstueck zu
|
||||
;; vfl-frage-as-winkel-seite-oder-achse und zu praeambel() in
|
||||
;; lib/vf_linienzug_grammatik.py):
|
||||
;; [x, y, z] -> PT (Zufuehrungsachse ueber einen zweiten Punkt)
|
||||
;; "ohne" -> NIL (bewusst ohne Achse gebaut)
|
||||
;; fehlt -> gar kein Token = Journalformat VOR 2026-10-21. Das replayt
|
||||
;; unveraendert; die Kettenrichtung kommt dann wie frueher aus
|
||||
;; dem naechsten Klick.
|
||||
(defun vsp-praeambel (kopf / punkt achse)
|
||||
(setq *vsp-wo* "start")
|
||||
(setq punkt (ssg-val kopf "start_punkt"))
|
||||
(if (and punkt (listp punkt) (>= (length punkt) 3))
|
||||
@@ -287,7 +298,13 @@
|
||||
(if (vsp-ja-p (ssg-val kopf "as"))
|
||||
(progn
|
||||
(vsp-wert-str (ssg-val kopf "as_winkel") "as_winkel")
|
||||
(vsp-code-raus *vsp-tab-seite* (ssg-val kopf "as_seite") "as_seite"))))
|
||||
(vsp-code-raus *vsp-tab-seite* (ssg-val kopf "as_seite") "as_seite")
|
||||
(setq achse (ssg-val kopf "as_achse"))
|
||||
(cond
|
||||
((and achse (listp achse) (>= (length achse) 3))
|
||||
(vsp-raus "PT" (mapcar 'float achse)))
|
||||
((equal achse "ohne") (vsp-raus "NIL" nil))
|
||||
))))
|
||||
|
||||
;; naechste: Felder der NAECHSTEN Top-Level-Sektion (oder nil) - wird nur fuer
|
||||
;; "Linie-GF" gebraucht (siehe dort). *vsp-es-verbraucht* (Ausgabe-Flag, vom
|
||||
|
||||
Reference in New Issue
Block a user