diff --git a/Lisp/vf_linienzug.lsp b/Lisp/vf_linienzug.lsp index 914ee50..bca6f2a 100644 --- a/Lisp/vf_linienzug.lsp +++ b/Lisp/vf_linienzug.lsp @@ -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, diff --git a/Lisp/vf_standard.lsp b/Lisp/vf_standard.lsp index 53f3d9d..a33cc53 100644 --- a/Lisp/vf_standard.lsp +++ b/Lisp/vf_standard.lsp @@ -609,7 +609,19 @@ ;; EIN reines VF-Sub-Segment. Wichtig: es BEGINNT und ENDET auf der ;; 3-Grad-Basisneigung, weil Ein- und Ausgangsbogen denselben Winkel haben. ;; Dadurch lassen sich mehrere Sub-Segmente (und Vario-Kurven dazwischen) -;; beliebig aneinanderreihen (siehe doc/VarioFoerderer_Linienzug_Prinzipien.md). +;; beliebig aneinanderreihen. +;; +;; Die Regel dahinter: der Vertikalbogen am ENDE eines VF (vor der +;; Motorstation) hat denselben Winkel wie der am ANFANG (nach der +;; Umlenkstation), und der abschliessende Bogen bringt die Strecke auf 3 Grad +;; NACH UNTEN - weil die Motorstation selbst mit 3 Grad geneigt eingebaut wird +;; und der Anschluss sonst knickt. Dasselbe gilt am anderen Ende: Umlenkstation +;; (VF-Start) und Separator+ES-Element (Kettenende) gibt es hardwareseitig nur +;; fuer die Anfahrt auf dieser Standard-Fallend-Basis; eine Anfahrt auf +;; STEIGENDER Basis ist physisch nicht vorgesehen. +;; Anfang und Ende auf derselben Basis zu halten ist also keine Konvention, +;; sondern die Voraussetzung dafuer, dass zwei Sub-Segmente ueberhaupt +;; aneinanderpassen. ;; 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 z-ein) diff --git a/tests/README.md b/tests/README.md index cf23aae..ce4c51c 100644 --- a/tests/README.md +++ b/tests/README.md @@ -87,7 +87,44 @@ dem gewuenschten Modus: Lauf ohne manuellen Zusatzschritt, aber ohne gleichzeitige visuelle Kontrolle aller Zeichnungen am Ende. Sinnvoll fuer reine CI-artige Validierung. -## Referenzfaelle Linienzug Modus 2 (manuell, mit Soll-Werten) +## Anordnung der Linienzug-Testketten + +Der Menueeintrag **Tests -> Foerderer-Linienzug** faehrt drei Befehle +nacheinander (`TEST_LINIENZUG`, `TEST_LINIENZUG_STUFE2`, +`TEST_LINIENZUG_MODUS2`) und baut dabei **sieben** Ketten. Damit sie +nebeneinander auf einer Grundlinie entstehen statt verstreut, tragen die +Testdaten versetzte Startpunkte - 20 m Abstand, alle auf `Y = 0`: + +| X | Z | Kette | Datei | +|---|---|---|---| +| 0 | 2154 | Modus 1, Standardfall | `linienzug_tests.json` | +| 20000 | 2154 | Modus 1, Stufe-2-Fallback | `linienzug_tests_stufe2.json` | +| 40000 | 0 | Variante A (Vario-Kurve) | `linienzug_modus2_variokurve.json` | +| 60000 | 0 | Variante B (GF-Bogen) | `linienzug_modus2_gfbogen.json` | +| 80000 | 355 | U-Form 1 (GF alles am Einlauf) | `..._uform_gf1.json` | +| 100000 | 711 | U-Form 2 (1/2 + 1/2) | `..._uform_halb.json` | +| 120000 | 709 | U-Form 3 (steilerer Winkel) | `..._uform_halb_steil.json` | + +Die Koordinaten sind also **nicht** die der aufgezeichneten Laeufe, die +uebrige Geometrie schon. Verschoben wurde rein translatorisch: Laengen, +Winkel und die geprueften Abweichungen sind davon unabhaengig. `Z` blieb +jeweils stehen - die Starthoehe ist ein Eingabewert des Solvers, kein +Layout-Parameter. + +Technisch unterscheiden sich die beiden Datenarten: die Modus-1-Skripte +brauchen nur ihren EINEN `point_abs` (alles Weitere ist `point_rel` mit +`dL`/`hz`), waehrend bei Modus 2 sowohl die `PT`-Eintraege ALS AUCH die +Pfadkoordinaten in `SEGS` (Felder 6..9) mitwandern muessen - sonst zeigt der +Pfad woanders hin als Start und Ziel. + +## Referenzfaelle Linienzug Modus 2 (`c:TEST_LINIENZUG_MODUS2`) + +Fuenf aufgezeichnete Laeufe, die als zwei Paare gebildet sind: A/B +unterscheiden die Eck-BAUTEILART, U-Form 1..3 den gefalteten Lauf nach +GF-Verteilung und Winkel. Ausgefuehrt ueber Menue -> Tests -> +Foerderer-Linienzug. + +### Erster und zweiter Fall: Eck-Bauteilart Zwei Laeufe auf **demselben gezeichneten Pfad**, die sich nur in der Segment-Klassifizierung unterscheiden. Sie decken die beiden Eck-Bauteilarten @@ -132,20 +169,71 @@ letzte Gerade auf der gezeichneten Linie und der ES-`KS_AUS` landet seitlich daneben, oder umgekehrt. Entschieden ist: der Hauptstrang bleibt gerade, der seitliche Versatz des ES-Elements ist dessen Bauform und kein Fehler. +**`laengs` wird trotzdem geprueft** - nicht als Genauigkeits-, sondern als +FORMkriterium (`erwartung_laengs_mm` in den Testdaten, Toleranz 5 mm). Der Wert +ist die Ausladung des ES-Elements und damit je Fall eine Konstante: 104.68 mm +bei `ES_Element_30`, 637.58 mm bei `ES_Element_90`. +Grund: am 2026-10-29 loeste ein Experiment den Schluss-Fueller gegen Richtung +UND Laenge und traf den Zielpunkt dadurch in X und Y exakt - um den Preis, dass +es die letzte Gerade um 6.15 Grad verdrehte. `quer` und `dZ` waren dabei NULL, +der Test meldete brav OK, und der schiefe Schenkel fiel nur beim Blick in die +Zeichnung auf. Ein verdrehter Hauptstrang zielt auf den Endpunkt und drueckt +`laengs` von ~638 mm auf ~0 - genau daran ist er zu erkennen. +Die Pruefung selbst ist gegengeprueft: mit einer kuenstlich auf 0.01 mm +gesetzten Toleranz kippen alle fuenf Faelle auf ABWEICHUNG. + Im Protokoll muessen die Zuschlags-Zeilen erscheinen: `AS-Fussabdruck`, `Eck-Korrektur` je Ecke, und bei Variante A zusaetzlich `Abschluss-Fussabdruck`. **Eine FEHLENDE Zeile ist das Warnsignal** - sie bedeutet, dass ein Eck-Bauteil nicht messbar war und die Ecke unkorrigiert blieb (so wurde der 2.4-mm-Rest bei Variante B gefunden). -> Noch nicht automatisiert. Dafuer muesste der Testfall den Pfad selbst per -> `entmake` zeichnen und das Eingabe-Journal replayen; das Journal einer -> gebauten Kette laesst sich mit `lib/vf_journal_export.py` aus der Zeichnung -> ziehen. Die reinen Rechenkerne dieser Faelle sind dagegen bereits file-frei -> abgedeckt (`tu-tests-vfl-parallel` in `test_unit.lsp`: `vfl-eck-zerlegen`, +> **Automatisiert seit 2026-10-27** als `c:TEST_LINIENZUG_MODUS2` (Menue: +> Tests -> Foerderer-Linienzug). Der Pfad muss dafuer NICHT gezeichnet werden: +> ein Modus-2-Journal traegt einen `SEGS`-Eintrag mit der kompletten +> Segment-Essenz und ist damit von den Original-Objekten unabhaengig - der +> Test spielt schlicht das mit `lib/vf_journal_export.py` ausgelesene Journal +> ab. Die reinen Rechenkerne sind zusaetzlich file-frei abgedeckt +> (`tu-tests-vfl-parallel` in `test_unit.lsp`: `vfl-eck-zerlegen`, > `vfl-es-achs-reserve`, `vfl-projiziere-neigung` - jeweils mit den echten > Messwerten aus diesen beiden Laeufen). +### Dritter bis fuenfter Fall: gefalteter Lauf (U-Form) + +Aufgezeichnet 2026-10-29, Datendateien `tests/testdata/linienzug_modus2_uform_*.json`. + +Der Pfad wechselt ueber zwei 90-Grad-Vario-Kurven **dreimal die +Fahrtrichtung**; die Kletterstrecke liegt dadurch in einem ANDEREN Schenkel als +der Lauf-Eingang. Genau diese Konstellation war bis 2026-10-29 falsch +bilanziert (gemessen 1424 mm quer), weil Posten dem falschen Schenkel +zugerechnet wurden. + +| Segment | Art | Mass | +|---|---|---| +| 1 | Linie | L = 5855 mm, hz = 90 | +| 2 | Bogen | 90 Grad rechts, R500 -> **Vario-Kurve aussen** | +| 3 | Linie | L = 270 mm, hz = 0 (automatisch VF) | +| 4 | Bogen | 90 Grad rechts, R500 -> **Vario-Kurve aussen** | +| 5 | Linie | L = 7806 mm, hz = -90 (der Kletterer) | + +| Fall | GF-Verteilung | Winkel-Option | Testdatei | +|---|---|---|---| +| U-Form 1 | alles am Einlauf (GF1) | 2 | `..._uform_gf1.json` | +| U-Form 2 | 1/2 GF1 + 1/2 GF2 | 2 (= 9 Grad) | `..._uform_halb.json` | +| U-Form 3 | 1/2 GF1 + 1/2 GF2 | 3 (steiler) | `..._uform_halb_steil.json` | + +**Warum drei und nicht einer:** die GF-VERTEILUNG entscheidet, ob ueberhaupt +Gefaellestrecke im fremden Schenkel steht (und damit, ob Nachrechner und das +unterdrueckte Fueller-A greifen) - mit "alles am Einlauf" liegt das gesamte GF1 +dort, mit 1/2+1/2 nur die Haelfte. Der WINKEL ist noetig, weil der Restfehler +der alten Bilanz mit `L_GF` skalierte: bei 6 Grad waren es 90 mm, bei 9 Grad +934 mm. Zwei Laeufe mit demselben Winkel haetten den Fehler also beinahe +verdeckt. + +Soll-Ergebnis wie oben: `quer` und `dZ` jeweils ~0 (gemessen 0.56 mm bei +9 Grad und 0.7 mm bei der steileren Option), `laengs` ~638 mm - das ist die +Ausladung des `ES_Element_90_links` und in allen drei Faellen gleich. + ## alltests.json — Testregistry Die Datei `tests/alltests.json` ist die zentrale Registry aller Test-Module. diff --git a/tests/test_linienzug.lsp b/tests/test_linienzug.lsp index 1752dbd..6880dc1 100644 --- a/tests/test_linienzug.lsp +++ b/tests/test_linienzug.lsp @@ -270,7 +270,7 @@ ;; ============================================================ -;; MODUS 2 (aus 3D-Linie mit Zielhoehe) - Replay zweier echter Laeufe +;; MODUS 2 (aus 3D-Linie mit Zielhoehe) - Replay echter Laeufe ;; ============================================================ ;; Anders als die Modus-1-Faelle oben braucht Modus 2 KEINE Mocks und KEINEN ;; gezeichneten Pfad: sein Journal traegt einen SEGS-Eintrag mit der kompletten @@ -279,19 +279,51 @@ ;; schon vfl-konvertiere-ent beruht (vfl-journal-hat-segs-p). Der Test spielt ;; daher das echte, aus der Zeichnung ausgelesene Journal ab. ;; -;; Die beiden Faelle sind BEWUSST ein Paar: derselbe Pfad, nur die 90-Grad-Ecke -;; einmal als Vario-Kurve (waagerecht) und einmal als GF-Bogen (geneigt). Sie -;; laufen durch verschiedene Zweige - mit und ohne flache Zone - und genau der -;; VERGLEICH hat am 2026-10-26/27 Fehler aufgedeckt, die ein einzelner Lauf -;; nicht gezeigt haette (ES-Fussabdruck am falschen Segment: 878 mm nur in der -;; GF-Bogen-Variante). Einen davon zu loeschen nimmt dem Test seinen Wert. +;; Die Faelle sind zwei BEWUSST gebildete Paare, kein Sammelsurium: ;; -;; Aufgezeichnet mit lib/vf_journal_export.py aus einem echten BricsCAD-Lauf. +;; A/B (Ecke als Vario-Kurve bzw. als GF-Bogen) - derselbe Pfad, nur die +;; 90-Grad-Ecke einmal waagerecht und einmal geneigt eingebaut. Sie laufen +;; durch verschiedene Zweige (mit und ohne flache Zone), und genau der +;; VERGLEICH hat am 2026-10-26/27 Fehler aufgedeckt, die ein einzelner +;; Lauf nicht gezeigt haette (ES-Fussabdruck am falschen Segment: 878 mm +;; nur in der GF-Bogen-Variante). +;; +;; U-Form 1..3 (gefalteter Lauf) - der Pfad wechselt ueber zwei 90-Grad- +;; Vario-Kurven dreimal die Fahrtrichtung, die Kletterstrecke liegt +;; dadurch in einem ANDEREN Schenkel als der Lauf-Eingang. Hier variieren +;; GF-VERTEILUNG (alles am Einlauf vs. 1/2+1/2) und WINKEL. Beides ist +;; noetig: die Verteilung entscheidet, ob ueberhaupt GF im fremden +;; Schenkel steht (Nachrechner, Fueller-A), und der Restfehler der alten +;; Bilanz skalierte mit L_GF, also mit dem Winkel (6 Grad 90 mm, 9 Grad +;; 934 mm) - zwei Laeufe mit demselben Winkel haetten das verdeckt. +;; +;; Einen Fall zu loeschen nimmt dem Test den jeweiligen Vergleich und damit +;; seinen Wert. +;; +;; Aufgezeichnet mit lib/vf_journal_export.py aus echten BricsCAD-Laeufen +;; (A/B am 2026-10-27, U-Form am 2026-10-29). ;; Pruefkriterium (Nutzer-Vorgabe 2026-10-26): quer zur ES-KS_AUS-Achse und dZ ;; MUESSEN ~0 sein, laengs DARF abweichen (Ausladung des ES-Elements). (setq *tlz-m2-toleranz* 1.0) ; mm; 0.2 ist die Messaufloesung der Blockmasse +;; Toleranz fuer den LAENGS-Wert gegen "erwartung_laengs_mm" aus den Testdaten. +;; Der Wert ist die Ausladung des ES-Elements und damit je Fall eine Konstante +;; (gemessen: 104.68 mm bei ES_Element_30, 637.58 mm bei ES_Element_90) - 5 mm +;; reichen also fuer Rundung, ohne echte Abweichungen durchzulassen. +;; +;; Warum ueberhaupt geprueft, wo laengs doch ausdruecklich abweichen DARF: +;; Am 2026-10-29 loeste ein Experiment den Schluss-Fueller gegen Richtung UND +;; Laenge und traf den Zielpunkt dadurch in X und Y exakt - um den Preis, dass +;; es die letzte Gerade um 6.15 Grad verdrehte (sichtbar schiefer Schenkel im +;; U-Form-Fall). quer und dZ waren dabei NULL, der Test meldete OK; gefunden +;; wurde der Fehler nur mit dem Auge in der Zeichnung. +;; laengs ist der Wert, der das verraet: ein verdrehter Hauptstrang zielt auf +;; den Endpunkt und drueckt laengs von ~638 mm auf ~0. Die Pruefung ist also +;; kein zweites Genauigkeitskriterium, sondern ein Formkriterium - sie stellt +;; sicher, dass der ES-Versatz noch da ist, wo er hingehoert. +(setq *tlz-m2-laengs-toleranz* 5.0) + ;; Wert als String - eigene Kopie statt hmrec:als-string aus ;; test_hm_recformat.lsp: diese Datei soll fuer sich allein ladbar bleiben. (defun tlz-m2-str (v) @@ -321,7 +353,8 @@ ;; Einen Modus-2-Fall abspielen. Rueckgabe: (status laengs quer dz offen). (defun tlz-m2-run (json-datei test-id anzeige / daten journal meta offen err status abw j - old-headless old-gui quer dz laengs) + old-headless old-gui quer dz laengs + soll-laengs laengs-ok) (if (or (not *lib-initialized*) (null bogen-auf)) (init-bibliothek)) (princ (strcat "\n\n--- " anzeige " ---")) ;; Vorbelegen, damit der Ergebnis-Record auch im Fehlerzweig Zahlen hat - @@ -375,38 +408,83 @@ (if (> offen 0) (princ (strcat "\n WARNUNG: " (itoa offen) " Journal-Eintraege NICHT verbraucht (Ablauf weicht ab)."))) + ;; laengs gegen den erwarteten ES-Versatz pruefen, sofern die + ;; Testdaten einen nennen (siehe *tlz-m2-laengs-toleranz*). + (setq soll-laengs (if meta (ssg-val meta "erwartung_laengs_mm") nil)) + (setq laengs-ok + (if (numberp soll-laengs) + (<= (abs (- laengs (float soll-laengs))) *tlz-m2-laengs-toleranz*) + T)) + (if (not laengs-ok) + (princ (strcat "\n WARNUNG: laengs " (rtos laengs 2 1) + " statt erwarteter " (rtos (float soll-laengs) 2 1) + " mm - der Hauptstrang zeigt nicht mehr in die" + " gezeichnete Richtung (ES-Versatz verschwunden?)."))) (setq status (if (and (<= (abs quer) *tlz-m2-toleranz*) (<= (abs dz) *tlz-m2-toleranz*) + laengs-ok (= offen 0)) "OK" "ABWEICHUNG")) (princ (strcat "\n -> " status " (Soll: |quer| und |dZ| <= " (rtos *tlz-m2-toleranz* 2 1) - " mm, laengs frei)")))) + " mm, laengs = " + (if (numberp soll-laengs) + (strcat (rtos (float soll-laengs) 2 0) " +/- " + (rtos *tlz-m2-laengs-toleranz* 2 0) " mm") + "frei") + ")")))) (ssg-end))) (list status laengs quer dz offen)) -(defun c:TEST_LINIENZUG_MODUS2 ( / basis a b) +;; Testfall-Tabelle: (Dateiname test-id Anzeigename). Ein weiterer Fall ist +;; damit EINE Zeile - der Ablauf darunter ist generisch. Reihenfolge = +;; Ausgabereihenfolge; die beiden Paare stehen bewusst beieinander. +(setq *tlz-m2-faelle* + (list + (list "linienzug_modus2_variokurve.json" "LZ_M2_variokurve" + "Variante A: Ecke = Vario-Kurve") + (list "linienzug_modus2_gfbogen.json" "LZ_M2_gfbogen" + "Variante B: Ecke = GF-Bogen") + (list "linienzug_modus2_uform_gf1.json" "LZ_M2_uform_gf1" + "U-Form 1: GF alles am Einlauf") + (list "linienzug_modus2_uform_halb.json" "LZ_M2_uform_halb" + "U-Form 2: GF 1/2 + 1/2") + (list "linienzug_modus2_uform_halb_steil.json" "LZ_M2_uform_halb_steil" + "U-Form 3: GF 1/2 + 1/2, steilere Winkel-Option"))) + +(defun c:TEST_LINIENZUG_MODUS2 ( / basis fall r erg zeilen anzahl-ok) ;; Doppelte Backslashes: "\t" waere in AutoLISP ein TABULATOR, der Pfad ;; wuerde zu "...dxfmakrosestsestdata" (real passiert 2026-10-27). (setq basis (strcat (getenv "DXFMAKRO") "\\tests\\testdata\\")) (princ "\n================================================================") - (princ "\n TEST_LINIENZUG_MODUS2 - zwei Varianten DERSELBEN Strecke") + (princ (strcat "\n TEST_LINIENZUG_MODUS2 - " (itoa (length *tlz-m2-faelle*)) + " Ketten aus echten BricsCAD-Laeufen")) (princ "\n================================================================") - (setq a (tlz-m2-run (strcat basis "linienzug_modus2_variokurve.json") - "LZ_M2_variokurve" "Variante A: Ecke = Vario-Kurve")) - (setq b (tlz-m2-run (strcat basis "linienzug_modus2_gfbogen.json") - "LZ_M2_gfbogen" "Variante B: Ecke = GF-Bogen")) + (setq erg '() zeilen '() anzahl-ok 0) + (foreach fall *tlz-m2-faelle* + (setq r (tlz-m2-run (strcat basis (car fall)) (cadr fall) (caddr fall))) + (if (= (car r) "OK") (setq anzahl-ok (1+ anzahl-ok))) + (setq erg (cons (list (caddr fall) (car r)) erg)) + (setq zeilen + (cons (strcat " { \"test_id\": \"" (cadr fall) + "\", \"status\": \"" (car r) + "\", \"quer_mm\": " (rtos (caddr r) 2 2) + ", \"dz_mm\": " (rtos (cadddr r) 2 2) + ", \"laengs_mm\": " (rtos (cadr r) 2 2) " }") + zeilen))) + (setq erg (reverse erg) zeilen (reverse zeilen)) (princ "\n\n================================================================") - (princ (strcat "\n ERGEBNIS: Variante A " (car a) " | Variante B " (car b))) + (princ "\n ERGEBNIS") + (princ "\n----------------------------------------------------------------") + (foreach e erg + (princ (strcat "\n " (car e) ": " (cadr e)))) + (princ (strcat "\n----------------------------------------------------------------" + "\n " (itoa anzahl-ok) " von " (itoa (length *tlz-m2-faelle*)) + " OK")) (princ "\n================================================================") - ;; Ergebnis fuer run-all (Konvention wie linienzug:export-results) - (setq *linienzug-m2-test-results* - (strcat " { \"test_id\": \"LZ_M2_variokurve\", \"status\": \"" (car a) - "\", \"quer_mm\": " (rtos (caddr a) 2 2) - ", \"dz_mm\": " (rtos (cadddr a) 2 2) " },\n" - " { \"test_id\": \"LZ_M2_gfbogen\", \"status\": \"" (car b) - "\", \"quer_mm\": " (rtos (caddr b) 2 2) - ", \"dz_mm\": " (rtos (cadddr b) 2 2) " }")) + ;; Ergebnis fuer run-all (Konvention wie linienzug:export-results). + ;; ssg-join aus ssg_core - die Zeilen sind bereits fertige JSON-Objekte. + (setq *linienzug-m2-test-results* (ssg-join zeilen ",\n")) (princ) ) diff --git a/tests/test_unit.lsp b/tests/test_unit.lsp index bc08050..444f846 100644 --- a/tests/test_unit.lsp +++ b/tests/test_unit.lsp @@ -3036,54 +3036,6 @@ ) -;; --- Schlussstueck: Richtung UND Laenge aus der IST-Lage --------------------- -;; vfl-zsolve-schluss-ziel loest den letzten Fueller gegen den Zielpunkt, mit der -;; Richtung als zweiter Unbekannter. Mit es-block = nil braucht die Funktion -;; weder Zeichnung noch Blockdatei - der Querversatz P ist dann 0 und uebrig -;; bleibt die reine Geometrie. -;; Bewusst NICHT gegen eine nachgerechnete Konstante C geprueft (das waere die -;; Formel ein zweites Mal hingeschrieben), sondern gegen Eigenschaften, die -;; unabhaengig von C gelten: der Winkel zeigt exakt zum Ziel, und eine -;; Zielverschiebung bzw. ein groesseres GF2 schlaegt 1:1 auf die Laenge durch. -(defun tu-tests-vfl-schluss ( / _rad3 _p0 _a _b _c _d) - (princ "\n[vf_linienzug Schlussstueck]") - (setq _rad3 (/ (* 3.0 pi) 180.0) - _p0 '(0.0 0.0 0.0)) - - ;; Der Winkel zeigt ohne ES-Element exakt zum Zielpunkt (P = 0). - (tu-eqf "vfl-zsolve-schluss-ziel/winkel-ost" - 0.0 (cadr (vfl-zsolve-schluss-ziel _p0 '(10000.0 0.0 0.0) 0.0 nil 0.0 _rad3))) - (tu-eqf "vfl-zsolve-schluss-ziel/winkel-nord" - 90.0 (cadr (vfl-zsolve-schluss-ziel _p0 '(0.0 10000.0 0.0) 0.0 nil 0.0 _rad3))) - ;; 3/4/5-Dreieck: die Richtung folgt dem Ziel, NICHT dem uebergebenen seg-hz. - ;; Genau das ist der Kern der Aenderung - darum wird hier ein voellig anderer - ;; Planwinkel (-137) hineingegeben. - (tu-eqf "vfl-zsolve-schluss-ziel/winkel-folgt-ziel-nicht-plan" - (/ (* 180.0 (atan 4000.0 3000.0)) pi) - (cadr (vfl-zsolve-schluss-ziel _p0 '(3000.0 4000.0 0.0) -137.0 nil 0.0 _rad3))) - - ;; Laenge: 1000 mm weiter entferntes Ziel -> 1000 mm mehr Fueller. - (setq _a (car (vfl-zsolve-schluss-ziel _p0 '(10000.0 0.0 0.0) 0.0 nil 0.0 _rad3)) - _b (car (vfl-zsolve-schluss-ziel _p0 '(11000.0 0.0 0.0) 0.0 nil 0.0 _rad3))) - (tu-eqf "vfl-zsolve-schluss-ziel/laenge-folgt-ziel" 1000.0 (- _b _a)) - - ;; GF2 steht im Schwanz und liegt unter 3 Grad: 1000 mm GF2 verbrauchen - ;; 1000*cos(3) in der Laengsrichtung, der Fueller wird genau darum kuerzer. - (setq _c (car (vfl-zsolve-schluss-ziel _p0 '(10000.0 0.0 0.0) 0.0 nil 1000.0 _rad3))) - (tu-eqf "vfl-zsolve-schluss-ziel/gf2-verkuerzt-fueller" - (* 1000.0 (cos _rad3)) (- _a _c)) - - ;; Die Loesung ist richtungsunabhaengig: dasselbe Ziel, um 90 Grad gedreht, - ;; ergibt dieselbe Fuellerlaenge. - (setq _d (car (vfl-zsolve-schluss-ziel _p0 '(0.0 10000.0 0.0) 0.0 nil 0.0 _rad3))) - (tu-eqf "vfl-zsolve-schluss-ziel/laenge-drehinvariant" _a _d) - - ;; Kein loesbarer Fall: Ziel liegt auf dem Startpunkt -> nil (Aufrufer faellt - ;; dann auf den bisherigen Weg zurueck, statt etwas zu raten). - (tu-nil "vfl-zsolve-schluss-ziel/ziel-auf-startpunkt" - (vfl-zsolve-schluss-ziel _p0 '(0.0 0.0 0.0) 0.0 nil 0.0 _rad3)) -) - (defun c:TEST_UNIT ( / out-dir report) (tu-reset) @@ -3097,7 +3049,6 @@ "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" - "tu-tests-vfl-schluss" "tu-tests-werkzeuge" "tu-tests-kf" "tu-tests-hoehen-fam") (tu-run-block fn)) diff --git a/tests/testdata/linienzug_modus2_gfbogen.json b/tests/testdata/linienzug_modus2_gfbogen.json index 86c9573..b602980 100644 --- a/tests/testdata/linienzug_modus2_gfbogen.json +++ b/tests/testdata/linienzug_modus2_gfbogen.json @@ -1,6 +1,6 @@ [ { - "beschreibung": "Linienzug Modus 2, Variante B: 90-Grad-Ecke als GF-BOGEN (geneigt eingebaut). Deckt die Neigungs-Projektion der Eck-Korrektur ab (vfl-projiziere-neigung) und den Zweig OHNE flache Zone, in dem der ES-Fussabdruck frueher faelschlich vom VF-Lauf abgezogen wurde (878 mm). Aufgezeichnet 2026-10-27 aus einem echten BricsCAD-Lauf.", + "beschreibung": "Linienzug Modus 2, Variante B: 90-Grad-Ecke als GF-BOGEN (geneigt eingebaut). Deckt die Neigungs-Projektion der Eck-Korrektur ab (vfl-projiziere-neigung) und den Zweig OHNE flache Zone, in dem der ES-Fussabdruck frueher faelschlich vom VF-Lauf abgezogen wurde (878 mm). Aufgezeichnet 2026-10-27 aus einem echten BricsCAD-Lauf. Startpunkt fuer die Testreihe versetzt: alle Koordinaten (Start-/Zielpunkt und Pfadsegmente) um einen gemeinsamen Vektor verschoben, damit TEST_LINIENZUG_MODUS2 die Ketten nebeneinander auf einer Grundlinie baut statt verstreut. Reine Translation - Laengen, Winkel und die geprueften Abweichungen sind davon unabhaengig; Z bleibt unveraendert, weil die Starthoehe ein Eingabewert des Solvers ist.", "test_id": "LZ_M2_gfbogen", "kurz": "Ecke als GF-Bogen", "erwartung_quer_mm": 0, @@ -10,8 +10,8 @@ }, { "art": "PT", - "x": 6373.07914, - "y": 6047.735576, + "x": 60000.0, + "y": 0.0, "z": 0.0 }, { @@ -32,8 +32,8 @@ }, { "art": "PT", - "x": 17373.07914, - "y": -267.387621, + "x": 71000.0, + "y": -6315.123197, "z": 184.3 }, { @@ -54,7 +54,7 @@ }, { "art": "SEGS", - "wert": "Linie|0|9700|0|links|6373.07914|6047.735576|16073.07914|6047.735576;Bogen|0|707.106781|90|rechts|16073.07914|6047.735576|16573.07914|5547.735576;Linie|-90|4295.507955|0|links|16573.07914|5547.735576|16573.07914|1252.227621;Bogen|-90|258.819045|30|links|16573.07914|1252.227621|16640.066438|1002.227621;Linie|-60|1466.025404|0|links|16640.066438|1002.227621|17373.07914|-267.387621" + "wert": "Linie|0|9700|0|links|60000|0|69700|0;Bogen|0|707.106781|90|rechts|69700|0|70200|-500;Linie|-90|4295.507955|0|links|70200|-500|70200|-4795.507955;Bogen|-90|258.819045|30|links|70200|-4795.507955|70266.987298|-5045.507955;Linie|-60|1466.025404|0|links|70266.987298|-5045.507955|71000|-6315.123197" }, { "art": "STR", diff --git a/tests/testdata/linienzug_modus2_uform_gf1.json b/tests/testdata/linienzug_modus2_uform_gf1.json new file mode 100644 index 0000000..f4ddccc --- /dev/null +++ b/tests/testdata/linienzug_modus2_uform_gf1.json @@ -0,0 +1,99 @@ +[ + { + "beschreibung": "Linienzug Modus 2, GEFALTETER Lauf (U-Form): der Pfad wechselt ueber zwei 90-Grad-Vario-Kurven dreimal die Fahrtrichtung, die Kletterstrecke liegt dadurch in einem ANDEREN Schenkel als der Lauf-Eingang. GF-Verteilung 1 (alles am Einlauf, GF1) - diese Verteilung war bis 2026-10-29 durch keinen Test abgedeckt. Aufgezeichnet 2026-10-29 aus einem echten BricsCAD-Lauf. Startpunkt fuer die Testreihe versetzt: alle Koordinaten (Start-/Zielpunkt und Pfadsegmente) um einen gemeinsamen Vektor verschoben, damit TEST_LINIENZUG_MODUS2 die Ketten nebeneinander auf einer Grundlinie baut statt verstreut. Reine Translation - Laengen, Winkel und die geprueften Abweichungen sind davon unabhaengig; Z bleibt unveraendert, weil die Starthoehe ein Eingabewert des Solvers ist.", + "test_id": "LZ_M2_uform_gf1", + "kurz": "U-Form, GF alles am Einlauf", + "erwartung_quer_mm": 0, + "erwartung_dz_mm": 0, + "erwartung_laengs_mm": 638, + "erwartung_hinweis": "quer zur ES-KS_AUS-Achse MUSS ~0 sein und dZ ~0; laengs darf abweichen - das ist die Ausladung des ES-Elements und kein Fehler. Der laengs-Wert von rund 638 mm ist die Ausladung des ES_Element_90_links und in allen drei U-Form-Faellen gleich; geprueft werden nur quer und dZ." + }, + { + "art": "PT", + "x": 80000.0, + "y": 0.0, + "z": 355.289671 + }, + { + "art": "REAL", + "wert": 355.3 + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "STR", + "wert": "90" + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "PT", + "x": 81269.916932, + "y": 0.0, + "z": 355.289671 + }, + { + "art": "REAL", + "wert": 355.3 + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "STR", + "wert": "90" + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "SEGS", + "wert": "Linie|90|5854.769733|0|links|80000|0|80000|5854.769733;Bogen|90|707.106781|90|rechts|80000|5854.769733|80500|6354.769733;Linie|0|269.916931|0|links|80500|6354.769733|80769.916932|6354.769733;Bogen|0|707.106781|90|rechts|80769.916932|6354.769733|81269.916932|5854.769733;Linie|-90|5854.769733|0|links|81269.916932|5854.769733|81269.916932|0" + }, + { + "art": "STR", + "wert": "m2v2" + }, + { + "art": "STR", + "wert": "vf" + }, + { + "art": "STR", + "wert": "vario-kurve" + }, + { + "art": "STR", + "wert": "aussen" + }, + { + "art": "STR", + "wert": "vario-kurve" + }, + { + "art": "STR", + "wert": "aussen" + }, + { + "art": "STR", + "wert": "mit-gf1" + }, + { + "art": "STR", + "wert": "3" + }, + { + "art": "INT", + "wert": 2 + }, + { + "art": "STR", + "wert": "1" + } +] diff --git a/tests/testdata/linienzug_modus2_uform_halb.json b/tests/testdata/linienzug_modus2_uform_halb.json new file mode 100644 index 0000000..6a84abd --- /dev/null +++ b/tests/testdata/linienzug_modus2_uform_halb.json @@ -0,0 +1,99 @@ +[ + { + "beschreibung": "Linienzug Modus 2, GEFALTETER Lauf (U-Form), GF-Verteilung 2 (1/2 GF1 + 1/2 GF2). DAS ist der Lauf, an dem die Laengenbilanz des gefalteten Laufs entwickelt und gemessen wurde: 1424 -> 934 -> 402 -> 0.56 mm quer (9 Grad). Er deckt alle vier Teilstuecke zugleich ab - Eingangs-Hardware im fremden Schenkel, kletter-ende-fp, GF1-Fremdanteil (Nachrechner) und das unterdrueckte Fueller-A. Aufgezeichnet 2026-10-29 aus einem echten BricsCAD-Lauf. Startpunkt fuer die Testreihe versetzt: alle Koordinaten (Start-/Zielpunkt und Pfadsegmente) um einen gemeinsamen Vektor verschoben, damit TEST_LINIENZUG_MODUS2 die Ketten nebeneinander auf einer Grundlinie baut statt verstreut. Reine Translation - Laengen, Winkel und die geprueften Abweichungen sind davon unabhaengig; Z bleibt unveraendert, weil die Starthoehe ein Eingabewert des Solvers ist.", + "test_id": "LZ_M2_uform_halb", + "kurz": "U-Form, GF 1/2+1/2", + "erwartung_quer_mm": 0, + "erwartung_dz_mm": 0, + "erwartung_laengs_mm": 638, + "erwartung_hinweis": "quer zur ES-KS_AUS-Achse MUSS ~0 sein und dZ ~0; laengs darf abweichen - das ist die Ausladung des ES-Elements und kein Fehler. Der laengs-Wert von rund 638 mm ist die Ausladung des ES_Element_90_links und in allen drei U-Form-Faellen gleich; geprueft werden nur quer und dZ." + }, + { + "art": "PT", + "x": 100000.0, + "y": 0.0, + "z": 710.579341 + }, + { + "art": "REAL", + "wert": 710.6 + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "STR", + "wert": "90" + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "PT", + "x": 101269.916932, + "y": -1951.333591, + "z": 710.579341 + }, + { + "art": "REAL", + "wert": 710.6 + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "STR", + "wert": "90" + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "SEGS", + "wert": "Linie|90|5854.769733|0|links|100000|0|100000|5854.769733;Bogen|90|707.106781|90|rechts|100000|5854.769733|100500|6354.769733;Linie|0|269.916931|0|links|100500|6354.769733|100769.916932|6354.769733;Bogen|0|707.106781|90|rechts|100769.916932|6354.769733|101269.916932|5854.769733;Linie|-90|7806.103325|0|links|101269.916932|5854.769733|101269.916932|-1951.333591" + }, + { + "art": "STR", + "wert": "m2v2" + }, + { + "art": "STR", + "wert": "vf" + }, + { + "art": "STR", + "wert": "vario-kurve" + }, + { + "art": "STR", + "wert": "aussen" + }, + { + "art": "STR", + "wert": "vario-kurve" + }, + { + "art": "STR", + "wert": "aussen" + }, + { + "art": "STR", + "wert": "mit-gf1" + }, + { + "art": "STR", + "wert": "3" + }, + { + "art": "INT", + "wert": 2 + }, + { + "art": "STR", + "wert": "2" + } +] diff --git a/tests/testdata/linienzug_modus2_uform_halb_steil.json b/tests/testdata/linienzug_modus2_uform_halb_steil.json new file mode 100644 index 0000000..614b16f --- /dev/null +++ b/tests/testdata/linienzug_modus2_uform_halb_steil.json @@ -0,0 +1,99 @@ +[ + { + "beschreibung": "Linienzug Modus 2, GEFALTETER Lauf (U-Form) wie LZ_M2_uform_halb, aber mit der naechststeileren Winkel-Option. Der Restfehler der alten Bilanz skalierte mit L_GF und damit mit dem Winkel (6 Grad: 90 mm, 9 Grad: 934 mm) - zwei Winkel auf derselben Pfadfamilie sichern deshalb mehr ab als zwei Laeufe mit demselben. Aufgezeichnet 2026-10-29 aus einem echten BricsCAD-Lauf. Startpunkt fuer die Testreihe versetzt: alle Koordinaten (Start-/Zielpunkt und Pfadsegmente) um einen gemeinsamen Vektor verschoben, damit TEST_LINIENZUG_MODUS2 die Ketten nebeneinander auf einer Grundlinie baut statt verstreut. Reine Translation - Laengen, Winkel und die geprueften Abweichungen sind davon unabhaengig; Z bleibt unveraendert, weil die Starthoehe ein Eingabewert des Solvers ist.", + "test_id": "LZ_M2_uform_halb_steil", + "kurz": "U-Form, GF 1/2+1/2, steilere Winkel-Option", + "erwartung_quer_mm": 0, + "erwartung_dz_mm": 0, + "erwartung_laengs_mm": 638, + "erwartung_hinweis": "quer zur ES-KS_AUS-Achse MUSS ~0 sein und dZ ~0; laengs darf abweichen - das ist die Ausladung des ES-Elements und kein Fehler. Der laengs-Wert von rund 638 mm ist die Ausladung des ES_Element_90_links und in allen drei U-Form-Faellen gleich; geprueft werden nur quer und dZ." + }, + { + "art": "PT", + "x": 120000.0, + "y": 0.0, + "z": 709.285191 + }, + { + "art": "REAL", + "wert": 709.3 + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "STR", + "wert": "90" + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "PT", + "x": 121269.916932, + "y": 0.077406, + "z": 709.275779 + }, + { + "art": "REAL", + "wert": 709.3 + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "STR", + "wert": "90" + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "SEGS", + "wert": "Linie|90|5854.769733|0|links|120000|-21.403816|120000|5833.365917;Bogen|90|707.106781|90|rechts|120000|5833.365917|120500|6333.365917;Linie|0|269.916931|0|links|120500|6333.365917|120769.916932|6333.365917;Bogen|0|707.106781|90|rechts|120769.916932|6333.365917|121269.916932|5833.365917;Linie|-90|5854.769733|0|links|121269.916932|5833.365917|121269.916932|-21.403816" + }, + { + "art": "STR", + "wert": "m2v2" + }, + { + "art": "STR", + "wert": "vf" + }, + { + "art": "STR", + "wert": "vario-kurve" + }, + { + "art": "STR", + "wert": "aussen" + }, + { + "art": "STR", + "wert": "vario-kurve" + }, + { + "art": "STR", + "wert": "aussen" + }, + { + "art": "STR", + "wert": "mit-gf1" + }, + { + "art": "STR", + "wert": "3" + }, + { + "art": "INT", + "wert": 3 + }, + { + "art": "STR", + "wert": "2" + } +] diff --git a/tests/testdata/linienzug_modus2_variokurve.json b/tests/testdata/linienzug_modus2_variokurve.json index ccf96b6..7bbda36 100644 --- a/tests/testdata/linienzug_modus2_variokurve.json +++ b/tests/testdata/linienzug_modus2_variokurve.json @@ -1,6 +1,6 @@ [ { - "beschreibung": "Linienzug Modus 2, Variante A: 90-Grad-Ecke als VARIO-KURVE (waagerecht eingebaut), Segment 3 dadurch automatisch VF. Deckt die flache Zone ab (Abschluss-Fussabdruck Bogen+Motorstation) und die Eck-Korrektur von 93.8 mm je Nachbargerade. Aufgezeichnet 2026-10-27 aus einem echten BricsCAD-Lauf.", + "beschreibung": "Linienzug Modus 2, Variante A: 90-Grad-Ecke als VARIO-KURVE (waagerecht eingebaut), Segment 3 dadurch automatisch VF. Deckt die flache Zone ab (Abschluss-Fussabdruck Bogen+Motorstation) und die Eck-Korrektur von 93.8 mm je Nachbargerade. Aufgezeichnet 2026-10-27 aus einem echten BricsCAD-Lauf. Startpunkt fuer die Testreihe versetzt: alle Koordinaten (Start-/Zielpunkt und Pfadsegmente) um einen gemeinsamen Vektor verschoben, damit TEST_LINIENZUG_MODUS2 die Ketten nebeneinander auf einer Grundlinie baut statt verstreut. Reine Translation - Laengen, Winkel und die geprueften Abweichungen sind davon unabhaengig; Z bleibt unveraendert, weil die Starthoehe ein Eingabewert des Solvers ist.", "test_id": "LZ_M2_variokurve", "kurz": "Ecke als Vario-Kurve", "erwartung_quer_mm": 0, @@ -10,8 +10,8 @@ }, { "art": "PT", - "x": 20702.423223, - "y": 6047.735576, + "x": 40000.0, + "y": 0.0, "z": 0.0 }, { @@ -32,8 +32,8 @@ }, { "art": "PT", - "x": 31702.423223, - "y": -267.387621, + "x": 51000.0, + "y": -6315.123197, "z": 184.3 }, { @@ -54,7 +54,7 @@ }, { "art": "SEGS", - "wert": "Linie|0|9700|0|links|20702.423223|6047.735576|30402.423223|6047.735576;Bogen|0|707.106781|90|rechts|30402.423223|6047.735576|30902.423223|5547.735576;Linie|-90|4295.507955|0|links|30902.423223|5547.735576|30902.423223|1252.227621;Bogen|-90|258.819045|30|links|30902.423223|1252.227621|30969.410521|1002.227621;Linie|-60|1466.025404|0|links|30969.410521|1002.227621|31702.423223|-267.387621" + "wert": "Linie|0|9700|0|links|40000|0|49700|0;Bogen|0|707.106781|90|rechts|49700|0|50200|-500;Linie|-90|4295.507955|0|links|50200|-500|50200|-4795.507955;Bogen|-90|258.819045|30|links|50200|-4795.507955|50266.987298|-5045.507955;Linie|-60|1466.025404|0|links|50266.987298|-5045.507955|51000|-6315.123197" }, { "art": "STR", diff --git a/tests/testdata/linienzug_tests.json b/tests/testdata/linienzug_tests.json index cac4547..6291254 100644 --- a/tests/testdata/linienzug_tests.json +++ b/tests/testdata/linienzug_tests.json @@ -8,8 +8,8 @@ }, { "typ": "point_abs", - "wert": [-1289.407125, 95.871332, 2154], - "kommentar": "getpoint Startpunkt der Kette" + "wert": [0.0, 0.0, 2154], + "kommentar": "getpoint Startpunkt der Kette - fuer die Testreihe auf X=0/Y=0 versetzt, damit die Ketten aller Linienzug-Tests nebeneinander auf einer Grundlinie entstehen statt verstreut. Unkritisch, weil dies der EINZIGE absolute Punkt des Skripts ist: alle weiteren Punkte sind relativ (point_rel mit dL/hz), die Geometrie also unveraendert. Z bleibt stehen - das ist die Starthoehe und ein echter Eingabewert." }, { "typ": "real", diff --git a/tests/testdata/linienzug_tests_stufe2.json b/tests/testdata/linienzug_tests_stufe2.json index b198676..fed5ec8 100644 --- a/tests/testdata/linienzug_tests_stufe2.json +++ b/tests/testdata/linienzug_tests_stufe2.json @@ -8,8 +8,8 @@ }, { "typ": "point_abs", - "wert": [21377.904954, -10300, 2067], - "kommentar": "getpoint Startpunkt der Kette" + "wert": [20000.0, 0.0, 2067], + "kommentar": "getpoint Startpunkt der Kette - fuer die Testreihe auf X=20000/Y=0 versetzt, damit die Ketten aller Linienzug-Tests nebeneinander auf einer Grundlinie entstehen statt verstreut. Unkritisch, weil dies der EINZIGE absolute Punkt des Skripts ist: alle weiteren Punkte sind relativ (point_rel mit dL/hz), die Geometrie also unveraendert. Z bleibt stehen - das ist die Starthoehe und ein echter Eingabewert." }, { "typ": "real",