ba01455d52
Ziel: eine VF_n-Kette soll aus einem Stapel Eingabedaten gebaut werden koennen - ohne Dialog, ohne Konsolenfrage. Fahrplan und Begruendungen in doc/TODO-plan-vf-interactive.md. Alle Aenderungen sind No-Ops, solange *ssg-gui-aus* und *vfl-headless* nil sind. Produktion (Lisp/vf_linienzug.lsp, Lisp/vf_core.lsp): - vfl-journal-reset im Dispatcher VOR die Modus-cond gezogen. Bisher nur im Modus-1-Zweig: ein frischer Modus-2-Lauf erbte das Journal des Vorlaufs und schrieb es in die XDATA, ein spaeterer Doppelklick spielte fremde Eingaben vor. - Lokale Variable "member" in vf-linienzug-modus2 umbenannt. Sie verdeckte im selben Scope das Builtin member, das weiter unten gebraucht wird - jedes Kletterer-Segment waere in "bad function" gelaufen. - Neu vfl-meldung: sammelt den Text nach *vfl-meldungen* + dbgmsg und zeigt ihn nur bei erlaubter GUI modal, sonst per princ. Die 12 Bau-Pfad-alerts darauf umgestellt; ein Alert blockierte sonst jeden Batch-Lauf, und sein Text ist die einzige Auskunft, WELCHE Sektion abgewiesen wurde. Die reinen Interaktiv-Alerts (fehlendes DCL, "nicht editierbar", "kein Journal") bleiben alert. - Neu *vfl-headless* (+ vfl-headless-p/-abbruch/-notausgang/-ort, Diagnose *vfl-headless-fehler*, optionaler Antwort-Hook *vfl-headless-antwort-fn*): eine erschoepfte Replay-Queue ist damit ein harter Abbruch MIT Fundstelle (Art der Eingabe, Glied- und Eingabe-Nummer) statt eines stillen Rueckfalls auf Live-Eingabe. Eingebaut in vfl-in-value, vfl-in-value-p, vfl-in-selection und vfl-in-abstand. - vfl-journal-reset loescht Meldungen und Diagnose mit (gehoeren zum Lauf); vfl-view-refresh ueberspringt headless _PLAN/_ZOOM. Testfall HundM05 (5 echte Ketten aus data/polylines.dxf): - tests/testdata/hundm05.json neu erzeugt aus den XDATA-Journalen der VF_n-Bloecke (lib/vf_journal_export.py) - flach, weil ssg-load-json zeilenweise liest. Die drei kopierten Ketten bekommen ihren echten Einfuegepunkt, nicht das veraltete HOEHE_VON-Attribut. - tests/test_hundm05.lsp arbeitet jetzt per Journal-Replay statt mit Eingabe-Mocks: ein echtes Journal fuehrt die geerbte Fahrtrichtung nicht mit (vfl-in-abstand journalisiert hz nur beim ersten Segment), ein Mock kann sie also nicht kennen. Schaltet *vfl-headless* ein und schreibt prompts, headless_fehler und meldungen ins Ergebnis-JSON. - Kettenschleife fangt je Kette: ein Fehler NACH dem Bau nimmt nicht mehr die restlichen Ketten mit. - entprev gibt es in AutoLISP nicht (nur entnext/entlast) - die Suche nach dem fertigen Block laeuft vorwaerts ab dem Zeichnungsstand vor dem Bau. Dieselbe Falle in tests/test_mubea.lsp mitbehoben; sie schlug dort nie zu, weil entlast immer sofort traf. Absicherung ohne CAD: - tests/test_vf_headless_statisch.py: eingechecktes Inventar aller alert/get*/ssget/new_dialog-Fundstellen je Funktion (ein neues getreal in einer Bau-Funktion faellt auf, auch wenn sein Zweig im Test nie erreicht wird), Praesenz des Riegels in allen vier Wrappern, Diagnose-Reset und die Reset-Reihenfolge im Dispatcher. Dazu ein Waechter gegen erfundene AutoLISP-Funktionen (entprev u.a.) - diese Fehlerklasse kostet sonst jedes Mal einen CAD-Lauf. - tests/test_hundm05.py prueft zusaetzlich prompts == 0, keine Headless-Abbrueche und keine Bau-Meldungen. tests/alltests.json: hundm05-Zeile laedt VarioFoerderer (nicht KreiselInsert) und bleibt bis zu einem gruenen CAD-Lauf abgeschaltet. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
701 lines
33 KiB
Markdown
701 lines
33 KiB
Markdown
# JSON-Schema fuer tests/testdata/*.json
|
|
|
|
Diese Datei leitet **aus den Produktions-Routinen in `Lisp/`** (nicht aus den
|
|
Test-Hilfsfunktionen in `tests/*.lsp`) ab, welche Angaben pro Element-Typ
|
|
noetig sind, um das jeweilige Bauteil programmgesteuert (per JSON) zu
|
|
erzeugen. Fuer jeden Typ wird die tatsaechlich aufgerufene LISP-Funktion samt
|
|
Parameterliste referenziert.
|
|
|
|
Jede Objekt-Sektion enthaelt ein **vollstaendiges** JSON-Beispiel: es listet
|
|
*alle* Werte auf, die man setzen muss, damit die dahinterliegende
|
|
Produktionsfunktion mit saemtlichen Parametern aufgerufen werden kann — so,
|
|
als gaebe es keine `tests/test_*.lsp`-Wrapper. Wo Koordinaten (x/y/z) als
|
|
Eingang noetig sind, stehen sie explizit im Beispiel. Optionale Felder sind
|
|
mit ihrem Default annotiert; laesst man sie weg, greift der Default.
|
|
|
|
Wichtige Unterscheidung, die sich beim Durcharbeiten herauskristallisiert hat:
|
|
|
|
- **Scriptbar** = es existiert eine Produktions-Funktion, die alle noetigen
|
|
Werte als normale Parameter entgegennimmt (kein `getpoint`/`getstring` noetig).
|
|
Diese Funktionen sind 1:1 aus JSON aufrufbar.
|
|
- **Nicht scriptbar** = die Produktions-Funktion fragt Punkte/Optionen
|
|
interaktiv ab (`getpoint`, `getstring`, `ssget` auf bereits gezeichnete
|
|
Geometrie). Es gibt in `Lisp/` keinen parametrischen Einstiegspunkt; ein
|
|
JSON-Testfall kann diese Faelle nur ueber einen eigens geschriebenen
|
|
Wrapper (wie es `tests/*.lsp` tut) nicht-interaktiv nachbilden.
|
|
|
|
Einheiten durchgaengig: **mm** fuer Laengen/Koordinaten, **Grad** fuer Winkel
|
|
(intern wird oft in Radiant gerechnet, die LISP-API-Grenze ist aber immer
|
|
Grad). Richtung `hz`/`hz_grad`: 0=Ost(+X), 90=Nord(+Y), 180=West(-X),
|
|
270=Sued(-Y).
|
|
|
|
---
|
|
|
|
## 0. Uebersicht — alle skriptbaren Objekte
|
|
|
|
| # | Objekt | Produktionsfunktion (Bau) | Scriptbar? | Koordinaten-Eingang | Sektion |
|
|
|---|---|---|---|---|---|
|
|
| 1.1 | Kreisel Insert | `kreisel-insert-script (pt abstand rotation typ hoehe)` | **ja** | 1 Punkt `x,y,z` | [#11](#11-kreisel-insert-freier-punkt) |
|
|
| 1.2 | Kreisel Connect | `kreisel-connect-script (ptStart ptEnd typ hoehe)` | **ja** | 2 Punkte `start_*`/`end_*` | [#12](#12-kreisel-connect-start-endpunkt) |
|
|
| 2.1 | Gefaellestrecke Modus 1 | `gf-modus12-abschluss` → `gefaellestrecke-einfuegen` | **ja** | 1 Punkt `start_mm` | [#21](#21-gefaellestrecke-modus-1--manuelle-werteingabe) |
|
|
| 2.2 | Gefaellestrecke Modus 2 | `gf-modus12-abschluss` (deltaL/hz aus 2 Punkten) | **ja** | 3 Punkte (`linie_*`, `start_mm`) | [#22](#22-gefaellestrecke-modus-2--3d-linie-als-richtungsreferenz) |
|
|
| 2.3 | Gefaellestrecke Modus 3 | `gf-linienzug-modus ()` | **nein** | vorgezeichnete LINE/ARC-Auswahl | [#23](#23-gefaellestrecke-modus-3--linienzug--nicht-scriptbar) |
|
|
| 3.1 | VarioFoerderer Standard | `variofoerderer-einfuegen (…)` | **ja** | 1 Punkt `startpunkt` | [#31](#31-variofoerderer-standard--scriptbar) |
|
|
| 3.2 | VarioFoerderer Etage | `etage-foerderanlage-einfuegen (…)` | **ja** | 1 Punkt `startpunkt` | [#32](#32-variofoerderer-etage--scriptbar) |
|
|
| 3.3 | VarioFoerderer Linienzug | `vf-linienzug-modus ()` | **nein** | interaktiver Assistent | [#33](#33-variofoerderer-linienzug--nicht-scriptbar) |
|
|
| 3.4 | Vario_Kette_Merge | `vfl-kette-verfolgen` (Re-Packaging) | n/a | 1 Entity-Pick | [#34](#34-vario_kette_merge--kein-neubau) |
|
|
| 4.1 | Omniflo Bogen/Weiche | `omni:insert-dxf (sivasnr hoehe drehung)` + `_.INSERT` | Kern ja, Befehl nein | 1 Punkt `x,y,z` (nur via Wrapper) | [#41](#41-omniflo-boegenweichen) |
|
|
| 4.2 | Omniflo Aluprofil-Gerade | `omni:make-gerade (blockname pt pt2 …)` | Kern ja | 2 Punkte `pt`/`pt2` | [#42](#42-omniflo-aluprofil-gerade-ap60ap110apg110) |
|
|
| 4.3 | Omniflo TEF/Zubehoer | `omni:insert-dxf` (fester Sivasnr) | Position ja, Punkt interaktiv | 1 Punkt (nur via Wrapper) | [#43](#43-omniflo-tefzubehoer) |
|
|
| 4.4 | Omniflo TV_*/APBW_* | — (DUMMY) | **nein** | — | [#44](#44-omniflo-tv_-apbw_) |
|
|
| 5 | Separator/Scanner/Sensor | `ils-insert-sensor (fname)` + `_.INSERT` | **nein** (Schleife) | 1 Punkt `x,y,z` (nur via Wrapper) | [#5](#5-separatorscannersensor) |
|
|
| 6 | Waagrechte Foerderstrecke (`gerade`) | `insert-hz-scaled-block-by-ks (blockname startpunkt laenge hz vert)` | **ja** | 1 Punkt `startpunkt` (+ `endpunkt` als Doku) | [#6](#6-waagrechte-foerderstrecke-gerade) |
|
|
|
|
Legende Scriptbar-Spalte:
|
|
- **ja** — direkt per JSON aufrufbar.
|
|
- **Kern ja, Befehl nein** — die Bau-Funktion nimmt alle Werte an, aber der
|
|
ausgelieferte `c:…`-Befehl fragt den Einfuegepunkt per Maus (`pause`) ab; ein
|
|
JSON-Treiber muss den `_.INSERT` selbst nachbauen.
|
|
- **nein** — nur interaktiv; JSON beschreibt hoechstens die gewuenschte
|
|
Geometrie, nicht einen Funktions-Parametersatz.
|
|
|
|
---
|
|
|
|
## 1. Kreisel — `Lisp/KreiselInsert.lsp`
|
|
|
|
Scriptbar. Zwei Varianten.
|
|
|
|
### 1.1 Kreisel Insert (freier Punkt)
|
|
|
|
Produktionsfunktion: `kreisel-insert-script (pt abstand rotation typ hoehe)`
|
|
|
|
| Feld | Typ | Pflicht | Bedeutung | Default |
|
|
|---|---|---|---|---|
|
|
| `x`, `y` | real (mm) | **ja** | Einfuegepunkt (Welt-XY), zusammen `pt` | - |
|
|
| `z` | real (mm) | nein | Z von `pt`; wird verwendet, wenn `hoehe` fehlt | - |
|
|
| `hoehe` | real (mm) | nein | Ueberschreibt Z; sonst `pt`s Z | `*kreisel-default-hoehe*` (config `kreisel.default_hoehe`, 2000.0) |
|
|
| `abstand` | real (mm) | nein | Abstand zwischen AN-/SP-Kreiselhaelfte (Kreisel-Baulaenge) | `*kreisel-default-laenge*` (config `kreisel.default_laenge`, 2300.0) |
|
|
| `rotation` | real (Grad) | nein | freie Rotation, kein Rasterzwang | 0.0 |
|
|
| `typ` | string | nein | `"STANDARD"` oder `"PIN"` (einzige Optionen aus `kreisel-ask-typ`) | `"STANDARD"` |
|
|
|
|
Konstanten (Config `[kreisel]`): `durchmesser` (800.0mm, fuer Connect-Abstandsberechnung), `default_laenge`, `default_hoehe`.
|
|
|
|
Vollstaendiges JSON (alle Parameter gesetzt):
|
|
```json
|
|
{
|
|
"id": "K1",
|
|
"function": "insert",
|
|
"x": 500,
|
|
"y": 500,
|
|
"z": 2500,
|
|
"hoehe": 2500,
|
|
"abstand": 2300,
|
|
"rotation": 0.0,
|
|
"typ": "STANDARD"
|
|
}
|
|
```
|
|
`id` und `expect_*`-Felder (`expect_block_prefix`, `expect_hoehe`,
|
|
`expect_kreiselart`) sind **keine** Produktionsparameter — reine
|
|
Test-Erwartungswerte fuer die Ergebnispruefung, nicht von
|
|
`kreisel-insert-script` konsumiert.
|
|
|
|
### 1.2 Kreisel Connect (Start-/Endpunkt)
|
|
|
|
Produktionsfunktion: `kreisel-connect-script (ptStart ptEnd typ hoehe)`
|
|
|
|
| Feld | Typ | Pflicht | Bedeutung | Default |
|
|
|---|---|---|---|---|
|
|
| `start_x`,`start_y`,`start_z` | real (mm) | **ja** | aeusserster Punkt AN-Seite (Antriebsstation) | - |
|
|
| `end_x`,`end_y`,`end_z` | real (mm) | **ja** | aeusserster Punkt SP-Seite (Spannstation) | - |
|
|
| `typ` | string | nein | `"STANDARD"`/`"PIN"` | `"STANDARD"` |
|
|
| `hoehe` | real (mm) | nein | Einfuegehoehe | Z von `ptStart`, sonst `*kreisel-default-hoehe*` |
|
|
|
|
`abstand`/`rotation` werden **intern** aus den beiden Punkten berechnet
|
|
(`abstand = distanz - *kreisel-durchmesser*`; Rotation aus dem Winkel der
|
|
Verbindungslinie) — bei Connect KEIN Eingabefeld.
|
|
|
|
Vollstaendiges JSON (alle Parameter gesetzt):
|
|
```json
|
|
{
|
|
"id": "K2",
|
|
"function": "connect",
|
|
"start_x": 0,
|
|
"start_y": 0,
|
|
"start_z": 2000,
|
|
"end_x": 5000,
|
|
"end_y": 0,
|
|
"end_z": 2000,
|
|
"typ": "STANDARD",
|
|
"hoehe": 2000
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Gefaellestrecke — `Lisp/Gefaellestrecke.lsp`
|
|
|
|
Drei Modi, siehe Kopfkommentar der Datei. Modus 1+2 teilen sich denselben
|
|
Abschluss (`gf-modus12-abschluss`) und sind beide scriptbar. Modus 3
|
|
(Linienzug) ist in Produktion **nicht scriptbar**.
|
|
|
|
Gemeinsame Bau-Funktion (von allen Modi letztlich aufgerufen):
|
|
`gefaellestrecke-einfuegen (L_stau winkel startpunkt as-seite es-seite hz deltaL-total as-winkel es-winkel geruest-einzelmodul geruest-typ)`
|
|
|
|
Wichtig: **`deltaL` (horizontale Laenge) ist der Eingang, nicht die
|
|
Hoehendifferenz.** Bei festem `winkel` legen Laenge und Hoehendifferenz
|
|
sich gegenseitig fest (`L_stau = (deltaL - aus-dx - ein-dx - sep-x) / cos(rad)`,
|
|
`sep-x = separator_breite * cos(rad)`, config `gefaelle.separator_breite`
|
|
Default 300.0). Es gibt **keinen** Parameter fuer eine gewuenschte
|
|
Ziel-Hoehendifferenz — die ergibt sich aus `L_stau`/`winkel`.
|
|
|
|
### 2.1 Gefaellestrecke Modus 1 — Manuelle Werteingabe
|
|
|
|
Eingangsfunktion (nach DCL-Dialog `gefaellestrecke.dcl`): `gf-modus12-abschluss (deltaL winkel hz-winkel as-seite es-seite startpunkt as-winkel es-winkel dialog-bestaetigt geruest-einzelmodul geruest-typ)`
|
|
|
|
| Feld | Typ | Pflicht | Bedeutung | Default |
|
|
|---|---|---|---|---|
|
|
| `deltaL_mm` | real (mm) | **ja** | horizontale Gesamtlaenge (AS+Staustrecke+Separator+ES) | config `gefaelle.default_delta_l` 5000.0 |
|
|
| `winkel_grad` | real (Grad) | nein | Gefaelle-Neigungswinkel | config `gefaelle.default_winkel` 3.0 |
|
|
| `hz_grad` | real (Grad) | nein | Fahrtrichtung (0/90/180/270 ueblich, frei waehlbar) | 0.0 |
|
|
| `start_mm` | [x,y,z] (mm) | **ja** | Startpunkt; Z = Einfuegehoehe | - |
|
|
| `as_seite` | string | nein | `"links"`/`"rechts"` (AUS-Element-Seite) | `"links"` |
|
|
| `es_seite` | string | nein | `"links"`/`"rechts"` (EIN-Element-Seite) | `"links"` |
|
|
| `as_winkel` | string | nein | `"90"`/`"30"` (AUS-Element-Variante) | `"90"` |
|
|
| `es_winkel` | string | nein | `"90"`/`"30"` (EIN-Element-Variante) | `"90"` |
|
|
| `geruest_einzelmodul` | string "0"/"1" | nein | Geruest je Einzelmodul | `"1"` |
|
|
| `geruest_typ` | string | nein | einer aus `*ssg-geruest-optionen*` (s.u.) | `"Schoenenberger Geruest"` (Index 2) |
|
|
|
|
`*ssg-geruest-optionen*` (aus `ssg_core.lsp`): `"IPE-Geruest abgestuft"`,
|
|
`"Obergeruest oben"`, `"Schoenenberger Geruest"`, `"nur Doppelrohrtraeger"`.
|
|
Interner Parameter `dialog-bestaetigt` ist immer `T` (kein Datenfeld).
|
|
|
|
Vollstaendiges JSON (alle Parameter gesetzt):
|
|
```json
|
|
{
|
|
"test_id": "GF_M1",
|
|
"modus": 1,
|
|
"deltaL_mm": 10000,
|
|
"winkel_grad": 3.0,
|
|
"hz_grad": 0.0,
|
|
"start_mm": [0, 0, 5000],
|
|
"as_seite": "links",
|
|
"es_seite": "links",
|
|
"as_winkel": "90",
|
|
"es_winkel": "90",
|
|
"geruest_einzelmodul": "1",
|
|
"geruest_typ": "Schoenenberger Geruest"
|
|
}
|
|
```
|
|
Hinweis: In `gefaellestrecke_tests.json` stehen `deltaL_mm`/`winkel_grad`/
|
|
`z_start_mm` als gemeinsamer Kopf-Eintrag (ein Objekt ohne `test_id`), weil
|
|
alle Modus-1-Faelle dieselbe Laenge teilen. Produktionsseitig ist `deltaL`
|
|
aber pro Aufruf ein normaler, nicht geteilter Parameter — daher hier
|
|
vollstaendig im Einzelfall aufgefuehrt.
|
|
|
|
### 2.2 Gefaellestrecke Modus 2 — 3D-Linie als Richtungsreferenz
|
|
|
|
Gleiche Ziel-Funktion (`gf-modus12-abschluss`), aber `deltaL`/`hz-winkel`
|
|
werden **nicht** direkt angegeben, sondern aus zwei Linienpunkten berechnet:
|
|
```
|
|
deltaX = ende.x - start.x ; deltaY = ende.y - start.y
|
|
deltaL = hypot(deltaX, deltaY)
|
|
hz-winkel = angle(deltaX, deltaY) [Grad, 0=Ost]
|
|
```
|
|
In Produktion werden diese zwei Punkte interaktiv per `get-line-start-end-points`
|
|
(Linie in der Zeichnung anklicken) bestimmt — fuer einen JSON-Treiber
|
|
genuegen aber zwei beliebige Punkte, da die Berechnung rein geometrisch ist.
|
|
|
|
| Feld | Typ | Pflicht | Bedeutung | Default |
|
|
|---|---|---|---|---|
|
|
| `linie_start_mm` | [x,y,z] | **ja** | erster Linienpunkt (nur X/Y verwendet) | - |
|
|
| `linie_ende_mm` | [x,y,z] | **ja** | zweiter Linienpunkt (nur X/Y verwendet) | - |
|
|
| `start_mm` | [x,y,z] | **ja** | Einfuegepunkt der Kette (unabhaengig von der Linie) | - |
|
|
| `winkel_grad` | real (Grad) | nein | Neigungswinkel | 3.0 |
|
|
| `as_seite`,`es_seite` | string | nein | `"links"`/`"rechts"` | `"links"` |
|
|
| `as_winkel`,`es_winkel` | string | nein | `"90"`/`"30"` | `"90"` |
|
|
|
|
Geruestoptionen sind in Modus 2 (reine Konsoleneingabe) nicht abfragbar,
|
|
bleiben auf Default (`geruest_einzelmodul="0"`, `geruest_typ="Schoenenberger Geruest"`).
|
|
|
|
Vollstaendiges JSON:
|
|
```json
|
|
{
|
|
"test_id": "GF_M2",
|
|
"modus": 2,
|
|
"winkel_grad": 3.0,
|
|
"linie_start_mm": [0, 0, 0],
|
|
"linie_ende_mm": [10000, 0, 0],
|
|
"start_mm": [0, 0, 5000],
|
|
"as_seite": "links",
|
|
"es_seite": "links",
|
|
"as_winkel": "90",
|
|
"es_winkel": "90"
|
|
}
|
|
```
|
|
|
|
### 2.3 Gefaellestrecke Modus 3 — Linienzug — **nicht scriptbar**
|
|
|
|
Eingangsfunktion: `gf-linienzug-modus ()` — **keine Parameter**.
|
|
|
|
Ablauf in Produktion:
|
|
1. `(ssget '((0 . "LINE,ARC")))` — der Nutzer muss die Leitlinie (Kette aus
|
|
bereits in der Zeichnung vorhandenen LINE-/ARC-Entities) **vorher zeichnen
|
|
und dann per Maus auswaehlen**. Es gibt keine Funktion, die eine Leitlinie
|
|
aus Koordinaten/Bogen-Parametern (`start_mm`/`ende_mm`/`bogen`) direkt als
|
|
Argument entgegennimmt.
|
|
2. `getpoint` fuer Startpunkt (Kettenanfang, Z = obere Anschlusshoehe) und
|
|
Endpunkt-Referenz (Z = untere Anschlusshoehe); `deltaH` wird aus der
|
|
Differenz der beiden Z-Werte gebildet.
|
|
3. `getstring`-Abfragen fuer AS-/ES-Winkel (`"90"`/`"30"`) und -Seite
|
|
(`"links"`/`"rechts"`) — inhaltlich identisch zu Modus 1/2.
|
|
4. Interne Analyse der selektierten Kette (`gf-sortiere-objekte`,
|
|
`gf-analysiere-kette`) leitet Ein-/Ausgangsrichtung sowie
|
|
Segment-Laengenkorrekturen ab.
|
|
|
|
JSON beschreibt hier nur die **gewuenschte Leitlinien-Geometrie**, nicht
|
|
direkte Funktionsparameter. Um Modus 3 aus JSON zu treiben, muss man zuerst
|
|
die LINE/ARC-Geometrie per `entmake` erzeugen und dann eine eigene
|
|
(nicht-interaktive) Nachbildung von `gf-linienzug-modus` schreiben — genau
|
|
das tut `tests/test_gefaellestrecke.lsp`.
|
|
|
|
JSON (Intent-Beschreibung, kein Parametersatz):
|
|
```json
|
|
{
|
|
"test_id": "M3_Bogen",
|
|
"modus": 3,
|
|
"start_mm": [30000, -50000, 2000],
|
|
"ende_mm": [38500, -43500, 1800],
|
|
"bogen": {"winkel_grad": 90, "radius_mm": 500, "seite": "links"},
|
|
"as_seite": "links",
|
|
"es_seite": "links",
|
|
"as_winkel": "90",
|
|
"es_winkel": "90"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 3. VarioFoerderer — `Lisp/vf_core.lsp` + `vf_standard.lsp`/`vf_etage.lsp`/`vf_linienzug.lsp`
|
|
|
|
Dispatcher `c:VarioFoerderer` waehlt einen registrierten Anlagetyp
|
|
(`"standard"`, `"etage"`, `"linienzug"`). Registry-Vertrag fuer scriptbare
|
|
Typen:
|
|
```
|
|
berechne-fn (deltaL deltaH richtung seite) -> (best-winkel best-L_GF best-L_VF ergebnis-liste)
|
|
einfuege-fn (deltaL deltaH richtung best-winkel L_GF1 L_GF2 L_VF startpunkt seite hz) -> endpunkt
|
|
```
|
|
Der Wrapper `vf-block-erstellen` fasst danach zentral alles zu einem
|
|
`VF_n`-Block zusammen (kein JSON-Feld dafuer noetig — laeuft automatisch).
|
|
|
|
`best-winkel`, `L_GF1`, `L_GF2`, `L_VF` stammen normalerweise aus dem Solver
|
|
(`berechne-fn`). Fuer einen scriptbaren Aufruf gibt man daher die
|
|
**Eingangsgroessen** (`deltaL`, `deltaH`, `richtung`, `seite`, optional
|
|
`winkel`, `gf_verteilung`) sowie `startpunkt`+`hz` an; der Solver liefert die
|
|
inneren Laengen/Winkel. Zwingt man `winkel`, wird dieser Kandidat statt der
|
|
Auto-Wahl verwendet.
|
|
|
|
### 3.1 VarioFoerderer Standard — scriptbar
|
|
|
|
- Winkel-/Laengen-Solver: `berechne-standard (deltaL deltaH richtung seite)` → wrappt `berechne-alle-winkel (deltaL deltaH richtung feste-hz)`.
|
|
Kandidatenwinkel (config `vario.bogen_winkel`, Default):
|
|
`3 6 9 12 15 18 21 27 33 39 45 51` Grad — **nur diese Werte sind moeglich**, kein freier Winkel.
|
|
- Bau-Funktion: `variofoerderer-einfuegen (deltaL deltaH richtung best-winkel L_GF1 L_GF2 L_VF startpunkt seite hz)`
|
|
|
|
| Feld | Typ | Pflicht | Bedeutung | Default |
|
|
|---|---|---|---|---|
|
|
| `deltaL` | real (mm) | **ja** | horizontale Gesamtlaenge | - |
|
|
| `deltaH` | real (mm) | **ja** | Ziel-Hoehendifferenz (hier IST deltaH ein direkter Eingang, anders als bei Gefaellestrecke!) | - |
|
|
| `richtung` | string | **ja** | `"Auf"` oder `"Ab"` | - |
|
|
| `winkel` | int | nein | einer der 12 Kandidatenwinkel; ohne Angabe waehlt der Solver den **kleinsten gueltigen** | (Solver) |
|
|
| `gf_verteilung` | string | nein | `"gleichmaessig"`/`"vorne"`/`"hinten"` (Modus `0`/`1`/`2`); bestimmt `L_GF1`/`L_GF2` | `"gleichmaessig"` |
|
|
| `startpunkt` | [x,y,z] (mm) | **ja** | Einfuegepunkt | - |
|
|
| `seite` | string | nein | `"links"`/`"rechts"` (AS/ES-Element-Seite) | `"rechts"` (Dialog) |
|
|
| `hz` | real (Grad) | nein | Fahrtrichtung | 0.0 |
|
|
| `motorseite` | string | nein | `"links"`/`"rechts"` — nur Dialog/Anzeige, kein Geometrie-Parameter von `variofoerderer-einfuegen` | `"links"` |
|
|
|
|
Verteilungsmodi ausfuehrlich (in Produktion per Dialog): `0`=gleichmaessig
|
|
(beide `L_GF/2`), `1`=alles vorne (Rest hinten), `2`=alles hinten (Rest
|
|
vorne), `3`=manuell (`L_GF1` frei, `L_GF2`=Rest).
|
|
|
|
Vollstaendiges JSON (alle Parameter gesetzt):
|
|
```json
|
|
{
|
|
"test_id": "VF_Auf_2000",
|
|
"typ": "standard",
|
|
"richtung": "Auf",
|
|
"deltaL": 7000,
|
|
"deltaH": 2000,
|
|
"winkel": 27,
|
|
"gf_verteilung": "gleichmaessig",
|
|
"startpunkt": [0, 0, 0],
|
|
"seite": "rechts",
|
|
"hz": 0.0,
|
|
"motorseite": "links"
|
|
}
|
|
```
|
|
Minimal genuegt (Solver fuellt den Rest): `richtung`, `deltaL`, `deltaH` (+
|
|
`startpunkt`, falls nicht am Ursprung).
|
|
|
|
### 3.2 VarioFoerderer Etage — scriptbar
|
|
|
|
- Solver: `berechne-etage (deltaL deltaH richtung seite)` → `berechne-winkel-etage (deltaL deltaH richtung)`. Gleiche 12 Kandidatenwinkel wie Standard.
|
|
- Bau-Funktion: `etage-foerderanlage-einfuegen (deltaL deltaH richtung best-winkel L_GF1 L_GF2 L_VF startpunkt seite hz)`
|
|
— **identische Signatur** wie Standard (Registry-Vertrag), Unterschied liegt
|
|
im internen Aufbau (30-Grad-AS/ES-Elemente statt 90, AS/ES direkt
|
|
uebereinander, zusaetzlicher fixer "Gefaellebogen" je nach `seite`
|
|
gegenueber dem AS-Element).
|
|
|
|
Felder: identisch zu 3.1 (`deltaL`, `deltaH`, `richtung`, `winkel`,
|
|
`gf_verteilung`, `startpunkt`, `seite`, `hz`). Nur `typ` unterscheidet sich.
|
|
|
|
Vollstaendiges JSON:
|
|
```json
|
|
{
|
|
"test_id": "VF_Etage_Auf_2000",
|
|
"typ": "etage",
|
|
"richtung": "Auf",
|
|
"deltaL": 7000,
|
|
"deltaH": 2000,
|
|
"winkel": 27,
|
|
"gf_verteilung": "gleichmaessig",
|
|
"startpunkt": [0, 0, 0],
|
|
"seite": "rechts",
|
|
"hz": 0.0,
|
|
"motorseite": "links"
|
|
}
|
|
```
|
|
|
|
### 3.3 VarioFoerderer Linienzug — **nicht scriptbar**
|
|
|
|
Eingangsfunktion `vf-linienzug-modus ()` — **keine Parameter**, rein
|
|
interaktiver Mehrschritt-Assistent (Kettenaufbau aus GF-Boegen,
|
|
Vario-Kurven, VF-Einheiten, Horizontal-Stuecken). Jeder Schritt fragt per
|
|
`getpoint`/`getstring`/`getint`/`getreal` einzeln ab. Es existiert **keine**
|
|
einzelne Produktionsfunktion, die eine ganze Kette aus einer Liste von
|
|
Segment-Beschreibungen entgegennimmt.
|
|
|
|
`linienzug_tests.json` bildet die Prompt-Sequenz als Frage-Antwort-Protokoll
|
|
ab (`typ`: `point_abs`/`point_rel`/`real`/`string`/`int`, jeweils mit
|
|
`wert`/`dL`+`hz` und einem `kommentar`, der beschreibt, WELCHE Frage die
|
|
Antwort beantwortet) — das ist die einzige Moeglichkeit, den interaktiven
|
|
Ablauf nicht-interaktiv nachzubilden, kein direkter Parametersatz einer
|
|
Bau-Funktion. Prompt-Reihenfolge (Kurzfassung, Details in `vf_linienzug.lsp`):
|
|
|
|
1. Startpunkt (`point_abs`), Hoehe Z (`real`)
|
|
2. AS-Element setzen? Ja/Nein, wenn ja: Winkel 90/30, Seite links/rechts
|
|
3. Schleife "naechstes Element": GF-Bogen | Neue Linie (GF) | Neue Linie
|
|
(Ab/Auf VF) | Horizontal-VF | Kettenende — jeweils eigene Unter-Prompts
|
|
(Endpunkt `point_rel` mit `dL`+`hz`, Ziel-Hoehe oder Neigungswinkel,
|
|
Separator vor/nach, GF-Verteilung, Vario-Kurve Winkel/Seite/Variante, ...)
|
|
4. Kettenende: ES-Winkel (90/30) + ES-Seite (links/rechts)
|
|
|
|
JSON (Prompt-Protokoll, Auszug):
|
|
```json
|
|
[
|
|
{ "typ": "point_abs", "wert": [0, 0, 5000], "kommentar": "Startpunkt + Hoehe Z" },
|
|
{ "typ": "string", "wert": "90", "kommentar": "AS-Element Winkel 90/30" },
|
|
{ "typ": "string", "wert": "links", "kommentar": "AS-Element Seite" },
|
|
{ "typ": "point_rel", "dL": 8000, "hz": 0.0, "kommentar": "Endpunkt naechstes Linien-Segment" },
|
|
{ "typ": "string", "wert": "90", "kommentar": "ES-Element Winkel" },
|
|
{ "typ": "string", "wert": "links", "kommentar": "ES-Element Seite" }
|
|
]
|
|
```
|
|
|
|
Dasselbe Protokoll steht produktionsseitig als **XDATA am fertigen
|
|
`VF_n`-Block** (App `SSG_VF_EDIT`, Marker `"linienzug"`, Serialisierung
|
|
`vfl-entry->string`): jede Eingabe wird beim Bau journalisiert und ist damit
|
|
wiederabspielbar (`vfl-journal-replay-start` + `vf-linienzug-modus`, genutzt
|
|
vom Doppelklick-Editieren). Ein Journal aus einer echten Zeichnung laesst
|
|
sich darum 1:1 in dieses Schema zuruecklesen — genau das tut
|
|
`lib/vf_journal_export.py` (siehe Abschnitt 8, `hundm05.json`). Zwei
|
|
Unterschiede zum handgeschriebenen `linienzug_tests.json`:
|
|
|
|
- Zusaetzlicher Eintragstyp `step` (Glied-Marker aus `vfl-journal-mark`,
|
|
Label = gewaehlter Segmenttyp). Beim Replay uebersprungen
|
|
(`vfl-replay-pop`), fuer den Sektions-/Glied-Edit aber der Anker.
|
|
- `hz` steht nur beim **ersten** Segment der Kette in einem `point_rel`
|
|
(`vfl-in-abstand` journalisiert die gesnappte Richtung nur bei freier
|
|
Richtungswahl); jedes weitere Segment erbt die Richtung des Vorgaengers
|
|
und traegt nur `dL`. Winkel von AS/ES stehen als **Wert** (`"90"`/`"30"`),
|
|
Seiten/Optionen als **Menue-Index** (`"1"`/`"2"`).
|
|
|
|
**Headless-Riegel (Stufe 0, siehe `doc/TODO-plan-vf-interactive.md`)**: der
|
|
Replay allein garantierte noch keinen prompt-freien Lauf - lief die Queue
|
|
mitten im Bau leer (Datenquelle passt nicht zum Ablauf), fielen die
|
|
`vfl-in-*`-Wrapper **stillschweigend** auf Live-Eingabe zurueck und der Lauf
|
|
blieb an einem `getpoint` haengen. Mit `*vfl-headless*` = T ist das jetzt ein
|
|
harter Abbruch mit Fundstelle (`vfl-headless-abbruch` -> `*vfl-headless-fehler*`
|
|
nennt Art der Eingabe, Glied-Nummer und Eingabe-Nummer). Die Meldungen der
|
|
geometrisch abgewiesenen Sektionen laufen ueber `vfl-meldung` statt `alert` und
|
|
stehen in `*vfl-meldungen*`, blockieren also nichts mehr. `tests/test_hundm05.lsp`
|
|
schaltet beides ein; die Diagnose landet im Ergebnis-JSON
|
|
(`headless_fehler`, `meldungen`, `prompts`).
|
|
|
|
### 3.4 Vario_Kette_Merge — kein Neubau
|
|
|
|
`c:Vario_Kette_Merge`: benoetigt nur **einen** Start-Entity-Pick (`entsel`),
|
|
sucht danach selbst alle KS_EIN/KS_AUS-kompatiblen Nachbarbloecke in der
|
|
ganzen Zeichnung ab (`vfl-kette-verfolgen`, Toleranzen 2mm/100mm) und fasst
|
|
sie zu einem neuen `VF_n` zusammen. Kein JSON-Parametersatz noetig/moeglich —
|
|
reine Nachbearbeitung bereits vorhandener Geometrie.
|
|
|
|
---
|
|
|
|
## 4. Omniflo — `Lisp/OmniModulInsert.lsp`
|
|
|
|
### 4.1 Omniflo Boegen/Weichen
|
|
|
|
Kern-Funktion: `omni:insert-dxf (sivasnr-str hoehe drehung)`
|
|
|
|
| Feld | Typ | Pflicht | Bedeutung | Default |
|
|
|---|---|---|---|---|
|
|
| `sivasnr` | string | **ja** | Komponenten-ID; **ist gleichzeitig der Dateiname** `<sivasnr>.dxf` unter `%DXFM_OMNIFLO%` | - |
|
|
| `hoehe` | string/real (mm) | nein | **absolute** Z-Koordinate + `HOEHE`-Attribut | config `omniflo.default_hoehe` bzw. hart "2000" |
|
|
| `drehung` | real (Grad) | nein | feste Rotation | in `c:OMNI_*` interaktiv per Maus |
|
|
| `x`, `y`, `z` | real (mm) | (Wrapper) | Einfuegepunkt — **kein** Parameter von `omni:insert-dxf`; muss ueber einen eigenen `_.INSERT`-Aufruf gesetzt werden | - |
|
|
|
|
**Wichtig**: Alle echten `c:OMNI_APB_*`/`c:OMNI_W*_*`-Befehle rufen
|
|
`omni:insert-dxf` **ohne X/Y** auf — der Einfuegepunkt kommt in `_.INSERT`
|
|
immer per `pause` (Mausklick). Es gibt in Produktion **keinen** Aufrufpfad,
|
|
der X/Y programmatisch uebergibt; `omni:insert-dxf` selbst akzeptiert keinen
|
|
Punkt-Parameter. Die Felder `x`/`y`/`z` beschreiben also nur, wo das Element
|
|
stehen soll — ein JSON-Treiber muss den `_.INSERT` selbst nachbauen (wie
|
|
`mubea:build-separator` in `tests/test_mubea.lsp`).
|
|
|
|
Sivasnr-Herkunft: `data/json/omniflo_boegen.json` und
|
|
`data/json/omniflo_weichen.json` (dienen der Dialog-Filterung/Anzeige, nicht
|
|
der Namensaufloesung — die ist `sivasnr == dateiname`).
|
|
|
|
Vollstaendiges JSON (alle fachlich noetigen Werte inkl. Position):
|
|
```json
|
|
{
|
|
"id": "821104025",
|
|
"type": "bogen",
|
|
"sivasnr": "821104025",
|
|
"x": 219.4,
|
|
"y": 223.06,
|
|
"z": 2000,
|
|
"hoehe": 2000,
|
|
"drehung": 0.0
|
|
}
|
|
```
|
|
`description`/`row` sind reine Dokumentations-/Gruppierungsfelder, keine
|
|
Produktionsparameter.
|
|
|
|
### 4.2 Omniflo Aluprofil-Gerade (AP60/AP110/APG110)
|
|
|
|
Kern-Funktion: `omni:make-gerade (blockname pt pt2 srcAttribs textHeight textGap textEnt)`
|
|
|
|
| Feld | Typ | Pflicht | Bedeutung | Default |
|
|
|---|---|---|---|---|
|
|
| `blockname` | string | **ja** | `"AP60"` / `"AP110"` / `"APG110"` | - |
|
|
| `pt` | [x,y,z] | **ja** | Startpunkt (absolute Weltkoordinaten) | - |
|
|
| `pt2` | [x,y,z] | **ja** | Endpunkt; Laenge/Rotation aus Differenz `pt→pt2` berechnet | - |
|
|
| `textHeight` | real | nein | Textgroesse | config `omniflo.text_height` (100.0) |
|
|
| `textGap` | real | nein | Textabstand | config `omniflo.text_gap` (20.0) |
|
|
|
|
`srcAttribs` wird aus der Vorlagen-DWG gelesen (`omni:read-src-attribs blockname`);
|
|
`textEnt` ist ein vorhandener Text-Entity zum Aktualisieren (bei Neuaufbau
|
|
`nil`). Beide sind keine JSON-Datenfelder. Der oeffentliche Befehl
|
|
`omni:insert-block (blockname laengemax)` fragt `pt`/`pt2` interaktiv per
|
|
`getpoint` ab — `omni:make-gerade` selbst ist mit festen Punkten aufrufbar.
|
|
|
|
Vollstaendiges JSON:
|
|
```json
|
|
{
|
|
"type": "gerade",
|
|
"blockname": "AP110",
|
|
"pt": [2000.0, 0.0, 2000.0],
|
|
"pt2": [3000.0, 0.0, 2000.0],
|
|
"textHeight": 100.0,
|
|
"textGap": 20.0
|
|
}
|
|
```
|
|
(In `omniflo_strecke_tests.json` wird die Gerade als `profil`/`x`/`y`/
|
|
`x_ende`/`y_ende`/`hoehe` beschrieben — dieselben Punkte, nur andere
|
|
Feldnamen fuer den Reihen-Layout-Test.)
|
|
|
|
### 4.3 Omniflo TEF/Zubehoer
|
|
|
|
Stopper, Scanner, Buerstenbremse, Umlenk-/Antriebsstationen:
|
|
`c:OMNI_STOPPER`/`c:OMNI_SCANNER`/... rufen `omni:insert-dxf` mit
|
|
**hartcodiertem** `sivasnr-str` (z.B. `"827062022"`) und `hoehe=nil,
|
|
drehung=nil` auf — Punkt weiterhin interaktiv. Kein Nutzer-JSON-Feld fuer
|
|
`sivasnr` noetig (fest im Code); Position/Hoehe/Rotation waeren
|
|
grundsaetzlich scriptbar (wie 4.1), aber nicht ueber die vorhandenen
|
|
`c:OMNI_*`-Befehle. JSON identisch strukturiert wie 4.1 (mit `sivasnr` fest
|
|
je Zubehoer-Typ).
|
|
|
|
### 4.4 Omniflo TV_* / APBW_*
|
|
|
|
Transferwagen-Verbinder (`c:OMNI_TV_*`) und Boegen fuer Weichen
|
|
(`c:OMNI_APBW_*`): **nicht implementiert** — reine `[DUMMY]`-Platzhalter ohne
|
|
Bau-Logik, kein Parametersatz.
|
|
|
|
`c:OMNI_UPDATE_ATTRIBS` (in `Lisp/export.lsp`) aktualisiert `HOEHE`/`DREHUNG`
|
|
aller Omniflo-Elemente aus der Zeichnung — kein Bau-/Einfuege-Befehl, daher
|
|
kein JSON-Parametersatz.
|
|
|
|
---
|
|
|
|
## 5. Separator/Scanner/Sensor — `Lisp/SSG_LIB_Commands.lsp`
|
|
|
|
Funktion: `ils-insert-sensor (fname)`
|
|
|
|
| Feld | Typ | Pflicht | Bedeutung | Default |
|
|
|---|---|---|---|---|
|
|
| `block` / `fname` | string | **ja** | Blockdateiname ohne Erweiterung, z.B. `"Separator_SP"`, `"Scanner"`, `"S-LP"` — aufgeloest ueber `ssg-ils-block-datei` (2D/3D-Suffix + Fallback) | - |
|
|
| `x`, `y`, `z` | real (mm) | (Wrapper) | Einfuegepunkt — **kein** Parameter von `ils-insert-sensor` | - |
|
|
| `rotation` | real (Grad) | (Wrapper) | Rotation — **kein** Parameter (kommt per `pause`) | - |
|
|
|
|
**Nicht scriptbar**: die Funktion fragt Einfuegepunkte in einer Schleife per
|
|
`getpoint` ab (`_.INSERT pfad pt "" "" pause` — auch die Rotation kommt per
|
|
Maus/`pause`), bis der Nutzer mit ENTER/ESC abbricht. Es gibt keinen
|
|
Parameter fuer Punkt, Anzahl oder Rotation. Ein JSON-Treiber muss den
|
|
`_.INSERT`-Aufruf direkt selbst nachbilden (Blockdatei-Pfad ueber
|
|
`ssg-ils-block-datei` bzw. `ssg-ils-block-laden`, dann
|
|
`_.INSERT pfad pt "" "" rot` mit festem `rot` statt `pause`) — der Ansatz von
|
|
`mubea:build-separator` in `tests/test_mubea.lsp`. Fachlich noetig sind nur
|
|
Blockname + Punkt + Rotation.
|
|
|
|
Vollstaendiges JSON (wie in `mubea.json`s Separator-Eintraegen):
|
|
```json
|
|
{
|
|
"function": "insert",
|
|
"block": "S-LP",
|
|
"x": 10310,
|
|
"y": -14158,
|
|
"z": 1467,
|
|
"rotation": 270
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Waagrechte Foerderstrecke (`gerade`)
|
|
|
|
Produktionsfunktion:
|
|
`insert-hz-scaled-block-by-ks (blockname startpunkt laenge hz-winkel vert-winkel)`
|
|
(`Lisp/vf_etage.lsp`) — dieselbe Primitive, mit der der Etage-Foerderer seine
|
|
waagrechten Abschnitte baut. Skaliert `Staustrecke_SP_1000_mm` auf `laenge`
|
|
(Massstab = `laenge / 1000`) und richtet sie ueber `KS_EIN`/`KS_AUS` am
|
|
`startpunkt` aus.
|
|
|
|
Dieser Typ entstand beim Nachbau von `results/ST500592_05.dxf`: ein
|
|
Antriebs-/Umlenkstation-Paar **ohne** Hoehendifferenz ist fachlich kein
|
|
VarioFoerderer. Dessen Solver (`berechne-standard` →
|
|
`berechne-alle-winkel`) muss einen Bogenwinkel aus der Kandidatenliste
|
|
3…51 Grad waehlen, was bei `deltaH ≈ 0` nicht aufgeht — der Eintrag waere
|
|
unbaubar. `lib/dxf_scan_components.py` trennt solche Paare darum ueber
|
|
`GERADE_MAX_DELTA_H` (10 mm) ab und gibt sie als `gerade` aus.
|
|
|
|
| Feld | Typ | Pflicht | Bedeutung | Default |
|
|
|---|---|---|---|---|
|
|
| `test_id` | string | **ja** | Kennung, Praefix `GERADE_` (steuert den Dispatcher) | - |
|
|
| `typ` | string | nein | `"gerade"` (Dokumentation, nicht ausgewertet) | - |
|
|
| `laenge` | real (mm) | **ja** | horizontale Laenge; Massstab der Staustrecke | - |
|
|
| `hz` | real (Grad) | nein | Fahrtrichtung in der XY-Ebene | 0.0 |
|
|
| `startpunkt` | [x,y,z] (mm) | **ja** | Anfangspunkt (`KS_EIN` wird hierhin gelegt) | - |
|
|
| `endpunkt` | [x,y,z] (mm) | nein | Endpunkt — reine Dokumentation/Herkunft, **kein** Parameter; die Geometrie folgt aus `startpunkt` + `laenge` + `hz` | - |
|
|
|
|
`vert-winkel` wird vom Treiber fest auf `0` gesetzt (waagrecht). Die Funktion
|
|
gibt den **Ausgangspunkt** zurueck, nicht die Entity — ein Treiber holt den
|
|
Block ueber `(entlast)`. Bei fehlender Blockdatei ruft sie `(exit)` auf und
|
|
wuerde einen Testlauf abbrechen, darum vorher mit `ssg-ils-block-laden`
|
|
pruefen.
|
|
|
|
Vollstaendiges JSON:
|
|
```json
|
|
{
|
|
"test_id": "GERADE_HundM05_08",
|
|
"typ": "gerade",
|
|
"laenge": 3305.26,
|
|
"hz": 143.35,
|
|
"startpunkt": [223150.89, 152953.65, 0.0],
|
|
"endpunkt": [220499.01, 154926.53, 0.0]
|
|
}
|
|
```
|
|
Einen Treiber dafuer gibt es derzeit nicht mehr: `tests/test_hundm05.lsp`
|
|
spielt seit dem Umbau auf die Linienzug-Journale nur noch Ketten ab (siehe
|
|
Abschnitt 8); der fruehere `hundm05:build-gerade` steht in der Git-Historie.
|
|
|
|
---
|
|
|
|
## 7. Zusammenfassung: scriptbar vs. nicht scriptbar
|
|
|
|
| Element | Produktionsfunktion | Scriptbar? |
|
|
|---|---|---|
|
|
| Kreisel Insert | `kreisel-insert-script` | ja |
|
|
| Kreisel Connect | `kreisel-connect-script` | ja |
|
|
| Gefaellestrecke Modus 1 | `gf-modus12-abschluss` → `gefaellestrecke-einfuegen` | ja |
|
|
| Gefaellestrecke Modus 2 | `gf-modus12-abschluss` (deltaL/hz aus 2 Punkten) | ja |
|
|
| Gefaellestrecke Modus 3 | `gf-linienzug-modus` | **nein** (erfordert vorgezeichnete LINE/ARC-Auswahl) |
|
|
| VarioFoerderer Standard | `variofoerderer-einfuegen` | ja |
|
|
| VarioFoerderer Etage | `etage-foerderanlage-einfuegen` | ja |
|
|
| VarioFoerderer Linienzug | `vf-linienzug-modus` | **nein** (mehrstufiger interaktiver Assistent) |
|
|
| Vario_Kette_Merge | `vfl-kette-verfolgen` | n/a (Re-Packaging, kein Parametersatz) |
|
|
| Omniflo Bogen/Weiche | `omni:insert-dxf` (Kern) | Kern ja, **Produktionsbefehle nein** (X/Y immer Maus) |
|
|
| Omniflo Aluprofil-Gerade | `omni:make-gerade` (Kern) | Kern ja, Befehl `omni:insert-block` fragt Punkte interaktiv |
|
|
| Omniflo TEF/Zubehoer | `omni:insert-dxf` (fester Sivasnr) | Position/Hoehe/Rotation ja, Punkt-Eingabe interaktiv |
|
|
| Omniflo TV_*/APBW_* | - | **nein** (nicht implementiert, DUMMY) |
|
|
| Separator/Scanner | `ils-insert-sensor` | **nein** (Schleife mit `getpoint`/`pause`) |
|
|
|
|
## 8. HundM05 — die 5 Linienzuege am Kreisel (`hundm05.json`)
|
|
|
|
`tests/testdata/hundm05.json` enthaelt die **Eingabe-Journale der 5
|
|
VarioFoerderer-Linienzuege** aus `data/polylines.dxf` (die Anlage HundM, ein
|
|
Kreisel mit fuenf daran haengenden Ketten). Quelle ist nicht die gezeichnete
|
|
Geometrie, sondern die XDATA `SSG_VF_EDIT` (Marker `"linienzug"`) an den
|
|
`VF_n`-Bloecken — also genau die Werte, mit denen die Ketten gebaut wurden.
|
|
Schema je Eintrag: Kopffelder (`test_id`, `block`, `dxf_handle`,
|
|
`startpunkt_mm`, `rotation_grad`, `sivas_id`, `beschreibung`,
|
|
`erwartung_hinweis`, `quelle`) plus die Prompt-Sequenz in `eingaben` — Format
|
|
wie `linienzug_tests.json`, siehe Abschnitt 3.3 (inkl. `step`-Marker).
|
|
|
|
| test_id | Block | Sivas | Startpunkt (mm) | Kette |
|
|
|---|---|---|---|---|
|
|
| VF_hundm05_LZ_01 | VF_87 | 0025 | 4912 / 1231 / 2154 | der komplizierte links: 2x Horizontal-VF, 4 Vario-Kurven (90/90/30/30) |
|
|
| VF_hundm05_LZ_02 | VF_46 | 0019 | 8572 / 1276 / 2495 | Standardkette |
|
|
| VF_hundm05_LZ_03 | VF_46 | 0018 | 12916 / 1276 / 2495 | Standardkette |
|
|
| VF_hundm05_LZ_04 | VF_46 | 0020 | 17202 / 1205 / 2154 | Standardkette (die zuerst gebaute) |
|
|
| VF_hundm05_LZ_05 | VF_46 | 0008 | 21490 / 1196 / 2495 | Standardkette |
|
|
|
|
Die vier `VF_46`-Bloecke sind **Kopien EINER** gebauten Kette: sie referenzieren
|
|
dieselbe Blockdefinition und tragen darum Wort fuer Wort dasselbe Journal,
|
|
inklusive des Startpunkts der zuerst gebauten Kette (17201.78/1205.36/2100 mit
|
|
Starthoehe 2154). Im JSON ist dieser eine absolute Eintrag je Instanz auf ihren
|
|
echten Blockeinfuegepunkt gezogen (alle weiteren Eintraege sind relativ), damit
|
|
jeder Testfall fuer sich abspielbar ist. Achtung bei den Kopien: ihre
|
|
Block-Attribute (`HOEHE_VON_mm` = 2154, so auch im Sivas-Export) stammen aus
|
|
dem Original und sind nach dem Verschieben veraltet — die drei Kopien liegen
|
|
tatsaechlich 340.93 mm hoeher (belegt durch ihre Separator-Z-Werte im
|
|
Sivas-Export: 2575.43 statt 2234.50).
|
|
|
|
Neu erzeugen:
|
|
|
|
```
|
|
python lib/vf_journal_export.py data/polylines.dxf \
|
|
tests/testdata/hundm05.json --csv results/HundM_export.csv
|
|
```
|
|
|
|
Die frueheren Inhalte (Kreisel/Gefaellestrecke/Sensor-Eintraege aus dem
|
|
Fenster 215000/148000..250000/161000 von `results/ST500592_05.dxf`, erzeugt mit
|
|
`lib/dxf_scan_components.py`) stehen in der Git-Historie dieser Datei.
|
|
|
|
**Aufbau flach, nicht verschachtelt**: `ssg-load-json`/`ssg-parse-json-array`
|
|
(`Lisp/ssg_core.lsp`) liest die Datei ZEILENWEISE und behandelt jedes `{` als
|
|
Objektanfang — Verschachtelung (z.B. `"eingaben": [ {...} ]`) wuerde die
|
|
Kopf-Objekte verschlucken. Darum steht je Kette ein Kopf-Objekt (traegt
|
|
`test_id`) und danach ihre Eingaben (tragen `typ`), wie in
|
|
`linienzug_tests.json`. Der Anlagetyp im Kopf heisst `anlagetyp` und NICHT
|
|
`typ`, damit Kopf und Eingabe unterscheidbar bleiben.
|
|
|
|
Abgespielt wird das per `tests/test_hundm05.lsp` (`TEST_HUNDM05`,
|
|
`TEST_HUNDM05_2D`/`_3D`): der Treiber gruppiert die Objekte
|
|
(`hundm05:gruppiere`), baut daraus das Vorwaerts-Journal
|
|
(`hundm05:eintrag->journal`) und spielt es je Kette ueber
|
|
`vfl-journal-replay-start` + `vf-linienzug-modus` ab — denselben Weg nimmt die
|
|
Produktion beim Editieren/Konvertieren (`vfl-konvertiere-ent`). Bewusst KEINE
|
|
Eingabe-Mocks wie in `test_linienzug.lsp`: ein Mock muesste zu jedem Segment
|
|
die Fahrtrichtung kennen, die im Journal nur beim ersten Segment steht.
|