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
+61 -3
View File
@@ -682,9 +682,67 @@
(defun vf-set-as-masse (winkel seite / m)
(setq m (vf-element-masse (strcat "AS_Element_" winkel "_" seite)))
(if m (setq aus-dx (car m) aus-dy (cadr m) aus-dz (caddr m))))
(defun vf-set-es-masse (winkel seite / m)
(setq m (vf-element-masse (strcat "ES_Element_" winkel "_" seite)))
(if m (setq ein-dx (car m) ein-dy (cadr m) ein-dz (caddr m))))
;; Fussabdruck eines Elements ENTLANG der Fahrtrichtung (Laengsanteil).
;;
;; Warum das nicht (car (vf-element-masse ...)) ist: vf-element-masse liefert
;; KS_EIN->KS_AUS im BLOCK-Koordinatensystem. Ein Element wird aber so gedreht
;; eingebaut, dass sein KS_EIN auf der Fahrtrichtung liegt (insert-block-ks-to-ks
;; bzw. insert-block-by-ks mit (hz - ein-ang)). Bei einem drehenden Element -
;; ES_Element_30 hat ein-ang = 120 Grad - landet dadurch ein TEIL der
;; Block-Y-Komponente auf der Fahrtrichtung, und die Block-X-Komponente allein
;; unterschaetzt den Laengsverbrauch massiv: beim ES_Element_30_rechts 242.6 mm
;; statt tatsaechlich 576.2 mm (realer Bug, Nutzer-Befund 2026-10-09: die Kette
;; ragte 333.65 mm ueber den gepickten Endpunkt hinaus).
;;
;; Die Projektion ist hz-UNABHAENGIG (der Einbauwinkel kuerzt sich heraus), sie
;; haengt nur am blockinternen ein-ang:
;; laengs = vx*cos(ein-ang) + vy*sin(ein-ang)
;; Gleiche Rechnung wie etage-laengs in vf_etage.lsp mit d = -ein-ang, dort fuer
;; die Rand-Bilanz des Etage-Typs.
;;
;; Rueckgabe: Laenge in mm, oder nil wenn der Block/sein KS fehlt (Aufrufer
;; faellt dann auf das alte Verhalten zurueck).
(defun vf-element-laengs (blockname / i rad)
(setq i (vf-element-ks-info blockname))
(if (null i)
nil
(progn
(setq rad (* (car i) (/ pi 180.0)))
(+ (* (caddr i) (cos rad)) (* (cadddr i) (sin rad))))))
;; Gegenstueck zu vf-element-laengs: Versatz QUER zur Fahrtrichtung.
;; quer = -vx*sin(ein-ang) + vy*cos(ein-ang)
;; Ebenfalls hz-unabhaengig. Beim ES_Element_30 sind das rund -52.5 mm - der
;; seitliche Versatz, mit dem das ES-KS_AUS neben der Fahrtachse landet. Er
;; wird NICHT ausgeglichen (der Hauptstrang bleibt gerade, Nutzer-Entscheidung
;; 2026-09-15), aber er muss BEKANNT sein: die Bahn des ES-KS_AUS verlaeuft um
;; genau diesen Betrag seitlich versetzt, und nur mit ihm trifft die
;; Schnittpunkt-Rechnung gegen eine Ziellinie die richtige Stelle.
(defun vf-element-quer (blockname / i rad)
(setq i (vf-element-ks-info blockname))
(if (null i)
nil
(progn
(setq rad (* (car i) (/ pi 180.0)))
(+ (* (- (caddr i)) (sin rad)) (* (cadddr i) (cos rad))))))
;; Setzt ein-dx/ein-dy/ein-dz (BLOCK-Koordinaten, fuer Quer-/Hoehenrechnungen)
;; und zusaetzlich ein-laengs: den Fussabdruck ENTLANG der Fahrtrichtung. Wer
;; eine Laenge von deltaL reserviert, nimmt ein-laengs - NICHT (abs ein-dx),
;; siehe vf-element-laengs.
(defun vf-set-es-masse (winkel seite / m blk)
(setq blk (strcat "ES_Element_" winkel "_" seite))
(setq m (vf-element-masse blk))
(if m (setq ein-dx (car m) ein-dy (cadr m) ein-dz (caddr m)))
;; Fallback auf das alte (zu kleine) Mass, wenn das KS nicht lesbar ist -
;; lieber etwas zu kurz reservieren als gar nicht bauen koennen.
(setq ein-laengs (vf-element-laengs blk))
(if (and (null ein-laengs) m) (setq ein-laengs (abs (car m))))
;; ein-quer: seitlicher Versatz des ES-KS_AUS zur Fahrtachse (siehe
;; vf-element-quer). Wird fuer die Ziellinien-Schnittpunktrechnung gebraucht.
(setq ein-quer (vf-element-quer blk))
(if (null ein-quer) (setq ein-quer 0.0))
ein-laengs)
;; ============================================================