fix: Fussabdruecke aller Festbauteile im Segmentbudget (Modus 2)

Leitsatz, aus dem alle Einzelaenderungen folgen (neu als Abschnitt 0 in
doc/VarioFoerderer_Linienzug_Prinzipien.md): die gezeichneten GERADEN
besitzen den Pfad, ein gezeichneter Bogen ist Hilfsgeometrie und nennt nur
Ort und Drehsinn. Jedes fest gebaute Teil zieht seine Laenge von dem
Segment ab, auf dem es steht - und zwar in LAENGEN- UND HOEHENbilanz mit
demselben, GEMESSENEN Wert.

Behoben:
- AS-Element: Fussabdruck wurde bei vf-start = 0 gar nicht abgezogen
  (die Trimmung lief nur im Front-Lauf, der dort leer ist). Jetzt gemessen
  aus dem gebauten KS_AUS - ein aus dem Block-dx gerechneter Wert lag
  184 mm daneben.
- Abschlussbogen + Motorstation: standen auf dem letzten Segment des
  VF-Laufs, fehlten aber im Budget (feste-vf traegt den Motor nur im Zweig
  OHNE flache Zone).
- ES-Element: die letzte Gerade reservierte nur den Laengsanteil. Jetzt die
  Strecke, die auch den Querversatz aufhebt (vfl-es-achs-reserve) - Vorgabe:
  quer zur KS_AUS-Achse MUSS 0 sein, laengs darf abweichen, dZ MUSS 0 sein.
- ES-Abzug griff auch, wenn ein Back-Lauf zwischen VF-Lauf und ES liegt,
  und verkuerzte dann das falsche Segment um die volle ES-Laenge (878 mm).
  Jetzt nur noch bei direktem Anschluss (vf-ende = n-1).
- Eck-Bauteile: Vario-Kurve/Gefaellebogen ersetzen den gezeichneten Bogen
  mit eigenem Fussabdruck. Die Differenz der Tangentenabstaende geht als
  Zuschlag an beide angrenzenden Geraden (vfl-eck-korrekturen/-zerlegen),
  damit die Mittellinie beide beruehrt. Der gezeichnete Radius kuerzt sich
  dabei heraus. GF-Boegen werden geneigt eingebaut - ihr Grundriss-
  Fussabdruck wird mit vfl-projiziere-neigung projiziert.
- Kletterlaenge wurde anteilig mit der Planlaenge im Zaehler und dem
  korrigierten climber-span im Nenner verteilt; die Anteile summierten sich
  dadurch auf weniger als 1.
- Absturz bei fehlendem Uebergangsbogen: get-bogen-mass wurde zweimal fuer
  dieselbe Suche aufgerufen und sein nil ungeprueft an
  vfl-projiziere-neigung gereicht.

Messreihe ueber die Sitzung (gleicher Pfad, Abweichung quer):
695.7 -> 270 -> 139.5 -> 98.5 -> 45.7 -> 2.4 -> 0.2 mm, dZ durchgehend 0.
Beide Pfad-Varianten (Ecke als Vario-Kurve bzw. als GF-Bogen) landen auf
demselben Wert - 0.2 mm ist die Messaufloesung, kein Restfehler.

21 neue file-freie Unit-Tests mit den echten Messwerten; TEST_UNIT 866/866.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-10-26 14:29:43 +01:00
parent aabac03d7c
commit ce4ad0f328
5 changed files with 1231 additions and 31 deletions
+822
View File
@@ -0,0 +1,822 @@
# VarioFoerderer / Gefaellestrecke - Konstruktionsprinzipien (Linienzug)
Referenzdokument fuer den Anlagen-Typ "linienzug" (gemischte GF/VF-Kette).
Fasst alle im Gespraech festgelegten Prinzipien und Definitionen zusammen.
> Hinweis: Dieses Dokument beschreibt das ZIEL-Verhalten. Der aktuelle
> Umsetzungsstand und bekannte Abweichungen sind in Abschnitt 13 gesammelt.
---
## 0. Leitsatz: die Geraden besitzen den Pfad, Boegen sind Verbindungsstuecke
Festgelegt am 2026-10-26, gilt fuer alle Modi und fuer GF wie VF.
**Massgeblich sind die gezeichneten GERADEN.** Die Mittellinie jedes geraden
Abschnitts liegt auf seiner Pfadlinie - das ist die Bedingung, an der sich
alles ausrichtet.
**Ein gezeichneter Bogen ist dagegen nur Hilfsgeometrie.** Er sagt, WO die
Ecke liegt und WIE HERUM es geht. Sein Radius und seine Masse sind KEINE
Vorgabe; wer R300 oder R800 zeichnet, bekommt dieselbe Kette.
**Das Eck-Bauteil ist ein Verbindungsstueck und hat keinen eigenen
Freiheitsgrad.** Seine Lage folgt aus den beiden Geraden, die es verbindet:
seine Mittellinie beruehrt beide. `KS_EIN` liegt auf der Geraden davor und
zeigt in deren Richtung, `KS_AUS` auf der Geraden danach und in deren
Richtung. Damit laeuft die Kette knickfrei und ohne Seitenversatz durch die
Ecke.
### Daraus folgt: jedes fest gebaute Teil zieht seine Laenge von dem Segment ab, auf dem es steht
Ein gerades Segment vergibt Laenge an alles, was darauf gebaut wird. Was
dort ein festes Mass hat, gehoert nicht mehr dem frei rechenbaren Rest:
| Stelle | Vorgabe aus der Zeichnung | Mass kommt vom Bauteil |
|---|---|---|
| Kettenanfang | Startpunkt | AS-Element (Fussabdruck entlang des Segments) |
| Ende des VF-Laufs | Segmentlaenge | Abschlussbogen + Motorstation |
| letzte Gerade vor dem ES | Endpunkt | Separator + ES-Laengsanteil |
| Ecke | NUR Ort und Drehsinn | Tangentenabstand des Eck-Bauteils |
**Die Masse werden GEMESSEN, nicht aus Block-Massen oder Radien gerechnet.**
Gerechnete Werte lagen in der Praxis daneben: der AS-Fussabdruck um 184 mm
(das Block-`dx` kennt den Achs-Versatz nicht), der ES-Laengsanteil um ~520 mm
(das Block-`dx` kennt den Schwenk des 30-Grad-Elements nicht).
**Laengen- und Hoehenbilanz muessen denselben Wert benutzen.** Laufen sie
auseinander, stimmt die Laenge und die Hoehe kippt um
`Differenz * sin(Neigung)` - real aufgetreten: 820 mm Differenz ergaben
43 mm Hoehenfehler. Darum wird jeder Fussabdruck EINMAL gemessen und an
beide Bilanzen gegeben (Bau-Pfad und `vfl-zsolve-rueckanker`).
### Grenzen
- Ein Eck-Bauteil kann nur dann beide Geraden beruehren, wenn sein Schwenk
zum Eckwinkel passt (90-Grad-Kurve an 90-Grad-Ecke). Weichen sie ab,
bleibt ein Knick, den keine Laengenaenderung aufhebt.
- Der **seitliche Versatz des ES-Elements** ist GEWOLLT und bleibt bestehen
(Entscheidung aus Modus 1: der Hauptstrang bleibt gerade). Entweder liegt
die letzte Gerade exakt auf der gezeichneten Linie und der ES-`KS_AUS`
landet daneben, oder umgekehrt - beides zugleich geht nicht.
---
## 1. Grundkonzept "Kette"
- Eine Kette (Linienzug) ist eine durchgehende Foerderstrecke entlang eines
beliebigen 3D-Pfades.
- Eine Kette beginnt **immer** mit genau **einem** `AS_Element`
(Kettenanfang) und endet **immer** mit genau **einem** `ES_Element`
(Kettenende).
- Pro Kette gibt es also **genau ein** AS_Element und **genau ein** ES_Element.
- Die Mittelachse der gesamten Kette liegt exakt auf dem gewaehlten/gezeichneten
Pfad (wie in der Gefaellestrecke, ueber KS_EIN/KS_AUS-Frame-Kettung).
### Eingabemodi (Konsolen-Nummerierung, intern GLEICHNAMIG - kein Tausch)
1. **Modus 1 - Wert manuell eingeben** (`vf-linienzug-modus`): Startpunkt
waehlen, dann Punkt-fuer-Punkt eine Linie in beliebige Richtung ziehen,
Endhoehe abfragen usw. (interaktiv). Gegenstand der Abschnitte 1-13.
2. **Modus 2 - Pfad + Ziel-Hoehe** (`vf-linienzug-modus2`): Ein bereits
gezeichneter Pfad (LINE/ARC-Kette) wird ausgewaehlt, Start-/Endpunkt +
Zielhoehe abgefragt; die Kette wird als Randwertproblem geloest (Ziel-Hoehe
wird EXAKT getroffen). Siehe Abschnitt 14.
3. **Modus 3 - Vorwaerts-Nachbau** (`vf-linienzug-modus3`): baut eine Kette
Segment fuer Segment vorwaerts anhand ausgewaehlter 3D-Objekte; die
Endhoehe ist nur ein Ergebnis, nicht vorgebbar (Anfangswertproblem).
Legacy, wird schrittweise umgebaut - nicht Gegenstand dieses Dokuments.
---
## 2. Definition: reiner VarioFoerderer (VF)
- **Prinzipiell ist ein reiner VarioFoerderer die Gesamtheit aller Segmente
zwischen einer Umlenkstation und einer Motorstation.**
- Die **Umlenkstation** steht **einmal** am Anfang einer VF-Einheit, die
**Motorstation** steht **einmal** am Ende einer VF-Einheit.
- Alles dazwischen (geneigte Strecken, horizontale Strecken, Vario-Kurven,
Vertikalboegen) gehoert zum reinen VarioFoerderer und kann eine
Unter-Kette bilden.
### Warum GF1/GF2 und Separatoren dazugehoeren
Was `variofoerderer-einfuegen` aktuell baut, ist eine Kombination MIT
`AS_Element`, `ES_Element`, `GF1`, `GF2` und Separatoren. Grund:
- `AS_Element` hat zwischen KS_EIN und KS_AUS eine Neigung von ca. **3 Grad**.
Deshalb ist eine **3-Grad-Gefaellestrecke `GF1`** noetig, um das AS_Element
mit der Umlenkstation zu verbinden.
- Ebenso ist eine **3-Grad-Gefaellestrecke `GF2`** noetig, um die Motorstation
mit dem `ES_Element` zu verbinden.
### Standard-Aufbau (11 Schritte, Typ "standard")
```
1. AS_Element (Kettenanfang, ~3 Grad Neigung)
2. GF1 Gefaellestrecke (3 Grad) -> verbindet AS mit Umlenkstation
3. Separator (300 mm)
4. Umlenkstation (500 mm, 3 Grad) <-- Beginn reiner VF
5. Vertikalbogen 1
6. L_VF variable Strecke
7. Vertikalbogen 2
8. Motorstation (500 mm, 3 Grad) <-- Ende reiner VF
9. GF2 Gefaellestrecke (3 Grad) -> verbindet Motorstation mit ES
10. Separator (300 mm)
11. ES_Element (Kettenende)
```
Der "reine VF" sind hier die Schritte 5-7 (zwischen Umlenk- und Motorstation).
### Aufbau einer VF-Einheit im LINIENZUG (Abweichung vom Standard)
Im Linienzug sitzt die Staustrecke bevorzugt am **Einlauf** und der Separator
wird erst spaeter gesetzt:
```
[AS bzw. vorheriges Element]
GF1 Gefaellestrecke (3 Grad) <- ganze oder halbe Staustrecke (Wahl)
Separator (300 mm)
Umlenkstation (500 mm, 3 Grad) <-- Beginn reiner VF
[1..n Koerper-Sub-Segmente + Vario-Kurven] <-- reiner VF (mehrsegmentig)
Motorstation (500 mm, 3 Grad) <-- Ende reiner VF
[GF2 Gefaellestrecke (3 Grad)] <- nur falls "halbe am Ausgang"
-> KEIN Separator direkt hinter der Motorstation/GF2
```
Der abschliessende Separator + das ES-Element kommen erst am **Kettenende**
(bzw. optional ein Separator zwischen zwei Foerderern). Details: Abschnitt 5, 8,
9 (GF-Verteilung) und 12 (Block-Attribute).
---
## 3. Segment-Entscheidung: GF oder VF
Fuer jedes gerade Linien-Segment wird anhand von Start-/Endhoehe entschieden.
**Wichtig: Eine reine Gefaellestrecke ist NIE steiler als 3 Grad.** Deshalb ist
die reine GF auf ~3 Grad beschraenkt, alles Steilere ist ein VarioFoerderer:
| Bedingung | Ergebnis |
|---|---|
| Endpunkt **hoeher** als Startpunkt | **immer VF** (eine Gefaellestrecke kann als reine Schwerkraftstrecke nicht steigen) - **Ausnahme:** "Neue Linie: GF" bietet dafuer einen eigenen, bewusst getrennten Sonderfall "Steigende GF" (siehe unten) |
| Endpunkt **tiefer**, Neigung **~ 3 Grad** (Toleranzband) | **reine Gefaellestrecke (GF)** bei fest 3 Grad |
| Endpunkt **tiefer**, Neigung **> 3 Grad** | **VF-ab** (angetrieben, erreicht die Steilheit ueber Vertikalboegen 3-51 Grad) |
| Endpunkt **tiefer**, Neigung **< 3 Grad** | **VF** (zu flach fuer reine GF: Horizontale Mitte oder diskreter Winkel) |
Das Toleranzband um 3 Grad ist ueber `*vfl-gf-winkel-toleranz*` (Vorgabe 0.5 Grad)
einstellbar.
### Sonderfall: Steigende GF (bis 3 Grad)
"Neue Linie: GF" hat eine dritte, eigenstaendige Laengen-Modus-Option
("Steigende GF (Sonderfall, bis 3 Grad)", `gf-laenge-modus="3"`) NUR fuer
diesen einen Ausnahmefall: eine reine Gefaellestrecke, die bis zu 3 Grad
STEIGT statt faellt (Vorzeichenkonvention wie `frame->hz-winkel`: negativer
Winkel = steigend). Bewusst getrennt von den normalen Zweigen A (Endpunkt
waehlen) und B (Zielhoehe zuerst) - kein Separator wird dafuer gefragt
(Separatoren gelten nur fuer die normale, fallende GF).
- Die Bibliothek kennt nur EINEN 3-Grad-Bogen gegenueber FLACH (0 Grad,
`Vario_Bogen_auf_3`/`Vario_Bogen_ab_3`) - ein Wechsel zwischen der
fallenden (+3) und der steigenden (-3) Basis braucht daher IMMER 1-2
Boegen ueber 0 Grad als Zwischenhalt (`vfl-bogen-uebergang`, generischer
Uebergangs-Helfer): 3 Grad Differenz = ein Bogen, 6 Grad Differenz (voll
fallend -> voll steigend oder umgekehrt) = zwei Boegen.
- `vfl-bogen-uebergang` wird sowohl VOR jeder normalen (fallenden) GF
eingehaengt (falls der Vorgaenger noch steigend ist - No-Op, wenn schon
passend) als auch VOR jeder Separator+ES-Element-Anhaengung ans
Kettenende: **ES-Element-Hardware gibt es nur fuer die Anfahrt auf der
Standard-Fallend-Basis** - kommt die Kette steigend an, wird zuerst
automatisch zurueckgewandelt (siehe Abschnitt 6).
- **3 Grad** ist die kleinste im gesamten Projekt verfuegbare Neigung
(`Vario_Bogen_auf_3` / `Vario_Bogen_ab_3`). Eine flachere GF gibt es nicht.
### Kurzsegment-Regel (deltaL < 1000 mm)
- Ein VarioFoerderer braucht mindestens **1000 mm** deltaL, weil Umlenkstation
(500 mm) + Motorstation (500 mm) diese Strecke bereits belegen. Unterhalb
1000 mm ist kein VF baubar.
- Ist deltaL < 1000 mm, wird das Segment **automatisch eine 3-Grad-geneigte
Gefaellestrecke** (die kleinstmoegliche GF-Neigung).
- Fuer solche Kurzsegmente wird die **Endpunkt-Hoehe NICHT abgefragt** - die
Hoehe ergibt sich fest aus `deltaH = deltaL * tan(3 Grad)`.
- Ein steigendes Kurzsegment ist nicht baubar (GF kann nicht steigen, VF kein
Platz). Da fuer Kurzsegmente keine Hoehe abgefragt wird, entsteht dieser Fall
im interaktiven Ablauf ohnehin nicht (immer fallend mit 3 Grad).
- Beim VF-Fall (< 3 Grad Gefaelle) wird die Machbarkeit in dieser Reihenfolge
geprueft:
1. Horizontaler VarioFoerderer (`berechne-horizontale-mitte`),
2. sonst diskreter Winkel 3-51 Grad (`berechne-alle-winkel`).
- **Ein VarioFoerderer ist im Kern eine Kombination aus Foerderer und
Gefaellestrecke** - deshalb greifen fuer die geneigten Anteile eines VF
dieselben 3-Grad-Prinzipien.
---
## 4. Verfeinerter interaktiver Ablauf eines VF-Segments
Wird ein Linien-Segment als VF eingestuft, folgt diese Logik:
### 4.1 Frage: Ist der Endpunkt dieser Linie das Ende des Foerderers?
**JA (Foerderer-Ende):**
- Es wird eine **Motorstation** gebaut (unabhaengig von Auf/Ab).
- Der gewaehlte **Vertikalbogen** muss **denselben Winkel** wie der
**vorherige Vertikalbogen** haben. Dadurch neigt sich der KS_AUS des
Vertikalbogens um **3 Grad nach unten** - passend zur 3-Grad-Neigung der
Motorstation.
**NEIN (kein Foerderer-Ende):**
- Es wird **keine Motorstation** gebaut.
- Stattdessen Frage: **Horizontalen Foerderer fortsetzen?**
- Falls ja: eine weitere Linie **ohne Hoehendifferenz** zeichnen und einen
**horizontalen VF-Abschnitt** bauen.
- Nach dem horizontalen Foerderer folgt erneut eine 3-fache Auswahl
(siehe 4.2).
### 4.2 Auswahl nach einem horizontalen Foerderer-Abschnitt
1. **Foerderer-Ende bauen**: einen **3-Grad-Bogen (auf oder ab)** einfuegen,
sodass KS_AUS sich 3 Grad nach unten neigt, danach die **Motorstation**
(die selbst 3 Grad geneigt ist).
2. **Vario-Kurve einfuegen?** Falls ja: Winkel abfragen. Reihenfolge/Vorgabe:
**90 / 60 / 30 Grad** (90 Grad auf Position 1 und als Standard, da am
haeufigsten gebraucht).
3. **Auf/Ab-Foerderer fortsetzen**: naechste Linie zeichnen, Endhoehe abfragen
und pruefen, ob das das Foerderer-Ende ist (entscheidet, ob eine
Motorstation gebaut wird - zurueck zu 4.1).
### 4.3 Rekursion
Erreicht der Foerderer noch nicht das Ende, wird immer wieder gefragt, ob der
horizontale Foerderer fortgesetzt werden soll (Schleife ueber 4.1 -> 4.2), bis
schliesslich ein Foerderer-Ende (mit Motorstation) gesetzt wird.
### 4.4 Prompt "Ist der Endpunkt der Foerderer?" - drei Optionen
Der Prompt in der VF-Koerper-Schleife hat drei Optionen:
1. **Ja (nur Motorstation setzen)** - VF-Einheit schliessen, Kette laeuft weiter
(weiterer Foerderer/Motor moeglich, siehe Abschnitt 8).
2. **Nein (weiterbauen)** - naechstes Koerper-Sub-Segment (zurueck zu 4.2).
3. **Ja (Motorstation setzen, Kettenende definieren)** - siehe 4.5.
### 4.5 Option 3: Kettenende exakt am Zielpunkt definieren (ein Motor)
Deckt den Fall ab, dass **Start- und Endpunkt der Kette feststehen** und die
Strecke - unter Nutzung von Horizontal-Stuecken/Vario-Kurven, aber mit **nur
einem Motor** - genau am Ziel schliessen soll.
Ablauf (`vfl-body-abschluss` / `vfl-body-zerlegung`):
1. Zielpunkt (XY, auf die Fahrtrichtung projiziert) + Zielhoehe (Z) abfragen.
2. Der verbleibende **gerade** Lauf wird mit der bewaehrten Standard-Logik
zerlegt (`berechne-alle-winkel` bzw. `berechne-horizontale-mitte`), aber mit
**reduziertem Mid-Body-Budget**: der Einlauf (AS/GF1/Separator/Umlenk) ist
schon gebaut, deshalb `aus-dx = aus-dz = 0` und festes Budget nur
**Motor 500 + Auslauf-Separator 300 = 800 mm** (statt 1300).
3. **GF2 variiert mit dem gewaehlten Winkel** (Winkeltabelle wie aussen, jede
Zeile hat ihr eigenes L_GF) und sitzt **hinter dem Motor**. Die
GF-Verteilungs-Frage (Abschnitt 9) wird fuer diesen GF2-Anteil ueberschrieben;
Mindestwert `*vfl-gf-min-laenge*` (400 mm).
4. **Hoehe** kommt aus gewinkeltem VF + GF2, die ueberschuessige **Laenge** aus
einem horizontalen VF (flacher/langer Lauf).
5. Abschluss automatisch: Motorstation -> GF2 -> Separator -> ES-Element.
Horizontale **Vario-Kurven** (XY-Richtungswechsel) bleiben **manuell** und werden
von Option 3 nicht platziert - Option 3 baut nur den geraden Schluss.
**Ist-Ziel-Report:** Nach dem ES wird Soll (Zielpunkt) vs. Ist (ES-KS_AUS)
ausgegeben (dX/dY/dZ). Ein `ES_Element_90` macht einen 90-Grad-Schwenk; sein
KS_AUS liegt daher ~637 mm **seitlich** (dY) neben der Kettenachse. dX/dZ treffen
das Ziel exakt - das dY ist der Fussabdruck des ES-Elements, **kein Fehler** (die
Soll-Berechnung modelliert nur den geraden Lauf ohne den seitlichen ES-Versatz).
### 4.6 "Neue Linie BIS Kettenende" (Option 4/6): Startpunkt-Typ-Erkennung
Das Hauptmenue "Naechstes Element waehlen" bietet daneben eine EIGENE Option
("Neue Linie BIS Kettenende (danach Separator + ES-Element)"), die IMMER mit
Separator+ES-Element abschliesst, aber - anders als Option 3 oben - auch am
echten Kettenanfang (allererster Klick der Session) aufgerufen werden kann.
Damit sich die Bau-Logik dabei nicht blind auf die generische GF/VF-Automatik
(Abschnitt 3) verlaesst, wird zuerst erkannt, ob der gewaehlte Startpunkt zu
einer bestehenden VF- oder GF-Kette gehoert:
- **Laufende Fortsetzung** (ein Frame existiert schon in dieser Session):
der Vorgaengertyp ist bereits bekannt (`letzter-typ`) - `"Vario-Kurve"`
zaehlt zur VF-Familie, `"GF"`/`"Separator"` zur GF-Familie. `"VF"` (eine
gerade FERTIG gebaute VF-Einheit) zaehlt bewusst NICHT zur VF-Familie fuer
diesen Zweck - eine neue VF-Einheit direkt danach braucht trotzdem eine
frische Umlenkstation (siehe unten).
- **Echter Kettenanfang ohne AS-Element**: KS_AUS-Scan am gepickten Punkt
(`vfl-ks-aus-hz-an-punkt`, dieselbe Erkennung wie in
`vfl-eingang-modus-bestimmen`) - trifft der Punkt exakt auf das KS_AUS
eines bestehenden Bausteins, wird dessen Typ uebernommen.
**VF-Familie erkannt** (kein eigener Umlenkstation-Bedarf, z.B. Fortsetzung
einer Vario-Kurve): baut ueber `vfl-body-abschluss` + `vfl-vf-ausgang-bauen`
- dieselben Bausteine wie Option 3 oben (800 mm Budget statt 1300, volle
Stufe-1/2-Diagnose inkl. exakter Zielhoehe bleibt erhalten, da kein
GF1-Stumpf noetig ist, dessen Wegfall die Loesung stoeren wuerde).
**GF-Familie erkannt** (Fortsetzung einer Gefaellestrecke): dieselbe
Endpunkt-/Zielhoehe-Wahl wie "Neue Linie: GF" Zweig A/B (Abschnitt 3) statt
der generischen Automatik - eine reine Gefaellestrecke kann nicht steigen.
**Nicht eindeutig zuordenbar** (z.B. frisch gesetztes AS-Element ohne
erkennbaren Vorgaenger): unveraendert die generische Machbarkeits-Automatik
(`vfl-segment-entscheidung`, Abschnitt 3).
---
## 5. Separator-Regeln
Ein Separator (300 mm) wird eingefuegt:
- am **Ende jeder Gefaellestrecke (GF)**, und
- **vor jedem Gefaellebogen**.
### Basis-Regel (keine Verdopplung)
Da nach einer GF nur ein GF-Bogen oder eine neue Linie folgen darf, fallen die
beiden obigen Regeln an einer direkten **GF -> Gefaellebogen**-Verbindung auf
**dieselbe Nahtstelle**. Dort wird nur **EIN** Separator eingefuegt (nicht zwei
- kein Separator "am GF-Ende" zusaetzlich zu einem Separator "vor dem Bogen").
Ein Separator sitzt also genau einmal an der Grenze zwischen GF und
Gefaellebogen.
### Separator im LINIENZUG (Platzierung)
Damit zwischen einem AS und ES **mehrere Foerderer (Motoren)** liegen koennen,
wurde der Separator vom VF-Ausgang geloest:
- **Direkt hinter Motorstation/GF2: KEIN Separator** (`vfs-vf-exit` wird mit
`mit-separator=nil` aufgerufen).
- **Am Kettenende (Ja):** Separator (300 mm) + ES-Element werden zusammen
gesetzt (`vfl-insert-es-element`).
- **Bei "kein Kettenende" (Nein):** es wird gefragt, ob an dieser Stelle ein
**zusaetzlicher Separator** eingefuegt werden soll (`vfl-insert-separator`);
danach geht es mit dem naechsten Element weiter (neuer Foerderer moeglich).
- Der Standard-/Etage-VF (nicht Linienzug) behaelt den Separator direkt hinter
GF2 (`mit-separator=t`).
### Separator am horizontalen Stueck (0 Grad)
Wird VOR/NACH einem horizontalen Stueck ein Separator gewuenscht, liegt er in der
**horizontalen Ebene (0 Grad)** - also ZWISCHEN den beiden Vertikalboegen
(`auf_3` ... `ab_3`), nicht auf der 3-Grad-Basis davor/danach. Umgesetzt in
`vfl-sep-hz` (Einfuegung bei 0 Grad). Der optionale **Zwischen-Separator**
zwischen zwei Foerderern sitzt dagegen auf der 3-Grad-Basis (`vfl-insert-separator`).
---
## 6. Vertikalbogen-Regeln
- Der Vertikalbogen am **Ende** eines VF (vor der Motorstation) hat **denselben
Winkel** wie der Vertikalbogen am **Anfang** (nach der Umlenkstation).
- Der abschliessende Vertikalbogen bringt die Strecke auf **3 Grad Neigung nach
unten**, damit der Anschluss an die (3 Grad geneigte) Motorstation passt.
### Bogen-Blockname vs. Konsolen-Rotationsanzeige der Geraden (KEIN Fehler)
Beim Bau (`vfs-vf-koerper`) zeigt die Konsole fuer einen S-Bogen mit
Tabellenwinkel z.B. 18 Grad folgendes Muster:
```
5/11: Vario_Bogen_auf_18_TEF_rechts (3 Grad geneigt)
6/11: Steigungsstrecke (-15 Grad, L=... mm)
7/11: Vario_Bogen_ab_18_TEF_rechts (-15 Grad geneigt)
```
Die **Bogen-Bloecke** (`auf_18`/`ab_18`) tragen den ECHTEN, gewaehlten
Tabellenwinkel im Namen - das ist der massgebliche Wert (auch fuer
`Vario_Kette_Merge`s `VF_WINKEL`-Attribut, das ihn direkt aus dem Blocknamen
liest). Die **Gerade dazwischen** wird dagegen mit `winkel-eff = best-winkel -
3` inseriert (hier 18-3=15, negativ fuer "Auf") - NICHT mit dem vollen
Tabellenwinkel. Grund: der Eintrittsbogen hat den Frame bereits von der
3-Grad-Basis auf den vollen Winkel (18 Grad) gedreht; die Gerade wird relativ
zu diesem BEREITS gedrehten Frame eingefuegt und muss deshalb nur noch die
DIFFERENZ zur Basis nachdrehen. In Weltkoordinaten liegt die Gerade trotzdem
exakt bei 18 Grad - die "-15" ist eine reine Bau-interne Rotationsangabe,
kein zweiter, abweichender Winkel. Bestaetigt durch den Ist-Ziel-Report
(dX/dZ exakt) - waeren beide Werte real unterschiedliche Winkel, koennte das
Ergebnis nicht exakt stimmen.
### Flache Zone (horizontale Stuecke bleiben flach - Uebergang spaeter)
Ein horizontales Stueck endet **NICHT** mehr automatisch mit `ab_3` auf der
3-Grad-Basis, sondern bleibt **flach (0 Grad)**:
- Der `auf_3`-Eintritt wird nur gesetzt, wenn der Frame noch **nicht** flach ist
(sonst bleibt die laufende flache Zone erhalten).
- Der `ab_3`-Uebergang zurueck auf 3 Grad kommt **erst dann**, wenn ein echtes
3-Grad-Element folgt: Motorstation, Auf/Ab-Koerper oder Option-3-Abschluss
(`vfl-nach-3grad`).
- Die aktuelle Neigung wird direkt aus dem Frame gelesen (`vfl-frame-flach-p`,
Schwelle 1,5 Grad).
Vorteil: aufeinanderfolgende horizontale Elemente (Strecken, Separatoren,
Vario-Kurven) bleiben **durchgehend flach** - kein unnoetiges 3->0->3-Gezappel.
Die VF-Einheit als Ganzes endet weiterhin auf 3-Grad-Basis (der Guard vor der
Motorstation stellt das sicher), sodass die aeussere Kette unveraendert
3-Grad-basiert bleibt.
### ES-Element/Umlenkstation brauchen die Standard-Fallend-Basis
Separator+ES-Element (Kettenende) UND eine Umlenkstation (VF-Einheit-Start)
gibt es hardwareseitig nur fuer die Anfahrt auf der Standard-Fallend-Basis
(+3 Grad) - eine Anfahrt auf der steigenden Basis (-3 Grad, siehe Abschnitt 3
"Steigende GF") ist physisch nicht vorgesehen. Vor beiden Anhaengepunkten wird
deshalb `vfl-bogen-uebergang` (Ziel = die Standard-Fallend-Basis) eingehaengt
- bei einer bereits fallenden Ankunft ist das ein No-Op, bei einer steigenden
Ankunft werden automatisch die noetigen 1-2 Ausgleichsboegen eingefuegt.
### Motorstation-Seite
- Jede Motorstation hat eine **Seite** (links/rechts). Aktuell existiert nur die
**rechts**-DWG (`Vario_Motorstation_500mm`), daher wird derzeit immer "rechts"
verwendet und im Attribut `MOTORSEITE` (kommagetrennt je Motorstation)
festgehalten. Die "links"-Einzel-DWG wird spaeter ergaenzt.
---
## 7. 20-Meter-Regel (Motorstation)
- Ueberschreitet die **Gesamtlaenge der VF-Segmente nach einer Umlenkstation
20 m**, erscheint der Hinweis:
**"Foerderer laenger als 20 m - Motorstation einfuegen?"**
---
## 8. Uebergangsregeln zwischen Elementen
- Vario-Kurven werden **innerhalb** einer VF-Einheit behandelt (im
Foerderer-Ende-Ablauf, Abschnitt 4), nicht auf Ketten-Ebene.
- Nach einem **GF-Segment ODER einer abgeschlossenen VF-Einheit** (beide enden
auf 3-Grad-Neigung) darf als naechstes ein **GF-Bogen** oder eine **neue
Linie** folgen. Nur am Kettenanfang folgt direkt eine neue Linie.
- Bei Boegen/Kurven ist **keine Hoehenabfrage** noetig (die Hoehe ergibt sich
aus der Bogen-/Kurvengeometrie). Bei Linien wird die Endhoehe abgefragt (Aus-
nahme: Kurzsegment < 1000 mm, siehe Abschnitt 3).
### Mehrere Foerderer (Motoren) je Kette
Zwischen **einem** AS und **einem** ES koennen **mehrere VF-Einheiten** liegen
(jede mit eigener Umlenk- und Motorstation). Nachdem eine VF-Einheit mit der
Motorstation geschlossen ist und "kein Kettenende" gewaehlt wurde, kann die
Kette (optional mit Zwischen-Separator) mit einem GF-Bogen oder einer neuen
Linie weitergebaut werden - ist die neue Linie wieder ein VF, entsteht eine
weitere VF-Einheit (weiterer Motor). Die Motorenzahl/-seiten stehen im Attribut
`MOTORSEITE`.
### Fahrtrichtung folgt dem Vorgaengerelement
Eine gerade Foerderstrecke kann die Fahrtrichtung nicht aendern - das geht nur
ueber einen GF-Bogen bzw. eine Vario-Kurve. Beim Zeichnen einer neuen Linie
wird der gewaehlte Punkt daher auf die aktuelle Fahrtrichtung **projiziert**
(`vfl-neue-linie-messen`); nur das allererste Segment definiert die Richtung
frei. Auch die Start-Z-Hoehe der Kette wird abgefragt.
---
## 9. GF-Verteilung (Staustrecke: Einlauf / Ausgang)
Pro VF-Einheit wird gefragt, wie die Staustrecke (L_GF) verteilt wird:
- **1** - halbe Staustrecke als **GF2 am Ausgang**, halbe als **GF1 am Einlauf**.
- **2** - **gesamte** Staustrecke am **Einlauf** (GF1), kein GF2.
- Mindest-Gesamt-Staustrecke (GF1+GF2) = `*vfl-gf-min-laenge*` (Vorgabe **400 mm**);
faellt das berechnete L_GF darunter, wird angehoben.
- Hinter GF2 folgt **nie** direkt ein Separator (siehe Abschnitt 5).
---
## 10. Laengenbudget & FESTE_HORIZONTAL
`berechne-alle-winkel` zieht das horizontale Budget der festen Elemente von
deltaL ab (`FESTE_HORIZONTAL`):
- **Standard-/Etage-VF:** `FESTE_HORIZONTAL = 1600` mm
(Umlenk 500 + Motor 500 + **2** Separatoren 300).
- **Linienzug:** `*vfl-feste-horizontal* = 1300` mm
(Umlenk 500 + Motor 500 + **1** Separator am Einlauf 300; der Ausgangs-
Separator entfaellt). Wird als optionaler 4. Parameter an
`berechne-alle-winkel` uebergeben.
> Offen: Bei mehrsegmentigen VF-Einheiten rechnet `berechne-alle-winkel` je
> Sub-Segment mit eigener Entry/Exit-Annahme - der reale Fussabdruck kann
> abweichen (empirisch pruefen).
---
## 11. Bedienung
- Alle Ja/Nein- und Auswahl-Abfragen sind **zahlenbasiert** (1/2 bzw. 1/2/3),
keine Buchstaben.
- **Winkelauswahl:** Gibt es fuer einen VF mehrere gueltige Winkel, listet das
System sie (mit L_GF/L_VF) und der Nutzer waehlt (`vfl-waehle-winkel`).
- Beim Start wird die **Z-Hoehe des Kettenstartpunkts** abgefragt.
- **Lueckenlose Nummerierung** im Prompt "Naechstes Element waehlen": der
GF-Bogen ist nur mit vorhandenem Frame Option 1; ohne Frame ruecken die
uebrigen Optionen auf 1/2/3 auf (keine Luecke wie frueher 2/3/4).
- **Vario-Kurve-Winkel:** Reihenfolge 90 / 60 / 30 Grad, 90 Grad ist Standard.
- **GF-Verteilungstext:** "1 - 1/2GF am Ausgang (GF2), 1/2GF am Einlauf (GF1)".
---
## 12. Block-Attribute (TYP = "Streckengruppe")
Der Linienzug erzeugt EINEN Block `VF_<Nr>` mit der vollen Attributstruktur
(analog Standard/Etage-VF), aber mit **segmentweisen, kommagetrennten** Werten.
Zwei parallele Segment-Achsen:
- **VF-Sub-Segmente:** `L_VF_m` <-> `WINKEL` <-> `ANTRIEBFAHRTRICHTUNG`
- **GF-Segmente:** `L_GF_m` <-> `GF_WINKEL`
| Attribut | Inhalt |
|---|---|
| `NUMMER` | fortlaufende VF-Nummer |
| `ID` | aufsteigende, eindeutige ID (`ssg-id-generate`, wie Kreisel) |
| `TYP` | `"Streckengruppe"` |
| `MONTAGEHOEHE_m` | mittlere Hoehe (m) |
| `HOEHE_VON` / `HOEHE_BIS` / `DELTA_H` | Start-/End-/Differenzhoehe (mm) |
| `DELTA_L` | planare Gesamtdistanz Start->Ende (mm) |
| `L_VF_m` | Laenge je VF-Sub-Segment (m), kommagetrennt |
| `WINKEL` | Vertikalbogen-Winkel je VF-Sub-Segment (0 = horizontal), kommagetrennt |
| `ANTRIEBFAHRTRICHTUNG` | `Auf`/`Ab`/`horizontal` je VF-Sub-Segment, kommagetrennt |
| `L_GF_m` | Laenge je GF-Segment **inkl. GF1/GF2** (m), kommagetrennt |
| `GF_WINKEL` | Neigung je GF-Segment (Grad), parallel zu `L_GF_m`, kommagetrennt |
| `MOTORSEITE` | Seite je Motorstation (`rechts`/`links`), kommagetrennt |
| `ANZAHL_SEGMENTE` / `ANZAHL_GF` / `ANZAHL_VF` | Segmentzaehler |
| `SEITE` | AS-Seite (links/rechts) |
| `GF_Bogen_L_90/60/30`, `GF_Bogen_R_90/60/30` | Anzahl GF-Boegen je Seite + Winkel (je eigenes Attribut) |
| `VF_Bogen_A_90/60/30`, `VF_Bogen_I_90/60/30` | Anzahl Vario-Kurven je Variante (A=aussen/I=innen) + Winkel (je eigenes Attribut) |
Gefuellt werden diese Werte ueber Akkumulatoren (`vfl-acc-*`), die waehrend des
Baus in Reihenfolge angehaengt bzw. hochgezaehlt werden.
---
## 13. Umsetzungsstand & bekannte Abweichungen
Stand `vf_linienzug.lsp` (Modus 1).
### Umgesetzt
- **Kettenstruktur** (Abschnitt 1): AS am Anfang, ES am Ende, EIN Block je Kette.
- **GF/VF-Entscheidung** (Abschnitt 3): `vfl-segment-entscheidung` - reine GF
nur ~3 Grad, steiler VF-ab, flacher VF; Kurzsegment < 1000 mm -> 3-Grad-GF
ohne Hoehenabfrage.
- **VF-Einheit, mehrsegmentig** (Abschnitt 2/4): `vfl-vf-einheit` baut Entry
(Umlenkstation) einmal, dann beliebig viele Koerper-Sub-Segmente +
Vario-Kurven, dann Exit (Motorstation) einmal. Bausteine in `vf_standard.lsp`:
`vfs-vf-entry` / `vfs-vf-koerper` / `vfs-vf-exit`.
- **Mehrere Foerderer (Motoren) je Kette** (Abschnitt 8): nach einer VF-Einheit
kann (optional mit Zwischen-Separator) weitergebaut werden.
- **Foerderer-Ende-Abfrage + horizontale Fortsetzung + Vario-Kurve** (Abschn. 4).
- **Vertikalbogen-Winkelgleichheit** (Abschnitt 6): jeder Koerper faengt/endet
auf 3-Grad-Basis.
- **20-m-Regel** (Abschnitt 7): `vfl-20m-check` gibt den Hinweis aus.
- **GF-Verteilung waehlbar** (Abschnitt 9): ½ am Ausgang (GF2) oder alles am
Einlauf; Mindest-GF `*vfl-gf-min-laenge*` = 400 mm.
- **Separator-Platzierung** (Abschnitt 5): kein Separator hinter Motorstation/
GF2; Separator + ES am Kettenende bzw. optionaler Zwischen-Separator.
`vfs-vf-exit` mit `mit-separator=nil` (Linienzug) bzw. `t` (Standard-VF).
- **FESTE_HORIZONTAL = 1300** im Linienzug (Abschnitt 10).
- **Fahrtrichtung folgt dem Vorgaenger** (Projektion), Start-Z-Abfrage (Abschn. 8/11).
- **Winkelauswahl** bei mehreren gueltigen Winkeln (Abschnitt 11).
- **Zahlenbasierte Menues** (Abschnitt 11).
- **ID-Vergabe** (`ssg-id-generate`) fuer Linienzug-, Standard-/Etage-VF- und
Gefaellestrecke-Bloecke.
- **Volle Block-Attribute** (Abschnitt 12): TYP="Streckengruppe", segmentweise
L_VF_m/L_GF_m/GF_WINKEL/ANTRIEBFAHRTRICHTUNG/WINKEL, MOTORSEITE, GF_Bogen_*/
VF_Bogen_*-Zaehler.
- **Option 3 "Kettenende definieren"** (Abschnitt 4.5): Mid-Body-Zerlegung mit
reduziertem Budget (800), GF2 variiert mit Winkel (min 400), gewinkeltes +
horizontales VF, Auto-Abschluss (Motor->GF2->Separator->ES), Ist-Ziel-Report.
- **Flache Zone** (Abschnitt 6): horizontales Stueck endet flach, `ab_3` erst vor
einem 3-Grad-Element (`vfl-nach-3grad` / `vfl-frame-flach-p`).
- **Horizontale Separatoren** (Abschnitt 5): Separator am horizontalen Stueck in
der 0-Grad-Ebene (`vfl-sep-hz`).
- **Menue-Nummerierung lueckenlos** + **Vario-Kurve 90/60/30** (Abschnitt 11).
- **Regressionstest `TEST_LINIENZUG`** (in `tests/test_linienzug.lsp`, Skript aus
`tests/testdata/linienzug_tests.json`): spielt eine reale Session per
Eingabe-Mock ab (getpoint/getstring/getint/getreal), laesst den echten
`vf-linienzug-modus` durchlaufen. Punkt-Abfragen laufen ueber den
verhaltensneutralen Wrapper **`vfl-getpoint`** (feste 2-Arity), damit der Mock
greift. Zusaetzlich `TEST_LINIENZUG_STUFE2` (`linienzug_tests_stufe2.json`,
siehe `doc/vf_linienzug_modus1_anleitung.md`) fuer den Stufe-2-Fallback am
Kettenende.
- **Steigende GF (Sonderfall, bis 3 Grad)** (Abschnitt 3): eigener Zweig C in
"Neue Linie: GF" (`gf-laenge-modus="3"`), `vfl-bogen-uebergang` als
genereller Uebergangs-Helfer zwischen Basis-Neigungen (auch in Zweig A/B
eingehaengt, falls der Vorgaenger steigend war).
- **"Neue Linie BIS Kettenende" erkennt VF-/GF-Startpunkt** (Abschnitt 4.6):
`vfl-ks-aus-hz-an-punkt`/`letzter-typ`-basierte Familien-Erkennung,
VF-Familie baut ueber `vfl-body-abschluss` + `vfl-vf-ausgang-bauen` (wie
Option 3), GF-Familie ueber dieselbe Endpunkt-/Zielhoehe-Wahl wie "Neue
Linie: GF".
- **Abbruch-Trigger vollstaendig** (`vfl-in-value`/`-value-p`): ein per
Wizard-Dialog gesetztes Abbruch-Flag wird jetzt auch von den Funktionen mit
eigener Replay-/Pending-Logik erkannt (`vfl-in-abstand`, `vfl-in-selection`)
- vorher konnte ein Dialog-Abbruch dort auf einen rohen `getpoint` statt auf
Terminierung zurueckfallen.
### Noch offen / zu pruefen (bitte in BricsCAD verifizieren)
1. **Laengen-Budget** bei mehrsegmentigen VF-Einheiten (Abschnitt 10) -
empirisch nachmessen.
2. **20-m-Regel** nur Hinweis, noch keine automatische Zwischen-Motorstation.
3. **Knick-Risiko** am Uebergang GF-Segment -> VF-Einheit (Entry startet immer
bei 3 Grad).
4. **AS-/ES-Fusspunkte** (`aus-dx` / `ein-dx`) werden nicht von der Segmentlaenge
abgezogen (anders als in `gf-linienzug-modus`).
5. **"Neue Linie BIS Kettenende" bei erkannter VF-Familie MIT Umlenkstation**
(letzter-typ="VF", eine gerade fertig gebaute VF-Einheit, oder ein per
KS_AUS erkannter reiner Umlenk-/Motor-/Bogen-Typ am Kettenanfang): faellt
bewusst auf die generische Automatik zurueck (Abschnitt 4.6) - noch NICHT
live in BricsCAD getestet.
6. **Regressionstests noch nicht nachgezogen**: keiner der Tests
(`test_linienzug.lsp`, `test_vf_spec.lsp`/`.py`) deckt bisher die neuen
Punkte oben ab (Steigende GF, Kettenende-Familien-Erkennung,
Abbruch-Trigger-Fix) - nur manuell in BricsCAD verifiziert.
7. **Modus 3** (`vf-linienzug-modus3`, Vorwaerts-Nachbau, siehe Eingabemodi in
Abschnitt 1): Grundgeruest gebaut (GF-Kette + VF-Laeufe per
Run-State-Machine, AS-Querschub auf Pfad). Offen: Laengen-Reservierung am
Kettenende (Exit-Fussabdruck ueberschiesst). Kann eine vorgegebene
Endpunkt-Hoehe NICHT treffen - dafuer ist Modus 2 vorhanden (Abschnitt 14).
8. **Option-3 Ist-Ziel-Report**: die Soll-Berechnung modelliert nur den geraden
Lauf und beruecksichtigt den **seitlichen Versatz des ES_Element_90** nicht
(dY ~ 637 mm ist erwartet, kein Fehler). dX/dZ treffen exakt. Zwei bekannte
Naeherungen koennten dennoch kleine Restabweichungen erzeugen: der
Eintrittsbogen wird mit 3-Grad-Basis gerechnet (Sonderfall: Start nach einer
horizontalen Vario-Kurve), und GF2 wird bei < 400 mm auf das Minimum
angehoben. Bei Bedarf empirisch nachjustieren.
### Geloest
- **Vario-Kurve-Bloecke** (`data/ils/3D/Vario_Kurve_*`): fuehren ihre KS als
`KSYS_EIN`/`KSYS_AUS` (statt `KS_EIN`/`KS_AUS`); `extract-ks-from-block-raw`
normalisiert beide ueber `ks-normalize-name` - die Kurven docken korrekt an.
- **Versatz Separator/ES** (Bild-Befund): Ursache war das erzwungene Z-Ziel von
`insert-block-mixed-to-ks` (setzt ES-KS_AUS auf eine feste Hoehe - sinnvoll im
Standalone-Gefaelle mit vorgegebener Endhoehe, aber falsch im frei auslaufenden
Linienzug). Der Linienzug-ES wird jetzt rein per **KS-zu-KS**
(`insert-block-ks-to-ks`) an den Separator angekettet - ES-KS_EIN folgt exakt
dem Separator-Ausgang, kein Z-Ziel -> Versatz behoben (in BricsCAD gegenpruefen).
- **Vario-Kurve war 3 Grad geneigt**: der uebergebene Frame trug die
3-Grad-Basisneigung. Die Kurve wird jetzt auf einem abgeflachten Frame (0 Grad)
eingefuegt (horizontaler Richtungswechsel).
---
## 14. Modus 2: Pfad + Ziel-Hoehe (Randwert-Solver)
> **Hinweis zur Nummerierung:** Dieser Solver ist im finalen Menue **Modus 2**
> (Befehl waehlt intern `vf-linienzug-modus2`); Modus 3 ist der aeltere
> Vorwaerts-Nachbau (`vf-linienzug-modus3`, siehe Eingabemodi in Abschnitt 1
> und Abschnitt 13 Punkt 7).
>
> Die internen Helfer trugen bis 2026-10-22 die Praefixe `vfl3-`/`vfl2-` aus
> einer frueheren Planungsphase - und zwar GENAU VERTAUSCHT zur endgueltigen
> Menue-Zuordnung. Sie heissen jetzt nach ihrer ROLLE statt nach einer
> Modus-Nummer:
>
> | Praefix | Rolle | genutzt von |
> |---|---|---|
> | `vfl-zsolve-*` (frueher `vfl3-*`) | rechnet die Hoehen (Z) durch | nur Modus 2 |
> | `vfl-pfad-*` (frueher `vfl2-*`) | arbeitet auf dem gezeichneten Pfad (Eckwinkel, AS einfuegen, VF oeffnen/schliessen) | Modus 2 **und** Modus 3 |
>
> Eine Modus-Nummer war fuer die zweite Gruppe ohnehin nicht richtig
> vergebbar, weil drei dieser Funktionen von beiden Modi benutzt werden.
Modus 3 (Vorwaerts-Nachbau) kann eine vorgegebene Endpunkt-Hoehe nicht treffen,
weil er die Kette Segment fuer Segment vorwaerts baut - die Endhoehe ist nur ein
Ergebnis (Anfangswertproblem / initial value problem). Modus 2 loest stattdessen
ein Randwertproblem (boundary value problem): Start UND Ziel (je X,Y,Z) sind
bekannt, die Zwischenhoehen werden gerechnet.
### 14.0 Grundprinzip (zwei getrennte Probleme)
- XY = gezeichneter Pfad, reine KS-Kettung (wie Modus 3, mm-Drift akzeptiert).
- Z = wird gerechnet, sodass das Kettenende die Ziel-Hoehe EXAKT trifft.
Ablauf in zwei Phasen: erst planen (alle Hoehen durchrechnen), dann bauen.
### 14.1 Entkopplung Neigung <-> XY
Die Neigung eines Teils aendert seine Hoehe (Z), aber nicht seinen
XY-Fussabdruck: ein Staustrecken-Teil mit Planlaenge L belegt in der Draufsicht
immer L (die 3D-Laenge waechst mit L/cos(w), die Projektion bleibt L). Deshalb
lassen sich Z-Ziel und Pfadtreue unabhaengig loesen.
### 14.2 GF-Rollen
- GF1/GF2 INNERHALB einer VF-Einheit: fest 3 Grad, Laenge variabel (Ausgleich).
- Eigenstaendige GF-Laeufe: Neigung per Eingabe (wie Modus 3, Vorgabe 3 Grad).
### 14.3 VF-Bruecke = Standard-VF-Einheit
Jede VF-Strecke im Pfad ist eine Standard-VF-Einheit ohne eigene AS/ES:
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 Bruecken-Enden bleiben fix. Pro Bruecke 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. Das loest der
vorhandene Modus-1-Solver (berechne-alle-winkel / berechne-horizontale-mitte).
### 14.4 Anker rechnen (Zwei-Anker / shooting)
- Front-Anker: Z von AS vorwaerts durch alle fuehrenden deterministischen Teile
(GF-Geraden mit Eingabe-Winkel + GF-Boegen) bis zur ersten VF-Bruecke.
- Rueck-Anker (Junction): Z_Ende RUECKWAERTS durch alle nachlaufenden
deterministischen Teile - reine Rechnung, kein Rueckwaerts-Bauen.
- delta-H_Bruecke = Z_Front - Z_Junction; Spannweite = Pfad-Planlaenge der
VF-Strecke (minus Fussabdruck etwaiger Vario-Kurven darin).
### 14.5 Ecken in der Hoehen-Bilanz
- GF-Bogen: Z-Drop aus der KS_EIN->KS_AUS-Z-Differenz des Blocks
(Temp-Objekt + extract-ks-from-block, wie insert-block-mixed-to-ks).
- Vario-Kurve: auf 0 Grad geflacht -> delta-Z ~ 0 (verifizieren).
### 14.6 Phasen
Phase A (planen): Pfad waehlen; Start (X,Y,Z)+AS-Seite; Ende (X,Y,Z)+ES-Seite;
sortieren/analysieren; Eck-Vorpruefung; Segmente klassifizieren (Ergebnis nur
speichern); deterministische delta-Z; Anker rechnen; Bruecke loesen. Nicht
loesbar -> Meldung + Abbruch.
Phase B (bauen): vorwaerts, KS-Kettung; alle Bau-Primitive existieren bereits
(vfl-pfad-as-gf-einfuegen, vfl-insert-gf-segment, vfl-insert-gf-bogen-block,
vfl-pfad-vf-oeffnen / vfs-vf-koerper / vfl-pfad-vf-schliessen mit GELOESTEN Werten,
vfl-insert-vario-kurve-block, vfl-insert-es-element, vfl-block-erstellen).
### 14.7 Machbarkeit (warum eine Bruecke "infeasibel" sein kann)
Hoehen-Erhaltung (conservation of height): delta-H_gesamt = Z_Start - Z_Ende ist
fest und wird aufgeteilt in Summe(deterministische GF+Boegen) + delta-H_Bruecke.
Die deterministischen Anteile bestimmen die Benutzer-Winkel; der Rest muss die
Bruecke ueber ihre feste Spannweite liefern.
WICHTIG - Vorzeichen ist nur Richtung, nicht Machbarkeit: Ein VF ist
ANGETRIEBEN und kann STEIGEN und FALLEN (VF-Auf / VF-Ab). Eine reine GF kann nur
fallen; steigen erzwingt daher immer VF (siehe Abschnitt 3).
- delta-H_Bruecke > 0 -> Bruecke faellt -> VF-Ab.
- delta-H_Bruecke < 0 -> Bruecke steigt -> VF-Auf (voellig gueltig, KEIN Fehler).
Infeasibel wird es nur ueber die MAGNITUDE: die noetige mittlere Neigung
uebersteigt den Vario-Bereich (rund 3..51 Grad), oder die Spannweite fasst den
Pflicht-Fussabdruck nicht (Separator 300 + Umlenk 500 + Motor 500 + min. GF1/GF2
+ mind. 1 Vario-Koerper). Dann: saubere Meldung statt Fehlbau. Flachere GF-Winkel
verschieben den Rest-delta-H der Bruecke.
### 14.8 Staffelung
- M2a - EINE VF-Bruecke (GF ... VF ... GF): delta-H_Bruecke voll determiniert ->
eindeutig loesbar. Erster Wurf (Fokus).
- M2b - MEHRERE VF-Bruecken: die delta-H-Verteilung auf N Bruecken ist
unterbestimmt; Regel: die fehlende Hoehe je Bruecke wird abgefragt. Spaeter.
### 14.9 Grenzen (bewusst)
Z trifft die Ziel-Hoehe EXAKT (Solver). XY landet auf dem Pfad mit mm-Drift
(reine KS-Kettung); der Endpunkt wird in XY nahe, nicht mathematisch exakt
getroffen. Exakter XY-Endschluss = eigenes Inverse-Kinematik-Problem, das mit
reiner KS-Kettung kollidiert - vorerst nicht Ziel.
### 14.10 Wiederverwendung
Vorhanden: Pfad-Analyse (gf-sortiere-objekte / gf-analysiere-kette), Eck-Pruefung
(vfl-pfad-eckwinkel-pruefen, geteilt mit Modus 3), Klassifizierung (aus Modus 3),
alle Bau-Primitive, Bruecken-Solver (Modus 1). Neu (~mittel): delta-Z-Helfer
(vfl-zsolve-gf-dz / vfl-zsolve-bogen-dz / vfl-zsolve-kurve-dz), Vorwaerts/Rueckwaerts-Z-
Propagation, Endpunkt/ES-Setup, Zwei-Phasen-Orchestrierung
(`vf-linienzug-modus2`).
### 14.11 Umsetzungsstand M2a (umgesetzt, in BricsCAD getestet)
**Ablauf (`vf-linienzug-modus2`):** Pfad waehlen; Start (X,Y,Z) + AS-Winkel(30/90)
+ AS-Seite; Ende (X,Y,Z) + ES-Winkel + ES-Seite; sortieren/analysieren/Eck-Pruefung;
Segmente klassifizieren; VF-Lauf finden; Phase B (bauen).
**Hoehe exakt (messen statt schaetzen):**
- **Front-Anker** wird GEMESSEN: AS + Front-GF werden zuerst gebaut, dann die reale
KS_AUS-Hoehe abgelesen (AS-Eigen-dz + Trimmung automatisch enthalten).
- **Junction (Rueck-Anker)** exakt rueckwaerts vom Ziel gerechnet (`vfl-zsolve-rueckanker`:
GF-Bogen bei Neigung, Separator, ES-dz).
- **GF2** = kleine gemessene Feinkorrektur bis zur Junction -> **dZ = 0**.
**VF-Bruecke = Standard-Vario:** `berechne-alle-winkel` auf dem Kletter-Segment,
GF-Verteilung feste-hz = 800/1300 + Hoehen-Anpassung fuer Motor/Uebergaenge. Bei
mehreren gueltigen Winkeln waehlt der Nutzer (`vfl-waehle-winkel`).
**Vario-Kurve = mehrsegmentiger VF-Lauf (eine VF-Einheit):**
- VF-Geraden + Vario-Kurven bilden EINEN Lauf (die Kurve unterbricht ihn nicht).
- **Kletterer = GENAU EINE VF-Gerade: die laengste des Laufs.** Alle anderen
werden **horizontal** (nur Anschluss). Verbindet also eine Vario-Kurve zwei
VF-Geraden, wird die kuerzere flach gebaut und die laengere traegt die ganze
Hoehe (Regel 2026-10-22).
Grund: der Solver budgetiert EIN Kletterstueck mit EINEM Paar Vertikalboegen,
der Bau setzt dieses Paar aber je Kletterer. Mit zwei Kletterern fehlten ein
zweites Bogenpaar UND die Uebergaenge der zusaetzlichen flachen Zone im
Laengenbudget - gemessen: erstes Segment 1355.9 mm zu lang, Kette insgesamt
3185 mm zu lang, bei korrekter Hoehe (dZ -10.2 mm).
Die frueher benutzte Schwelle `*vfl-min-climber-laenge*` (Vorgabe 3000) spielt
fuer die Auswahl damit keine Rolle mehr.
- **Flache Zone:** genau EIN `auf_3` rein, EIN `ab_3` raus; Kurve + horizontale
Fueller sind bei 0 Grad DIREKT verbunden (keine Zwischen-Boegen).
- **Horizontaler Fueller** gleicht die Restlaenge aus (dein „Laenge folgt").
**GF-Verteilung waehlbar:** 1 = alles am Einlauf (GF1); 2 = 1/2 GF1 + 1/2 GF2. Bei
1/2/1/2 wird der im Kletter-Segment durch das halbe GF1 frei werdende Platz mit
einem horizontalen Fueller-A in VF1 gefuellt; GF2 sitzt hinter dem Motor.
**AS/ES 30 oder 90 Grad waehlbar** (auch in Gefaellestrecke):
- Abfrage `vf-frage-element-winkel` vor der Seite; Blockname
`AS_Element_<30|90>_<seite>` / `ES_...`; Masse pro Wahl neu gesetzt
(`vf-set-as-masse` / `vf-set-es-masse`) -> berechne/GF rechnen variantengerecht.
- **AS-Schwenk GEMESSEN** (`vf-element-plan-turn`, KS_EIN.xu -> KS_AUS.xu), damit
KS_AUS entlang hz zeigt - unabhaengig von der Bauform (30/90/gerade).
**AS/ES-Achs-Verankerung (Start-/Endpunkt liegen auf der KS-Achse):**
- **AS:** Versatz ENTLANG der KS_EIN-Achse (statt senkrecht zum Pfad) -> KS_AUS
auf dem Pfad UND Startpunkt auf der KS_EIN-Achse.
- **erste GF-Trimmung:** echter AS-Fussabdruck entlang des Pfads aus dem realen
KS_AUS (nicht Block-dx) -> GF-Bogen sitzt exakt auf der Ecke.
- **ES:** letzte Fueller-Laenge so geloest (`vfl-zsolve-es-fueller` + `vf-element-ks-info`),
dass der Endpunkt auf der ES-KS_AUS-Achse liegt (Spiegel der AS-Regel).
**Ergebnis (Test 30 und 90 Grad):** dZ = 0; Startpunkt auf AS-KS_EIN-Achse;
Endpunkt auf ES-KS_AUS-Achse (Quer zur Achse ~0). Der Rest-Laengs-Wert ist die
seitliche ES-Ausladung (Bauform), kein Fehler.
**Bekannte Rest-Abweichung (bewusst akzeptiert):** nach einem GF-Bogen driftet die
Mittellinie ~einige mm vom gezeichneten Pfad (reine KS-Kettung: Folge-Teile haengen
am Bogen-KS_AUS, nicht am gezeichneten Eckpunkt). Kein Re-Anchoring (Wunsch: Teile
schliessen exakt aneinander).
### 14.12 Noch offen
- **25-m-Regel** im Pfad-Modus (VF-Kette zu lang -> Motorstation als Einheitsende).
- **M2b:** mehrere getrennte VF-Bruecken (delta-H-Verteilung abfragen).
- Standard-VarioFoerderer (`vf_standard.lsp`) bleibt bei 90 Grad (bewusst).