From e1e5fbf0c1ed1db32555635101a9de9fba710a93 Mon Sep 17 00:00:00 2001 From: Yuelin Wang Date: Thu, 22 Oct 2026 12:01:16 +0200 Subject: [PATCH] feat: Modus 3 mit optionalem AS/ES, ES-Frage vor dem Bau; Helfer rollenbasiert benannt WARUM MODUS 3 BLEIBT Modus 2 und 3 arbeiten beide auf einem gezeichneten Pfad (LINE/ARC), aber sie loesen verschiedene Aufgaben: Modus 2 = Randwertproblem - Start UND Ziel (je X/Y/Z) sind bekannt, die Zwischenhoehen werden gerechnet, die Zielhoehe wird exakt getroffen. Modus 3 = Anfangswertproblem - die Kette wird mit vorgegebenen Winkeln vorwaerts durchgebaut, die Endhoehe ist das ERGEBNIS. Modus 3 kann damit etwas, was Modus 2 grundsaetzlich nicht kann: ohne vorgegebene Zielhoehe arbeiten ("folge dieser Linie mit 3 Grad und lass uns sehen, wo wir landen") - und er hat keinen Solver, der scheitern kann. Dazu kommt ein harter Bestandsgrund: Modus 3 schreibt ein eigenes Journal (Marker "linienzug3") und ist per Doppelklick editierbar. Faellt der Code weg, verlieren alle bereits damit gebauten Ketten ihren Editier-Pfad. Der Stempel "Legacy / wird umgebaut" war ueberholt und ist raus. MODUS 3 - DREI AENDERUNGEN (Nutzer-Vorgabe 2026-10-22) 1. "AS bauen?" und 2. "ES bauen?" sind jetzt abfragbar (vorher wurden beide immer gebaut), zusammen mit Winkel und Seite in je EINEM Dialog - dasselbe Muster, das Modus 2 schon nutzt (vflw-gruppe-as-impl), kein neuer Code. Ohne AS beginnt die Kette direkt am Startpunkt (flacher Rahmen statt Block); die Fussabdruck-Trimmung der ersten Geraden rechnet dann von selbst 0, weil Rahmen und Startpunkt zusammenfallen. 3. Die ES-Frage steht jetzt VOR dem Bau. Das behebt einen echten Fehler: die letzte Gerade wird um "Separator + ein-dx" gekuerzt, ein-dx wurde aber gelesen, BEVOR es gesetzt war - beim ersten Lauf griff der Schaetzwert *vfk-as-es-fallback-dx*, bei jedem weiteren stand dort der Wert der VORHERIGEN Kette (falscher Winkel, falsche Seite). Jetzt traegt die Trimmung den echten Fussabdruck der gewaehlten ES-Variante; ohne ES entfaellt sie ganz. ABWAERTSKOMPATIBILITAET Das Verschieben der ES-Frage aendert die Journal-Reihenfolge. Bestehende "linienzug3"-Ketten bleiben per Doppelklick nachbaubar: alt-journal erkennt sie am WERT des ersten Antwort-Eintrags ("30"/"90" = alt, "1"/"2" = neu, die Mengen sind disjunkt) und spielt sie in der alten Reihenfolge ab. Dafuer der neue Helfer vfl-replay-peek-wert neben vfl-replay-peek-art. DIALOG vflw_as Die Seitenauswahl wurde bei 30 Grad ausgegraut und NICHT in die Pending-Queue gelegt - eine reine Modus-1-Regel (dort ersetzte die Zufuehrungsachse die Seitenfrage). Modus 1 hat seit 2026-10-21 seinen eigenen Dialog; uebrig blieben ES-Element sowie Modus 2/3, wo die Seite IMMER gebraucht wird - dort ging bei 30 Grad ein zweites Fenster nur fuer die Seite auf. Entfernt. NAMENSSCHEMA (faellt in denselben Commit, weil dieselbe Datei) Die Helfer-Praefixe vfl2-/vfl3- stammten aus einer Planungsphase vor der endgueltigen Menue-Zuordnung und waren dazu VERTAUSCHT: alle vfl3-* gehoeren zu Modus 2, die vfl2-* zu Modus 3 - und drei davon zu BEIDEN. Eine Modus-Nummer war fuer diese drei also gar nicht richtig vergebbar. Sie heissen jetzt nach ihrer Rolle: vfl-zsolve-* (rechnet die Hoehen durch, nur Modus 2) und vfl-pfad-* (arbeitet am gezeichneten Pfad, Modus 2 UND 3). 18 Funktionen, jede Aufrufstelle maschinell gegen die Definitionen geprueft. Die falsche Block-Ueberschrift "MODUS 3: Pfad + Ziel-Hoehe" (gemeint war Modus 2) ist korrigiert, beide Gruppen haben jetzt einen erklaerenden Kopf. vfl-zsolve-bruecke (frueher vfl3-solve-bruecke) wird von niemandem aufgerufen - bewusst stehen gelassen und markiert, Loeschen gehoert in ein Tote-Code-Review. MENUE Die Modi heissen jetzt nach ihrem Unterschied statt nach der Bedienung: "aus 3D Linie mit Zielhoehe" / "aus 3D Linie ohne Zielhoehe" (vorher "3D Objekte stueckweise (in Arbeit)"). Co-Authored-By: Claude Opus 5 --- CLAUDE.md | 2 +- Lisp/vf_konstanten.lsp | 8 +- Lisp/vf_linienzug.lsp | 317 ++++++++++++++++-------- doc/plan/vf-parameter-struct-analyse.md | 2 +- doc/todo/modus2-achsenweise-bilanz.md | 2 +- doc/todo/plan-vf-interactive.md | 9 +- doc/variofoerderer.md | 27 +- lang/de_DE.json | 11 +- lang/en_GB.json | 11 +- menu/SSG_LIB.mnu | 2 +- 10 files changed, 254 insertions(+), 137 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e7b8501..2b0b848 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -106,7 +106,7 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. | `ssg_texttools.lsp` | SSG_TEXT_ERSETZEN, SSG_TEXT_PARALLEL, SSG_TEXT_HOEHE, SSG_TEXT_STIL | Text-Werkzeuge (Ursprung ACADSST `CHGTEXT`/`PARTEXT`/`ALTHOEHE`/`ALTSTIL`): Suchen/Ersetzen in TEXT, MTEXT und Block-Attributen (nutzt `ssg-bt-*`, daher NACH `ssg_blocktools` laden), Text parallel zu Linie/Polylinie/Bogen (lesbar ausgerichtet, Abstand), Hoehe/Stil aendern. Arbeitet in der XY-Ebene des Welt-KS. Reine Kerne `ssg-tt-lesbarer-winkel`, `ssg-tt-versetzt` getestet | | `ssg_stueckliste.lsp` | SSG_FAEHNCHEN_STUECKLISTE | Positions-Faehnchen + Stuecklistentabelle, komplett AUS DER ZEICHNUNG - es wird keine Datei eingelesen. Der Benutzer waehlt die Elemente aus (`ssg-sl-erkannte-elemente`: `ssget`-Auswahl, Enter ohne Auswahl = alle erkannten im aktuellen Layout; der reine Filter `ssg-sl-elemente-aus-ss` laesst nicht erkannte Objekte still wegfallen, man darf also grosszuegig ein Fenster aufziehen). `ssg-sl-klasse` klassifiziert Blocknamen (`KREISEL_*`/`ECKRAD_*` -> "ILS Kreisel/Eckrad", `VF_*`/`GF_*` -> "ILS Streckengruppe", `GR_*` -> "Rohrgeruest", `AP60*`/`AP110*`/`AP_110*`/`APG110*` -> je eigene Omniflo-Geraden-Gruppe; wirksamer Blockname ueber `ssg-bt-effname`, also auch dynamische Bloecke). Jedes einzelne Element bekommt ein Faehnchen (`ssg-sl-faehnchen`, Rechteck/Kreis/Automation-Rahmen + Text) an der unteren linken Ecke seiner Bounding-Box (aus `csv:get-bbox` - liefert Zentrum+Abmessungen, NICHT Eckpunkte, die Ecke wird im Code daraus berechnet); die Tabelle (`ssg-sl-tabelle-zeichnen`) gruppiert GROB je Elementklasse (keine Sivas-Artikelaufloesung wie `export_sivas.py`) zu einer Zeile mit Anzahl + Laengensumme aus dem `LAENGE`-Attribut (`ssg-sl-gruppieren`/reiner Kern `ssg-sl-gruppieren-werte`), mehrere gleichartige Elemente tragen daher dieselbe Positionsnummer. **Bewusst KEIN Datei-Import wie bei Walz/Bihler**: dort vergab ein externes System die Positionsnummern und lieferte sie als Datei zurueck, die das CAD nur abzeichnete - bei Walz (`MENU/POSITION.LSP`) eine `.pos`/`.zei` aus einem Clipper-Warenwirtschaftssystem mit Koordinaten-Zuordnung, bei Bihler ITB (`Walz_und_Bihler/SBCADBib/ITB-Module_ori.lsp`, `c:bea_pos`) eine `.pos` mit Zuordnung ueber den Entity-Handle. Diese Umwege sind hier nicht nachgebaut (Entscheidung 2026-10): Nummern und Mengen entstehen in dieser Funktion, die Stuecklisten-AUSGABE liefern EXPORTSIVAS/EXPORTCSV aus denselben Block-Attributen. Der alte `c:stueckl` (Laengen-Summierung ueber hartcodierte Walz-Profillayer wie `L-2`=ST, `A-7`=AP110) hat ebenfalls kein Aequivalent im dxfmakros-Datenmodell (Block-Attribute statt Linien-Layer). Braucht `csv:get-bbox`/`csv:get-attrib` aus `export.lsp` und `ssg-bt-effname` aus `ssg_blocktools.lsp` - muss daher NACH beiden geladen werden (siehe `ssg-ensure`-Reihenfolge in `SSG_LIB.mnl`/`ssg_load.lsp`). Reine Kerne `ssg-sl-klasse`, `ssg-sl-gruppieren-werte` in `tests/test_unit.lsp` getestet | | `KreiselInsert.lsp` | KreiselInsert, KreiselConnect, KreiselRedraw, KreiselQuick, KreiselEdit, KreiselParams, KreiselLabelSetup, KreiselLabelPos, KreiselLabelHoehe, ILS_Eckrad, EckradEdit, KREISEL_WEICHEN | ILS Kreisel und Eckrad komplett in AutoLISP. **Drehrichtungspfeil**: `draw-module` fuegt `data/ils/Drehrichtungspfeil.dwg` auf AN8-Mitte (Block-KS 90 Grad, da die DWG fuer Kreisel Nord->Sued gezeichnet ist; cfg `kreisel.pfeil_winkel`) und SP8-Mitte (+180) mit in den KREISEL_n-Block ein, GUZ = X-Skalierung -1 (reiner Kern `kreisel-pfeil-params`, getestet); Eckrad: ein Pfeil auf der Radmitte mit dem AN8-Winkel (`eckrad-pfeil-params`); bei wiederverwendeter Blockdefinition (KREISEL_n bzw. ECKRAD_n) zieht `kreisel-pfeil-aktualisieren` die Spiegelung per `entmod` nach. **Beruehrpunkte/Weichen** (`kreisel-bp-*`, Befehl KREISEL_WEICHEN, Menue Kreisel-Module -> Weichenpunkte ermitteln): ermittelt aus den Blockparametern (Einfuegepunkt, Drehung, ABSTAND - nicht aus der Geometrie, Modell wie `draw-module`) die Beruehrpunkte aller `KREISEL_*`/`ECKRAD_*` GLEICHER Hoehe (`toleranz_hoehe`): Rad/Rad (`Kreis/Kreis`) und Rad/Laufprofil (`Kreis/Tangente`), nur auf der freien Radseite (aeusserer Halbkreis inkl. Flanken; Eckrad ganz frei), Toleranz `toleranz_beruehrung` (component_defaults.json, Sektion kreisel). Kapsel-Mindestabstand < 2r - tol = KOLLISION (Ueberschneidung), Kreisel Seite an Seite (Beruehrung nur an Flanke/Profil) = KOLLISION `Tangente/Tangente` - beide werden gemeldet, aber nie zur Weiche. Ausgabe: Konsolenliste + Kreis-Marker (Layer `kreisel_weiche`/`kreisel_kollision` aus layer.cfg, XDATA `SSG_KR_WEICHE`, jeder Lauf ersetzt die alten). Der Export schreibt dieselben Punkte als `kreisel_weichen.json` neben `export_raw.json` (`csv:kreisel-weichen-schreiben`, export.lsp); `export_csv.py` uebernimmt sie (`export_neighbors.load_lisp_kreisel_weichen`/`lisp_touch_switches`, Rueckfall auf `compute_kreisel_touch_switches` nur ohne Datei), `export_sivas.py` setzt daraus Merkmal 4403 "Anzahl Weichen ILS". Reine Kerne `kreisel-bp-element`/`-paar`/`-berechnen` in `tests/test_unit.lsp` (`tu-tests-kreisel-bp`, u.a. mit den 11 Einfuegungen aus `tests/testdata/schnittspunkte_kreisel.dxf` -> 10 Beruehrungen) getestet. Eckrad: eigener Dialog `eckrad_edit.dcl` (`eckrad-dialog`, reiner Kern `eckrad-dialog-werte` getestet) beim Einfuegen (ILS_Eckrad, ohne GUI Konsolen-Rueckfall) und per Doppelklick (EckradEdit); kein Abstand/Typ, Drehung als freier Winkel statt fester Kreisel-Ausrichtung. `ils-eckrad-insert` behaelt eine vorhandene NUMMER (Edit -> gleicher Blockname `ECKRAD_n`). Kreiselname: `draw-module` setzt `Bezeichnung` nur noch bei leerem Wert auf die Vorgabe `KreiselN` (eigener Name aus KreiselEdit bleibt erhalten); Beschriftung `kreisel-label-text` = `KREISEL n: _` (ohne Namen bzw. bei Vorgabename wie bisher `KREISEL n: _`); da die Beschriftung als TEXT in der wiederverwendeten Blockdefinition `KREISEL_n_TYP_ABSTAND` steckt, setzt `kreisel-label-aktualisieren` sie dort per `entmod` neu (wirkt auf alle Referenzen der Definition) | -| `VarioFoerderer.lsp` (Wrapper fuer `vf_core.lsp`/`vf_standard.lsp`/`vf_etage.lsp`/`vf_linienzug.lsp`) | FOERDERANLAGE, VARIOFOERDERER_EDIT, VARIOFOERDERER_NACHRUESTEN, Vario_Kette_Merge, VF_SEKTION_RESTORE, VF_WIZARD_AN, VF_WIZARD_AUS | Vario-Foerderanlagen Generator (Typen Standard/Etage/Linienzug); Standard- UND Etage-Typ: Werteingabe per DCL-Dialog, inkl. der vorgelagerten Eingabemodus-Wahl 3D-Linie/Werte manuell (`vfc_eingabemodus`, `vfc-dialog-eingabemodus-waehlen`) - beide Modi laufen seitdem in denselben Basis-/Winkel-Dialog, der Konsolen-Pfad ist nur noch Rueckfall bei abgeschalteter GUI/anderer Sprache. Der Dialog-Ablauf ist zentral in vf_core (`vf-dialog-ablauf`/`vf-dialog-berechnen-einfuegen`, parametrisiert ueber Typ-Registry `*vf-typ-registry*` + Flag `horizontal-p`); `vfs-standard-dialog-ablauf`/`vfe-etage-dialog-ablauf` sind nur noch duenne Wrapper darauf. Beide nutzen dieselben Dialoge `vfs-dialog-eingabe-basis`/`vfs-dialog-winkel-verteilung` und den gemeinsamen L_GF/L_VF-Solve `vf-winkel-solve` (vf_core; berechne-alle-winkel/berechne-winkel-etage teilen ihn); Doppelklick auf VF_n-Block ruft VARIOFOERDERER_EDIT, das per SSG_VF_EDIT-XDATA-Marker ("standard"/"etage"/"linienzug") in den passenden Neuaufbau-Zweig dispatcht (`vfe-edit-ent` fuer Etage, `vfl-edit-ent` fuer Linienzug); Altbestand-Bloecke ohne Marker werden abgewiesen. Linienzug (Modus 1, `vf-linienzug-modus`) zeichnet jede interaktive Eingabe in einem Journal auf (`vfl-in-point`/`-string`/`-real`/`-int`) und schreibt es als XDATA auf den fertigen `VF_n`-Block; ein Abbruch (ESC) loescht dadurch nichts mehr, sondern wickelt die bis dahin gebaute Teil-Geometrie ebenso zu einem Block (`vfl-modus-abbruch-sichern`) - sie bleibt stehen und ist sofort per Doppelklick weiter editierbar/fortsetzbar. Der komplette Linienzug-Hauptstrang (Menue-Fragen von AS-Element bis Kettenende, inkl. GF-Bogen/Vario-Kurve/VF-Einheit-Fortsetzung) laeuft per Default ueber DCL-Dialoge statt Konsole (`*vfl-wizard-mode*`, Befehle VF_WIZARD_AN/VF_WIZARD_AUS): `vfl-in-string`/`-int`/`-real` zeigen bei aktivem Wizard-Modus generische Dialoge aus `dcl/vf_linienzug_wizard.dcl` (Zahl-Eingabe bzw. Mehrfachauswahl aus `vfl-menu`/`vfl-menu-int`) statt `getstring`/`getint`/`getreal` aufzurufen; die ORIGINALEN Konsolen-Fragen (princ + get*, de/en ueber ssg-text) bleiben unveraendert im Code (Fallback bei Fehlern via `vl-catch-all-apply`, siehe `doc/variofoerderer.md`). `vfl-edit-ent` liest das Journal, zeigt die Sektionen ueber einen DCL-Dialog (`vfl-dlg-position`, `dcl/vfl_edit.dcl`) an, kuerzt bei Bedarf auf eine gewaehlte Sektion (stummer Replay der behaltenen Eingaben, umgeht den Wizard-Zweig komplett) und baut danach interaktiv weiter. Linienzug Modus 2 (Pfad+Zielhoehe-Solver, `vf-linienzug-modus2`) nutzt dieselben Wrapper PLUS die neue Objektauswahl-Wrapper-Funktion `vfl-in-selection` (Pfad-Objekte als stabile Entity-Handles journalisiert, neue Journal-Art `"OBJS"`) und schreibt sein Journal unter dem eigenen XDATA-Marker `"linienzug2"`; Doppelklick baut hier NICHT abschnittsweise, sondern per vollem Reset 1:1 aus dem Journal neu auf (`vfl-edit-ent2`, dispatcht aus `vfl-edit-ent` per Marker) - Modus 3 (Vorwaerts-Nachbau) bleibt bewusst reine Konsole (im Code selbst als Legacy/"wird umgebaut" markiert). `Vario_Kette_Merge` (in vf_linienzug.lsp) fuehrt mehrere einzeln gebaute VF_n-Bloecke ab einem gewaehlten Start-Baustein ueber die reale KS_AUS->KS_EIN-Nachbarschaft zu einem Gesamt-Block zusammen (aggregierte Attribute, Luecken-Erkennung). Die interaktiven Editier-Pfade (`vfl-edit-ent` Sektions-Zweig, `vfl-edit-ent2`) rufen den Neuaufbau BEWUSST direkt auf, NICHT ueber `vl-catch-all-apply`: der alte Block ist beim Neuaufbau schon per `entdel` weg, und ein Catch faengt den Abbruch VOR `*error*` ab - der Abbruch-Wickler `vfl-modus-abbruch-sichern` kaeme nie zum Zug und die ganze Kette bliebe als lose Einzelteile ohne Block liegen (Fehlerbild "VF-Block aufgebrochen"). Nur der nicht-interaktive Batch-Konverter `vfl-konvertiere-ent` behaelt den Catch (die Batch-Schleife muss weiterlaufen) und meldet den betroffenen Block. Die Abbruch-Handler setzen zusaetzlich `*ssg-ils-dim*` zurueck, weil der Aufrufer, der das sonst tut, nach einem Abbruch nicht mehr erreicht wird. Recovery-Pfad fuer bereits aufgebrochene Ketten: `VF_SEKTION_RESTORE` (vf_linienzug.lsp) setzt das Ketten-Journal aus der XDATA der losen Objekte zusammen - `SSG_VF_EDIT_SEG` traegt pro Entity den Journal-Abschnitt DER ITERATION, in der es entstand (indiziert mit dem ersten Glied-Index darin; eine VF-Einheit mit eingebetteten Vario-Kurven erzeugt mehrere Glieder in einer Iteration), `SSG_VF_EDIT_PRE` auf den Entities des ersten Gliedes die Praeambel (Startpunkt/Starthoehe/AS). Die `.dbg`-Dateien sind reine AUSGABE und werden von keinem Befehl gelesen (dbgopen legt sie bei jedem Lauf neu an) - Wiederherstellungs-Daten gehoeren in die XDATA. `vf_konstanten.lsp` (von vf_core.lsp vor den drei Submodulen geladen) sammelt alle Laengen-/Winkel-/Toleranz-Magic-Numbers aus dem VarioFoerderer-Cluster als dokumentierte `*vfk-*`-Konstanten. Die Migration ist abgeschlossen: vf_core/vf_standard/vf_etage/vf_linienzug referenzieren durchgaengig die zentralen Konstanten statt roher Literale (Winkel, Stations-/Separator-Laengen, Mindestlaengen, AS/ES-Fallback-Versaetze, Text-/Label-Masse) - Ausnahmen sind in `vf_konstanten.lsp` selbst dokumentiert (Werte mit fuehrender Config-Anbindung via `ssg-cfg-or`, itoa-/Integer-Kontexte, Blocknamen-Strings, die 2000.0-mm/m-Umrechnung). `*vfk-gf-bogen-winkel*` (30/60/90, GF-Bogen + Vario-Kurve) und `*vfk-as-es-winkel*` ("30"/"90", AS/ES; bewusst STRING, da 2-wertig und im Journal als STR gefuehrt) sind Beispiele; vf_linienzug hat fuer beide einen Fallback, falls vf_konstanten nicht geladen wurde. **Nicht-interaktiver Betrieb**: `*vfl-headless*` (+ `vfl-headless-p`/`-abbruch`/`-notausgang`, Diagnose `*vfl-headless-fehler*`, optionaler Antwort-Hook `*vfl-headless-antwort-fn*`) verbietet jede Live-Eingabe - eine erschoepfte Replay-Queue ist damit ein harter Abbruch MIT Fundstelle (Art der Eingabe, Glied- und Eingabe-Nummer) statt eines stillen Rueckfalls auf `getpoint`/`getreal`; eingebaut in `vfl-in-value`/`-value-p`/`-selection`/`-abstand`. Die Bau-Pfade melden abgewiesene Sektionen ueber `vfl-meldung` (sammelt nach `*vfl-meldungen*` + `dbgmsg`, `alert` nur bei erlaubter GUI, sonst `princ`) statt per blockierendem `alert`; reine Interaktiv-Alerts (fehlendes DCL, "nicht editierbar", "kein Journal") bleiben `alert`. Genutzt von `tests/test_hm_recformat.lsp` (Replay der echten Aufzeichnungen) und von `vf_spec.lsp`; Fahrplan in `doc/todo/plan-vf-interactive.md`. **Zufuehrungsachse + "Parallel zum Kreisel"** (Modus 1, 2026-10-21): die AS-Praeambel fragt jetzt Winkel, Seite UND eine optionale Zufuehrungsachse (2. Punkt) - beide zusammen legen AS-Lage (KS_EIN auf der Achse) und Kettenrichtung (KS_AUS ueber die Seiten-Variante) fest, BEVOR eine Strecke geklickt wird; Journalfolge `[STR winkel][STR seite][PT p2 | NIL]`, welche Fragen gestellt wurden wird NICHT journalisiert, sondern beim Replay aus der Eintragsart erkannt (PT direkt nach dem Winkel = Alt-Achse ohne Seite 2026-10-14..10-20, PT/NIL nach der Seite = neues Format, alles andere = Altbestand ohne Achse). Darauf setzt die 5. Option der gf-laenge-modus-Frage auf, intern `"parallel"` (`vfl-gf-parallel-kreisel`): baut AS -> GF-Stueck -> GF-Bogen aus EINEM Abstandswert (senkrecht zur Zufuehrungsachse, AS-KS_EIN bis Bogen-KS_AUS), ohne Separator dazwischen, und stellt die Kettenende-Frage selbst NACH dem Bau. Nur am Kettenanfang mit AS UND Achse waehlbar (sonst Kachel deaktiviert). Bogenwahl nicht hartcodiert, sondern ueber den gemessenen `vf-element-plan-turn` - gewaehlt wird der Bogen, der den AS-Schwenk aufhebt (AS 30 -> 30-Grad-Bogen, AS 90 -> 90-Grad-Bogen, immer Gegenseite; die Zuordnung ist das ERGEBNIS der Messung, keine gepflegte Tabelle). Reine Kerne `vfl-par-bogen-waehlen`/`vfl-par-gf-laenge` in `tests/test_unit.lsp` (`tu-tests-vfl-parallel`) getestet; Ablauf in `doc/vf_linienzug_modus1_anleitung.md` Abschnitt 3a. Details/Entscheidungsbaum: `doc/variofoerderer.md` | +| `VarioFoerderer.lsp` (Wrapper fuer `vf_core.lsp`/`vf_standard.lsp`/`vf_etage.lsp`/`vf_linienzug.lsp`) | FOERDERANLAGE, VARIOFOERDERER_EDIT, VARIOFOERDERER_NACHRUESTEN, Vario_Kette_Merge, VF_SEKTION_RESTORE, VF_WIZARD_AN, VF_WIZARD_AUS | Vario-Foerderanlagen Generator (Typen Standard/Etage/Linienzug); Standard- UND Etage-Typ: Werteingabe per DCL-Dialog, inkl. der vorgelagerten Eingabemodus-Wahl 3D-Linie/Werte manuell (`vfc_eingabemodus`, `vfc-dialog-eingabemodus-waehlen`) - beide Modi laufen seitdem in denselben Basis-/Winkel-Dialog, der Konsolen-Pfad ist nur noch Rueckfall bei abgeschalteter GUI/anderer Sprache. Der Dialog-Ablauf ist zentral in vf_core (`vf-dialog-ablauf`/`vf-dialog-berechnen-einfuegen`, parametrisiert ueber Typ-Registry `*vf-typ-registry*` + Flag `horizontal-p`); `vfs-standard-dialog-ablauf`/`vfe-etage-dialog-ablauf` sind nur noch duenne Wrapper darauf. Beide nutzen dieselben Dialoge `vfs-dialog-eingabe-basis`/`vfs-dialog-winkel-verteilung` und den gemeinsamen L_GF/L_VF-Solve `vf-winkel-solve` (vf_core; berechne-alle-winkel/berechne-winkel-etage teilen ihn); Doppelklick auf VF_n-Block ruft VARIOFOERDERER_EDIT, das per SSG_VF_EDIT-XDATA-Marker ("standard"/"etage"/"linienzug") in den passenden Neuaufbau-Zweig dispatcht (`vfe-edit-ent` fuer Etage, `vfl-edit-ent` fuer Linienzug); Altbestand-Bloecke ohne Marker werden abgewiesen. Linienzug (Modus 1, `vf-linienzug-modus`) zeichnet jede interaktive Eingabe in einem Journal auf (`vfl-in-point`/`-string`/`-real`/`-int`) und schreibt es als XDATA auf den fertigen `VF_n`-Block; ein Abbruch (ESC) loescht dadurch nichts mehr, sondern wickelt die bis dahin gebaute Teil-Geometrie ebenso zu einem Block (`vfl-modus-abbruch-sichern`) - sie bleibt stehen und ist sofort per Doppelklick weiter editierbar/fortsetzbar. Der komplette Linienzug-Hauptstrang (Menue-Fragen von AS-Element bis Kettenende, inkl. GF-Bogen/Vario-Kurve/VF-Einheit-Fortsetzung) laeuft per Default ueber DCL-Dialoge statt Konsole (`*vfl-wizard-mode*`, Befehle VF_WIZARD_AN/VF_WIZARD_AUS): `vfl-in-string`/`-int`/`-real` zeigen bei aktivem Wizard-Modus generische Dialoge aus `dcl/vf_linienzug_wizard.dcl` (Zahl-Eingabe bzw. Mehrfachauswahl aus `vfl-menu`/`vfl-menu-int`) statt `getstring`/`getint`/`getreal` aufzurufen; die ORIGINALEN Konsolen-Fragen (princ + get*, de/en ueber ssg-text) bleiben unveraendert im Code (Fallback bei Fehlern via `vl-catch-all-apply`, siehe `doc/variofoerderer.md`). `vfl-edit-ent` liest das Journal, zeigt die Sektionen ueber einen DCL-Dialog (`vfl-dlg-position`, `dcl/vfl_edit.dcl`) an, kuerzt bei Bedarf auf eine gewaehlte Sektion (stummer Replay der behaltenen Eingaben, umgeht den Wizard-Zweig komplett) und baut danach interaktiv weiter. Linienzug Modus 2 (Pfad+Zielhoehe-Solver, `vf-linienzug-modus2`) nutzt dieselben Wrapper PLUS die neue Objektauswahl-Wrapper-Funktion `vfl-in-selection` (Pfad-Objekte als stabile Entity-Handles journalisiert, neue Journal-Art `"OBJS"`) und schreibt sein Journal unter dem eigenen XDATA-Marker `"linienzug2"`; Doppelklick baut hier NICHT abschnittsweise, sondern per vollem Reset 1:1 aus dem Journal neu auf (`vfl-edit-ent2`, dispatcht aus `vfl-edit-ent` per Marker) - Modus 3 (Vorwaerts-Nachbau) baut dieselbe Pfad-Geometrie VORWAERTS mit vorgegebenen Winkeln durch: die Endhoehe ist dort ein Ergebnis, kein Ziel (Anfangs- statt Randwertproblem) - genau das ist sein eigener Anwendungsfall, und er schreibt ein eigenes Journal (Marker `"linienzug3"`), ist also ebenso per Doppelklick editierbar. Seit 2026-10-22 fragt er wie Modus 2 "AS bauen?"/"ES bauen?" (je mit Winkel+Seite in EINEM Dialog, `vflw-gruppe-as-impl`), und die **ES-Frage steht VOR dem Bau** - erst damit traegt die Trimmung der letzten Geraden (`- Separator - ein-dx`) den echten ES-Fussabdruck statt eines Schaetzwerts bzw. des Werts der vorherigen Kette. Aeltere `"linienzug3"`-Journale erkennt `alt-journal` am WERT des ersten Antwort-Eintrags (`"30"`/`"90"` = alt vs. `"1"`/`"2"` = neu, disjunkte Mengen; Helfer `vfl-replay-peek-wert`) und spielt sie in der alten Reihenfolge ab. **Helfer-Namensschema**: die Rechenkerne heissen nach ihrer ROLLE, nicht nach der Modus-Nummer - `vfl-zsolve-*` (Hoehen-Solve, nur Modus 2) und `vfl-pfad-*` (Arbeit am gezeichneten Pfad, von Modus 2 UND 3 genutzt). Die frueheren Praefixe `vfl3-`/`vfl2-` stammten aus einer Planungsphase vor der endgueltigen Menue-Zuordnung und waren dazu vertauscht (umbenannt 2026-10-22). `Vario_Kette_Merge` (in vf_linienzug.lsp) fuehrt mehrere einzeln gebaute VF_n-Bloecke ab einem gewaehlten Start-Baustein ueber die reale KS_AUS->KS_EIN-Nachbarschaft zu einem Gesamt-Block zusammen (aggregierte Attribute, Luecken-Erkennung). Die interaktiven Editier-Pfade (`vfl-edit-ent` Sektions-Zweig, `vfl-edit-ent2`) rufen den Neuaufbau BEWUSST direkt auf, NICHT ueber `vl-catch-all-apply`: der alte Block ist beim Neuaufbau schon per `entdel` weg, und ein Catch faengt den Abbruch VOR `*error*` ab - der Abbruch-Wickler `vfl-modus-abbruch-sichern` kaeme nie zum Zug und die ganze Kette bliebe als lose Einzelteile ohne Block liegen (Fehlerbild "VF-Block aufgebrochen"). Nur der nicht-interaktive Batch-Konverter `vfl-konvertiere-ent` behaelt den Catch (die Batch-Schleife muss weiterlaufen) und meldet den betroffenen Block. Die Abbruch-Handler setzen zusaetzlich `*ssg-ils-dim*` zurueck, weil der Aufrufer, der das sonst tut, nach einem Abbruch nicht mehr erreicht wird. Recovery-Pfad fuer bereits aufgebrochene Ketten: `VF_SEKTION_RESTORE` (vf_linienzug.lsp) setzt das Ketten-Journal aus der XDATA der losen Objekte zusammen - `SSG_VF_EDIT_SEG` traegt pro Entity den Journal-Abschnitt DER ITERATION, in der es entstand (indiziert mit dem ersten Glied-Index darin; eine VF-Einheit mit eingebetteten Vario-Kurven erzeugt mehrere Glieder in einer Iteration), `SSG_VF_EDIT_PRE` auf den Entities des ersten Gliedes die Praeambel (Startpunkt/Starthoehe/AS). Die `.dbg`-Dateien sind reine AUSGABE und werden von keinem Befehl gelesen (dbgopen legt sie bei jedem Lauf neu an) - Wiederherstellungs-Daten gehoeren in die XDATA. `vf_konstanten.lsp` (von vf_core.lsp vor den drei Submodulen geladen) sammelt alle Laengen-/Winkel-/Toleranz-Magic-Numbers aus dem VarioFoerderer-Cluster als dokumentierte `*vfk-*`-Konstanten. Die Migration ist abgeschlossen: vf_core/vf_standard/vf_etage/vf_linienzug referenzieren durchgaengig die zentralen Konstanten statt roher Literale (Winkel, Stations-/Separator-Laengen, Mindestlaengen, AS/ES-Fallback-Versaetze, Text-/Label-Masse) - Ausnahmen sind in `vf_konstanten.lsp` selbst dokumentiert (Werte mit fuehrender Config-Anbindung via `ssg-cfg-or`, itoa-/Integer-Kontexte, Blocknamen-Strings, die 2000.0-mm/m-Umrechnung). `*vfk-gf-bogen-winkel*` (30/60/90, GF-Bogen + Vario-Kurve) und `*vfk-as-es-winkel*` ("30"/"90", AS/ES; bewusst STRING, da 2-wertig und im Journal als STR gefuehrt) sind Beispiele; vf_linienzug hat fuer beide einen Fallback, falls vf_konstanten nicht geladen wurde. **Nicht-interaktiver Betrieb**: `*vfl-headless*` (+ `vfl-headless-p`/`-abbruch`/`-notausgang`, Diagnose `*vfl-headless-fehler*`, optionaler Antwort-Hook `*vfl-headless-antwort-fn*`) verbietet jede Live-Eingabe - eine erschoepfte Replay-Queue ist damit ein harter Abbruch MIT Fundstelle (Art der Eingabe, Glied- und Eingabe-Nummer) statt eines stillen Rueckfalls auf `getpoint`/`getreal`; eingebaut in `vfl-in-value`/`-value-p`/`-selection`/`-abstand`. Die Bau-Pfade melden abgewiesene Sektionen ueber `vfl-meldung` (sammelt nach `*vfl-meldungen*` + `dbgmsg`, `alert` nur bei erlaubter GUI, sonst `princ`) statt per blockierendem `alert`; reine Interaktiv-Alerts (fehlendes DCL, "nicht editierbar", "kein Journal") bleiben `alert`. Genutzt von `tests/test_hm_recformat.lsp` (Replay der echten Aufzeichnungen) und von `vf_spec.lsp`; Fahrplan in `doc/todo/plan-vf-interactive.md`. **Zufuehrungsachse + "Parallel zum Kreisel"** (Modus 1, 2026-10-21): die AS-Praeambel fragt jetzt Winkel, Seite UND eine optionale Zufuehrungsachse (2. Punkt) - beide zusammen legen AS-Lage (KS_EIN auf der Achse) und Kettenrichtung (KS_AUS ueber die Seiten-Variante) fest, BEVOR eine Strecke geklickt wird; Journalfolge `[STR winkel][STR seite][PT p2 | NIL]`, welche Fragen gestellt wurden wird NICHT journalisiert, sondern beim Replay aus der Eintragsart erkannt (PT direkt nach dem Winkel = Alt-Achse ohne Seite 2026-10-14..10-20, PT/NIL nach der Seite = neues Format, alles andere = Altbestand ohne Achse). Darauf setzt die 5. Option der gf-laenge-modus-Frage auf, intern `"parallel"` (`vfl-gf-parallel-kreisel`): baut AS -> GF-Stueck -> GF-Bogen aus EINEM Abstandswert (senkrecht zur Zufuehrungsachse, AS-KS_EIN bis Bogen-KS_AUS), ohne Separator dazwischen, und stellt die Kettenende-Frage selbst NACH dem Bau. Nur am Kettenanfang mit AS UND Achse waehlbar (sonst Kachel deaktiviert). Bogenwahl nicht hartcodiert, sondern ueber den gemessenen `vf-element-plan-turn` - gewaehlt wird der Bogen, der den AS-Schwenk aufhebt (AS 30 -> 30-Grad-Bogen, AS 90 -> 90-Grad-Bogen, immer Gegenseite; die Zuordnung ist das ERGEBNIS der Messung, keine gepflegte Tabelle). Reine Kerne `vfl-par-bogen-waehlen`/`vfl-par-gf-laenge` in `tests/test_unit.lsp` (`tu-tests-vfl-parallel`) getestet; Ablauf in `doc/vf_linienzug_modus1_anleitung.md` Abschnitt 3a. Details/Entscheidungsbaum: `doc/variofoerderer.md` | | `vf_spec.lsp` (von vf_core.lsp NACH vf_linienzug.lsp geladen) | VF_SPEC_BAU | Linienzug-Ketten aus **Eingabedaten** bauen, ohne Dialog und ohne Konsolenfrage (Stufe 1 aus `doc/todo/plan-vf-interactive.md`). Eine **Spec** beschreibt eine Kette in Domaenenwerten (`"links"`, `"winkel"`, `"aussen"`, ja/nein) statt in Menue-Codes; `vsp-journal` uebersetzt sie in ein Eingabe-Journal, `vsp-bau-aus-spec` spielt es per `vfl-journal-replay-start` durch den UNVERAENDERTEN `vf-linienzug-modus` (Replay-Kern `vsp-bau-journal` - nimmt auch ein unveraendert uebernommenes, aufgezeichnetes Journal, z.B. aus `dxf_anlage_export.py`). Damit traegt der fertige Block dasselbe `SSG_VF_EDIT`-Journal wie eine handgebaute Kette und bleibt per Doppelklick editier- und 2D/3D-konvertierbar - kein Journal-Konsument muss etwas von Specs wissen. Wichtige Regeln, die der Uebersetzer kennt: der Menue-Code haengt am Frame (erste Sektion 4 Optionen ohne GF-Bogen, danach 5), `hz` steht nur beim ERSTEN Segment im Journal, und `erst-hor` unterscheidet den horizontalen Erstkoerper einer VF-Einheit (Separator-/Endpunktfragen vorab) vom gewinkelten (keine Frage). Fehlerverhalten: fail fast - `vsp-pruefen` sammelt ALLE Spec-Fehler, gebaut wird dann nichts (nichts wird geraten). Ergebnis-Record je Kette mit `status` (`executed`/`warnung`/`desync`/`abbruch`/`spec-fehler`), Block/Handle/Einfuegepunkt/Attributen, `prompts` (muss 0 sein), `glieder_soll` vs. `glieder_ist` (Desync-Detektor, der auch bei aufgehender Queue greift) und den gesammelten `meldungen`. Headless-Rahmen `vsp-headless-an`/`-aus` (Save/Restore von `*vfl-headless*`, `*vfl-wizard-mode*`, `*ssg-gui-aus*` + zaehlende Eingabe-Stubs). Spec-Datei flach als JSON (`ssg-load-json` liest zeilenweise), erzeugt von `lib/vf_spec_export.py`. Gegenstueck/Referenz in Python: derselbe Emitter, gegen die 5 echten HundM-Ketten rundlaufgeprueft | | `Gefaellestrecke.lsp` | GEFAELLESTRECKE, GEFAELLESTRECKE_EDIT | Gefaelle-Foerderanlage (AUS -> Staustrecke skaliert -> Separator -> EIN); Modus 1 per DCL-Dialog (Einfuegehoehe, Element-Winkel 30/90); Doppelklick auf GF_n-Block ruft GEFAELLESTRECKE_EDIT (Dialog vorbelegt, Neuaufbau; die Einfuegehoehe kommt aus der aktuellen Z des Einfuegepunkts statt aus XDATA/HOEHE_VON_mm, damit ein in Z verschobener Block per OK direkt auf der neuen Hoehe neu entsteht - gleiches gilt fuer die 2D/3D-Umschaltung `gf-konvertiere-ent`; der GF-Linienzug-Rebuild nutzt weiter die absoluten Segmentpunkte aus XDATA) | | `export.lsp` | EXPORTSIVAS, EXPORTCSV, OMNI_UPDATE_ATTRIBS, CSV_EXPORT_KONFIG | JSON-Sammlung und Python-Export (Omniflo-Merkmale/Sum-Zeile via lib/export_csv.py). **Gefrorene Layer**: `csv:collect-export-blocks` laesst Bloecke auf gefrorenen Layern aus (ausgeschaltete Layer zaehlen NICHT), Schalter `*csv-gefrorene-ausschliessen*` (Standard an, Toggle im Dialog CSV_EXPORT_KONFIG). Die Hilfsobjekte eines gefrorenen VF_n/GF_n (Separator-/Element-Kopien, Einheiten-/AS-ES-Marker) liegen auf eigenen Layern und werden darum ueber `*csv-ausschluss-enames*` mit ausgelassen (gesetzt in `csv:export-vorbereiten` per `csv:hilfskopien-ausschluss`); erzeugt und nummeriert werden sie trotzdem, damit IDs stabil bleiben. DrawPlanquadrate nutzt dieselbe Sammlung und folgt dem Filter. **Hoehen-Neuberechnung**: erster Schritt von `csv:export-vorbereiten` ist `csv:hoehen-aktualisieren` - in Z verschobene `KREISEL_*`/`ECKRAD_*`/`VF_*`/`GF_*` bekommen ihre Hoehen-Attribute aus der Einfuege-Z neu (reiner Kern `csv:hoehen-werte`, getestet; Formeln/Rundung wie beim Bau: Kreisel HOEHE + MONTAGEHOEHE_m=z/1000, Eckrad HOEHE, GF/VF HOEHE_VON_mm=(fix z), MONTAGEHOEHE_m GF=z/1000 bzw. VF=(VON+BIS)/2000). HOEHE_BIS_mm = VON - (VON_alt - BIS_alt), bewusst NICHT z - DELTA_H_mm (ohne Vorzeichen -> steigende VF falsch, separat abgeschnitten -> 1 mm Abweichung); DELTA_H_mm nur Rueckfall. Nicht verschobene Bloecke (Attribut passt zu z) bleiben unangetastet, damit Bau-Werte und Hand-Korrekturen (z.B. Buehnen-Abzug aus HOEHEN_CHECK) bit-genau erhalten bleiben | diff --git a/Lisp/vf_konstanten.lsp b/Lisp/vf_konstanten.lsp index b9c3f82..c40dcd7 100644 --- a/Lisp/vf_konstanten.lsp +++ b/Lisp/vf_konstanten.lsp @@ -101,8 +101,8 @@ (if (null *vfk-etage-hz-winkel*) (setq *vfk-etage-hz-winkel* 30.0)) ;; Eckwinkel-Toleranz bei der automatischen Pfad-Klassifizierung (Modus 3, -;; vf-linienzug-modus3 -> vfl2-pruefe-eckwinkel). Aktiv referenziert in -;; vf_linienzug.lsp (beide Aufrufstellen von vfl2-pruefe-eckwinkel). +;; vf-linienzug-modus3 -> vfl-pfad-eckwinkel-pruefen). Aktiv referenziert in +;; vf_linienzug.lsp (beide Aufrufstellen von vfl-pfad-eckwinkel-pruefen). (if (null *vfk-eckwinkel-toleranz*) (setq *vfk-eckwinkel-toleranz* 5.0)) ;; Schwellwert (Grad), ab dem ein Frame noch als "flach" (~0 Grad) gilt. @@ -123,7 +123,7 @@ ;; (vf_etage.lsp Z.41) ;; - Linienzug-Kettenende/Body-Abschluss (nur Motor+1 Separator, KEIN ;; Umlenk-Anteil): 800 als rohes Literal an >10 Stellen in -;; vf_linienzug.lsp (vfl-body-zerlegung, vfl3-waehle-winkel, ...) +;; vf_linienzug.lsp (vfl-body-zerlegung, vfl-zsolve-winkel-waehlen, ...) ;; Diese vier NICHT vereinheitlichen ohne sorgfaeltige Pruefung - sie ;; entstehen aus unterschiedlicher Bauteil-Zusammensetzung (siehe jeweiliger ;; Kommentar im Modul), keine Kopiergleichheit. @@ -166,7 +166,7 @@ ;; Mindestlaenge (mm) fuer die 3-Grad-GF-Anschlussstrecke (GF1 am Einlauf ;; einer VF-Einheit). Bereits als *vfl-gf-min-laenge* in vf_linienzug.lsp ;; benannt (Wert 400.0) - hier nur gespiegelt. Das fruehere rohe 400.0- -;; Duplikat (br-gf1 in vfl3-*) referenziert jetzt *vfl-gf-min-laenge*. +;; Duplikat (br-gf1 in vfl-zsolve-*) referenziert jetzt *vfl-gf-min-laenge*. (if (null *vfk-gf-anschluss-mindestlaenge*) (setq *vfk-gf-anschluss-mindestlaenge* 400.0)) ;; ============================================================ diff --git a/Lisp/vf_linienzug.lsp b/Lisp/vf_linienzug.lsp index 054fe7c..26e9766 100644 --- a/Lisp/vf_linienzug.lsp +++ b/Lisp/vf_linienzug.lsp @@ -382,6 +382,18 @@ (while (and q (= (car (car q)) "STEP")) (setq q (cdr q))) (if q (car (car q)) nil)) +;; WERT des naechsten Replay-Eintrags, ohne ihn zu verbrauchen (nil bei leerer +;; Queue). Gegenstueck zu vfl-replay-peek-art fuer den Fall, dass die ART +;; allein nicht reicht: wird an einer Stelle eine neue Frage GLEICHEN Typs +;; eingefuegt, unterscheidet nur noch der Wert alt von neu. Genutzt in +;; vf-linienzug-modus3, wo seit 2026-10-22 ein "AS bauen?" (STR "1"/"2") VOR +;; dem AS-Winkel (STR "30"/"90") steht - die beiden Wertemengen sind disjunkt, +;; ein Blick auf den Wert erkennt das Alt-Journal also eindeutig. +(defun vfl-replay-peek-wert ( / q) + (setq q *vfl-replay-queue*) + (while (and q (= (car (car q)) "STEP")) (setq q (cdr q))) + (if q (cdr (car q)) nil)) + ;; ============================================================ ;; TEIL 0b-1b: GLIED-SCHEMA (single source of truth) ;; ============================================================ @@ -910,33 +922,24 @@ " -> Achse " (rtos (vfl-planar-hz achse-basis gpunkt) 2 1) " Grad"))))) - ;; Seitenauswahl ist OHNE Achsen-Dialog nur beim 90-Grad-Element - ;; wirksam: dort folgt die Seite beim 30-Grad-Element aus der - ;; Zufuehrungsachse (Nutzer-Vorgabe 2026-10-14). Sie wird darum - ;; ausgegraut - und unten auch NICHT in die Pending-Queue gelegt, sonst - ;; zoege die Punktfrage sie als vermeintlichen Punkt heraus und - ;; erschiene gar nicht. MIT Achsen-Dialog wird die Seite dagegen immer - ;; gebraucht (sie ist die AS-Variante, nicht mehr aus der Achse - ;; ableitbar) und bleibt daher auch bei 30 Grad waehlbar. + ;; Die Seite ist in JEDEM verbleibenden Anwendungsfall noetig und daher + ;; auch beim 30-Grad-Element waehlbar. Bis 2026-10-22 wurde sie dort + ;; ausgegraut und NICHT in die Pending-Queue gelegt - das war eine + ;; reine Modus-1-Regel (dort ersetzte die Zufuehrungsachse die + ;; Seitenfrage). Modus 1 hat seit 2026-10-21 seinen eigenen Dialog + ;; (vflw_as_achse), uebrig bleiben ES-Element sowie Modus 2/3 - und + ;; dort fuehrte die Ausgrauung dazu, dass bei 30 Grad ein ZWEITES + ;; Fenster nur fuer die Seite aufging (die nachfolgende Frage fand + ;; keinen Wert in der Queue). (action_tile "setzen" - (if mit-achse + (strcat "(mode_tile \"winkel_90\" (if (= (get_tile \"setzen\") \"1\") 0 1)) (mode_tile \"winkel_30\" (if (= (get_tile \"setzen\") \"1\") 0 1)) (mode_tile \"seite_links\" (if (= (get_tile \"setzen\") \"1\") 0 1)) - (mode_tile \"seite_rechts\" (if (= (get_tile \"setzen\") \"1\") 0 1)) - (mode_tile \"pick\" (if (= (get_tile \"setzen\") \"1\") 0 1))" - "(mode_tile \"winkel_90\" (if (= (get_tile \"setzen\") \"1\") 0 1)) - (mode_tile \"winkel_30\" (if (= (get_tile \"setzen\") \"1\") 0 1)) - (mode_tile \"seite_links\" (if (and (= (get_tile \"setzen\") \"1\") (/= (get_tile \"winkel_30\") \"1\")) 0 1)) - (mode_tile \"seite_rechts\" (if (and (= (get_tile \"setzen\") \"1\") (/= (get_tile \"winkel_30\") \"1\")) 0 1))")) - (if (not mit-achse) - (progn - (action_tile "winkel_30" - "(mode_tile \"seite_links\" 1) - (mode_tile \"seite_rechts\" 1)") - (action_tile "winkel_90" - "(mode_tile \"seite_links\" (if (= (get_tile \"setzen\") \"1\") 0 1)) - (mode_tile \"seite_rechts\" (if (= (get_tile \"setzen\") \"1\") 0 1))"))) + (mode_tile \"seite_rechts\" (if (= (get_tile \"setzen\") \"1\") 0 1))" + (if mit-achse + "(mode_tile \"pick\" (if (= (get_tile \"setzen\") \"1\") 0 1))" + ""))) (if mit-achse (action_tile "pick" "(setq gsetzen (get_tile \"setzen\")) @@ -974,13 +977,11 @@ ;; Winkel-Slot wird von vfl-in-value (AS-Winkel, ueber ;; vf-frage-element-winkel) konsumiert - der erwartet direkt ;; "30"/"90", NICHT den Auswahl-Index wie beim Seite-Slot. + ;; Die Seite geht IMMER mit (siehe Kommentar oben), nur der + ;; Achsen-Punkt haengt am Dialogtyp. (if mit-achse (vflw-pending-push-all (list "1" gwinkel gseite gpunkt)) - ;; Ohne Achsen-Dialog beim 30-Grad-Element KEINE Seite - ;; mitgeben (siehe Kommentar oben). - (if (= gwinkel "30") - (vflw-pending-push-all (list "1" gwinkel)) - (vflw-pending-push-all (list "1" gwinkel gseite)))) + (vflw-pending-push-all (list "1" gwinkel gseite))) (vflw-pending-push-all (list "2")))) ((= ergebnis (if mit-achse 3 2)) (setq fertig t) (setq *vfl-wizard-abbruch-grund* "zurueck")) @@ -9800,9 +9801,22 @@ ;; - GF-Bogen hat feste Eigen-Neigung -> bei unterschiedlichen Nachbar- ;; Neigungen entsteht ein (akzeptierter) Knick. +;; ============================================================ +;; PFAD-HELFER (vfl-pfad-*) - geteilt von MODUS 2 UND MODUS 3 +;; ============================================================ +;; Alles, was auf dem GEZEICHNETEN Pfad arbeitet: Eckwinkel pruefen, +;; AS-Element einfuegen, VF-Einheit oeffnen/schliessen. Bewusst OHNE +;; Modus-Nummer im Namen - bis 2026-10-22 hiessen sie vfl2-*, was zu Modus 2 +;; passte, obwohl die Haelfte davon zu Modus 3 gehoert und drei von ihnen von +;; BEIDEN Modi benutzt werden (vfl-pfad-eckwinkel-pruefen, +;; vfl-pfad-as-gf-einfuegen, vfl-pfad-as-vf-einfuegen). Eine Nummer waere hier +;; also gar nicht richtig vergebbar; der Name nennt jetzt die Rolle. +;; Gegenstueck: vfl-zsolve-* (Hoehen-Rechenkern von Modus 2, weiter unten). +;; ============================================================ + ;; Alle Eck-Winkel des Pfades gegen 30/60/90 Grad pruefen (Toleranz tol). ;; Rueckgabe: nil (alle ok) oder der erste abweichende Winkel (Grad). -(defun vfl2-pruefe-eckwinkel (kette tol / item obj sa ea sweep bad) +(defun vfl-pfad-eckwinkel-pruefen (kette tol / item obj sa ea sweep bad) (setq bad nil) (foreach item kette (setq obj (car item)) @@ -9829,12 +9843,12 @@ ;; Ergebnis: KS_EIN.X = Startpunkt.X, KS_EIN quer um das AS-Y-Mass versetzt, ;; KS_AUS liegt exakt auf dem Pfad -> die ganze Kette folgt der Mittellinie. ;; Rueckgabe: (korrigierter) Frame am KS_AUS. -;; winkel-Parameter bleibt aus Call-Kompatibilitaet bestehen (vfl2-insert-as-vf +;; winkel-Parameter bleibt aus Call-Kompatibilitaet bestehen (vfl-pfad-as-vf-einfuegen ;; ruft mit 0.0), wird aber NICHT mehr fuer eine Kippung verwendet: das AS- ;; Element hat keine eigene Neigung (per Einzel-Insert-Test in BricsCAD ;; bestaetigt, siehe vfl-insert-as-element in Modus 1) - unabhaengig vom ;; folgenden Segmenttyp (GF/VF) wird es IMMER flach eingefuegt. -(defun vfl2-insert-as-gf (startpunkt hz winkel as-seite / +(defun vfl-pfad-as-gf-einfuegen (startpunkt hz winkel as-seite / ein-hz-as rad-h xu-ein frame blk ks-aus rad-hz perp-x perp-y d-perp sx sy as-turn rad-ein de-x de-y de-dot-np t-shift) @@ -9877,12 +9891,12 @@ ;; (0 Grad Neigung). Das AS wird mit KS_EIN auf den Startpunkt gesetzt und dann ;; senkrecht zu hz auf den Pfad geschoben (reine KS-Kettung, KS_AUS auf Pfad). ;; Damit liegt auch eine mit VF beginnende Kette auf dem gezeichneten Pfad. -(defun vfl2-insert-as-vf (startpunkt hz as-seite) - (vfl2-insert-as-gf startpunkt hz 0.0 as-seite)) +(defun vfl-pfad-as-vf-einfuegen (startpunkt hz as-seite) + (vfl-pfad-as-gf-einfuegen startpunkt hz 0.0 as-seite)) ;; VF-Einheit OEFFNEN (Modus 2): GF1 (Basis-Staustrecke) + Separator + ;; Umlenkstation. Rueckgabe: Frame nach der Umlenkstation (Beginn reiner VF). -(defun vfl2-vf-open (frame hz / f) +(defun vfl-pfad-vf-oeffnen (frame hz / f) (setq f (vfl-frame-3grad (vfs-vf-entry (car frame) *vfl-gf-min-laenge* hz nil) hz)) (if (> *vfl-gf-min-laenge* 0.1) (vfl-acc-gf-seg *vfl-gf-min-laenge* (ssg-cfg-or "vario" "gefaelle_winkel" 3))) @@ -9891,7 +9905,7 @@ ;; VF-Einheit SCHLIESSEN (Modus 2): Motorstation + GF2 (Basis), KEIN Separator ;; (der sitzt erst am Kettenende bzw. optional zwischen Foerderern). Rueckgabe: ;; Frame nach GF2. -(defun vfl2-vf-close (frame hz / f) +(defun vfl-pfad-vf-schliessen (frame hz / f) (setq *vfl-acc-motorseite* (append *vfl-acc-motorseite* (list "rechts"))) (setq f (vfl-frame-3grad (vfs-vf-exit (car frame) *vfl-gf-min-laenge* hz nil) hz)) (if (> *vfl-gf-min-laenge* 0.1) @@ -9899,7 +9913,7 @@ f) ;; Vario-Winkel (Vertikalbogen) auf die verfuegbaren Werte 3..51 einrasten. -(defun vfl2-snap-vfwinkel (w / liste best bd d) +(defun vfl-pfad-vfwinkel-snappen (w / liste best bd d) (setq liste (ssg-cfg-or "vario" "bogen_winkel" '(3 6 9 12 15 18 21 27 33 39 45 51))) (setq best (car liste) bd 1e9) (foreach x liste (setq d (abs (- x w))) (if (< d bd) (setq bd d best x))) @@ -9996,7 +10010,7 @@ (vfl-journal-record "NIL" nil) nil) (progn (setq segmente (gf-analysiere-kette kette)) - (setq ecke-bad (vfl2-pruefe-eckwinkel kette ecke-tol)) + (setq ecke-bad (vfl-pfad-eckwinkel-pruefen kette ecke-tol)) (if ecke-bad (progn (vfl-meldung (ssg-textf "vfl-vwnb-alert-eckwinkel" (list (rtos ecke-bad 2 1)))) @@ -10013,6 +10027,7 @@ ecke-bad first-line last-line letzt-winkel aus ein soll-ende ist-ende run-typ richtn best-w kvariante L_VF ent-fp rad3 just-open + as-vorhanden es-vorhanden alt-journal dbg-an old-error dbg-old-error vfl-ins) (princ "\n\n=========================================") (princ (ssg-text "vfl-vwnb-titel")) @@ -10057,27 +10072,76 @@ ;; Startpunkt + Hoehe (gemeinsame Praeambel-Schale, siehe vfl-frage-punkt-hoehe). (setq startpunkt (vfl-frage-punkt-hoehe "vfl-m3-prompt-startpunkt" "vfl-prompt-hoehe-startpunkt" "vfl-abgebrochen" "Starthoehe (Z, mm):")) - ;; AS-Element (in Modus 3 immer gesetzt): Winkel(30/90) + Seite als EIN - ;; Gruppen-Dialog. vflw-gruppe-winkel-seite-impl legt Winkel ("90"/"30") - ;; und Seite ("1"/"2") in *vflw-pending* ab - genau die Reihenfolge, die - ;; die beiden Reads unten erwarten. AS-Winkel ueber vfl-in-value (pending- - ;; aware; vf-frage-element-winkel selbst ist es NICHT), damit der vom Dialog - ;; abgelegte Wert konsumiert wird statt live erneut zu fragen. - (if (vfl-wizard-aktiv) - (vl-catch-all-apply 'vflw-gruppe-winkel-seite-impl - (list "vf-winkel-aus-header" - (list (ssg-text "vf-winkel-90") (ssg-text "vf-winkel-30")) - (list "90" "30")))) - (princ (ssg-text "vf-winkel-aus-header")) - (princ (ssg-text "vf-winkel-90")) - (princ (ssg-text "vf-winkel-30")) - (setq *vfl-as-winkel* - (vfl-in-value "STR" - (function (lambda () (vf-frage-element-winkel "vf-winkel-aus-header"))))) ; 30/90 vor Seite + ;; --- ALT-JOURNAL-ERKENNUNG (einmal, gilt fuer AS UND ES) --- + ;; Bis 2026-10-22 kannte Modus 3 weder "AS bauen?" noch "ES bauen?", und die + ;; ES-Frage stand am ENDE (nach dem Bau). Seither steht vor dem AS-Winkel + ;; ein Ja/Nein und die ES-Frage VOR dem Bau - beides aendert die Reihenfolge + ;; im Journal. Ketten, die vorher gebaut wurden, muessen per Doppelklick + ;; weiter nachbaubar bleiben; erkannt werden sie am WERT des naechsten + ;; Eintrags: dort steht im Altbestand direkt der AS-Winkel ("30"/"90"), im + ;; neuen Format die Ja/Nein-Antwort ("1"/"2"). Die Wertemengen sind + ;; disjunkt, die Unterscheidung also eindeutig (vfl-replay-peek-wert). + ;; Live (ohne Replay-Queue) ist alt-journal immer nil = neuer Ablauf. + (setq alt-journal + (and *vfl-replay-queue* + (= (vfl-replay-peek-art) "STR") + (member (vfl-replay-peek-wert) '("30" "90")))) + (if alt-journal (princ (ssg-text "vfl-m3-alt-journal"))) + ;; Winkel-Globals pro Lauf zuruecksetzen (wie in Modus 1/2): ohne AS bzw. + ;; ES wuerde sonst der Wert der VORHERIGEN Kette in die Block-Attribute + ;; WINKEL_AS/WINKEL_ES wandern. + (setq *vfl-as-winkel* nil *vfl-es-winkel* nil) + + ;; AS-Element: "bauen?" + Winkel(30/90) + Seite als EIN Gruppen-Dialog - + ;; dasselbe Muster wie in Modus 2 (vflw-gruppe-as-impl legt Ja/Nein, Winkel + ;; "90"/"30" und Seite "1"/"2" in *vflw-pending* ab, genau in der + ;; Reihenfolge, die die Reads unten erwarten). Die Ja/Nein-Frage war in + ;; Modus 3 bis 2026-10-22 gar nicht vorhanden (AS wurde immer gebaut, + ;; Nutzer-Wunsch). + (if alt-journal + (setq as-vorhanden t) + (progn + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-as-impl (list "vfl-as-setzen-frage" nil))) + (princ (ssg-text "vfl-as-setzen-frage")) + (princ (ssg-text "vfl-ja")) + (princ (ssg-text "vfl-m3-as-nein")) + (setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2") + (list (ssg-text "vfl-ja") (ssg-text "vfl-m3-as-nein")) 1 + "vfl-as-setzen-frage")) + (setq as-vorhanden (/= antwort "2")))) + ;; Winkel + Seite (setzt *vfl-as-winkel* und ueber vf-set-as-masse die + ;; aus-dx/aus-dz der Variante) - gemeinsame Schale mit Modus 2. + (if as-vorhanden + (setq as-seite (vfl-frage-as-winkel-seite "gf-seite-aus-header"))) (if dbg-an (progn (dbgmsg "AS-Winkel:") (dbg '*vfl-as-winkel*) (dbgflush))) - (princ (ssg-text "vfl-vwnb-aus-seite-menu")) - (setq as-seite (if (= (vfl-in-string (ssg-text "prompt-wahl-1-2")) "2") "rechts" "links")) - (vf-set-as-masse *vfl-as-winkel* as-seite) ; Masse fuer Variante + + ;; --- ES-Element JETZT fragen, VOR dem Bau (Nutzer-Vorgabe 2026-10-22, + ;; wie in Modus 1) --- + ;; Erst damit steht der ECHTE ES-Fussabdruck fest (ein-dx/ein-dz haengen an + ;; Winkel UND Seite), den die Trimmung der LETZTEN Geraden unten abzieht. + ;; Vorher wurde dort ein Wert benutzt, der zu diesem Zeitpunkt noch gar + ;; nicht gesetzt war: beim ersten Lauf griff der Schaetzwert + ;; *vfk-as-es-fallback-dx*, bei jedem weiteren stand dort der Wert der + ;; VORHERIGEN Kette. Beim Alt-Journal bleibt die Frage an ihrer alten + ;; Stelle (Schritt 7), damit die Replay-Reihenfolge stimmt. + (if alt-journal + (setq es-vorhanden t) ; Frage folgt in Schritt 7 + (progn + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-as-impl (list "vfl-es-setzen-frage" nil))) + (princ (ssg-text "vfl-es-setzen-frage")) + (princ (ssg-text "vfl-ja")) + (princ (ssg-text "vfl-nein")) + (setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2") + (list (ssg-text "vfl-ja") (ssg-text "vfl-nein")) 1 + "vfl-es-setzen-frage")) + (setq es-vorhanden (/= antwort "2")) + (if es-vorhanden + (setq es-seite (vfl-frage-es-winkel-seite "gf-seite-ein-header")) + ;; Ohne ES wird auch kein Fussabdruck reserviert - sonst bliebe die + ;; letzte Gerade um Separator+ES zu kurz. + (setq ein-dx 0.0 ein-dz 0.0)))) ;; --- 3. Pfad waehlen + Sortieren + Analysieren + Eck-Vorpruefung --- ;; vfl-in-segmente kapselt Live (ssget -> gf-sortiere-objekte -> @@ -10179,21 +10243,32 @@ ;; --- GF-Gerade --- ((or (= antwort "") (= antwort "1")) (if (= run-typ "VF") ; offenen VF-Lauf schliessen - (progn (setq frame (vfl2-vf-close frame (car (frame->hz-winkel frame)))) + (progn (setq frame (vfl-pfad-vf-schliessen frame (car (frame->hz-winkel frame)))) (setq run-typ nil))) (setq winkel (vfl-in-real (ssg-text "vfl-m3-prompt-gf-neigung"))) (if (null winkel) (setq winkel *vfk-gefaelle-winkel*)) (if (> winkel *vfk-gefaelle-winkel*) (progn (princ (ssg-text "vfl-m3-hinweis-gf-max")) (setq winkel *vfk-gefaelle-winkel*))) + ;; Ohne AS beginnt die Kette direkt am Startpunkt - nur ein flacher + ;; Rahmen, kein Block (wie vfl-kettenanfang-baustein in Modus 1). + ;; Die Fussabdruck-Trimmung unten rechnet dann automatisch 0, weil + ;; (car frame) und startpunkt zusammenfallen. (if (null frame) - (setq frame (vfl2-insert-as-gf startpunkt hz winkel as-seite))) + (setq frame (if as-vorhanden + (vfl-pfad-as-gf-einfuegen startpunkt hz winkel as-seite) + (make-frame-from-dir startpunkt (hz-winkel->xu hz 0.0))))) (setq deltaL laenge) ;; erste Gerade: AS-Fussabdruck ENTLANG des Pfads exakt aus KS_AUS abziehen (if (= i first-line) (setq deltaL (- deltaL (+ (* (- (car (car frame)) (car startpunkt)) (cos (* hz (/ pi 180.0)))) (* (- (cadr (car frame)) (cadr startpunkt)) (sin (* hz (/ pi 180.0)))))))) - (if (= i last-line) (setq deltaL (- deltaL *vfk-separator-laenge* ein))) + ;; letzte Gerade: Platz fuer Separator + ES freihalten - aber nur, + ;; wenn ueberhaupt ein ES kommt (seit 2026-10-22 abfragbar). "ein" + ;; traegt jetzt den ECHTEN ein-dx der gewaehlten ES-Variante, weil + ;; die ES-Frage vor dem Bau steht. + (if (and (= i last-line) es-vorhanden) + (setq deltaL (- deltaL *vfk-separator-laenge* ein))) (setq deltaL (max *vfk-restlaenge-min-clamp* deltaL)) (setq frame (vfl-insert-gf-segment (car frame) hz deltaL winkel)) (vfl-acc-gf-seg (/ deltaL (cos (* winkel (/ pi 180.0)))) winkel) @@ -10203,16 +10278,18 @@ (setq richtn (cond ((= antwort "3") "Auf") ((= antwort "4") "horizontal") (t "Ab"))) (setq just-open nil) (if (null frame) ; AS (flach) am Kettenanfang, KS_AUS auf Pfad - (setq frame (vfl2-insert-as-vf startpunkt hz as-seite))) + (setq frame (if as-vorhanden + (vfl-pfad-as-vf-einfuegen startpunkt hz as-seite) + (make-frame-from-dir startpunkt (hz-winkel->xu hz 0.0))))) (if (not (= run-typ "VF")) ; VF-Einheit oeffnen - (progn (setq frame (vfl2-vf-open frame hz)) + (progn (setq frame (vfl-pfad-vf-oeffnen frame hz)) (setq run-typ "VF" just-open t))) (if (= richtn "horizontal") (setq best-w 0) (progn (setq best-w (vfl-in-int (ssg-text "vfl-vwnb-prompt-vario-winkel"))) (if (null best-w) (setq best-w 3)) - (setq best-w (vfl2-snap-vfwinkel best-w)) + (setq best-w (vfl-pfad-vfwinkel-snappen best-w)) (if dbg-an (progn (dbgmsg "Vario-Winkel (gesnapt):") (dbg 'best-w) (dbgflush))))) (setq L_VF laenge) (if just-open (setq L_VF (- L_VF ent-fp))) ; Entry-Fussabdruck reservieren @@ -10243,7 +10320,7 @@ (if (null frame) (progn (vfl-meldung (ssg-text "vfl-m3-alert-beginnt-bogen")) (exit))) (if (= run-typ "VF") ; VF-Lauf vor GF-Bogen schliessen - (progn (setq frame (vfl2-vf-close frame (car (frame->hz-winkel frame)))) + (progn (setq frame (vfl-pfad-vf-schliessen frame (car (frame->hz-winkel frame)))) (setq run-typ nil))) (setq frame (vfl-insert-gf-bogen-block frame bwinkel bseite)) (setq run-typ "GF")))) @@ -10252,16 +10329,21 @@ ;; --- 7. Kettenende: offenen VF-Lauf schliessen, dann Separator + ES --- (if (null frame) (progn (princ (ssg-text "vfl-m3-nichts-gebaut")) (exit))) + ;; Alt-Journal: dort steht die ES-Frage GENAU HIER (siehe Schritt 2) - die + ;; Replay-Reihenfolge muss stimmen, also wird sie hier nachgeholt. ;; vfl-frage-es-seite nutzt intern bereits vfl-in-value/vfl-menu - wird also ;; automatisch mitgeloggt, kein manueller dbgmsg noetig. - (setq es-seite (vfl-frage-es-seite nil)) + (if alt-journal (setq es-seite (vfl-frage-es-seite nil))) (if (= run-typ "VF") (progn - (setq frame (vfl2-vf-close frame (car (frame->hz-winkel frame)))) - (setq frame (vfl-insert-es-element "VF" frame (car (frame->hz-winkel frame)) - 0.0 (caddr (car frame)) es-seite))) - (setq frame (vfl-insert-es-element "GF" frame (car (frame->hz-winkel frame)) - (if letzt-winkel letzt-winkel *vfk-gefaelle-winkel*) (caddr (car frame)) es-seite))) + (setq frame (vfl-pfad-vf-schliessen frame (car (frame->hz-winkel frame)))) + (if es-vorhanden + (setq frame (vfl-insert-es-element "VF" frame (car (frame->hz-winkel frame)) + 0.0 (caddr (car frame)) es-seite)))) + (if es-vorhanden + (setq frame (vfl-insert-es-element "GF" frame (car (frame->hz-winkel frame)) + (if letzt-winkel letzt-winkel *vfk-gefaelle-winkel*) + (caddr (car frame)) es-seite)))) ;; --- 8. Block + Journal-XDATA + Ist-Ziel-Report --- (setq hoehe-bis (caddr (car frame))) @@ -10305,16 +10387,27 @@ ) ;; ============================================================ -;; MODUS 3: Pfad + Ziel-Hoehe (Randwert-Solver) - M3a -;; Schritt 1+2: Geruest + Klassifizierung + Anker-Report. NOCH KEIN Bauen. -;; Details siehe doc/VarioFoerderer_Linienzug_Prinzipien.md, Abschnitt 14. +;; Z-SOLVER (vfl-zsolve-*) - Rechenkern von MODUS 2 (Pfad + Ziel-Hoehe) +;; ============================================================ +;; Gehoert zu vf-linienzug-modus2 (Menue-Modus 2), NICHT zu Modus 3 - die +;; Ueberschrift sagte bis 2026-10-22 faelschlich "MODUS 3", weil die Helfer +;; 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). +;; +;; Gegenstueck: die vfl-pfad-*-Helfer weiter oben arbeiten auf dem +;; gezeichneten Pfad selbst (Eckwinkel pruefen, AS einfuegen, VF oeffnen/ +;; schliessen) und werden von Modus 2 UND Modus 3 genutzt - auch sie tragen +;; deshalb bewusst keine Modus-Nummer. ;; ============================================================ ;; Signierte Z-Aenderung (mm) einer GF-Geraden: negativ = Abfall. ;; l-planar = XY-Planlaenge (aus Pfad), winkel = Neigung in Grad (fallend). ;; Ueber die Planlaenge gilt dz = -L * tan(winkel) (Fussabdruck bleibt L, ;; die 3D-Laenge waechst mit L/cos, siehe Doc 14.1). -(defun vfl3-gf-dz (l-planar winkel / rad) +(defun vfl-zsolve-gf-dz (l-planar winkel / rad) (setq rad (* (float winkel) (/ pi 180.0))) (- (* (float l-planar) (/ (sin rad) (cos rad))))) @@ -10323,10 +10416,10 @@ ;; GF-Bogen -> dz aus gf-bogen-masse (Block-KS) ;; Vario-Kurve -> 0 (auf 0 Grad geflacht) ;; VF-Gerade -> nil (unbekannt = Teil der Bruecke) -(defun vfl3-seg-dz (e) +(defun vfl-zsolve-seg-dz (e) (cond ((= (car e) "Linie") - (if (= (nth 3 e) "GF") (vfl3-gf-dz (caddr e) (nth 4 e)) nil)) + (if (= (nth 3 e) "GF") (vfl-zsolve-gf-dz (caddr e) (nth 4 e)) nil)) ((= (car e) "Bogen") (if (= (nth 5 e) "Vario-Kurve") 0.0 @@ -10340,7 +10433,12 @@ ;; ihre Laenge variiert (das ist der Ausgleich, siehe Doc 14.3). ;; dH-signiert: negativ = Auf (steigt), positiv = Ab (faellt). ;; Rueckgabe: (winkel L_GF L_VF richtung) oder nil (kein passender Winkel). -(defun vfl3-solve-bruecke (span dH-signiert extra-fest / +;; +;; HINWEIS: derzeit von NIEMANDEM aufgerufen - der Bau-Pfad loest die Bruecke +;; ueber vfl-zsolve-winkel-waehlen. Beim Umbenennen 2026-10-22 bewusst stehen +;; gelassen statt geloescht (gehoert in ein Tote-Code-Review, nicht in eine +;; Umbenennung). +(defun vfl-zsolve-bruecke (span dH-signiert extra-fest / o-adx o-adz o-eix o-eiz richtung fh res winkel) (setq richtung (if (< dH-signiert 0) "Auf" "Ab")) (setq fh (+ (if (boundp '*vfl-feste-horizontal*) *vfl-feste-horizontal* 1300.0) @@ -10356,7 +10454,7 @@ ;; GF-Bogen-dz, wenn der Bogen bei Neigung theta (Grad) KS-gekettet wird: ;; der lokale (dx,dz) des Blocks wird um theta gekippt. ;; Z-Anteil = -dx*sin(theta) + dz*cos(theta) (negativ = Abfall) -(defun vfl3-bogen-dz-incl (bwinkel bseite theta / m dx dz rad) +(defun vfl-zsolve-bogen-dz-incl (bwinkel bseite theta / m dx dz rad) (setq m (gf-bogen-masse bwinkel bseite) dx (car m) dz (cadr m)) (setq rad (* (float theta) (/ pi 180.0))) (+ (* (- dx) (sin rad)) (* dz (cos rad)))) @@ -10366,7 +10464,7 @@ ;; ES-Eigen-dz. Spiegelt den tatsaechlichen Bau (Trimmung der letzten Geraden um ;; 300+ein-fp, GF-Bogen bei Neigung). Eintritts-Neigung = 3 Grad (die Bruecke ;; endet mit GF2 auf 3 Grad). So wird die Junction-Hoehe exakt statt geschaetzt. -(defun vfl3-dback (plan start-idx n last-idx ein-fp / i seg drop inc w dL rad) +(defun vfl-zsolve-rueckanker (plan start-idx n last-idx ein-fp / i seg drop inc w dL rad) (setq drop 0.0 inc *vfk-gefaelle-winkel* i start-idx) (while (< i n) (setq seg (nth i plan)) @@ -10380,7 +10478,7 @@ (setq inc w)) ((= (car seg) "Bogen") (if (= (nth 5 seg) "GF-Bogen") - (setq drop (- drop (vfl3-bogen-dz-incl (nth 3 seg) (nth 4 seg) inc)))))) + (setq drop (- drop (vfl-zsolve-bogen-dz-incl (nth 3 seg) (nth 4 seg) inc)))))) (setq i (1+ i))) ;; Auslauf-Separator (300 mm bei aktueller Neigung inc) + ES-Eigen-dz (setq rad (* (float inc) (/ pi 180.0))) @@ -10394,7 +10492,7 @@ ;; Horizontal-Mitte-Koerper zwei 3-Grad-Uebergangsboegen. Einbau-Rotationen wie ;; in vfs-vf-koerper; Bogen-dz_eff = -dx*sin(rot) + dz_roh*cos(rot) (am Log ;; verifiziert). So ist die Hoehe rein rechnerisch bestimmt -> Kletterlaenge folgt. -(defun vfl3-einheit-fix-dz (w n-climb n-hor gf1 richtung / +(defun vfl-zsolve-einheit-fix-dz (w n-climb n-hor gf1 richtung / pi180 rad3 s3 tot m1 m2 r1 r2 dz1 dz2) (setq pi180 (/ pi 180.0) rad3 (* *vfk-gefaelle-winkel* pi180) s3 (sin rad3) tot 0.0) ;; feste 3-Grad-Teile senken immer ab (GF1 + Separator + Umlenk + Motor) @@ -10420,7 +10518,7 @@ ;; + je Kletterer die zwei Boegen + je Horizontal-Mitte-Koerper die zwei ;; 3-Grad-Boegen. dx_eff = dx*cos(rot) + dz_roh*sin(rot) (am Log verifiziert). ;; Dient der Winkelwahl: Fussabdruck + Kletter-Planlaenge soll die Lauflaenge treffen. -(defun vfl3-einheit-fix-dx (w n-climb n-hor gf1 richtung / +(defun vfl-zsolve-einheit-fix-dx (w n-climb n-hor gf1 richtung / pi180 rad3 tot m1 m2 r1 r2 dx1 dx2) (setq pi180 (/ pi 180.0) rad3 (* *vfk-gefaelle-winkel* pi180) tot 0.0) (setq tot (* (+ (float gf1) *vfk-separator-laenge* *vfk-stations-laenge* *vfk-stations-laenge*) (cos rad3))) ; Stationen planar @@ -10440,13 +10538,13 @@ ;; Uebergang von der 3-Grad-Kletterbasis in die FLACHE Zone (0 Grad): EIN auf_3-Bogen ;; (Rotation 3 Grad). Rueckgabe: neuer Punkt. -(defun vfl3-flach-ein (pt hz / m) +(defun vfl-zsolve-flach-ein (pt hz / m) (setq m (get-bogen-mass bogen-auf 3)) (insert-rotated-block-with-ks "Vario_Bogen_auf_3_TEF_rechts" pt 3 (car m) (caddr m) hz)) ;; Uebergang aus der flachen Zone (0 Grad) zurueck auf 3-Grad-Basis: EIN ab_3-Bogen ;; (Rotation 0 Grad). Rueckgabe: neuer Punkt. -(defun vfl3-flach-aus (pt hz / m) +(defun vfl-zsolve-flach-aus (pt hz / m) (setq m (get-bogen-mass bogen-ab 3)) (insert-rotated-block-with-ks "Vario_Bogen_ab_3_TEF_rechts" pt 0 (car m) (caddr m) hz)) @@ -10454,7 +10552,7 @@ ;; Mittige Bruecke -> KEIN terminales AS/ES (Masse auf 0, Save/Restore). feste = fester ;; Horizontal-Anteil des Kletter-Segments (Umlenk+Separator = 800; Motor sitzt spaeter ;; am Kettenende). Rueckgabe: (winkel L_GF L_VF richtung) oder nil. -(defun vfl3-waehle-winkel (span dH-signiert feste / +(defun vfl-zsolve-winkel-waehlen (span dH-signiert feste / o-adx o-adz o-eix o-eiz richtung res wahl) (setq richtung (if (< dH-signiert 0) "Auf" "Ab")) (setq o-adx aus-dx o-adz aus-dz o-eix ein-dx o-eiz ein-dz) @@ -10466,14 +10564,14 @@ ;; ES-Element-Fussabdruck ENTLANG/QUER zu einer Fahrtrichtung seg-hz (Welt- ;; Komponenten), aus der REALEN Blockgeometrie (vf-element-ks-info) berechnet. -;; Kernstueck von vfl3-es-fueller, hier ausgelagert, damit AUCH die feste-vf- +;; Kernstueck von vfl-zsolve-es-fueller, hier ausgelagert, damit AUCH die feste-vf- ;; Berechnung in vf-linienzug-modus2 (Fall hor-pairs=0, OHNE flache -;; Zone/vfl3-es-fueller) denselben Wert nutzen kann, statt den ES-Laengsanteil +;; Zone/vfl-zsolve-es-fueller) denselben Wert nutzen kann, statt den ES-Laengsanteil ;; im Laengenbudget des Solvers stillschweigend zu vergessen (realer Bug: ;; Kette ueberschoss um ungefaehr along-es+Separator, siehe dortiger Kommentar). ;; Rueckgabe: (list along-es perp-es) oder nil, wenn der Block nicht lesbar ;; ist (Aufrufer faellt dann auf eine grobe Naeherung zurueck). -(defun vfl3-es-vektor (es-block seg-hz / info theta dpx dpy npx npy phi vx vy vwx vwy) +(defun vfl-zsolve-es-vektor (es-block seg-hz / info theta dpx dpy npx npy phi vx vy vwx vwy) (setq info (vf-element-ks-info es-block)) (if (null info) nil @@ -10497,10 +10595,10 @@ ;; KS_AUS = pt + (fill + C)*dp + perp-es*np ;; C = 196 (ab_3) + (Motor 500 + GF2 + Sep 300)*cos3 + along-es ;; Achse u_a = seg-hz + (KS_AUS.xu - KS_EIN.xu)_Block ; (Endpunkt-KS_AUS)*n_a=0 -> fill -(defun vfl3-es-fueller (pt endp seg-hz es-block gf2 rad3 / +(defun vfl-zsolve-es-fueller (pt endp seg-hz es-block gf2 rad3 / vek theta dpx dpy npx npy info along-es perp-es ua na-x na-y cc dp-na np-na ep-na) - (setq vek (vfl3-es-vektor es-block seg-hz)) + (setq vek (vfl-zsolve-es-vektor es-block seg-hz)) (if (null vek) (- (+ (* (- (car endp) (car pt)) (cos (* seg-hz (/ pi 180.0)))) (* (- (cadr endp) (cadr pt)) (sin (* seg-hz (/ pi 180.0))))) @@ -10785,14 +10883,14 @@ ;; Vorwaerts: Start-Z durch alle Front-Segmente (Index < vf-start). (setq z-front (float start-hoehe) i 0) (while (< i vf-start) - (setq dz (vfl3-seg-dz (nth i plan))) + (setq dz (vfl-zsolve-seg-dz (nth i plan))) (if dz (setq z-front (+ z-front dz))) (setq i (1+ i))) ;; Rueckwaerts: Ziel-Z durch alle Back-Segmente (Index > vf-ende). ;; Vorwaerts gilt Z_next = Z_prev + dz -> rueckwaerts Z_prev = Z_next - dz. (setq z-junction (float end-hoehe) i (1- n)) (while (> i vf-ende) - (setq dz (vfl3-seg-dz (nth i plan))) + (setq dz (vfl-zsolve-seg-dz (nth i plan))) (if dz (setq z-junction (- z-junction dz))) (setq i (1- i))) @@ -10862,7 +10960,7 @@ ;; Back-Lauf danach) - sonst bleibt die Steuerung komplett unveraendert ;; (es-vorhanden aus der Upfront-Frage, Motorstation immer gebaut). "Ohne ;; Motorstation" muss VOR der Phase-B2-Zielhoehen-Berechnung feststehen, - ;; da sie die Separator/ES-Naeherung in vfl3-dback wieder aufhebt. + ;; da sie die Separator/ES-Naeherung in vfl-zsolve-rueckanker wieder aufhebt. (setq m2-offenes-ende nil) (if (= vf-ende (1- n)) (progn @@ -10947,7 +11045,7 @@ ;; (car frame) bereits gleich startpunkt ist. (if (null frame) (setq frame (if as-vorhanden - (vfl2-insert-as-gf startpunkt hz winkel as-seite) + (vfl-pfad-as-gf-einfuegen startpunkt hz winkel as-seite) (make-frame-from-dir startpunkt (hz-winkel->xu hz 0.0))))) (setq deltaL (caddr seg)) ;; erste Gerade: AS-Fussabdruck ENTLANG des Pfads exakt aus KS_AUS abziehen @@ -10995,17 +11093,17 @@ (setq hz (cadr (nth vf-start plan))) (if (null frame) (setq frame (if as-vorhanden - (vfl2-insert-as-vf startpunkt hz as-seite) + (vfl-pfad-as-vf-einfuegen startpunkt hz as-seite) (make-frame-from-dir startpunkt (hz-winkel->xu hz 0.0))))) (setq z-front (caddr (car frame))) ;; --- B2: Back-Abstieg -> Junction; Kletterer + Horizontal-Mitte bestimmen --- (setq z-junction (+ (float end-hoehe) - (vfl3-dback plan (1+ vf-ende) n last-line ein))) + (vfl-zsolve-rueckanker plan (1+ vf-ende) n last-line ein))) ;; Offenes Ende (kein Motor/Separator/ES danach) ODER Motor+GF2 OHNE ES ;; danach (Lauf-Abschluss "Motorstation", es-vorhanden nil - Motor selbst ;; ist bereits ueber dH-adj/*vfk-bruecke-korrektur* separat eingerechnet, - ;; siehe Phase B weiter unten): vfl3-dback's Tail-Naeherung (reserviert + ;; siehe Phase B weiter unten): vfl-zsolve-rueckanker's Tail-Naeherung (reserviert ;; IMMER einen Separator+ES-Fussabdruck) ist in BEIDEN Faellen falsch - die ;; Zielhoehe fuer den Loeser ist exakt end-hoehe. Realer Bug, bis dahin nur ;; fuer m2-offenes-ende behandelt: "Motorstation ohne ES" fiel durch dieselbe @@ -11077,7 +11175,7 @@ (setq feste-vf entry-fixed dH-adj (- dH-bruecke (+ (* *vfk-stations-laenge* (sin rad3v)) *vfk-bruecke-korrektur*))) ; Motor + auf_3/ab_3 (progn - ;; OHNE flache Zone gibt es KEIN vfl3-es-fueller, das den Separator+ES- + ;; OHNE flache Zone gibt es KEIN vfl-zsolve-es-fueller, das den Separator+ES- ;; Laengsanteil selbststaendig gegen den echten Zielpunkt korrigiert - ;; beide fehlten hier bislang komplett im Laengenbudget des Solvers ;; (realer Bug: die Kette ueberschoss um ungefaehr Separator+along-es, @@ -11085,7 +11183,7 @@ ;; WICHTIG: NUR die Laenge korrigieren, NICHT ueber feste-vf/dH-adj - ;; feste-vf fliesst in berechne-alle-winkel per sin(3°) AUCH in die ;; Hoehenbilanz ein, waehrend die reale Hoehe von Separator+ES bereits - ;; VOLLSTAENDIG ueber z-junction/vfl3-dback erfasst ist (Separator dort + ;; VOLLSTAENDIG ueber z-junction/vfl-zsolve-rueckanker erfasst ist (Separator dort ;; per tan(3°), ES-Eigenhoehe per ein-dz - siehe dortiger Kommentar). ;; Ueber feste-vf haette das die Hoehe ein zweites Mal (und fuer ;; along-es sogar physikalisch falsch, da along-es keinen sin(3°)- @@ -11095,7 +11193,7 @@ dH-adj dH-bruecke) (if es-vorhanden (progn - (setq es-vek-fix (vfl3-es-vektor + (setq es-vek-fix (vfl-zsolve-es-vektor (strcat "ES_Element_" (vfl-es-winkel) "_" es-seite) (cadr (nth vf-ende plan)))) (setq es-along-fix @@ -11107,7 +11205,7 @@ ;; es-along-fix (reine Laenge, siehe oben) NUR aus dem Laengenbudget (span) ;; abziehen - NICHT aus feste-vf, sonst floss es faelschlich ueber sin(3°) ;; auch in die Hoehenbilanz ein (siehe Kommentar oben). - (setq wahl3 (vfl3-waehle-winkel (- climber-span es-along-fix) dH-adj feste-vf)) + (setq wahl3 (vfl-zsolve-winkel-waehlen (- climber-span es-along-fix) dH-adj feste-vf)) (if (null wahl3) (progn ;; Stufe 2: KEIN Tabellenwinkel passt (der/die Kletterer sind bei JEDER @@ -11186,7 +11284,7 @@ (cond ;; --- Kletterer (geneigt, 3-Grad-Basis) --- ((and (= (car seg) "Linie") (member i climbers)) - (if flat-p (progn (setq pt (vfl3-flach-aus pt seg-hz)) (setq flat-p nil))) + (if flat-p (progn (setq pt (vfl-zsolve-flach-aus pt seg-hz)) (setq flat-p nil))) (setq this-lvf (max *vfk-restlaenge-min-clamp* (* br-lvf (/ (caddr seg) climber-span)))) (setq pt (vfs-vf-koerper pt br-richtn br-winkel this-lvf seg-hz)) (vfl-acc-vf-seg br-richtn br-winkel this-lvf) @@ -11195,7 +11293,7 @@ ((= (car seg) "Linie") (setq flat-zone-erste (not flat-p)) (if (not flat-p) - (progn (setq pt (vfl3-flach-ein pt letzt-koerper-hz)) (setq flat-p t) + (progn (setq pt (vfl-zsolve-flach-ein pt letzt-koerper-hz)) (setq flat-p t) ;; Fueller-A: der im Kletter-Segment durch 1/2 GF1 frei werdende Platz (if (and (> filler-A-len 0.1) (not filler-a-done)) (progn (vf-vfhoehe-merke pt) @@ -11215,7 +11313,7 @@ ;; nichts mehr gebaut wird - Fueller zielt direkt auf den Endpunkt. (setq fill-len (if es-vorhanden - (vfl3-es-fueller pt endpunkt seg-hz + (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)))) @@ -11242,7 +11340,7 @@ ;; --- Vario-Kurve (flach, direkt bei 0 Grad) --- ((= (car seg) "Bogen") (if (not flat-p) - (progn (setq pt (vfl3-flach-ein pt letzt-koerper-hz)) (setq flat-p t) + (progn (setq pt (vfl-zsolve-flach-ein pt letzt-koerper-hz)) (setq flat-p t) ;; Fueller-A: der im Kletter-Segment durch 1/2 GF1 frei werdende Platz (if (and (> filler-A-len 0.1) (not filler-a-done)) (progn (vf-vfhoehe-merke pt) @@ -11264,13 +11362,14 @@ ;; Rueck-Uebergang auf 3 Grad, KEINE Motorstation/GF2. (setq frame (make-frame-from-dir pt (hz-winkel->xu letzt-koerper-hz 0.0))) (progn - (if flat-p (progn (setq pt (vfl3-flach-aus pt letzt-koerper-hz)) (setq flat-p nil))) ; zurueck 3 Grad - ;; Motorstation + GF2 in EINEM Schritt mit dem im Solve (vfl3-waehle- - ;; winkel/GF-Verteilung, siehe br-gf2-exp oben) bereits geplanten Wert - + (if flat-p (progn (setq pt (vfl-zsolve-flach-aus pt letzt-koerper-hz)) (setq flat-p nil))) ; zurueck 3 Grad + ;; Motorstation + GF2 in EINEM Schritt mit dem im Solve + ;; (vfl-zsolve-winkel-waehlen/GF-Verteilung, siehe br-gf2-exp oben) + ;; bereits geplanten Wert - ;; NICHT mehr unabhaengig aus der gemessenen Resthoehe neu herleiten. ;; Die alte Zwei-Loesungen-Variante (Motor mit L_GF2=0.0, GF2 danach aus ;; z-aftermotor/z-junction gemessen) widersprach der Fueller-Position - ;; (fill-len, vfl3-es-fueller), die bereits br-gf2-exp als GF2-Laenge + ;; (fill-len, vfl-zsolve-es-fueller), die bereits br-gf2-exp als GF2-Laenge ;; angenommen hatte - jede Differenz zwischen den beiden GF2-Werten ;; verschob das Kettenende entlang der Fahrtrichtung (realer Bug: ;; "letztes Segment baut zu lang"). Identische Fehlerklasse wie der diff --git a/doc/plan/vf-parameter-struct-analyse.md b/doc/plan/vf-parameter-struct-analyse.md index a00d68b..94b350c 100644 --- a/doc/plan/vf-parameter-struct-analyse.md +++ b/doc/plan/vf-parameter-struct-analyse.md @@ -60,7 +60,7 @@ Erweiterung (AutoLISP-Konvention: Alist statt echtem Struct): | `vfl-modus-abbruch-sichern` | vf_linienzug.lsp | 9 | | `vf-winkel-solve` | vf_core.lsp | 8 | | `vfs-mitte-teil`, `vfl-vf-einheit`, `vfl-vf-einheit-abschluss` | standard/linienzug | je 7 | -| `vfs-vf-koerper`, `vfl-insert-es-element`, `vfl3-es-fueller` | standard/linienzug | je 5-6 | +| `vfs-vf-koerper`, `vfl-insert-es-element`, `vfl-zsolve-es-fueller` | standard/linienzug | je 5-6 | | die vier `insert-hz-*`-Funktionen | vf_etage.lsp | je 4-6 | ## Struct-Kandidaten diff --git a/doc/todo/modus2-achsenweise-bilanz.md b/doc/todo/modus2-achsenweise-bilanz.md index d6dcca0..3522a59 100644 --- a/doc/todo/modus2-achsenweise-bilanz.md +++ b/doc/todo/modus2-achsenweise-bilanz.md @@ -44,7 +44,7 @@ ganze Hoehe traegt, und rechnet die geneigte Laenge skalar: ```lisp ;; vf_linienzug.lsp:9990 - Solver bekommt die SKALARE Spanne -(setq wahl3 (vfl3-waehle-winkel climber-span dH-adj feste-vf)) +(setq wahl3 (vfl-zsolve-winkel-waehlen climber-span dH-adj feste-vf)) ;; feste-vf = Umlenk + Separator (+ Motor) -- ein fester Fussabdruck ;; vf_linienzug.lsp:10070 - Kletterer bekommt br-lvf proportional diff --git a/doc/todo/plan-vf-interactive.md b/doc/todo/plan-vf-interactive.md index b63210a..569c92b 100644 --- a/doc/todo/plan-vf-interactive.md +++ b/doc/todo/plan-vf-interactive.md @@ -149,8 +149,11 @@ Modus-uebergreifende Blocker: - **`ATTREQ`/`ATTDIA`**: ohne `0` fragt das `(command "_.INSERT" ...)` in den Einfuegeprimitiven nach Attributwerten - der wahrscheinlichste Haenger. -Namensfalle: die `vfl3-*`-Helfer (:5093-5276) gehoeren zu **Modus 2**, die -`vfl2-*`-Helfer (:4703-4804) zu **Modus 3**. +Namensschema (seit 2026-10-22 rollenbasiert statt nach Modus-Nummer, die +frueheren Praefixe `vfl3-`/`vfl2-` waren zur Menue-Nummerierung vertauscht): +die `vfl-zsolve-*`-Helfer rechnen die Hoehen durch und gehoeren zu **Modus 2**; +die `vfl-pfad-*`-Helfer arbeiten auf dem gezeichneten Pfad und werden von +**Modus 2 UND Modus 3** genutzt. --- @@ -695,7 +698,7 @@ Architektur, nicht Funktion. ### Ausdruecklich nicht anfassen -`vf-linienzug-modus3` + alle `vfl2-*`; die `vfl-in-*`-Wrapper und `vfl-menu*`; +`vf-linienzug-modus3` + alle `vfl-pfad-*`; die `vfl-in-*`-Wrapper und `vfl-menu*`; `vfl-entry->string` und das XDATA-Layout/die Marker; **alle Journal-Konsumenten** (brauchen sie Aenderungen, ist die Invariante gebrochen - das ist der Lackmustest); die reinen `vfs-*`/`berechne-*` in `vf_standard.lsp` (via diff --git a/doc/variofoerderer.md b/doc/variofoerderer.md index ad0d2a8..e29e1f4 100644 --- a/doc/variofoerderer.md +++ b/doc/variofoerderer.md @@ -387,7 +387,7 @@ arbeiten auf bereits in der Zeichnung vorhandener Geometrie statt auf freier Klick-Eingabe — fuer eine GUI eher Import/Solver-Werkzeuge als klassische Formulare. -### Modus 2 — Pfad + Zielhoehe (Solver) +### Modus 2 — aus 3D Linie MIT Zielhoehe (Solver) | Feld | Steuerelement | Werte | |---|---|---| @@ -400,15 +400,28 @@ Formulare. | -> Vario-Kurve-Variante | Dropdown | Aussen / Innen | | GF-Verteilung | Dropdown | alles am Einlauf (GF1) / 1/2 GF1 + 1/2 GF2 | -### Modus 3 — Vorwaerts-Nachbau (Legacy, wird umgebaut) +### Modus 3 — aus 3D Linie OHNE Zielhoehe (Vorwaerts-Bau) + +Baut dieselbe gezeichnete Geometrie wie Modus 2, aber VORWAERTS mit +vorgegebenen Winkeln: die Endhoehe ist hier ein Ergebnis, kein Ziel. Genau +das ist sein Anwendungsfall — wenn es keine feste Zielhoehe gibt. | Feld | Steuerelement | Werte | |---|---|---| -| Startpunkt (3D) | Punktwahl | KS_EIN AUS-Element / Kettenanfang | -| Gefaellewinkel | Zahl (Grad) | wird auch aus 2 gewaehlten 3D-Punkten vorgeschlagen | -| AUS-Element Seite | Dropdown | links / rechts | -| Separator vor EIN? | Dropdown | Ja/Nein | -| Einfuegen bestaetigen | Dropdown | Ja/Nein | +| Startpunkt (3D) + Starthoehe | Punktwahl + Zahl | Kettenanfang | +| AS-Element bauen? | Ja/Nein | bei Nein beginnt die Kette direkt am Startpunkt | +| -> AS Winkel + Seite | Dropdown | 30/90 Grad · links/rechts (ein Dialog zusammen mit "bauen?") | +| ES-Element bauen? | Ja/Nein | **vor** dem Bau gefragt, damit der ES-Fussabdruck von der letzten Geraden abgezogen werden kann | +| -> ES Winkel + Seite | Dropdown | 30/90 Grad · links/rechts | +| Pfad-Objekte | Objektauswahl | Linien + Boegen der Trasse | +| Je gerades Segment: Typ | Dropdown | GF / VF-Ab / VF-Auf / VF-Horizontal | +| -> GF-Neigung bzw. Vario-Winkel | Zahl (Grad) | kontextabhaengig | +| Je Bogen-Segment: Typ | Dropdown | GF-Bogen / Vario-Kurve (+ Variante) | + +Ketten, die vor dem 2026-10-22 gebaut wurden, kennen die beiden +"bauen?"-Fragen noch nicht; sie werden beim Doppelklick automatisch erkannt +und in der alten Reihenfolge nachgebaut (siehe `alt-journal` in +`vf-linienzug-modus3`). --- diff --git a/lang/de_DE.json b/lang/de_DE.json index bc35e45..dc861fd 100644 --- a/lang/de_DE.json +++ b/lang/de_DE.json @@ -181,7 +181,7 @@ "vfl-soll-xyz": "\n Soll: X=%1 Y=%2 Z=%3", "vfl-ist-xyz": "\n Ist : X=%1 Y=%2 Z=%3", "vfl-abweichung-xyz": "\n Abweichung: dX=%1 dY=%2 dZ=%3 mm", - "vfl-m3-titel": "\n VF-LINIENZUG - Modus 2: Pfad + Ziel-Hoehe (fertig; Anker + Solver + Bau)", + "vfl-m3-titel": "\n VF-LINIENZUG - Modus 2: aus 3D Linie MIT Zielhoehe (Anker + Solver + Bau)", "vfl-m3-alert-gf-modul": "Gefaellestrecke-Modul nicht geladen!", "vfl-m3-pfad-waehlen": "\n\nPfad-Objekte waehlen (Linien/Boegen):", "vfl-m3-keine-objekte": "\nKeine Objekte gewaehlt - Abbruch.", @@ -258,6 +258,7 @@ "vfl-m3-gf2-ausgleich": "\n GF2 (gemessener Ausgleich): L=%1 mm", "vfl-m3-kurve-back-uebersprungen": "\n >>> [M3a] Vario-Kurve im Back-Lauf - uebersprungen.", "vfl-m3-nichts-gebaut": "\nNichts gebaut - Abbruch.", + "vfl-m3-alt-journal": "\n Hinweis: Diese Kette stammt aus der Zeit vor den Fragen AS bauen / ES bauen - sie wird in der alten Reihenfolge nachgebaut.", "vfl-m3-fertig-header": "\n>>> VF-Linienzug (Modus 2) gebaut! <<<", "vfl-m3-ziel-soll": "\n Ziel (Soll): X=%1 Y=%2 Z=%3", "vfl-m3-es-ist": "\n ES (Ist): X=%1 Y=%2 Z=%3", @@ -941,13 +942,13 @@ "vfc-warnung-untermodule-nicht-geladen": "\n[vf_core] WARNUNG: DXFM_LISP nicht gesetzt - Untermodule konnten nicht geladen werden!", "vfc-linienzug-modus-header": "\n\nLinienzug-Modus waehlen:", "vfc-linienzug-modus-1": "\n 1 - Manuelle Eingabe (Punkte klicken)", - "vfc-linienzug-modus-2": "\n 2 - 3D-Objekte + Ziel-Hoehe (Randwert-Solver, fertig)", - "vfc-linienzug-modus-3": "\n 3 - 3D-Objekte stueckweise (Vorwaerts-Nachbau, in Arbeit)", + "vfc-linienzug-modus-2": "\n 2 - aus 3D Linie MIT Zielhoehe (Hoehen werden gerechnet)", + "vfc-linienzug-modus-3": "\n 3 - aus 3D Linie OHNE Zielhoehe (Vorwaerts-Bau mit vorgegebenen Winkeln)", "prompt-wahl-1-3": "\nIhre Wahl (1/2/3) [1]: ", "vfl-qc-uform-nicht-implementiert": "\nFEHLER: 'QC Linie mit GF und U-Form' ist noch nicht implementiert - bitte Option 4 oder einen anderen Modus waehlen.", "vfc-typ-standard-beschreibung": "Standard VarioFoerderer (AS/ES 90 Grad, horizontal versetzt)", "vfc-typ-etage-beschreibung": "Etage VarioFoerderer (AS/ES 30 Grad, direkt uebereinander)", - "vfc-typ-linienzug-beschreibung": "Streckengruppe (gemischte GF/VF-Kette; Modus 1 manuell / Modus 2 Ziel-Hoehe fertig / Modus 3 stueckweise in Arbeit)", + "vfc-typ-linienzug-beschreibung": "Streckengruppe (gemischte GF/VF-Kette; Modus 1 manuell / Modus 2 aus 3D Linie mit Zielhoehe / Modus 3 aus 3D Linie ohne Zielhoehe)", "vfs-schritt6-horizontal": "\n\n6/11: Horizontale Zwischenstrecke (0 Grad, L=%1 mm)", "vfs-schritt6-steigung": "\n\n6/11: Steigungsstrecke (%1 Grad, L=%2 mm)", "vfs-schritt6-gefaelle": "\n\n6/11: Gefaellestrecke (%1 Grad, L=%2 mm)", @@ -976,7 +977,7 @@ "vfe-step14": "\n\n14/15: Separator (300mm, cur-hz=%1)", "vfe-step15": "\n\n15/15: %1 (Ende, verkettet cur-hz=%2)", "vfe-eingefuegt": "\n>>> Etage-VarioFoerderer eingefuegt! <<<", - "vfl-vwnb-titel": "\n VF-LINIENZUG - Modus 3: 3D-Objekte stueckweise (Vorwaerts-Nachbau, in Arbeit)", + "vfl-vwnb-titel": "\n VF-LINIENZUG - Modus 3: aus 3D Linie OHNE Zielhoehe (Vorwaerts-Bau)", "vfl-vwnb-aus-seite-menu": "\n\nAUS-Element - Seite waehlen:\n 1 - Links\n 2 - Rechts", "vfl-vwnb-alert-eckwinkel": "Kein passender Bogen: Eck-Winkel %1 Grad ist nicht ~30/60/90.\nBitte die Winkel der Linien anpassen.", "vfl-vwnb-alert-keine-gerade": "Pfad enthaelt keine Gerade - eine Kette muss mit einer Geraden beginnen.", diff --git a/lang/en_GB.json b/lang/en_GB.json index 8bf87b5..543e8b6 100644 --- a/lang/en_GB.json +++ b/lang/en_GB.json @@ -181,7 +181,7 @@ "vfl-soll-xyz": "\n Target: X=%1 Y=%2 Z=%3", "vfl-ist-xyz": "\n Actual: X=%1 Y=%2 Z=%3", "vfl-abweichung-xyz": "\n Deviation: dX=%1 dY=%2 dZ=%3 mm", - "vfl-m3-titel": "\n VF LINE PATH - Mode 2: path + target height (finished; anchors + solver + build)", + "vfl-m3-titel": "\n VF LINE PATH - Mode 2: from 3D line WITH target height (anchors + solver + build)", "vfl-m3-alert-gf-modul": "Gefaellestrecke module not loaded!", "vfl-m3-pfad-waehlen": "\n\nSelect path objects (lines/arcs):", "vfl-m3-keine-objekte": "\nNo objects selected - aborting.", @@ -258,6 +258,7 @@ "vfl-m3-gf2-ausgleich": "\n GF2 (measured compensation): L=%1 mm", "vfl-m3-kurve-back-uebersprungen": "\n >>> [M3a] Vario curve in back run - skipped.", "vfl-m3-nichts-gebaut": "\nNothing built - aborting.", + "vfl-m3-alt-journal": "\n Note: this chain predates the build AS / build ES questions - it is rebuilt in the old order.", "vfl-m3-fertig-header": "\n>>> VF line path (mode 2) built! <<<", "vfl-m3-ziel-soll": "\n Target (nominal): X=%1 Y=%2 Z=%3", "vfl-m3-es-ist": "\n ES (actual): X=%1 Y=%2 Z=%3", @@ -941,13 +942,13 @@ "vfc-warnung-untermodule-nicht-geladen": "\n[vf_core] WARNING: DXFM_LISP not set - submodules could not be loaded!", "vfc-linienzug-modus-header": "\n\nSelect line-path mode:", "vfc-linienzug-modus-1": "\n 1 - Manual entry (click points)", - "vfc-linienzug-modus-2": "\n 2 - 3D objects + target height (boundary-value solver, finished)", - "vfc-linienzug-modus-3": "\n 3 - 3D objects step by step (forward reconstruction, work in progress)", + "vfc-linienzug-modus-2": "\n 2 - from 3D line WITH target height (heights are calculated)", + "vfc-linienzug-modus-3": "\n 3 - from 3D line WITHOUT target height (forward build with given angles)", "prompt-wahl-1-3": "\nYour choice (1/2/3) [1]: ", "vfl-qc-uform-nicht-implementiert": "\nERROR: 'QC line with GF and U-shape' is not yet implemented - please choose option 4 or a different mode.", "vfc-typ-standard-beschreibung": "Standard VarioFoerderer (AS/ES 90 degrees, offset horizontally)", "vfc-typ-etage-beschreibung": "Etage VarioFoerderer (AS/ES 30 degrees, directly stacked)", - "vfc-typ-linienzug-beschreibung": "Route group (mixed GF/VF chain; mode 1 manual / mode 2 target height finished / mode 3 step by step work in progress)", + "vfc-typ-linienzug-beschreibung": "Route group (mixed GF/VF chain; mode 1 manual / mode 2 from 3D line with target height / mode 3 from 3D line without target height)", "vfs-schritt6-horizontal": "\n\n6/11: Horizontal intermediate section (0 deg, L=%1 mm)", "vfs-schritt6-steigung": "\n\n6/11: Incline section (%1 deg, L=%2 mm)", "vfs-schritt6-gefaelle": "\n\n6/11: Slope section (%1 deg, L=%2 mm)", @@ -976,7 +977,7 @@ "vfe-step14": "\n\n14/15: Separator (300mm, cur-hz=%1)", "vfe-step15": "\n\n15/15: %1 (end, chained cur-hz=%2)", "vfe-eingefuegt": "\n>>> Etage VarioFoerderer inserted! <<<", - "vfl-vwnb-titel": "\n VF LINE PATH - Mode 3: 3D objects step by step (forward reconstruction, work in progress)", + "vfl-vwnb-titel": "\n VF LINE PATH - Mode 3: from 3D line WITHOUT target height (forward build)", "vfl-vwnb-aus-seite-menu": "\n\nOUT element - select side:\n 1 - Left\n 2 - Right", "vfl-vwnb-alert-eckwinkel": "No matching arc: corner angle %1 deg is not ~30/60/90.\nPlease adjust the angles of the lines.", "vfl-vwnb-alert-keine-gerade": "Path contains no straight - a chain must begin with a straight.", diff --git a/menu/SSG_LIB.mnu b/menu/SSG_LIB.mnu index 5c406bb..ce4d883 100644 --- a/menu/SSG_LIB.mnu +++ b/menu/SSG_LIB.mnu @@ -27,7 +27,7 @@ [->Streckengruppe] [Werte manuell]^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerdererManuell [aus 3D Linie mit Zielhoehe]^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerdererZielhoehe -[<-3D Objekte stueckweise (in Arbeit)]^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerdererStueckweise +[<-aus 3D Linie ohne Zielhoehe]^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerdererStueckweise [Vario_Kette_Merge]^C^C(ssg-ensure "VarioFoerderer") Vario_Kette_Merge [<-VarioFoerderer nachruesten (Marker)]^C^C(ssg-ensure "VarioFoerderer") VARIOFOERDERER_NACHRUESTEN [->Gefaellestrecke]