fix: VF-Linienzug - ES-Fussabdruck laengs korrekt reservieren + Endpunkt per Ziellinie

Drei zusammenhaengende Korrekturen am GF-Zweig mit ES-Element (Modus 1).

1) ES-Fussabdruck wurde massiv unterschaetzt (333.65 mm zu lang)

   Reserviert wurde (abs ein-dx) - die Block-X-Komponente aus
   vf-element-masse. Ein Element wird aber so gedreht eingebaut, dass sein
   KS_EIN auf der Fahrtrichtung liegt; beim drehenden ES_Element_30
   (ein-ang=120 Grad) landet dadurch ein Teil der Block-Y-Komponente auf der
   Fahrtachse. Real verbraucht es laengs 576.2 mm statt der reservierten
   242.6 mm - die Kette ragte um die Differenz ueber den gepickten Endpunkt
   hinaus (Nutzer-Befund 2026-10-09).

   Warum das lange unentdeckt blieb: beim ES_Element_90 ist ein-ang=0, dort
   ist (abs ein-dx) ZUFAELLIG richtig. Der frueher bestaetigende 90-Grad-Test
   konnte den Fehler strukturell nicht finden (Nutzer-Hinweis).

   Neu in vf_core.lsp: vf-element-laengs / vf-element-quer (hz-unabhaengige
   Projektion auf bzw. quer zur Fahrtrichtung), vf-set-es-masse setzt
   zusaetzlich ein-laengs / ein-quer. In vf_linienzug.lsp liest vfl-es-laengs
   den Wert mit Rueckfallkette; ein bewusst genulltes ein-dx gewinnt dabei,
   damit die rund zwei Dutzend Null-/Restore-Stellen keinen Doppelabzug
   bekommen.

   In BricsCAD bestaetigt: Separator+ES verbrauchen 875.83 mm gegen 875.79 mm
   Soll (0.04 mm), Hoehe 151.23 gegen 151.20 mm.

2) Endpunkt per Ziellinie statt per Klick

   Steht die Fahrtrichtung durch den Vorgaenger fest, ist die Laenge nicht
   mehr frei: die (um den ES-Querversatz seitlich versetzte) Bahn des
   ES-KS_AUS trifft eine Ziellinie in genau einem Punkt. Ein Klick kann den
   nur annaehern. Neue Frage mit zwei gleichwertigen Optionen (Radio-Buttons
   im Wizard-Modus): Ziellinie durch ZWEI PUNKTE zeichnen - Schnittpunkt wird
   gerechnet - oder wie bisher einen Punkt waehlen.

   REIN PLANAR: die Hoehe kommt weiterhin aus dem Gefaellewinkel, die
   Ziellinie bestimmt nur X/Y (Nutzer-Praezisierung).

   Beide Wege schreiben denselben einzelnen "DL"-Journaleintrag - Replay,
   Doppelklick-Edit und 2D/3D-Konvertierung muessen von Ziellinien nichts
   wissen. Die Bindung an die Linie besteht nur beim Bauen: wird die Linie
   spaeter verschoben, folgt die Kette NICHT.

   Abwaertskompatibilitaet: die neue Frage erzeugt einen zusaetzlichen
   Journaleintrag, den aeltere Ketten nicht haben. vfl-replay-peek-art sieht
   beim Replay nach, was tatsaechlich ansteht; steht dort ein "DL", ist es
   ein Altbestand und die Frage entfaellt - sonst haette sie den Laengenwert
   als Antwort verschluckt (Queue-Desync).

3) Bedienung: Achsenzwang und ruhige Ansicht

   vfl-getpoint-achse zwingt den Cursor beim Picken auf die Anschlussachse
   (SNAPANG + ORTHOMODE, kein BKS-Wechsel - getpoint liefert daher
   unveraenderte Koordinaten). Nur die horizontale Richtung wird erzwungen,
   die Hoehe bleibt frei.

   vfl-view-refresh zoomte vor JEDER Laengeneingabe hart auf _Extents - die
   Ansicht sprang bei grossen Anlagen nach jedem Klick weg. Jetzt wird nur
   noch eingegriffen, wenn der Baupunkt aus dem sichtbaren Ausschnitt laeuft,
   und dann per _ZOOM _Center unter Beibehaltung der Zoomstufe.

13 neue Unit-Tests (etage-laengs/-quer,
vfl-es-laengs, vfl-kreuz2, vfl-laenge-bis-ziellinie inkl. Realfall aus dem
BricsCAD-Log), Suite 533/533 gruen. lang-Paritaet geprueft.

Offen und bewusst nicht angefasst: vfl-winkel-machbar-p nutzt aus-dx/ein-dx
ebenfalls als Laengsmass und hat damit denselben Fehler (AS_30: 276 mm,
ES_30: 334 mm). Der saubere Fix fuellt ein-dx/aus-dx an der Quelle mit dem
Laengswert - das beruehrt rund 87 Fundstellen samt ihrer Null-/Restore-
Konvention und gehoert separat getestet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-10-14 09:04:57 +02:00
parent 8039251bb8
commit 821b81135d
5 changed files with 631 additions and 32 deletions
+90 -1
View File
@@ -360,6 +360,95 @@
)
;; ------------------------------------------------------------
;; TESTS: vf_linienzug.lsp - ES-Fussabdruck entlang der Fahrtrichtung
;; ------------------------------------------------------------
;; vfl-es-laengs liefert die Laenge, die ein Segment fuer das ES-Element
;; reservieren muss. Getestet wird die Rueckfallkette: ohne sie wuerde ein
;; fehlender Messwert zu (- deltaL nil) und damit zum Absturz fuehren.
(defun tu-tests-vfl-es ( / _s-laengs _s-dx)
(princ "\n[vf_linienzug ES]")
;; globale Masse sichern - sie gehoeren dem laufenden Bau-Kontext
(setq _s-laengs ein-laengs _s-dx ein-dx)
;; Normalfall: ein-laengs ist gesetzt und wird genommen.
;; 576.2 = ES_Element_30_rechts entlang der Fahrtrichtung; (abs ein-dx)
;; waere 242.6 - genau die 333.65 mm, um die die Kette frueher zu weit ragte.
(setq ein-laengs 576.2 ein-dx -242.6)
(tu-eqf "vfl-es-laengs/nimmt-laengs-nicht-dx" 576.2 (vfl-es-laengs))
;; Vorzeichen: reserviert wird immer ein Betrag
(setq ein-laengs -576.2)
(tu-eqf "vfl-es-laengs/betrag" 576.2 (vfl-es-laengs))
;; Genulltes ein-dx gewinnt: die Null-Konvention der Bau-Pfade bedeutet
;; "ES anderswo schon beruecksichtigt - hier nichts reservieren". Ohne diese
;; Kopplung wuerde der Fix einen doppelten Abzug einbauen.
(setq ein-laengs 576.2 ein-dx 0.0)
(tu-eqf "vfl-es-laengs/genulltes-dx-gewinnt" 0.0 (vfl-es-laengs))
;; KS nicht lesbar -> Rueckfall auf das alte (zu kleine) Blockmass
(setq ein-laengs nil ein-dx -242.6)
(tu-eqf "vfl-es-laengs/fallback-auf-dx" 242.6 (vfl-es-laengs))
;; gar nichts gemessen -> 0.0, niemals nil (Absturzschutz)
(setq ein-dx nil)
(tu-eqf "vfl-es-laengs/fallback-null" 0.0 (vfl-es-laengs))
(setq ein-laengs _s-laengs ein-dx _s-dx)
)
;; ------------------------------------------------------------
;; TESTS: vf_linienzug.lsp - Laenge aus einer Ziellinie (X/Y)
;; ------------------------------------------------------------
;; Steht die Fahrtrichtung fest, ist die Laenge nicht mehr frei: die (ggf.
;; seitlich versetzte) Bahn trifft die Ziellinie in genau einem Punkt.
;; REIN PLANAR - die Hoehe kommt weiterhin aus dem Gefaellewinkel.
(defun tu-tests-vfl-ziellinie ( / _p0 _l _ks)
(princ "\n[vf_linienzug Ziellinie]")
(tu-eqf "vfl-kreuz2/einheitsachsen" 1.0 (vfl-kreuz2 1.0 0.0 0.0 1.0))
(tu-eqf "vfl-kreuz2/parallel" 0.0 (vfl-kreuz2 2.0 4.0 1.0 2.0))
(setq _p0 '(0.0 0.0 0.0))
;; Fahrtrichtung 0 Grad, senkrechte Ziellinie bei x=1000 -> L=1000
(tu-eqf "vfl-laenge-bis-ziellinie/senkrecht"
1000.0 (vfl-laenge-bis-ziellinie _p0 0.0 0.0 '(1000.0 -500.0 0.0) '(1000.0 500.0 0.0)))
;; Querversatz verschiebt die BAHN seitlich, nicht laengs: bei einer zur
;; Fahrtrichtung senkrechten Ziellinie bleibt L deshalb gleich.
(tu-eqf "vfl-laenge-bis-ziellinie/querversatz-ohne-wirkung"
1000.0 (vfl-laenge-bis-ziellinie _p0 0.0 52.5 '(1000.0 -500.0 0.0) '(1000.0 500.0 0.0)))
;; 45-Grad-Ziellinie durch (1000,0): die um +100 versetzte Bahn trifft sie
;; 100 frueher (y=100 wird bei x=1100 erreicht -> ohne Versatz 1000+100).
(tu-eqf "vfl-laenge-bis-ziellinie/schraege-linie"
1100.0 (vfl-laenge-bis-ziellinie _p0 0.0 100.0 '(1000.0 0.0 0.0) '(2000.0 1000.0 0.0)))
;; Ziellinie PARALLEL zur Fahrtrichtung -> kein eindeutiger Treffer -> nil
(tu-nil "vfl-laenge-bis-ziellinie/parallel"
(vfl-laenge-bis-ziellinie _p0 0.0 0.0 '(0.0 500.0 0.0) '(1000.0 500.0 0.0)))
;; Z der Ziellinie ist irrelevant (rein planare Rechnung, Nutzer-Vorgabe):
;; dieselbe Linie auf anderer Hoehe liefert dasselbe L.
(tu-eqf "vfl-laenge-bis-ziellinie/z-ignoriert"
1000.0 (vfl-laenge-bis-ziellinie _p0 0.0 0.0 '(1000.0 -500.0 7777.0) '(1000.0 500.0 -99.0)))
;; Realfall aus dem Nutzer-Log: nach dem 30-Grad-Bogen steht die Kette bei
;; (901.21,-2728.97) mit hz=-120; das ES-KS_AUS laeuft 52.51 mm versetzt und
;; landete bei (231.42,-3994.11). Eine Ziellinie durch diesen Punkt quer zur
;; Fahrtrichtung muss genau die damals gebaute Gesamtlaenge liefern.
(setq _ks '(231.42 -3994.11 0.0))
(setq _l (vfl-laenge-bis-ziellinie '(901.21 -2728.97 0.0) -120.0 52.51
_ks (list (+ (car _ks) (cos (/ pi 6.0))) ; 30 Grad = quer zu -120
(+ (cadr _ks) (sin (/ pi 6.0))) 0.0)))
(tu-true "vfl-laenge-bis-ziellinie/realfall-plausibel"
(and _l (> _l 1430.0) (< _l 1431.0)))
)
;; ------------------------------------------------------------
;; TESTS: export.lsp - CSV/KOS-Kodierung
;; ------------------------------------------------------------
@@ -2138,7 +2227,7 @@
(princ "\n================================================================")
(foreach fn '("tu-tests-core" "tu-tests-lang" "tu-tests-id" "tu-tests-vfcore"
"tu-tests-etage"
"tu-tests-etage" "tu-tests-vfl-es" "tu-tests-vfl-ziellinie"
"tu-tests-export" "tu-tests-hoehen" "tu-tests-gf" "tu-tests-omni" "tu-tests-kreisel" "tu-tests-kreisel-bp"
"tu-tests-sepliste" "tu-tests-json" "tu-tests-geruest"
"tu-tests-sepscan" "tu-tests-vfl-segs" "tu-tests-vfl-abbruch"