# JSON-Eingabe fuer den LISP-Bau Welche Objekte sich aus einer JSON-Datei an einer gegebenen x/y/z-Koordinate erzeugen lassen, in welchem Format sie beschrieben werden und welche LISP-Routine sie baut. Grundlage sind die Testdaten in `tests/testdata/*.json` und die Treiber in `tests/test_*.lsp`, die sie lesen. Die zugehoerigen LISP-Routinen mit Signaturen stehen in [lisp_methods.md](lisp_methods.md). Diese Seite ersetzt das fruehere `tests/testdata/object_data.md` (geloescht in Commit `e147b89`, auf das Code- Kommentare teilweise noch verweisen). **Feldnamen als Python-Konstanten**: `lib/testdata_schema.py` buendelt die Feldnamen/festen Werte der Abschnitte 1 (Kreisel), 2 (Einzelbloecke), 3 (VF Standard/Etage) und 4.1 (Gefaellestrecke Modus 1) als benannte Konstanten (`sch.F_ABSTAND`, `sch.SEITE_LINKS`, ...), genutzt von `lib/dxf_anlage_export.py` (eigene, mit unseren Makros gebaute Zeichnungen). `lib/dxf_scan_components.py` (fremde Zeichnungen) hat dieselben Feldnamen weiterhin als eigene String- Literale - gleiches Schema, noch nicht auf das gemeinsame Modul umgestellt. --- ## 0. Uebersicht | Objekt | Erkennungsmerkmal im JSON | Bau-Routine (Produktion) | Koordinaten-Eingang | Beispiel-Datei | |---|---|---|---|---| | [Kreisel (Insert)](#1-kreisel) | `"function": "insert"`, KEIN `block` | `kreisel-insert-script` | `x`,`y`,`z` = Einfuegepunkt | `kreisel_tests.json`, `mubea.json`, `hundm05.json`, `dematic_arvato.json` | | [Kreisel (Connect)](#12-connect-start--und-endpunkt) | `"function": "connect"` | `kreisel-connect-script` | `start_*`, `end_*` | (nur `test_kreisel.lsp`, z.Z. kein Datensatz) | | [Einzelblock](#2-einzelbloecke-separator-scanner-btmt-eingangausgang-vario-bausteine) (Separator, Scanner, BTMT, Eingang/Ausgang, Vario-Bausteine) | `"function": "insert"` + `"block"` | direktes `_.INSERT` nach `ssg-ils-block-laden` | `x`,`y`,`z` + `rotation` | `mubea.json`, `hundm05.json`, `dematic_arvato.json` | | [VarioFoerderer Standard](#3-variofoerderer-standard-und-etage) | `test_id` beginnt mit `VF_`, `typ` fehlt oder `"standard"` | `berechne-alle-winkel` + `variofoerderer-einfuegen` + `vf-block-erstellen` | `x`,`y`,`z` = KS_EIN des AS-Elements | `mubea.json`, `foerderer_tests.json` | | [VarioFoerderer Etage](#3-variofoerderer-standard-und-etage) | `test_id` `VF_*` + `"typ": "etage"` | `berechne-etage` + `etage-foerderanlage-einfuegen` + `vf-block-erstellen` | wie Standard | `mubea.json` | | [Gefaellestrecke Modus 1](#4-gefaellestrecke) | `test_id` `GF_*` bzw. `"modus": 1` | `gefaellestrecke-einfuegen` (bzw. `gf-rebuild`) | `start_mm` = KS_EIN des AS-Elements | `mubea.json`, `gefaellestrecke_tests.json` | | [Gefaellestrecke Modus 2](#42-modus-2---richtung-aus-zwei-punkten) | `"modus": 2` | wie Modus 1, `deltaL`/`hz` aus zwei Punkten | `start_mm` + `linie_start_mm`/`linie_ende_mm` | `gefaellestrecke_tests.json` | | [Gefaellestrecke Modus 3](#43-modus-3---linienzug) | `"modus": 3` | nur ueber `test_gefaellestrecke.lsp` | `start_mm`, `ende_mm`, `bogen` | `gefaellestrecke_tests.json` | | [VF-Linienzug-Kette (Spec)](#5-vf-linienzug-kette-spec) | Kopf mit `spec_id`, danach `glied`/`sub` | `vsp-bau-aus-spec` (Replay durch `vf-linienzug-modus`) | `start_punkt` = Kettenanfang | `hundm05.json` | | [VF-Linienzug (Journal)](#6-vf-linienzug-eingabe-journal) | Kopf mit `test_id`, danach `typ` = `point_abs`/`real`/`string`/... | `vfl-journal-replay-start` + `vf-linienzug-modus` | erstes `point_abs` | `linienzug_tests.json`, `hm_recformat.json` | | [Omniflo Bogen/Weiche](#71-bogen-und-weiche) | `"type": "bogen"` / `"weiche"` + `sivasnr` | `_.INSERT` der `.dxf` (Kern `omni:insert-dxf` fragt den Punkt interaktiv) | `x`,`y`, Z = `hoehe` | `omniflo_tests.json`, `omniflo_strecke_tests.json` | | [Omniflo Gerade](#72-aluprofil-gerade) | `"type": "gerade"` + `profil` | `omni:make-gerade` | `x`,`y` -> `x_ende`,`y_ende`, Z = `hoehe` | `omniflo_strecke_tests.json` | | [Waagrechte Foerderstrecke](#8-waagrechte-foerderstrecke-gerade---noch-ohne-bau-pfad) | `"typ": "gerade"` + `startpunkt` | **kein Bau-Pfad** (wird gemeldet und uebersprungen) | `startpunkt`, `endpunkt` | `dematic_arvato.json` | Nicht aus JSON baubar (es gibt keine Testdaten und keinen Treiber): Eckrad, Geruest, TEF-Foerderer-Linie, TRO-Marker, Connections, Omniflo-Ladeschleife. Fuer Eckrad und Geruest existiert ein skriptfaehiger Kern, siehe [lisp_methods.md](lisp_methods.md). ### Allgemeine Regeln - **Einheiten**: Laengen und Koordinaten in **mm**, Winkel in **Grad**. Fahrtrichtung `hz`: 0 = +X (Ost), 90 = +Y (Nord), 180 = -X, 270 = -Y. - **Z ist absolut**: `z` (bzw. Z in `start_mm`/`start_punkt`) ist die Weltkoordinate des Einfuegepunkts, also die Einbauhoehe. - **Dimension 2D/3D**: Gebaut wird in der aktuellen Dimension (`ssg-ils-dim-aktuell`: `*ssg-ils-dim*` -> `DXFM_DIM`, Default 3D). Das Feld `darstellung` in `dematic_arvato.json` ist reine Dokumentation und wird nicht ausgewertet; `TEST_HUNDM05_2D`/`_3D` erzwingen die Dimension. - **Flaches JSON**: Die meisten Dateien werden mit `ssg-load-json` gelesen (zeilenweise, ein Objekt je `{`). Verschachtelte Objekte und mehrzeilige Arrays darin funktionieren nicht - darum stehen z.B. die Glieder einer Kette als eigene Objekte hinter ihrem Kopf-Objekt. Ausnahme: `TEST_DEMATIC_ARVATO` liest mit dem rekursiven `ssg-json-laden`. - **Reine Doku-Felder**: `comment`, `beschreibung`, `description`, `quelle`, `row`, `seq`, `gruppe`, `assigned_to`, `hoehe_unbekannt`, `darstellung` sowie alle `expect_*`/`erwartung_*`-Felder werden beim Bau nicht gelesen. `expect_*` pruefen die Python-Tests gegen das Ergebnis. - **Template-Felder** (nur `test_mubea.lsp`): `anzahl`, `delta_x`, `delta_y` erzeugen aus einem Eintrag `anzahl` Kopien, jeweils um `delta_x`/`delta_y` versetzt; `test_id` bekommt dann das Suffix `_01` ... `_nn`. Gilt fuer VF, GF und Einzelbloecke. --- ## 1. Kreisel Block `KREISEL_n`, gebaut von `KreiselInsert.lsp`. ### 1.1 Insert (freier Punkt) ```json { "id": "KR_Kreuz_Q1_0Grad", "function": "insert", "x": 500, "y": 500, "z": 2500, "abstand": 2000, "rotation": 0.0, "typ": "STANDARD" } ``` | Feld | Pflicht | Bedeutung | Default | |---|---|---|---| | `id` | ja (fuer den Treiber) | Kennung im Ergebnis; NICHT die Block-ID (die vergibt `ssg-id-generate`) | - | | `function` | ja | `"insert"`; ohne `block` = Kreisel | - | | `x`, `y` | ja | Einfuegepunkt. Liegt auf der Kreiselachse **einen Radius (400 mm) vor der Mitte des Antriebsrads (AN)**, also am aeussersten Punkt der AN-Seite | - | | `z` | ja | Einbauhoehe; wird als `hoehe` uebergeben und in das Attribut `HOEHE` geschrieben | `kreisel.default_hoehe` (2000) | | `abstand` | ja | Mittenabstand Antriebsrad - Spannrad | `kreisel.default_laenge` (2300) | | `rotation` | nein | Drehung der Achse AN -> SP, frei (kein Raster) | 0.0 | | `typ` | nein | `"STANDARD"` oder `"PIN"` -> Attribut `KREISELART` | `"STANDARD"` | | `drehrichtung` | nein | `"GUZ"` oder `"UZS"` -> Attribut `DREHRICHTUNG` | `"UZS"` | Treiber: `kreisel:run-insert-test` (`test_kreisel.lsp`), `mubea:build-kreisel`, `hundm05:bau-kreisel` (auch fuer `dematic_arvato.json`/`showroom_ils.json`). Nur `hundm05:bau-kreisel` liest `drehrichtung` aus und reicht sie an `kreisel-insert-script` weiter; `mubea:build-kreisel` setzt es (noch) nicht um. ### 1.2 Connect (Start- und Endpunkt) ```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" } ``` `start_*` und `end_*` sind die aeussersten Punkte der AN- bzw. SP-Seite. `abstand` (= Distanz - Kreiseldurchmesser 800) und `rotation` werden daraus berechnet. Die Einbauhoehe kommt aus `start_z`. Nur `test_kreisel.lsp` kennt `connect`; die anderen Treiber bauen ausschliesslich `insert`. --- ## 2. Einzelbloecke (Separator, Scanner, BTMT, Eingang/Ausgang, Vario-Bausteine) Jeder Eintrag mit `"function": "insert"` UND `"block"` wird als einzelner Block eingefuegt, ohne Wrapper-Block und ohne Verkettung. ```json { "id": "HundM05_SCANNER_02", "function": "insert", "block": "Scanner", "x": 4095.5, "y": 1164.1, "z": 2154, "rotation": 270 } ``` | Feld | Pflicht | Bedeutung | Default | |---|---|---|---| | `block` | ja | Blockname OHNE `_2D`/`_3D`-Suffix | - | | `x`, `y`, `z` | ja | Einfuegepunkt = **Basispunkt der Block-DWG** (nicht KS_EIN) | - | | `rotation` | nein | Drehung um Z | 0 | | `id` / `test_id` | nein | Kennung im Ergebnis | `SEPARATOR_` bzw. Blockname | Ablauf: `ssg-ils-block-laden` loest den Namen auf `data/ils/_.dwg` auf (3D-Fallback), danach `_.INSERT eff pt "" "" rotation` und `ssg-id-generate`. **Fehlt die DWG, wird `Separator_SP` eingefuegt.** Treiber: `mubea:build-separator`, `hundm05:bau-sensor` (auch Dematic). Das Layer-Attribut `LAYER` wird dabei nicht angewendet; der Block landet auf dem aktuellen Layer. ### In den Testdaten verwendete Blocknamen | `block` | DWG in `data/ils` | Verwendet in | Hinweis | |---|---|---|---| | `Scanner` | `Scanner_2D/_3D.dwg` | mubea, hundm05, dematic_arvato | | | `Separator_SP` | `Separator_SP_2D/_3D.dwg` | (Fallback) | Block von `ILS_SEPARATOR_INSERT` | | `S-LP` | **fehlt** | mubea, hundm05, dematic_arvato | wird zu `Separator_SP` | | `S-SP` | **fehlt** | dematic_arvato | wird zu `Separator_SP` | | `BTMT-Beladung` | `BTMT-Beladung_2D/_3D.dwg` | mubea, hundm05 | wie `ILS_BTMT_Beladung` | | `SC_Entladung` | `SC_Entladung_2D/_3D.dwg` | mubea, hundm05 | wie `ILS_BTMT_Entladung` | | `Eingang` / `Ausgang` | `Eingang_*/Ausgang_*.dwg` | mubea | Symbole wie `ILS_EINGANG_INSERT`/`ILS_AUSGANG_INSERT` | | `AS_Element_90_links` / `_rechts` | vorhanden | dematic_arvato | loses AS-Element (sonst Teil eines VF/GF) | | `ES_Element_90_rechts`, `ES_Element_30_rechts` | vorhanden | dematic_arvato | loses ES-Element | | `Vario_Motorstation_500mm_rechts` | vorhanden | dematic_arvato | lose Motorstation | | `Vario_Umlenkstation_500mm_rechts` | vorhanden | dematic_arvato | lose Umlenkstation | | `Vario_Kurve_rechts_30_TEF_aussen` | vorhanden | dematic_arvato | lose Vario-Kurve | Grundsaetzlich ist **jeder** Blockname aus `data/ils` erlaubt (es gibt keine Whitelist). Die losen AS/ES-/Vario-Bausteine bilden aber keine Kette und keinen `VF_n`/`GF_n`-Block - fuer eine zusammenhaengende Strecke Abschnitt 3-5 nutzen. --- ## 3. VarioFoerderer Standard und Etage Block `VF_n`. Eingang sind die **Gesamtmasse** der Anlage; Winkel und Teillaengen berechnet der Solver. ```json { "test_id": "VF_Schnitt_C", "richtung": "Auf", "deltaL": 9110, "deltaH": 474, "winkel": 21, "gf_verteilung": "manuell", "L_GF1": 2298, "seite": "links", "hz": 0.0, "x": 400, "y": 14120, "z": 1554 } ``` | Feld | Pflicht | Bedeutung | Default | |---|---|---|---| | `test_id` | ja | muss mit `VF_` beginnen (steuert den Dispatcher in `test_mubea.lsp`) | - | | `typ` | nein | `"standard"` (AS/ES 90 Grad) oder `"etage"` (AS/ES 30 Grad, uebereinander) | `"standard"` | | `richtung` | ja | `"Auf"` oder `"Ab"` | - | | `deltaL` | ja | horizontale Gesamtlaenge inkl. AS/ES, Boegen, GF-Vor-/Nachlauf | - | | `deltaH` | ja | Hoehendifferenz (Betrag; Vorzeichen kommt aus `richtung`) | - | | `winkel` | nein | Bogenwinkel erzwingen, nur aus der Kandidatenliste (`vario.bogen_winkel`: 3, 6, 9, 12, 15, 18, 21, 27, 33, 39, 45, 51). Ist er nicht loesbar, wird NICHT gebaut | kleinster gueltiger Winkel | | `L_GF1` | nein (mubea) | Vorlauf-Laenge (GF vor dem Foerderer); Nachlauf = Rest von `L_GF` | - | | `gf_verteilung` | nein (foerderer) | `"gleichmaessig"`, `"vorne"`, `"hinten"`; in `mubea.json` nur Doku (dort zaehlt `L_GF1`) | `"gleichmaessig"` | | `seite` | nein | `"links"`/`"rechts"` (Seite der AS/ES-Elemente) | `"links"` | | `hz` | nein | Fahrtrichtung | 0.0 | | `x`, `y`, `z` | ja (mubea) | Startpunkt = **KS_EIN des AS-Elements**; `z` = Einbauhoehe am Anfang | - | Hinweise: - `foerderer_tests.json` hat statt `x/y/z` einen Kopf-Eintrag `{"y_abstand": 600}`: alle Foerderer starten bei x = 0, z = 0 und werden um `y_abstand` versetzt. Dieses Format kennt nur `test_foerderer.lsp`. - `"Ab"` mit `deltaH` < 1 ist geometrisch unmoeglich und wird abgewiesen. - Der Treiber schreibt nach dem Bau `vf-edit-xdata-schreiben` (Typ + `hz`), damit der Block per Doppelklick editierbar ist. --- ## 4. Gefaellestrecke Block `GF_n`: AS-Element -> Staustrecke (skaliert) -> Separator -> ES-Element. Eingang ist die **horizontale Laenge**, nicht die Hoehendifferenz - die ergibt sich aus Laenge und Neigung. ### 4.1 Modus 1 - Werteingabe ```json { "test_id": "GF_Mubea", "modus": 1, "deltaL_mm": 9110, "hz_grad": 180.0, "winkel_grad": 2.27, "start_mm": [9510, 12300, 2028], "as_seite": "links", "es_seite": "links", "as_winkel": "90", "es_winkel": "90" } ``` | Feld | Pflicht | Bedeutung | Default | |---|---|---|---| | `test_id` | ja | in `mubea.json` muss sie mit `GF_` beginnen | - | | `modus` | nein | `1` | - | | `deltaL_mm` | ja | horizontale Gesamtlaenge AS + Staustrecke + Separator + ES | - | | `winkel_grad` | nein | Neigung der Staustrecke | 3.0 | | `hz_grad` | nein | Fahrtrichtung | 0.0 | | `start_mm` | ja | `[x, y, z]` = **KS_EIN des AS-Elements**; Z = Einbauhoehe oben | - | | `as_seite`, `es_seite` | nein | `"links"`/`"rechts"` | `"links"` | | `as_winkel`, `es_winkel` | nein | `"90"` oder `"30"` (als STRING) | `"90"` | Die Staustrecke ergibt sich aus `L_stau = (deltaL - aus-dx - ein-dx - 300 * cos(w)) / cos(w)` (300 = `gefaelle.separator_breite`). Eine Ziel-Hoehe gibt es nicht. In `gefaellestrecke_tests.json` stehen `deltaL_mm`, `winkel_grad` und `z_start_mm` in einem gemeinsamen Kopf-Eintrag ohne `test_id` und gelten fuer alle Faelle der Datei. ### 4.2 Modus 2 - Richtung aus zwei Punkten Wie Modus 1, aber `deltaL` und `hz` werden aus `linie_start_mm` -> `linie_ende_mm` berechnet (nur X/Y). `start_mm` bleibt der Einfuegepunkt und ist unabhaengig von der Linie. ```json { "test_id": "M2_hz000", "modus": 2, "start_mm": [0, -35000, 5000], "linie_start_mm": [0, -35000, 0], "linie_ende_mm": [10000, -35000, 0], "as_seite": "links", "es_seite": "links", "as_winkel": "90", "es_winkel": "90" } ``` ### 4.3 Modus 3 - Linienzug In der Produktion nicht skriptbar (`gf-linienzug-modus` waehlt vorgezeichnete LINE/ARC-Objekte per Maus). `test_gefaellestrecke.lsp` zeichnet die Leitlinie selbst und baut sie nicht-interaktiv nach. Zwei Formen: ```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" } { "test_id": "M3_hz270", "modus": 3, "richtung": "Sued", "start_mm": [0, -50000, 5000], "deltaH_quelle": "M2_hz000", "deltaL_quelle": "M2_hz000", ... } ``` `deltaH_quelle`/`deltaL_quelle` uebernehmen die Masse eines frueher gebauten Falls. Dieses Format ist an den Treiber gebunden. Fuer neue Anlagen besser eine VF-Linienzug-Spec (Abschnitt 5) mit `Linie-GF`/`GF-Bogen` verwenden. --- ## 5. VF-Linienzug-Kette (Spec) Beliebige Ketten aus GF-Linien, GF-Boegen, Vario-Kurven und VF-Einheiten, **ohne Dialog** gebaut (`VF_SPEC_BAU`, `TEST_HUNDM05`). Eine Kette = ein Kopf-Objekt, danach ihre Glieder (`glied`) und deren Unterknoten (`sub`) in Baureihenfolge. Ergebnis ist ein `VF_n`-Block mit vollem `SSG_VF_EDIT`-Journal (per Doppelklick editierbar). ```json { "spec_id": "VF_spec_LZ_01", "modus": 1, "start_punkt": [4912.2, 1230.9, 2154.0], "start_hoehe": 2154.0, "as": 1, "as_winkel": "90", "as_seite": "links" } { "glied": "Linie-GF", "nr": 1, "dl": 2249.3, "hz": 90.0, "gefaelle": "winkel", "winkel": 3.0, "ende": "nein" } { "glied": "Horizontal-VF", "nr": 2, "dl": 3256.9, "gf_verteilung": "einlauf", "vf_sep_vor": 0, "vf_sep_nach": 0, "vf_ende": "nein", "vf_separator": 0 } { "sub": "vario-kurve", "winkel": 90, "seite": "rechts", "variante": "innen" } { "sub": "motorstation" } { "glied": "ES", "winkel": "90", "seite": "links" } ``` **Kopf** | Feld | Bedeutung | |---|---| | `spec_id` | Kennung der Kette | | `modus` | `1` (nur Modus 1 hat einen Uebersetzer) | | `start_punkt` | `[x, y, z]` Kettenanfang (KS_EIN des AS-Elements bzw. erstes Glied) | | `start_hoehe` | Einbauhoehe am Start | | `as` | `1` = AS-Element setzen, `0` = nicht | | `as_winkel` / `as_seite` | `"90"`/`"30"` bzw. `"links"`/`"rechts"` | **Glieder** (`glied`) | `glied` | wichtigste Felder | |---|---| | `Linie-GF` | `dl`, `hz` (nur beim ersten Glied der Kette), `laenge_modus` (`endpunkt`/`hoehe`/`steigend`), `ende` (`ja-mit-es`/`ja-ohne-es`/`nein`), `sep_vor`, `sep_nach`, `gefaelle` (`hoehe`/`winkel`) + `hoehe` bzw. `winkel` | | `GF-Bogen` | `winkel` (30/60/90), `seite` | | `Vario-Kurve` | als eigenes Glied (Kettenanfang) vom Uebersetzer noch NICHT unterstuetzt -> Spec-Fehler; Vario-Kurven als `sub` einer VF-Einheit angeben | | `Horizontal-VF` | `dl`, `eingang_hoehe`, `gf_verteilung` (`haelfte`/`einlauf`), `vf_sep_vor`, `vf_sep_nach`, `vf_ende` (`ja-mit-es`/`nein`/`automatisch`/`zielpunkt-ohne-es`), `vf_separator` (nur bei `vf_ende` = `nein`) + `sub`-Knoten | | `Linie-VF` | `dl`, `hoehe`, optional `winkel_idx` + `sub`-Knoten | | `Linie` | `dl`, `hoehe`, `segment_typ` (`GF`/`VF`), optional `winkel_idx` | | `ES` | `winkel` (`"90"`/`"30"`), `seite` | **Unterknoten einer VF-Einheit** (`sub`): `horizontal` (`sep_vor`, `sep_nach`), `vario-kurve` (`winkel`, `seite`, `variante` `aussen`/`innen`), `auf-ab` (`richtung` `auf`/`ab`, `hoehe`), `motorstation`, `kettenende` (`es`, `es_winkel`, `es_seite`). Ja/Nein-Felder (`as`, `sep_vor`, `vf_sep_vor`, `es`, ...) als `1`/`0` oder `"ja"`/`"nein"`; mehrwertige Felder (`ende`, `vf_ende`) nur mit den genannten Woertern. Vollstaendige Regeln (Menue-Codes je Frame, `hz` nur einmal, Verhalten bei `winkel_idx`): [variofoerderer.md, Abschnitt 8b](variofoerderer.md#spec-pfad-kette-aus-eingabedaten-vf_spec_bau). Die Spec wird nicht von Hand geschrieben, sondern mit `python lib/vf_spec_export.py ` aus einer aufgezeichneten Kette erzeugt. Fehlerhafte Specs werden komplett abgewiesen (`vsp-pruefen` sammelt alle Fehler, gebaut wird dann nichts). **Andere Objekte in derselben Datei**: Neben den Ketten darf `hundm05.json` Kreisel (Abschnitt 1) und Einzelbloecke (Abschnitt 2) enthalten. Erkennbar sind sie an `function`; `vsp-gruppieren` ueberspringt sie, und `hundm05:bau-zusatzobjekte` baut sie nach den Ketten. `vf_spec_export.py` haengt sie beim Neuerzeugen unveraendert ans Dateiende. --- ## 6. VF-Linienzug (Eingabe-Journal) Das Rohformat hinter der Spec: die Antworten auf die Fragen des interaktiven Linienzug-Ablaufs, in Reihenfolge. Nur fuer Regressionstests gedacht - fuer neue Anlagen die Spec (Abschnitt 5) verwenden. ```json { "test_id": "VF_hundm05_LZ_01", "anlagetyp": "linienzug", "modus": 1, ... } { "typ": "point_abs", "wert": [4912.2, 1230.9, 2154.0], "kommentar": "Startpunkt" } { "typ": "real", "wert": 2154.0, "kommentar": "Hoehe (Z)" } { "typ": "string", "wert": "1", "kommentar": "AS-Element? Ja" } { "typ": "step", "wert": "Linie-GF", "kommentar": "Glied-Marker" } { "typ": "point_rel", "dL": 2249.3, "hz": 90.0, "kommentar": "Endpunkt" } { "typ": "int", "wert": 90, "kommentar": "Vario-Kurve Winkel" } ``` `typ`: `point_abs` (absoluter Punkt), `point_rel` (Abstand `dL` + Richtung `hz`, `hz` nur beim ersten Segment), `real`, `int`, `string` (Menue-Code als String), `step` (Glied-Marker, beim Replay uebersprungen). Kopf-Feld heisst `anlagetyp`, nicht `typ`, damit Kopf und Eingabe unterscheidbar bleiben. | Datei | Treiber | |---|---| | `linienzug_tests.json`, `linienzug_tests_stufe2.json` | `TEST_LINIENZUG`, `TEST_LINIENZUG_STUFE2` | | `hm_recformat.json` (5 echte HundM-Ketten, erzeugt mit `lib/vf_journal_export.py`) | `TEST_HM_RECFORMAT` (in `alltests.json` abgeschaltet) | --- ## 7. Omniflo ### 7.1 Bogen und Weiche ```json { "id": "821104025", "type": "bogen", "sivasnr": "821104025", "x": 219.4, "y": 223.06, "hoehe": 2000, "drehung": 0.0 } ``` | Feld | Pflicht | Bedeutung | Default | |---|---|---|---| | `type` | ja | `"bogen"` oder `"weiche"` | - | | `sivasnr` | ja | Sivas-Nummer = Dateiname `%DXFM_OMNIFLO%/.dxf` | - | | `x`, `y` | ja | Einfuegepunkt (`$INSBASE` der DXF, gesetzt mit `set_einfuegepkt.py`) | - | | `hoehe` | nein | Z des Einfuegepunkts UND Attribut `HOEHE` | 2000 | | `drehung` | nein | Drehung + Attribut `DREHUNG` | 0 | Es gibt kein `z`: die Hoehe ist zugleich die Z-Koordinate. Gueltige Sivas-Nummern: `data/json/omniflo_boegen.json`, `omniflo_weichen.json`. Treiber: `omni:test-insert` (`test_omniflo.lsp`), `omnistr:insert-bogen` (`test_omniflo_strecke.lsp`). ### 7.2 Aluprofil-Gerade ```json { "seq": 1, "type": "gerade", "profil": "AP110", "laenge": 1000.0, "x": 2000.0, "y": 0.0, "x_ende": 3000.0, "y_ende": 0.0, "drehung": 0.0, "hoehe": 2000, "id": "0003" } ``` `profil` = `"AP60"`, `"AP110"` oder `"APG110"`. Die Gerade laeuft von (`x`,`y`) nach (`x_ende`,`y_ende`) auf Z = `hoehe`; Laenge und Drehung folgen aus den Punkten (`laenge` ist nur Doku). Gebaut mit `omni:make-gerade`. --- ## 8. Waagrechte Foerderstrecke (`gerade`) - noch ohne Bau-Pfad ```json { "test_id": "GERADE_Arvato_01", "typ": "gerade", "laenge": 8313.39, "hz": 90.0, "startpunkt": [2334.97, 177818.67, 0.0], "endpunkt": [2334.96, 186132.06, 0.0] } ``` Ein Antriebs-/Umlenkstation-Paar ohne Hoehendifferenz, so von `lib/dxf_scan_components.py` ausgegeben (ein VarioFoerderer ist bei `deltaH` = 0 nicht loesbar). `TEST_DEMATIC_ARVATO` meldet diese Eintraege und ueberspringt sie. Passende Primitive waere `insert-hz-scaled-block-by-ks` (`vf_etage.lsp`) mit `Staustrecke_SP_1000_mm`, siehe [lisp_methods.md](lisp_methods.md). --- ## 9. Testdaten-Dateien im Ueberblick | Datei | Inhalt | Treiber / Befehl | |---|---|---| | `kreisel_tests.json` | 8 Kreisel (`insert`) | `TEST_KREISEL` | | `foerderer_tests.json` | Kopf `y_abstand` + 17 VF Standard | `TEST_FOERDERER` | | `gefaellestrecke_tests.json` | Kopf + GF Modus 1/2/3 | `TEST_GEFAELLESTRECKE` | | `omniflo_tests.json` | 27 Boegen, 80 Weichen | `TEST_OMNIFLO` | | `omniflo_strecke_tests.json` | Streckenzug aus Geraden und Boegen | `TEST_OMNIFLO_STRECKE` | | `linienzug_tests.json` / `_stufe2.json` | Eingabe-Journal je einer Kette | `TEST_LINIENZUG` / `TEST_LINIENZUG_STUFE2` | | `hm_recformat.json` | 5 HundM-Ketten als Journal | `TEST_HM_RECFORMAT` | | `hundm05.json` | 5 HundM-Ketten als Spec + Kreisel, Separatoren, Scanner, BTMT | `TEST_HUNDM05`, `VF_SPEC_BAU` | | `mubea.json` | Gesamtanlage: Kreisel, VF Standard/Etage, GF-Template (20 Stueck), Separatoren, Scanner, BTMT, Eingang/Ausgang | `TEST_MUBEA` | | `dematic_arvato.json` | Vorlage aus `dxf_scan_components.py`: Kreisel, Einzelbloecke, `gerade` (Hoehen fehlen) | `TEST_DEMATIC_ARVATO` (abgeschaltet) | | `showroom_ils.json` | ILS-3.0-Showroom-Vorlage aus `dxf_scan_components.py` (Kreisel, Gefaellestrecken; Hoehen teils Platzhalter), gleicher Treiber wie `dematic_arvato.json` | `TEST_SHOWROOM_ILS` | | `test_system.json` | Testanlage aus `dxf_anlage_export.py` (`sps_skel/data/test_system.dxf`): 9 Kreisel, 10 Separatoren, BTMT Beladung, SC Entladung - Vorlage fuer die sps_skel-Pipeline (CSV -> TRO -> SCL), gleicher Treiber wie `dematic_arvato.json` | `TEST_TEST_SYSTEM` | | `hundm05_linienzug_polylines.json` | Polylinien aus `extract_polylines.py` | kein Treiber (Analyse-Daten) | | `vfl_journal_hm05_abbruch.json` | rohes Journal (`kind`/`value`) eines abgebrochenen Baus | kein Treiber | --- ## 10. Eigene Anlage beschreiben - Kurzanleitung 1. Kreisel als `insert` (Abschnitt 1): `x/y` am aeussersten Punkt der AN-Seite, `z` = Einbauhoehe. 2. Einfache Steig-/Fall-Strecken mit fester Form als VF Standard/Etage (Abschnitt 3) bzw. Gefaellestrecke Modus 1 (Abschnitt 4.1), Startpunkt jeweils = KS_EIN des AS-Elements. 3. Ketten mit Kurven, mehreren VF-Einheiten oder GF-Boegen als Spec (Abschnitt 5) - am einfachsten eine Kette einmal interaktiv bauen, mit `lib/vf_journal_export.py` + `lib/vf_spec_export.py` als Spec exportieren und Startpunkt/Laengen anpassen. 4. Separatoren, Scanner, BTMT-Stationen, Eingang/Ausgang als Einzelblock (Abschnitt 2). 5. Aus Kreisel, Einzelbloecken und Specs gemischt baut derzeit nur der HundM05-Treiber (`TEST_HUNDM05`); fuer VF Standard/Etage + GF zusammen mit Kreiseln den Mubea-Treiber (`TEST_MUBEA`) als Vorlage nehmen.