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
+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