test: U-Form-Faelle, Formkriterium laengs und Reihenanordnung der Linienzug-Tests
Drei neue Modus-2-Testfaelle aus echten Laeufen, ein Kriterium, das eine
heute eingebaute Fehlgeometrie gefunden haette, und ein aufgeraeumtes
Layout der Testketten.
1. Drei U-Form-Faelle (tests/testdata/linienzug_modus2_uform_*.json),
aufgezeichnet mit lib/vf_journal_export.py. Gefaltete Laeufe: der Pfad
wechselt ueber zwei 90-Grad-Vario-Kurven dreimal die Fahrtrichtung, die
Kletterstrecke liegt in einem ANDEREN Schenkel als der Lauf-Eingang -
genau der am 2026-10-29 korrigierte Fall. Variiert werden GF-Verteilung
(alles am Einlauf vs. 1/2+1/2) und Winkel; beides ist noetig, weil die
Verteilung entscheidet, ob ueberhaupt GF im fremden Schenkel steht, und
der Restfehler der alten Bilanz mit L_GF skalierte.
c:TEST_LINIENZUG_MODUS2 ist dafuer tabellengesteuert - ein weiterer Fall
ist jetzt eine Zeile in *tlz-m2-faelle*.
2. RUECKNAHME des Schluss-Solves (vfl-zsolve-schluss-ziel, heute frueh
eingebaut). Er loeste den letzten Fueller gegen Richtung UND Laenge und
traf den Zielpunkt dadurch in X und Y exakt - um den Preis, dass er die
letzte Gerade um 6.15 Grad verdrehte (hz-plan -90 -> -96.15), in der
Zeichnung als schiefer Schenkel sichtbar. Das widerspricht der
Entscheidung vom 2026-10-26: quer MUSS 0 sein, LAENGS DARF ABWEICHEN -
der Hauptstrang bleibt gerade, der seitliche Versatz des ES-Elements ist
dessen Bauform. Die Messwerte von heute (0.56 / 0.7 mm quer) stammen
nicht von dieser Aenderung, sondern von der Laengenbilanz des gefalteten
Laufs (35ebee1) - der Zweig blieb dort ungenutzt. Die Begruendung steht
jetzt an der Aufrufstelle, damit niemand den Solve erneut baut.
3. laengs wird geprueft - als FORM-, nicht als Genauigkeitskriterium
(erwartung_laengs_mm, Toleranz 5 mm). Der Wert ist die Ausladung des
ES-Elements und je Fall eine Konstante (104.68 bei ES_Element_30,
637.58 bei ES_Element_90). Punkt 2 war am Querwert NICHT erkennbar - die
Verdrehung macht ihn gerade null, der Test meldete OK, gefunden wurde sie
mit dem Auge. Ein verdrehter Hauptstrang zielt auf den Endpunkt und
drueckt laengs auf ~0; daran faellt er auf. Gegengeprueft: mit kuenstlich
auf 0.01 mm gesetzter Toleranz kippen alle fuenf Faelle auf ABWEICHUNG.
4. Alle sieben Ketten des Menueeintrags entstehen als Reihe auf Y=0, 20 m
Abstand, statt verstreut. Die Modus-1-Skripte brauchen dafuer nur ihren
EINEN point_abs (alles Weitere ist point_rel mit dL/hz); bei Modus 2
mussten PT-Eintraege UND die Pfadkoordinaten in SEGS (Felder 6..9)
mitwandern, sonst zeigt der Pfad woanders hin als Start und Ziel.
Reine Translation - Laengen, Winkel und die geprueften Abweichungen sind
davon unabhaengig; Z blieb stehen, weil die Starthoehe ein Eingabewert
des Solvers ist. Geprueft: erstes Segment beginnt exakt am Startpunkt,
letztes endet exakt am Zielpunkt, Messwerte unveraendert.
5. Die drei letzten Verweise auf doc/VarioFoerderer_Linienzug_Prinzipien.md
(bewusst unversioniert) tragen ihre Begruendung jetzt selbst: Entkopplung
Neigung/XY, warum es genau EINEN Kletterer je Lauf gibt, und warum ein
VF-Sub-Segment auf der 3-Grad-Basis beginnen und enden muss.
Geprueft: TEST_UNIT 897/897 (die 7 Tests der entfernten Funktion sind mit
ihr gegangen), TEST_LINIENZUG_MODUS2 5 von 5 OK, voller Menueablauf baut
sieben Ketten an den vorgesehenen Stellen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+62
-88
@@ -11173,8 +11173,22 @@
|
||||
;; aus einer Planungsphase vor der endgueltigen Menue-Zuordnung stammen. Seit
|
||||
;; der Umbenennung tragen sie darum gar keine Modus-Nummer mehr, sondern ihre
|
||||
;; ROLLE: sie rechnen die Hoehen (Z) durch, waehrend der Grundriss (XY) vom
|
||||
;; gezeichneten Pfad kommt. Genau diese Entkopplung macht das Randwertproblem
|
||||
;; loesbar (siehe doc/VarioFoerderer_Linienzug_Prinzipien.md, Abschnitt 14.1).
|
||||
;; gezeichneten Pfad kommt.
|
||||
;;
|
||||
;; Genau diese Entkopplung macht das Randwertproblem loesbar, und sie beruht
|
||||
;; auf einer Eigenschaft der Bauteile: die Neigung eines Teils aendert seine
|
||||
;; HOEHE, aber nicht seinen XY-FUSSABDRUCK. Ein Staustrecken-Teil mit
|
||||
;; Planlaenge L belegt in der Draufsicht immer L - die 3D-Laenge waechst auf
|
||||
;; L/cos(w), die Projektion bleibt L. Z-Ziel und Pfadtreue sind damit zwei
|
||||
;; unabhaengige Probleme und duerfen nacheinander geloest werden:
|
||||
;; XY = gezeichneter Pfad, reine KS-Kettung (wie Modus 3, mm-Drift akzeptiert)
|
||||
;; Z = gerechnet, sodass das Kettenende die Ziel-Hoehe EXAKT trifft
|
||||
;; Daher auch die zwei Phasen von vf-linienzug-modus2: erst alle Hoehen
|
||||
;; durchrechnen, dann bauen.
|
||||
;;
|
||||
;; (Zum Gegensatz Modus 2 / Modus 3: Modus 3 baut vorwaerts, seine Endhoehe ist
|
||||
;; ein ERGEBNIS - ein Anfangswertproblem. Modus 2 kennt Start UND Ziel je in
|
||||
;; X/Y/Z und rechnet die Zwischenhoehen - ein Randwertproblem.)
|
||||
;;
|
||||
;; Gegenstueck: die vfl-pfad-*-Helfer weiter oben arbeiten auf dem
|
||||
;; gezeichneten Pfad selbst (Eckwinkel pruefen, AS einfuegen, VF oeffnen/
|
||||
@@ -11590,60 +11604,6 @@
|
||||
(- (/ (- ep-na (* perp-es np-na)) dp-na) cc)
|
||||
100.0))))
|
||||
|
||||
;; --- Schlussstueck: RICHTUNG und LAENGE gemeinsam aus der IST-Lage loesen ---
|
||||
;; Nutzer-Vorgabe 2026-10-29: "nach der zweiten VF-Kurve den passenden Winkel
|
||||
;; neu aus dem KS_AUS der Kurve und dem Zielpunkt rechnen".
|
||||
;;
|
||||
;; Warum das noetig ist: vfl-zsolve-es-fueller loest NUR die Laenge und
|
||||
;; uebernimmt die Richtung unveraendert aus dem gezeichneten Pfad. Eine Laenge
|
||||
;; verschiebt die Kette aber ausschliesslich ENTLANG ihrer Achse. Steht der
|
||||
;; reale Kurvenausgang seitlich NEBEN der gezeichneten Geraden - und das tut er,
|
||||
;; sobald die echten Eck-Bauteile nicht in die gezeichnete Ecke passen -, dann
|
||||
;; laeuft die gebaute Achse PARALLEL zur Zielachse, und kein Fuellerwert der
|
||||
;; Welt holt den Querversatz noch ein (realer Befund 2026-10-29: waagerechte
|
||||
;; Kette, zwei 90-Grad-Vario-Kurven mit nur 269.9 mm gezeichnetem Zwischenstueck
|
||||
;; -> 637.6 mm quer, 1424.4 mm laengs daneben).
|
||||
;;
|
||||
;; Gibt man die Richtung mit frei, stehen zwei Unbekannte (fill, hz) zwei
|
||||
;; Gleichungen (X und Y des Zielpunkts) gegenueber - geschlossen loesbar, ohne
|
||||
;; Iteration. Der Schwanz (Fueller + ab_3 + Motor + GF2 + Separator + ES) ist
|
||||
;; starr; im Rahmen von hz hat sein Endpunkt die festen Komponenten
|
||||
;; (fill + C) laengs und P quer.
|
||||
;; Beide sind von hz UNABHAENGIG: vfl-zsolve-es-vektor dreht den ES-Vektor und
|
||||
;; den Bezugsrahmen um denselben Winkel. Also ist D = Ziel - pt genau der um hz
|
||||
;; gedrehte Vektor (fill + C, P), woraus folgt:
|
||||
;; A = sqrt(|D|^2 - P^2) (Laengskomponente, Pythagoras)
|
||||
;; fill = A - C
|
||||
;; hz = Winkel(D) - atan2(P, A)
|
||||
;; Damit wird der Zielpunkt in X UND Y exakt getroffen, nicht nur die ES-Achse.
|
||||
;;
|
||||
;; Das Schlussstueck weicht danach bewusst von der gezeichneten Richtung ab -
|
||||
;; genau im Sinn des Leitsatzes bei vfl-eck-korrekturen: massgeblich ist die
|
||||
;; reale Bauteilkette, der gezeichnete Pfad ist nur Hinweis.
|
||||
;;
|
||||
;; es-block = ES-Blockname oder nil (dann ohne ES-Element, P = 0).
|
||||
;; Rueckgabe: (fill hz-grad) oder nil, wenn der Zielpunkt naeher liegt als der
|
||||
;; Querversatz - dann gibt es keine Loesung und der Aufrufer faellt auf den
|
||||
;; bisherigen Weg (Richtung aus dem Plan) zurueck.
|
||||
(defun vfl-zsolve-schluss-ziel (pt endp seg-hz es-block gf2 rad3 /
|
||||
vek cc pp p0 p1 dd aa)
|
||||
(setq vek (if es-block (vfl-zsolve-es-vektor es-block seg-hz) nil))
|
||||
(if vek
|
||||
(setq cc (+ 196.0 (* (+ *vfk-feste-horizontal-kettenende* gf2) (cos rad3)) (car vek))
|
||||
pp (cadr vek))
|
||||
(setq cc (* (+ *vfk-stations-laenge* gf2) (cos rad3))
|
||||
pp 0.0))
|
||||
(setq p0 (list (car pt) (cadr pt))
|
||||
p1 (list (car endp) (cadr endp)))
|
||||
(setq dd (distance p0 p1))
|
||||
(if (<= dd (+ (abs pp) 1.0))
|
||||
nil
|
||||
(progn
|
||||
(setq aa (sqrt (- (* dd dd) (* pp pp))))
|
||||
(list (- aa cc)
|
||||
(- (/ (* 180.0 (angle p0 p1)) pi)
|
||||
(/ (* 180.0 (atan pp aa)) pi))))))
|
||||
|
||||
(defun vf-linienzug-modus2 ( / ss k obj-liste startpunkt start-hoehe as-seite
|
||||
endpunkt end-hoehe es-seite kette segmente segmente9 n i seg
|
||||
seg-ent
|
||||
@@ -11666,7 +11626,6 @@
|
||||
longest-idx climbers nonclimber-len
|
||||
nonclimber-cnt nkurve kurve-chords run-span
|
||||
hor-koerper-len hor-pairs flat-p flat-zone-erste fill-len wahl3
|
||||
schluss
|
||||
rad3v feste-vf dH-adj dir-x dir-y fill-D end-hz
|
||||
laengs-wert quer-wert soll-korrigiert
|
||||
es-vek-fix es-along-fix as-along-fix m-ueb
|
||||
@@ -12362,7 +12321,21 @@
|
||||
;; ohnehin auf den Zielpunkt rechnet (vfl-zsolve-es-fueller).
|
||||
;;
|
||||
;; *vfl-min-climber-laenge* wird dadurch fuer die Auswahl nicht mehr
|
||||
;; gebraucht (siehe doc/VarioFoerderer_Linienzug_Prinzipien.md, Abschnitt 14).
|
||||
;; gebraucht: es gibt keine Schwelle "ab welcher Laenge ist eine Gerade ein
|
||||
;; Kletterer", sondern genau EINEN Kletterer je Lauf - die laengste.
|
||||
;;
|
||||
;; Grund ist das Modell dahinter: jede VF-Strecke im Pfad ist eine
|
||||
;; Standard-VF-Einheit ohne eigenes AS/ES, also GF1 + Separator +
|
||||
;; Umlenkstation + Vario-Koerper + Motorstation + GF2. Alle Teile liegen
|
||||
;; kolinear auf derselben Pfad-Geraden; variieren ihre Laengen, verschieben
|
||||
;; sich nur die inneren Grenzen, die Enden der Bruecke bleiben fix. Je
|
||||
;; Bruecke steht damit ein 2-Gleichungs-System:
|
||||
;; Summe der Planlaengen = gezeichnete Spannweite (aus dem Pfad)
|
||||
;; Summe der Hoehenaenderung = delta-H zwischen den Ankern
|
||||
;; Freie Variablen: Vario-Winkel (diskret) + GF1-Laenge + GF2-Laenge. Genau
|
||||
;; das loest der vorhandene Solver (berechne-alle-winkel) - und er kennt
|
||||
;; EINEN Vario-Koerper. Mehrere Kletterer passen deshalb nicht ins Modell,
|
||||
;; unabhaengig von ihrer Laenge.
|
||||
(setq longest-idx -1 i vf-start)
|
||||
(while (<= i vf-ende)
|
||||
(setq seg (nth i plan))
|
||||
@@ -12817,36 +12790,37 @@
|
||||
;; Separator + ES kuemmert sich der Back-Lauf selbst (siehe dort die
|
||||
;; last-line-Reservierung).
|
||||
(if (and (= i vf-ende) (= vf-ende (1- n)))
|
||||
;; Letztes Segment UND Pfadende: RICHTUNG und LAENGE des Schlussstuecks
|
||||
;; gemeinsam aus der IST-Lage loesen (vfl-zsolve-schluss-ziel), statt
|
||||
;; die Richtung aus dem gezeichneten Pfad zu uebernehmen und nur die
|
||||
;; Laenge zu loesen. Damit wird der Zielpunkt in X UND Y getroffen;
|
||||
;; ein Querversatz, den die realen Eck-Bauteile vorher aufgebaut haben,
|
||||
;; wird hier eingefangen statt bis ans Kettenende mitgeschleppt.
|
||||
;; Scheitert der Solve (Ziel liegt naeher als der ES-Querversatz),
|
||||
;; bleibt es beim bisherigen Weg: Richtung aus dem Plan, Laenge so, dass
|
||||
;; der Endpunkt auf der ES-KS_AUS-Achse liegt (Spiegel der AS-Regel) -
|
||||
;; bzw. ohne ES-Element direkt auf den Endpunkt.
|
||||
(progn
|
||||
(setq schluss (vfl-zsolve-schluss-ziel pt endpunkt seg-hz
|
||||
(if es-vorhanden
|
||||
(strcat "ES_Element_" (vfl-es-winkel) "_" es-seite))
|
||||
br-gf2-exp rad3v))
|
||||
(if schluss
|
||||
(progn
|
||||
(dbgmsg (strcat "SCHLUSS-SOLVE hz-plan=" (rtos seg-hz 2 3)
|
||||
" hz-neu=" (rtos (cadr schluss) 2 3)
|
||||
" fill=" (rtos (car schluss) 2 1)))
|
||||
(setq fill-len (car schluss)
|
||||
seg-hz (cadr schluss)))
|
||||
(setq fill-len
|
||||
(if es-vorhanden
|
||||
(vfl-zsolve-es-fueller pt endpunkt seg-hz
|
||||
(strcat "ES_Element_" (vfl-es-winkel) "_" es-seite)
|
||||
br-gf2-exp rad3v)
|
||||
(- (+ (* (- (car endpunkt) (car pt)) (cos (* seg-hz (/ pi 180.0))))
|
||||
(* (- (cadr endpunkt) (cadr pt)) (sin (* seg-hz (/ pi 180.0)))))
|
||||
(* (+ *vfk-stations-laenge* br-gf2-exp) (cos rad3v)))))))
|
||||
;; letzter Fueller, MIT ES-Element: Laenge so, dass der ENDPUNKT auf
|
||||
;; der ES-KS_AUS-ACHSE liegt (Spiegel der AS-Regel). Der Schwanz
|
||||
;; (Fueller + ab_3 + Motor + GF2 + Separator + ES) verschiebt sich
|
||||
;; starr entlang seg-hz mit dem Fueller; KS_AUS = pt + (fill + C)*dp +
|
||||
;; perp-es*np, Achse u_a = seg-hz + ES-Turn. Aus (Endpunkt -
|
||||
;; KS_AUS)*n_a = 0 folgt fill (n_a senkrecht zu u_a). OHNE ES-Element
|
||||
;; (Nutzerwunsch): keine Achsen-Korrektur noetig, da nach Motor+GF2
|
||||
;; nichts mehr gebaut wird - Fueller zielt direkt auf den Endpunkt.
|
||||
;;
|
||||
;; HIER WIRD NUR DIE LAENGE GELOEST, NIE DIE RICHTUNG. Am 2026-10-29
|
||||
;; stand an dieser Stelle ein Solve, der beides freigab und damit den
|
||||
;; Zielpunkt in X UND Y exakt traf (vfl-zsolve-schluss-ziel, wieder
|
||||
;; entfernt). Rechnerisch war er korrekt - und trotzdem falsch: er
|
||||
;; erreicht den Querausgleich, indem er die letzte Gerade dreht. Im
|
||||
;; U-Form-Testfall waren das 6.15 Grad (hz-plan -90 -> -96.15), in der
|
||||
;; Zeichnung sofort als schiefer Schenkel sichtbar.
|
||||
;; Das widerspricht der Entscheidung vom 2026-10-26: quer zur
|
||||
;; KS_AUS-Achse MUSS 0 sein, LAENGS DARF ABWEICHEN - der Hauptstrang
|
||||
;; bleibt gerade, der seitliche Versatz des ES-Elements ist dessen
|
||||
;; Bauform und kein Fehler. Beides zugleich geht nicht.
|
||||
;; Wichtig fuer kuenftige Tests: eine solche Verdrehung ist am
|
||||
;; Querwert NICHT erkennbar (sie macht ihn gerade null) - nur an der
|
||||
;; Zeichnung bzw. am Vergleich von seg-hz mit dem Planwinkel.
|
||||
(setq fill-len
|
||||
(if es-vorhanden
|
||||
(vfl-zsolve-es-fueller pt endpunkt seg-hz
|
||||
(strcat "ES_Element_" (vfl-es-winkel) "_" es-seite)
|
||||
br-gf2-exp rad3v)
|
||||
(- (+ (* (- (car endpunkt) (car pt)) (cos (* seg-hz (/ pi 180.0))))
|
||||
(* (- (cadr endpunkt) (cadr pt)) (sin (* seg-hz (/ pi 180.0)))))
|
||||
(* (+ *vfk-stations-laenge* br-gf2-exp) (cos rad3v)))))
|
||||
;; Gewoehnlicher Fueller: volle Planlaenge des Segments, abzueglich
|
||||
;; der fest gebauten Teile, die auf GENAU diesem Segment stehen -
|
||||
;; das AS am Laufanfang, Abschlussbogen + Motorstation am Laufende,
|
||||
|
||||
Reference in New Issue
Block a user