feat: VF-Hoehe je Segment (Sivas 4433-4437) + AS-Zufuehrungsachse bei 30 Grad

Zwei Themen, die dieselben Dateien beruehren und daher zusammen gehen.

1) VF_HOEHE_m - Hoehe je VF-Segment, Sivas-Merkmale 4433-4437

   Sivas erwartet je Streckengruppe bis zu fuenf Variofoerderer-Hoehen.
   Neues Block-Attribut VF_HOEHE_m: kommagetrennte Liste in Metern mit 3
   Nachkommastellen, Eintrag fuer Eintrag parallel zu L_VF_m/VF_WINKEL.

   Je Eintrag der Mittelwert aus KS_EIN und KS_AUS DES GERADEN VF-Abschnitts.
   Zwischen Umlenk- und Motorstation koennen mehrere Abschnitte liegen
   (auf/ab/horizontal), jeder bekommt einen eigenen Wert.

   SONDERFALL Standard/Etage: dort gibt es nur einen Motor und nur einen
   geraden Abschnitt - gemessen wird die GANZE Kette (AS-KS_EIN bis
   ES-KS_AUS, vf-vfhoehe-kette). Das ersetzt den Segmentwert; der Linienzug
   laeuft nicht durch vf-dialog-berechnen-einfuegen und behaelt seine Liste.

   WICHTIG - vollstaendige Erfassung: die VF-Segmente entstehen NICHT alle in
   vfs-vf-koerper. Horizontale Zwischenstuecke, das "schon flach"-Segment und
   die Modus-2/3-Fuellstuecke bauen direkt mit insert-inclined-scaled-block,
   die Kette-Merge-Rekonstruktion liest sie aus bestehenden Bloecken. Ein
   erster Fix nur in vfs-vf-koerper lieferte darum zu wenige Werte (realer
   Befund: L_VF_m hatte drei Eintraege, VF_HOEHE_m einen). Jetzt sind alle 14
   Stellen erfasst, die vfl-acc-vf-seg aufrufen - dafuer das Paar
   vf-vfhoehe-merke/-schliesse, das ohne lokale Variable auskommt.

   REGEL (im Code dokumentiert): Jede Stelle, die vfl-acc-vf-seg aufruft,
   MUSS auch eine Hoehe erfassen - sonst verschiebt sich die Liste gegen
   L_VF_m und im Export landet eine Hoehe beim falschen Foerderer.

   Formatierung ueber vf-meter-3: (rtos x 2 3) allein kuerzt je nach DIMZIN
   nachfolgende Nullen ("2.5" statt "2.500", "-1" statt "-1.000") - im
   Testlauf real aufgetreten.

   Attribut-Schema *strecke-attr-gruppe* (ssg_core.lsp) ergaenzt, sonst
   verschluckt ssg-attrib-set-on den neuen Tag stillschweigend.
   export_sivas.py verteilt die Liste auf VF_HOEHE_MERKMALE (4433-4437);
   ueberzaehlige Abschnitte werden weggelassen statt zusammengefasst, fehlende
   lassen das Merkmal ganz weg.

2) AS-Element 30 Grad: Zufuehrungsachse statt Seitenwahl

   Der Startpunkt einer Kette mit AS-Element ist geometrisch keine Position,
   sondern eine ACHSE: das AS sitzt an einer durchlaufenden Strecke und
   schleust daraus aus, seine KS_EIN-Achse muss darauf liegen. Bisher richtete
   vfl-insert-as-element das KS_AUS entlang der Kettenrichtung aus, wodurch
   das KS_EIN um den Blockschwenk verdreht stand - beim 90-Grad-Element kaum
   sichtbar, beim 30-Grad-Element deutlich.

   Beim 30-Grad-Element wird die Seitenauswahl im AS-Gruppendialog jetzt
   ausgegraut; stattdessen gibt ein zweiter Punkt die Zufuehrungsrichtung
   (der Startpunkt bleibt der Sitz des Elements). Die Seite folgt aus der Lage
   des naechsten Kettenpunkts zur Achse (vfl-seite-aus-lage). 90 Grad bleibt
   unveraendert bei der Seitenfrage.

   Der Dialog legt bei 30 Grad bewusst KEINE Seite mehr in die Pending-Queue -
   sonst zog die nachfolgende Punktfrage sie als vermeintlichen Punkt heraus
   und erschien gar nicht (realer Fehler beim ersten Test).

   Abwaertskompatibilitaet: aeltere 30-Grad-Ketten wurden noch MIT Seitenfrage
   gebaut. vfl-replay-peek-art sieht beim Replay nach, was tatsaechlich
   ansteht ("PT" = Achse, "STR" = Seite) - die Modus-Wahl selbst wird nicht
   journalisiert, weil sie daraus eindeutig rekonstruierbar ist.

Unit-Suite 687/687 gruen. VF-Hoehe in BricsCAD bestaetigt. Die AS-Achsenfrage
ist dort noch NICHT gelaufen, seit die Seitenauswahl ausgegraut wird.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 12:54:56 +02:00
parent 4ce2a02205
commit cccd362bba
9 changed files with 440 additions and 10 deletions
+7
View File
@@ -1264,6 +1264,13 @@
("L_VF_m" "0.000")
("ANTRIEBFAHRTRICHTUNG" "Auf")
("VF_WINKEL" "0")
;; Hoehe je VF-SEGMENT in Metern (3 Nachkommastellen), kommagetrennt und
;; Eintrag fuer Eintrag parallel zu L_VF_m/VF_WINKEL: Mittelwert aus KS_EIN
;; und KS_AUS des jeweiligen geraden VF-Abschnitts (vf-vfhoehe-segment in
;; vf_core.lsp, erfasst in vfs-vf-koerper). Zwischen Umlenk- und
;; Motorstation koennen mehrere Abschnitte liegen (auf/ab/horizontal).
;; Sivas-Merkmale 4433-4437 (bis zu fuenf Abschnitte je Gruppe).
("VF_HOEHE_m" "0.000")
("VF_Bogen_A_90" "0")
("VF_Bogen_A_60" "0")
("VF_Bogen_A_30" "0")
+112
View File
@@ -218,6 +218,102 @@
(defun vf-motorseite-aktuell ( / )
(if (member *vf-motorseite* '("links" "rechts")) *vf-motorseite* "rechts"))
;; ============================================================
;; VF-HOEHE JE SEGMENT (Attribut VF_HOEHE_m, Sivas 4433-4437)
;; ============================================================
;; Sivas erwartet je Streckengruppe bis zu fuenf Variofoerderer-Hoehen. Ein
;; Eintrag gehoert zu EINEM VF-Segment (Koerper) - nicht zu einer ganzen
;; Foerdereinheit und nicht zur ganzen Kette (Nutzer-Korrektur 2026-10-21):
;;
;; Hoehe = Mittelwert aus KS_EIN und KS_AUS DIESES Segments.
;;
;; Eine Kette, die durch Vario-Boegen in drei Abschnitte geteilt ist, bekommt
;; dadurch drei Werte - die Liste laeuft Eintrag fuer Eintrag parallel zu
;; L_VF_m, VF_WINKEL und ANTRIEBFAHRTRICHTUNG.
;;
;; Erfasst wird an genau EINER Stelle: vfs-vf-koerper baut ein Segment, kennt
;; dessen KS_EIN als Eingangspunkt und liefert dessen KS_AUS zurueck. Alle
;; Modi (Standard, Etage, Linienzug) bauen ihre VF-Koerper darueber, deshalb
;; muss der verzweigte Bau-Pfad selbst nicht angefasst werden.
;;
;; Einheit: Meter mit 3 Nachkommastellen (wie L_VF_m), kommagetrennt ueber
;; vfl-join-komma - Reihenfolge = Bau-Reihenfolge.
(if (not (boundp '*vf-acc-vfhoehe*)) (setq *vf-acc-vfhoehe* '()))
(defun vf-vfhoehe-reset ()
(setq *vf-acc-vfhoehe* '()))
;; Ein VF-Segment erfassen: z-ein = Z des KS_EIN, z-aus = Z des KS_AUS (mm).
;; Fehlt einer der Werte, wird NICHTS angehaengt - sonst verschoebe sich die
;; Liste gegen L_VF_m/VF_WINKEL und im Export landete eine Hoehe beim falschen
;; Foerderer.
(defun vf-vfhoehe-segment (z-ein z-aus)
(if (and (numberp z-ein) (numberp z-aus))
(setq *vf-acc-vfhoehe*
(append *vf-acc-vfhoehe* (list (vf-meter-3 (/ (+ z-ein z-aus) 2.0)))))))
;; Bequemes Paar fuer die Bau-Pfade: vor dem Einbau den Startpunkt merken,
;; danach mit dem Endpunkt abschliessen. Beide geben ihren Punkt zurueck,
;; lassen sich also ohne zusaetzliche lokale Variable einsetzen:
;;
;; (vf-vfhoehe-merke pt)
;; (setq pt (insert-inclined-scaled-block ...))
;; (vf-vfhoehe-schliesse pt)
;;
;; Noetig, weil die VF-Segmente NICHT alle ueber vfs-vf-koerper laufen: die
;; horizontalen Zwischenstuecke und die Modus-2-Fuellstuecke bauen direkt mit
;; insert-inclined-scaled-block. Wurde dort nicht erfasst, fehlten ihre
;; Hoehen und VF_HOEHE_m war kuerzer als L_VF_m (realer Befund 2026-10-21:
;; L_VF_m hatte drei Eintraege, VF_HOEHE_m nur einen).
;;
;; REGEL: Jede Stelle, die (vfl-acc-vf-seg ...) aufruft, MUSS auch eine Hoehe
;; erfassen - sonst verschiebt sich die Liste gegen L_VF_m/VF_WINKEL und im
;; Sivas-Export landet eine Hoehe beim falschen Foerderer.
(if (not (boundp '*vf-vfhoehe-merk*)) (setq *vf-vfhoehe-merk* nil))
(defun vf-vfhoehe-merke (pt)
(setq *vf-vfhoehe-merk* (if (listp pt) (caddr pt) nil))
pt)
(defun vf-vfhoehe-schliesse (pt)
(vf-vfhoehe-segment *vf-vfhoehe-merk* (if (listp pt) (caddr pt) nil))
(setq *vf-vfhoehe-merk* nil)
pt)
;; SONDERFALL Standard/Etage: Hoehe ueber die GANZE Kette.
;;
;; Diese beiden Typen haben nur EINEN Motor und nur EINEN geraden
;; VF-Abschnitt (Nutzer-Vorgabe 2026-10-21). Statt des Segmentwerts gilt dort
;; der Mittelwert der ganzen Anlage:
;; Anfang = KS_EIN des AS-Elements (Startpunkt der Anlage)
;; Ende = KS_AUS des ES-Elements (Rueckgabewert der Einfuegefunktion)
;;
;; ERSETZT die Liste bewusst, statt anzuhaengen: vfs-vf-koerper hat beim Bau
;; bereits den Segmentwert gesammelt, der hier nicht gelten soll. Ergebnis ist
;; genau ein Eintrag.
;;
;; Gerechnet wird aus der GEBAUTEN Geometrie, nicht aus der Soll-Vorgabe
;; (anders als MONTAGEHOEHE_m, dessen hoehe-bis aus deltaH abgeleitet ist).
;; Beide Hoehen in mm.
(defun vf-vfhoehe-kette (z-anfang z-ende)
(if (and (numberp z-anfang) (numberp z-ende))
(setq *vf-acc-vfhoehe* (list (vf-meter-3 (/ (+ z-anfang z-ende) 2.0))))
(setq *vf-acc-vfhoehe* '())))
;; Millimeter -> Meter als String mit GENAU 3 Nachkommastellen.
;;
;; (rtos x 2 3) allein genuegt nicht: je nach DIMZIN schneidet es nachfolgende
;; Nullen ab und liefert "2.5" statt "2.500" bzw. "-1" statt "-1.000" (real
;; beobachtet im Testlauf). Fuer eine Merkmalsliste ist die feste Stellenzahl
;; aber gewollt, darum wird hier aufgefuellt - unabhaengig von der
;; Zeichnungseinstellung.
(defun vf-meter-3 (mm / s pos)
(setq s (rtos (/ (float mm) 1000.0) 2 3))
(if (not (vl-string-search "." s)) (setq s (strcat s ".")))
(setq pos (vl-string-search "." s))
(while (< (- (strlen s) pos 1) 3) (setq s (strcat s "0")))
s)
;; ============================================================
;; TEIL 5: KS_EIN/KS_AUS EXTRAKTION
;; ============================================================
@@ -977,6 +1073,9 @@
(cons "L_VF_m" (rtos (/ L_VF 1000.0) 2 3))
(cons "ANTRIEBFAHRTRICHTUNG" richtung)
(cons "VF_WINKEL" (itoa best-winkel))
;; Hoehe der (einen) Foerdereinheit - beim Standard-/Etage-Typ
;; fuellen vfs-vf-entry/-exit genau einen Listeneintrag.
(cons "VF_HOEHE_m" (vfl-join-komma *vf-acc-vfhoehe*))
(cons "ANZAHL_SEPARATOR" "2")
(cons "ANZAHL_SCANNER" (itoa n-scanner))
(cons "GERUEST_EINZELMODUL" geruest-einzelmodul)
@@ -1013,6 +1112,10 @@
horizontal-info winkelwahl best-winkel L_GF L_VF L_GF1 L_GF2
verteilung-modus n-scanner hoehe-von hoehe-bis lastEnt
vf-insert vf-endpunkt staustrecke-basis)
;; VF-Hoehen-Akkumulator pro Anlage zuruecksetzen - sonst erbte die naechste
;; Anlage die Hoehen der vorherigen. (Im Linienzug erledigt das
;; vfl-acc-reset; Standard/Etage laufen nicht darueber.)
(vf-vfhoehe-reset)
(setq berechne-fn (vf-registry-berechne-fn typ))
(setq einfuege-fn (vf-registry-einfuege-fn typ))
(setq ergebnis (apply berechne-fn (list deltaL deltaH richtung seite)))
@@ -1064,6 +1167,15 @@
(setq vf-endpunkt
(apply einfuege-fn
(list deltaL deltaH richtung best-winkel L_GF1 L_GF2 L_VF startpunkt seite hz)))
;; VF_HOEHE_m fuer Standard/Etage: Mittelwert ueber die GANZE Kette
;; (AS-KS_EIN = startpunkt, ES-KS_AUS = Rueckgabe der Einfuegefunktion),
;; weil es hier nur einen Motor und nur einen geraden VF-Abschnitt
;; gibt. Ersetzt den beim Bau gesammelten Segmentwert - siehe
;; vf-vfhoehe-kette. Der Linienzug laeuft NICHT hier durch und behaelt
;; daher seine Segmentliste.
(vf-vfhoehe-kette (caddr startpunkt)
(if (and vf-endpunkt (listp vf-endpunkt))
(caddr vf-endpunkt) nil))
(setq vf-insert
(vf-block-erstellen typ seite vf-nummer n-scanner
hoehe-von hoehe-bis deltaH deltaL L_VF L_GF1 L_GF2
+206 -9
View File
@@ -82,7 +82,12 @@
;; sichern): nil (normal) / "zurueck" (letztes Glied verwerfen und neu
;; fragen) / "abbrechen" (Bau hier stoppen, Baustand bleibt stehen).
*vfl-wizard-abbruch-grund* nil
*vfl-abbruch-letztes-ent* nil))
*vfl-abbruch-letztes-ent* nil)
;; VF-Hoehen je SEGMENT (Attribut VF_HOEHE_m, Sivas 4433-4437).
;; Die Liste fuellt vfs-vf-koerper beim Bau jedes geraden VF-Abschnitts
;; (siehe vf-vfhoehe-segment in vf_core.lsp); hier wird sie - wie alle
;; anderen Akkumulatoren - pro Kette zurueckgesetzt.
(vf-vfhoehe-reset))
;; Alist-Zaehler erhoehen / lesen
(defun vfl-inc-count (al key / e)
@@ -857,10 +862,22 @@
(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 (= (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\"))
@@ -877,7 +894,13 @@
;; 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.
(vflw-pending-push-all (list "1" gwinkel gseite))
;; 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"))
@@ -3811,6 +3834,35 @@
;; genommen (vlax-curve-*): fuer eine LINE ist das exakt die Linie selbst, fuer
;; eine Polylinie genau das angeklickte Segment - ohne Segment-Suche von Hand.
;; Rueckgabe: (pa pb) oder nil.
;; ============================================================
;; AS-BASISLINIE: Zufuehrungsachse am Kettenanfang
;; ============================================================
;; Der Startpunkt einer Kette mit AS-Element ist geometrisch KEINE Position,
;; sondern eine ACHSE: das AS sitzt an einer durchlaufenden Strecke (z.B. einer
;; Kreiselkette) und schleust daraus aus - seine KS_EIN-Achse MUSS auf dieser
;; Zufuehrungsachse liegen (Nutzer-Einsicht 2026-10-14, dieselbe wie beim
;; Endpunkt: "der Punkt ist eigentlich eine Linie").
;;
;; Beim AS_Element_90 faellt das kaum auf, beim AS_Element_30 steht das Element
;; sichtbar falsch: vfl-insert-as-element richtet heute das KS_AUS entlang der
;; Kettenrichtung aus, wodurch das KS_EIN um den Blockschwenk verdreht steht.
;;
;; Auf welcher Seite der Zufuehrung das AS ausschleust, ergibt sich dann aus der
;; Lage des naechsten Kettenpunkts zur Basislinie - es muss nicht gefragt werden
;; (Nutzer-Entscheidung 2026-10-14). Im Punkt-Modus bleibt die Seitenfrage
;; dagegen unveraendert erhalten.
;;
;; Reine Rechnung, in tests/test_unit.lsp getestet:
;; Vorzeichen des 2D-Kreuzprodukts (p2-p1) x (ziel-p1).
;; > 0 -> ziel liegt LINKS der Richtung p1->p2
;; < 0 -> rechts
;; Genau auf der Linie (0) gilt als "links" (willkuerlich, aber deterministisch -
;; der Aufrufer sollte diesen Fall ohnehin nicht erzeugen).
(defun vfl-seite-aus-lage (p1 p2 ziel / kr)
(setq kr (vfl-kreuz2 (- (car p2) (car p1)) (- (cadr p2) (cadr p1))
(- (car ziel) (car p1)) (- (cadr ziel) (cadr p1))))
(if (< kr 0.0) "rechts" "links"))
;; Ziellinie durch ZWEI selbst gesetzte Punkte definieren.
;;
;; Allgemeiner als das Anklicken eines vorhandenen Objekts (Nutzer-Idee
@@ -5063,7 +5115,10 @@
(if sep-vor (setq pt (vfl-sep-hz pt hz)))
;; horizontale Zwischenstrecke (0 Grad)
(princ (ssg-textf "vfl-horizontale-zwischenstrecke" (list (rtos dL 2 2))))
;; Hoehe dieses (horizontalen) VF-Segments erfassen - siehe vf-vfhoehe-merke.
(vf-vfhoehe-merke pt)
(setq pt (insert-inclined-scaled-block "Staustrecke_SP_1000_mm" pt dL 0 hz))
(vf-vfhoehe-schliesse pt)
(vfl-acc-vf-seg "horizontal" 0 dL)
;; optionaler Separator NACH (jetzt tatsaechlich bauen)
(if sep-nach (setq pt (vfl-sep-hz pt hz)))
@@ -5587,9 +5642,11 @@
;; (Ausgang in vfl-vf-einheit) erledigt den einzigen wirklich
;; noetigen Bogen.
((and schon-flach (= typ "VF") (= w 0) lvf (> lvf 1.0))
(vf-vfhoehe-merke (car frame))
(setq frame (make-frame-from-dir
(insert-inclined-scaled-block "Staustrecke_SP_1000_mm" (car frame) lvf 0 hzn)
(hz-winkel->xu hzn 0.0)))
(vf-vfhoehe-schliesse (car frame))
(vfl-acc-vf-seg "horizontal" 0 lvf)
(setq cnt (1+ cnt)))
;; Normalfall: gewinkelter ODER horizontaler Koerper - vfs-vf-koerper
@@ -6508,10 +6565,53 @@
;; die noetige Restlaenge ist damit einfach die urspruengliche Distanz MINUS
;; die tatsaechliche (gemessene) AS-Fussabdrucklaenge, keine Punkt-Projektion
;; noetig (Ersatz fuer das fruehere vfl-projiziere-distanz auf pick-punkt).
(defun vfl-kettenanfang-baustein (p-aktuell hz-neu deltaL as-seite as-vorhanden / frame fussabdruck)
;; AS-Element so einfuegen, dass seine KS_EIN-ACHSE auf der Zufuehrungsachse
;; (ein-hz) liegt - Gegenstueck zu vfl-insert-as-element, das stattdessen das
;; KS_AUS entlang der Kettenrichtung ausrichtet.
;;
;; Unterschied in einer Zeile: dort wird der Blockschwenk abgezogen
;; (ein-hz = hz - as-turn), hier NICHT - die uebergebene Richtung IST schon die
;; des KS_EIN. Das KS_AUS zeigt danach um den Blockschwenk gedreht weiter, also
;; beim AS_Element_30 um 30 Grad von der Zufuehrung weg: genau das reale
;; Ausschleusen aus einer durchlaufenden Strecke (Nutzer-Einsicht 2026-10-14).
(defun vfl-insert-as-element-auf-achse (typ startpunkt ein-hz as-seite / rad-h xu-ein)
(setq rad-h (* (float ein-hz) (/ pi 180.0)))
(setq xu-ein (list (cos rad-h) (sin rad-h) 0.0))
(insert-block-mixed-to-ks
(strcat "AS_Element_" (vfl-as-winkel) "_" as-seite)
(make-frame-from-dir startpunkt xu-ein)
(caddr startpunkt) nil "KS_EIN")
)
(defun vfl-kettenanfang-baustein (p-aktuell hz-neu deltaL as-seite as-vorhanden
/ frame fussabdruck ziel rad)
(if as-vorhanden
(progn
(setq frame (vfl-insert-as-element "GF" p-aktuell hz-neu 0.0 as-seite))
;; 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.
(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)))
;; 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)))
(setq frame (vfl-insert-as-element "GF" p-aktuell hz-neu 0.0 as-seite)))
(setq fussabdruck (vfl-planar-dist p-aktuell (car frame)))
(setq deltaL (- deltaL fussabdruck))
(princ (ssg-textf "vfl-info-as-eingefuegt" (list (rtos deltaL 2 1))))
@@ -6595,6 +6695,83 @@
(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").
;;
;; 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.
;;
;; 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.
;;
;; 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).
(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)
(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.
)
(progn
(princ (ssg-text seiten-headerkey))
(princ (ssg-text "gf-seite-links"))
(princ (ssg-text "gf-seite-rechts"))
(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"))))
(vf-set-as-masse *vfl-as-winkel* as-seite)
as-seite)
;; ES-Winkel (30/90) + Seite abfragen - MARKER-FREIE Schale fuer die Modi 2/3,
;; die das ES-Element als eigene Praeambel (Start/Ziel bereits fest) abfragen
;; und ihr eigenes Journal-/Masse-Schema fuehren. Unterscheidet sich bewusst
@@ -6731,6 +6908,9 @@
(cons "L_VF_m" (vfl-join-komma *vfl-acc-lvf*))
(cons "ANTRIEBFAHRTRICHTUNG" (vfl-join-komma *vfl-acc-richtung*))
(cons "VF_WINKEL" (vfl-join-komma *vfl-acc-winkel*))
;; Hoehe je Foerdereinheit (Mittelwert Umlenk-KS_EIN / Motor-KS_AUS),
;; Meter mit 3 Nachkommastellen - Sivas 4433-4437.
(cons "VF_HOEHE_m" (vfl-join-komma *vf-acc-vfhoehe*))
;; Vario-Kurven (Richtungswechsel im VF-Teil), A=aussen / I=innen
(cons "VF_Bogen_A_90" (itoa (vfl-get-count *vfl-acc-variokurve* "A_90")))
(cons "VF_Bogen_A_60" (itoa (vfl-get-count *vfl-acc-variokurve* "A_60")))
@@ -6995,9 +7175,12 @@
;; 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.
(if as-vorhanden
(setq as-seite (vfl-frage-as-winkel-seite "vfl-aus-seite-header"))
)
(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),
;; da das ES-Element erst dort eingefuegt wird.
@@ -10650,8 +10833,10 @@
(progn (setq pt (vfl3-flach-ein pt letzt-koerper-hz)) (setq flat-p t)
;; Fueller-A: der im Kletter-Segment durch 1/2 GF1 frei werdende Platz
(if (and (> filler-A-len 0.1) (not filler-a-done))
(progn (setq pt (insert-inclined-scaled-block "Staustrecke_SP_1000_mm"
(progn (vf-vfhoehe-merke pt)
(setq pt (insert-inclined-scaled-block "Staustrecke_SP_1000_mm"
pt filler-A-len 0 letzt-koerper-hz))
(vf-vfhoehe-schliesse pt)
(vfl-acc-vf-seg "horizontal" 0 filler-A-len)
(setq anzahl-vf (1+ anzahl-vf) filler-a-done t)))))
(if (= i vf-ende)
@@ -10684,7 +10869,9 @@
"vfl-m3-warnung-fueller-ausgang-zu-kurz")
(list (rtos fill-len 2 0) (rtos *vfk-restlaenge-min-clamp* 2 0)))))
(setq fill-len (max *vfk-restlaenge-min-clamp* fill-len))
(vf-vfhoehe-merke pt)
(setq pt (insert-inclined-scaled-block "Staustrecke_SP_1000_mm" pt fill-len 0 seg-hz))
(vf-vfhoehe-schliesse pt)
(vfl-acc-vf-seg "horizontal" 0 fill-len) (setq anzahl-vf (1+ anzahl-vf))
(setq letzt-koerper-hz seg-hz))
;; --- Vario-Kurve (flach, direkt bei 0 Grad) ---
@@ -10693,8 +10880,10 @@
(progn (setq pt (vfl3-flach-ein pt letzt-koerper-hz)) (setq flat-p t)
;; Fueller-A: der im Kletter-Segment durch 1/2 GF1 frei werdende Platz
(if (and (> filler-A-len 0.1) (not filler-a-done))
(progn (setq pt (insert-inclined-scaled-block "Staustrecke_SP_1000_mm"
(progn (vf-vfhoehe-merke pt)
(setq pt (insert-inclined-scaled-block "Staustrecke_SP_1000_mm"
pt filler-A-len 0 letzt-koerper-hz))
(vf-vfhoehe-schliesse pt)
(vfl-acc-vf-seg "horizontal" 0 filler-A-len)
(setq anzahl-vf (1+ anzahl-vf) filler-a-done t)))))
(setq bwinkel (nth 3 seg) bseite (nth 4 seg) kv-variante (nth 6 seg))
@@ -11230,6 +11419,12 @@
(setq gemessen (vfl-kette-neigung (vfl-kette-rec-ein entry-info) (vfl-kette-rec-aus rec)))
(setq betrag (vfl-kette-round (abs gemessen)))
(setq richtung (if (< gemessen 0.0) "Auf" "Ab"))))
;; Hoehe dieses Segments aus DENSELBEN Punkten, aus denen auch
;; die Laenge kommt (Ende des Eingangsbogens bis Anfang des
;; Ausgangsbogens) - dadurch bleiben VF_HOEHE_m und L_VF_m auch
;; beim Rekonstruieren aus bestehenden Bloecken gleich lang.
(vf-vfhoehe-segment (caddr (vfl-kette-rec-aus entry-info))
(caddr (vfl-kette-rec-ein rec)))
(vfl-acc-vf-seg richtung betrag
(distance (vfl-kette-rec-aus entry-info) (vfl-kette-rec-ein rec)))
(setq entry-info nil)
@@ -11286,6 +11481,8 @@
(cons "L_VF_m" (vfl-join-komma *vfl-acc-lvf*))
(cons "ANTRIEBFAHRTRICHTUNG" (vfl-join-komma *vfl-acc-richtung*))
(cons "VF_WINKEL" (vfl-join-komma *vfl-acc-winkel*))
;; Hoehe je Foerdereinheit - siehe oben.
(cons "VF_HOEHE_m" (vfl-join-komma *vf-acc-vfhoehe*))
(cons "VF_Bogen_A_90" (itoa (vfl-get-count *vfl-acc-variokurve* "A_90")))
(cons "VF_Bogen_A_60" (itoa (vfl-get-count *vfl-acc-variokurve* "A_60")))
(cons "VF_Bogen_A_30" (itoa (vfl-get-count *vfl-acc-variokurve* "A_30")))
+9 -1
View File
@@ -612,9 +612,15 @@
;; beliebig aneinanderreihen (siehe doc/VarioFoerderer_Linienzug_Prinzipien.md).
;; best-winkel=0 => horizontales Sub-Segment (Boegen fest auf_3/ab_3).
(defun vfs-vf-koerper (aktueller-punkt richtung best-winkel L_VF hz /
bogen-name bogen-mass bogen-dx bogen-dz)
bogen-name bogen-mass bogen-dx bogen-dz z-ein)
(if (null hz) (setq hz 0.0))
(setq hz (float hz))
;; Hoehe DIESES VF-Segments (Attribut VF_HOEHE_m, Sivas 4433-4437):
;; KS_EIN ist der Punkt beim Eintritt, KS_AUS der Rueckgabewert am Ende -
;; der Mittelwert beider wird unten angehaengt. Eine Kette mit drei durch
;; Vario-Boegen getrennten Abschnitten bekommt dadurch drei Werte, parallel
;; zu L_VF_m und VF_WINKEL (Nutzer-Vorgabe 2026-10-21).
(setq z-ein (caddr aktueller-punkt))
;; 5. 1. Vertikalbogen
;; Sonderfall best-winkel=0 (horizontale Zwischenstrecke, siehe
@@ -717,6 +723,8 @@
)
)
;; Segment-Hoehe anhaengen: Mittelwert aus KS_EIN (z-ein) und KS_AUS.
(vf-vfhoehe-segment z-ein (caddr aktueller-punkt))
aktueller-punkt
)