From e147b8976cc1caa345badd97db2b02601ce7f37e Mon Sep 17 00:00:00 2001 From: Samer Ayadi Date: Thu, 10 Sep 2026 10:31:10 +0200 Subject: [PATCH] =?UTF-8?q?BTMT=20Beladung=20und=20Entladung=20in=20HundM?= =?UTF-8?q?=20eingef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/testdata/hundmM05_1.csv | 45 --- tests/testdata/object_data.md | 717 ---------------------------------- 2 files changed, 762 deletions(-) delete mode 100644 tests/testdata/hundmM05_1.csv delete mode 100644 tests/testdata/object_data.md diff --git a/tests/testdata/hundmM05_1.csv b/tests/testdata/hundmM05_1.csv deleted file mode 100644 index 87b68ad..0000000 --- a/tests/testdata/hundmM05_1.csv +++ /dev/null @@ -1,45 +0,0 @@ -Elementnummer;TeileArt;TeileId;Bezeichnung;Planquadrat;Anzahl;Position;Boundingbox;Insertpoint;K1;K2;K3;K4;Nachbarn;Fehler;Warnungen;Merkmale -1;"ILS 2.0 Strecke";"0001";"VarioFoerderer :5";"N/4";1;"5767.81, 4188.30, 1929.22";"2931.92, 6056.23, 619.56";"SvRvEsgmIN4QAAAAAAAAAAAA";"AKgKADAUAFQk";"AQs6ADXRAEII";"";"";"0006-L";"nur ein Partner";"";{"Typ": "Streckengruppe", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "3,3,3", "VF_Winkel": "0,0,0,0", "DeltaH_mm": "463", "DeltaL_mm": "1934", "L_VF_m": "1.859,1.434,0.1,1.83", "L_GF_m": "1.826,0.4,0.4", "Montagehoehe_m": "1.922", "Hoehe_Von_mm": "2154", "Hoehe_Bis_mm": "1690", "Antriebfahrtrichtung": "horizontal,horizontal,horizontal,horizontal", "Anzahl_Separator": "4", "Anzahl_Scanner": "0"} -2;"ILS 2.0 Strecke";"0002";"VarioFoerderer :4";"P/4";1;"9161.98, 3793.34, 2300.16";"2400.37, 5274.44, 1082.19";"f///ErhJIN4QAAAAAAAAAAAA";"ATcBAC/sAFQk";"AZS7AC/oAFy8";"";"";"0006-L";"nur ein Partner";"";{"Typ": "Streckengruppe", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "3,3,3", "VF_Winkel": "0,0,39,0", "DeltaH_mm": "220", "DeltaL_mm": "1788", "L_VF_m": "0.177,0.339,0.356,0.548", "L_GF_m": "2.727,0.4,0.418", "Montagehoehe_m": "2.264", "Hoehe_Von_mm": "2154", "Hoehe_Bis_mm": "2374", "Antriebfahrtrichtung": "horizontal,horizontal,Auf,horizontal", "Anzahl_Separator": "3", "Anzahl_Scanner": "1"} -3;"ILS 2.0 Strecke";"0003";"VarioFoerderer :3";"R/4";1;"13506.79, 3804.49, 2300.16";"2400.37, 5274.44, 1082.19";"f///EuPTIN4QAAAAAAAAAAAA";"AeC6ADBbAFQk";"Aj5zADBXAFy8";"";"";"0006-L";"nur ein Partner";"";{"Typ": "Streckengruppe", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "3,3,3", "VF_Winkel": "0,0,39,0", "DeltaH_mm": "220", "DeltaL_mm": "1788", "L_VF_m": "0.177,0.339,0.356,0.548", "L_GF_m": "2.727,0.4,0.418", "Montagehoehe_m": "2.264", "Hoehe_Von_mm": "2154", "Hoehe_Bis_mm": "2374", "Antriebfahrtrichtung": "horizontal,horizontal,Auf,horizontal", "Anzahl_Separator": "2", "Anzahl_Scanner": "0"} -4;"ILS 2.0 Strecke";"0004";"VarioFoerderer :2";"T/4";1;"17791.58, 3771.88, 2300.16";"2400.37, 5274.44, 1082.19";"f///EmRwIN4QAAAAAAAAAAAA";"AogZAC8VAFQk";"AuXTAC8RAFy8";"";"";"0006-L";"nur ein Partner";"";{"Typ": "Streckengruppe", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "3,3,3", "VF_Winkel": "0,0,39,0", "DeltaH_mm": "220", "DeltaL_mm": "1788", "L_VF_m": "0.177,0.339,0.356,0.548", "L_GF_m": "2.727,0.4,0.418", "Montagehoehe_m": "2.264", "Hoehe_Von_mm": "2154", "Hoehe_Bis_mm": "2374", "Antriebfahrtrichtung": "horizontal,horizontal,Auf,horizontal", "Anzahl_Separator": "2", "Anzahl_Scanner": "1"} -5;"ILS 2.0 Strecke";"0005";"VarioFoerderer :1";"V/4";1;"22081.12, 3780.10, 2300.16";"2400.37, 5274.44, 1082.19";"f///EoSOIN4QAAAAAAAAAAAA";"Ay+pAC9nAFQk";"A41jAC9jAFy8";"";"";"0006-L";"nur ein Partner";"";{"Typ": "Streckengruppe", "Seite_AS": "links", "Seite_ES": "links", "Winkel": "3,3,3", "VF_Winkel": "0,0,39,0", "DeltaH_mm": "220", "DeltaL_mm": "1788", "L_VF_m": "0.177,0.339,0.356,0.548", "L_GF_m": "2.727,0.4,0.418", "Montagehoehe_m": "2.264", "Hoehe_Von_mm": "2154", "Hoehe_Bis_mm": "2374", "Antriebfahrtrichtung": "horizontal,horizontal,Auf,horizontal", "Anzahl_Separator": "3", "Anzahl_Scanner": "1"} -6;"ILS 2.0 Kreisel";"0006";"Kreisel :1";"L/3";1;"13594.00, 767.00, 2154.00";"24100.00, 800.00, 1.00";"F49AC7QYIN4QAAAAAAAAAAAA";"";"";"";"";"0005, 0004, 0003, 0002, 0001";"";"";{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "23.3", "Anzahl der Separatoren": "5", "Kreiselart": "STANDARD", "Anzahl der Scanner": "3", "Anzahl der Rampen": "0", "Höhe in m": "2.15", "Drehrichtung": "UZS", "Drehung": 0, "Name": "Kreisel1", "Geruest fuer Einzelmodul": true} -7;"ILS 2.0 Separator";"0007";"Separator :19";"L/3";1;"2414.95, 365.00, 2155.50";"209.90, 150.00, 3.00";"I+84BZHIIN4QAAAAAAAAAAAA";"";"";"";"";"";"";"";{"Zuordnung": "0006-R", "ARTINR": "200000077", "Höhe": "2154", "Drehung": 0} -8;"ILS 2.0 Separator";"0008";"Separator :18";"M/4";1;"3992.84, 1165.94, 2155.50";"209.90, 150.00, 3.00";"Pdc2Ecp0IN4QAAAAAAAAf///";"";"";"";"";"";"";"";{"Zuordnung": "0006-L", "ARTINR": "200000077", "Höhe": "2154", "Drehung": 180} -9;"ILS 2.0 Scanner";"0009";"Scanner :6";"M/4";1;"4095.51, 804.08, 2154.00";"150.00, 280.00, 1.00";"Pn4WEcMwIN4QAAAAAAAApX2I";"";"";"";"";"";"";"";{"Zuordnung": "0006-L", "ARTINR": "829534306", "Höhe": "2154", "Drehung": 270, "Naechster Separator": "0008"} -10;"ILS 2.0 Separator";"0010";"Separator :17";"O/4";1;"7656.12, 1169.07, 2155.50";"209.90, 150.00, 3.00";"dbzrEdawIN4QAAAAAAAAf///";"";"";"";"";"";"";"";{"Zuordnung": "0006-L", "ARTINR": "200000077", "Höhe": "2154", "Drehung": 180} -11;"ILS 2.0 Scanner";"0011";"Scanner :5";"O/4";1;"7874.49, 807.67, 2154.00";"150.00, 280.00, 1.00";"eCe6EdE2IN4QAAAAAAAApX2I";"";"";"";"";"";"";"";{"Zuordnung": "0006-L", "ARTINR": "829534306", "Höhe": "2154", "Drehung": 270, "Naechster Separator": "0010"} -12;"ILS 2.0 Separator";"0012";"Separator :16";"Q/4";1;"12002.69, 1166.67, 2155.50";"209.90, 150.00, 3.00";"f///Ec1PIN4QAAAAAAAAf///";"";"";"";"";"";"";"";{"Zuordnung": "0003", "ARTINR": "200000077", "Höhe": "2154", "Drehung": 180} -13;"ILS 2.0 Scanner";"0013";"Scanner :4";"Q/4";1;"12233.73, 806.39, 2154.00";"150.00, 280.00, 1.00";"f///Ecw2IN4QAAAAAAAApX2I";"";"";"";"";"";"";"";{"Zuordnung": "0006-L", "ARTINR": "829534306", "Höhe": "2154", "Drehung": 270, "Naechster Separator": "0012"} -14;"ILS 2.0 Separator";"0014";"Separator :15";"S/4";1;"16288.21, 1167.73, 2155.50";"209.90, 150.00, 3.00";"f///EdF0IN4QAAAAAAAAf///";"";"";"";"";"";"";"";{"Zuordnung": "0004", "ARTINR": "200000077", "Höhe": "2154", "Drehung": 180} -15;"ILS 2.0 Scanner";"0015";"Scanner :3";"T/4";1;"16531.10, 809.84, 2154.00";"150.00, 280.00, 1.00";"f///EdmwIN4QAAAAAAAApX2I";"";"";"";"";"";"";"Distanz-Zuordnung unsicher: 0004 (2891mm) vs. 0006 (2965mm)";{"Zuordnung": "0004", "ARTINR": "829534306", "Höhe": "2154", "Drehung": 270, "Naechster Separator": "0014"} -16;"ILS 2.0 Separator";"0016";"Separator :14";"V/4";1;"20571.61, 1168.65, 2155.50";"209.90, 150.00, 3.00";"f///EdUHIN4QAAAAAAAAf///";"";"";"";"";"";"";"";{"Zuordnung": "0006-L", "ARTINR": "200000077", "Höhe": "2154", "Drehung": 180} -17;"ILS 2.0 Scanner";"0017";"Scanner :2";"V/4";1;"20807.68, 804.32, 2154.00";"150.00, 280.00, 1.00";"f///EcQgIN4QAAAAAAAApX2I";"";"";"";"";"";"";"";{"Zuordnung": "0005", "ARTINR": "829534306", "Höhe": "2154", "Drehung": 270, "Naechster Separator": "0016"} -18;"ILS 2.0 Separator";"0018";"Separator :13";"W/4";1;"23678.08, 1170.63, 2155.50";"209.90, 150.00, 3.00";"f///EdzGIN4QAAAAAAAAf///";"";"";"";"";"";"";"";{"Zuordnung": "0006-L", "ARTINR": "200000077", "Höhe": "2154", "Drehung": 180} -19;"ILS 2.0 Scanner";"0019";"Scanner :1";"W/4";1;"23780.75, 808.77, 2154.00";"150.00, 280.00, 1.00";"f///EdWCIN4QAAAAAAAApX2I";"";"";"";"";"";"";"";{"Zuordnung": "0006-L", "ARTINR": "829534306", "Höhe": "2154", "Drehung": 270, "Naechster Separator": "0018"} -20;"ILS 2.0 Separator";"0020";"Separator :12";"W/4";1;"24337.61, 1164.21, 2155.50";"209.90, 150.00, 3.00";"f///EcO1IN4QAAAAAAAAf///";"";"";"";"";"";"";"";{"Zuordnung": "0006-L", "ARTINR": "200000077", "Höhe": "2154", "Drehung": 180} -21;"ILS 2.0 BTMT Entladung";"0021";"BTMT Entladung :1";"X/4";1;"25342.34, 1545.51, -152.91";"1475.53, 962.00, 467.01";"f///Edt0AAAAAAAAAAAAARWq";"A8eHAC1/AAAA";"A9Tl//m4//9E";"";"";"";"";"";{"ARTINR": "400100156", "Höhe": "0", "Drehung": 1} -22;"ILS 2.0 BTMT Beladung";"0022";"BTMT Beladung :2";"M/3";1;"4503.28, 269.83, -44.69";"651.30, 406.65, 316.02";"QQViBbXdAAAAAAAAAAAAf/8q";"AKdD//et//ps";"AKOGAA6pAAAA";"";"";"";"";"";{"ARTINR": "829662012", "Höhe": "0", "Drehung": 179} -23;"ILS 2.0 BTMT Beladung";"0023";"BTMT Beladung :1";"N/3";1;"5532.64, 265.18, -44.69";"652.35, 408.39, 316.02";"ULt1BaZCAAAAAAAAAAAAf/7R";"AM9s//eF//ps";"AMu+AA6DAAAA";"";"";"";"";"";{"ARTINR": "829662012", "Höhe": "0", "Drehung": 179} -24;"ILS 2.0 Separator";"0024";"Separator :1";"N/4";1;"6203.44, 1934.69, 1842.17";"150.00, 209.77, 13.98";"XqgvHglvGoC5AAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0001", "ARTINR": "200000077", "Höhe": "1736", "Drehung": 90} -25;"ILS 2.0 Separator";"0025";"Separator :2";"O/6";1;"7158.77, 5463.57, 1920.56";"150.00, 209.77, 13.98";"bTv2U99GGOEZAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0001", "ARTINR": "200000077", "Höhe": "1630", "Drehung": 90} -26;"ILS 2.0 Separator";"0026";"Separator :3";"I/1";1;"4912.24, 4058.51, 2019.89";"150.00, 209.77, 13.98";"tQuRwtrpIf8/AAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0001", "ARTINR": "200000077", "Höhe": "2228", "Drehung": 90} -27;"ILS 2.0 Separator";"0027";"Separator :4";"P/4";1;"9723.58, 1783.30, 2525.81";"150.00, 209.77, 13.98";"f///HEarJQqAAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0002", "ARTINR": "200000077", "Höhe": "2427", "Drehung": 90} -28;"ILS 2.0 Separator";"0028";"Separator :5";"G/1";1;"8572.18, 4954.60, 1972.72";"150.00, 209.77, 13.98";"gAABtSm6If5qAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0002", "ARTINR": "200000077", "Höhe": "2227", "Drehung": 90} -29;"ILS 2.0 Separator";"0029";"Separator :6";"R/4";1;"14068.39, 1794.45, 2525.81";"150.00, 209.77, 13.98";"f///HHIlJQg5AAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0003", "ARTINR": "200000077", "Höhe": "2426", "Drehung": 90} -30;"ILS 2.0 Separator";"0030";"Separator :7";"E/1";1;"12916.99, 4965.75, 1972.72";"150.00, 209.77, 13.98";"gAABtP4/IgCyAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0003", "ARTINR": "200000077", "Höhe": "2228", "Drehung": 90} -31;"ILS 2.0 Separator";"0031";"Separator :8";"T/4";1;"18353.18, 1761.84, 2525.81";"150.00, 209.77, 13.98";"f///G/LwJQ7kAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0004", "ARTINR": "200000077", "Höhe": "2428", "Drehung": 90} -32;"ILS 2.0 Separator";"0032";"Separator :9";"C/1";1;"17201.78, 4933.14, 1972.72";"150.00, 209.77, 13.98";"gAABtX10IfoHAAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0004", "ARTINR": "200000077", "Höhe": "2226", "Drehung": 90} -33;"ILS 2.0 Separator";"0033";"Separator :10";"W/4";1;"22642.72, 1770.06, 2525.81";"150.00, 209.77, 13.98";"f///HBMCJQ01AAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0005", "ARTINR": "200000077", "Höhe": "2428", "Drehung": 90} -34;"ILS 2.0 Separator";"0034";"Separator :11";"A/1";1;"21491.32, 4941.36, 1972.72";"150.00, 209.77, 13.98";"gAABtV1iIfu1AAAAAAAAWoJ4";"";"";"";"";"";"";"";{"Zuordnung": "0005", "ARTINR": "200000077", "Höhe": "2227", "Drehung": 90} -35;"ILS Ausschleuselement";"0035";"ILS Ausschleuselement :1";"V/4";1;"20830.90, 1213.51, 2227.08";"100.04, 250.02, 30.00";"";"";"";"";"";"0006, 0005";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0006", "Strecke": "0005", "Streckenende": "Anfang"} -36;"ILS Einschleuselement";"0036";"ILS Einschleuselement :1";"W/4";1;"23330.30, 1213.09, 2227.08";"100.04, 250.02, 30.00";"";"";"";"";"";"0006, 0005";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0006", "Strecke": "0005", "Streckenende": "Ende"} -37;"ILS Ausschleuselement";"0037";"ILS Ausschleuselement :2";"T/4";1;"16541.30, 1205.31, 2227.08";"100.04, 250.02, 30.00";"";"";"";"";"";"0006, 0004";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0006", "Strecke": "0004", "Streckenende": "Anfang"} -38;"ILS Einschleuselement";"0038";"ILS Einschleuselement :2";"U/4";1;"19040.70, 1204.89, 2227.08";"100.04, 250.02, 30.00";"";"";"";"";"";"0006, 0004";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0006", "Strecke": "0004", "Streckenende": "Ende"} -39;"ILS Ausschleuselement";"0039";"ILS Ausschleuselement :3";"Q/4";1;"12256.60, 1237.91, 2227.08";"100.04, 250.02, 30.00";"";"";"";"";"";"0006, 0003";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0006", "Strecke": "0003", "Streckenende": "Anfang"} -40;"ILS Einschleuselement";"0040";"ILS Einschleuselement :3";"S/4";1;"14755.90, 1237.49, 2227.08";"100.04, 250.02, 30.00";"";"";"";"";"";"0006, 0003";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0006", "Strecke": "0003", "Streckenende": "Ende"} -41;"ILS Ausschleuselement";"0041";"ILS Ausschleuselement :4";"O/4";1;"7911.70, 1226.81, 2227.08";"100.04, 250.02, 30.00";"";"";"";"";"";"0006, 0002";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0006", "Strecke": "0002", "Streckenende": "Anfang"} -42;"ILS Einschleuselement";"0042";"ILS Einschleuselement :4";"P/4";1;"10411.10, 1226.39, 2227.08";"100.04, 250.02, 30.00";"";"";"";"";"";"0006, 0002";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0006", "Strecke": "0002", "Streckenende": "Ende"} -43;"ILS Ausschleuselement";"0043";"ILS Ausschleuselement :5";"M/4";1;"4251.88, 1227.91, 2041.61";"114.27, 255.36, 30.00";"";"";"";"";"";"0006, 0001";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0006", "Strecke": "0001", "Streckenende": "Anfang"} -44;"ILS Einschleuselement";"0044";"ILS Einschleuselement :5";"O/4";1;"6890.92, 1380.59, 2041.61";"114.27, 255.36, 30.00";"";"";"";"";"";"0006, 0001";"";"";{"Erzeugt aus": "Kreisel-Strecke-Kollision", "Kreisel": "0006", "Strecke": "0001", "Streckenende": "Ende"} diff --git a/tests/testdata/object_data.md b/tests/testdata/object_data.md deleted file mode 100644 index c3824b1..0000000 --- a/tests/testdata/object_data.md +++ /dev/null @@ -1,717 +0,0 @@ -# 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, `hm_recformat.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_hm_recformat.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** `.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/BTMT-Station — `Lisp/SSG_LIB_Commands.lsp` - -Funktion: `ils-insert-sensor (fname)` (Separator/Scanner) bzw. -`ils-insert-station (rohname)` (BTMT-Beladung/SC_Entladung) — beide fuegen -wiederholt denselben Block interaktiv ein und sind fuer JSON-Testdaten -gleich zu behandeln (siehe unten). - -| Feld | Typ | Pflicht | Bedeutung | Default | -|---|---|---|---|---| -| `block` / `fname` / `rohname` | string | **ja** | Blockdateiname ohne Erweiterung, z.B. `"Separator_SP"`, `"Scanner"`, `"S-LP"`, `"BTMT-Beladung"`, `"SC_Entladung"` — aufgeloest ueber `ssg-ils-block-datei` (2D/3D-Suffix + Fallback) | - | -| `x`, `y`, `z` | real (mm) | (Wrapper) | Einfuegepunkt — **kein** Parameter von `ils-insert-sensor`/`ils-insert-station` | - | -| `rotation` | real (Grad) | (Wrapper) | Rotation — **kein** Parameter (kommt per `pause`) | - | - -**Nicht scriptbar**: beide Funktionen fragen 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`/`hundm05:bau-sensor` in `tests/test_mubea.lsp`/ -`tests/test_hundm05.lsp`. Fachlich noetig sind nur Blockname + Punkt + -Rotation, der Blockname selbst ist dabei beliebig (kein Katalog/Whitelist) — -BTMT-Beladung/SC_Entladung laufen ueber denselben JSON-Treiber wie -Separator/Scanner. - -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_hm_recformat.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 - -Zwei Dateien beschreiben dieselben 5 Ketten, in zwei Formaten: - -| Datei | Inhalt | Test | -|---|---|---| -| `tests/testdata/hm_recformat.json` | die **Aufzeichnung**: rohes Eingabe-Journal aus der XDATA der Kundenzeichnung, als Frage-Antwort-Protokoll | `TEST_HM_RECFORMAT` (in `alltests.json` abgeschaltet) | -| `tests/testdata/hundm05.json` | die daraus abgeleitete **Spec** (Domaenenwerte statt Menue-Codes, 52 statt 281 Objekte) - hier werden weitere Teile der Anlage nachgetragen | `TEST_HUNDM05` | - -In `hundm05.json` stehen neben den Ketten auch **andere Objekte der Anlage**, erkennbar am Feld `function` - Format wie in den jeweiligen Einzel-Testdaten (ein Kreisel also wie in `kreisel_tests.json`, Schema in Abschnitt 1). Damit beschreibt EINE Datei die ganze Anlage. Der Ketten-Uebersetzer ueberspringt diese Objekte (`vsp-gruppieren`), `hundm05:bau-zusatzobjekte` in `tests/test_hundm05.lsp` baut sie, und `lib/vf_spec_export.py` uebernimmt sie beim Neuerzeugen der Spec-Daten. Im Ergebnis-JSON unterscheidet das Feld `kind` die Objektarten (`linienzug` / `kreisel` / `sensor`). `sensor` sind Separator/Scanner-Eintraege (erkennbar an `block`, Schema wie Abschnitt 5/`mubea.json`) - `hundm05:bau-sensor` baut sie per direktem `_.INSERT` nach, analog zu `mubea:build-separator-one` in `tests/test_mubea.lsp` (`ils-insert-sensor` selbst ist nicht scriptbar). - -Die Spec ist das Eingabeformat, die Aufzeichnung die Vorlage, an der sie gemessen wird (Rundlauf-Beweis in `tests/test_vf_spec.py`). Warum beide bleiben: die Aufzeichnung ist die einzige eingecheckte Kopie der Originaldaten (`data/polylines.dxf` ist zu gross fuer das Repo) UND der einzige Test dafuer, dass ein BESTEHENDER `VF_n`-Block weiter abspielbar ist - also dass Doppelklick-Edit und 2D/3D-Konvertierung an Altbestand funktionieren. Gebaut wird routinemaessig nur noch aus der Spec, damit nicht zweimal dieselbe Geometrie entsteht. - -`tests/testdata/hm_recformat.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/hm_recformat.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_hm_recformat.lsp` (`TEST_HM_RECFORMAT`, -`TEST_HUNDM05_2D`/`_3D`): der Treiber gruppiert die Objekte -(`hmrec:gruppiere`), baut daraus das Vorwaerts-Journal -(`hmrec: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.