Merge branch 'master' of https://gitea.schoenenberger.de/Schoenenberger_Systeme_GmbH/dxfmakros
This commit is contained in:
@@ -16,11 +16,6 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
;; --- ILS / Foerderer ---
|
;; --- ILS / Foerderer ---
|
||||||
(defun c:ILS_ETF_Etagenfoerderer ()
|
|
||||||
(princ "\n[DUMMY] ILS_ETF_Etagenfoerderer aufgerufen")
|
|
||||||
(princ)
|
|
||||||
)
|
|
||||||
|
|
||||||
(defun c:ILS_TEF_Strecke ()
|
(defun c:ILS_TEF_Strecke ()
|
||||||
(princ "\n[DUMMY] ILS_TEF_Strecke aufgerufen")
|
(princ "\n[DUMMY] ILS_TEF_Strecke aufgerufen")
|
||||||
(princ)
|
(princ)
|
||||||
|
|||||||
+1
-1
@@ -370,7 +370,7 @@
|
|||||||
(progn
|
(progn
|
||||||
(setq tag (cdr (assoc 2 ed)))
|
(setq tag (cdr (assoc 2 ed)))
|
||||||
(setq wert (cdr (assoc tag attrib-alist)))
|
(setq wert (cdr (assoc tag attrib-alist)))
|
||||||
(if (and wert (> (strlen wert) 0))
|
(if (and wert (= (type wert) 'STR) (> (strlen wert) 0))
|
||||||
(progn
|
(progn
|
||||||
(entmod (subst (cons 1 wert) (assoc 1 ed) ed))
|
(entmod (subst (cons 1 wert) (assoc 1 ed) ed))
|
||||||
(entupd obj)
|
(entupd obj)
|
||||||
|
|||||||
@@ -70,7 +70,7 @@
|
|||||||
)
|
)
|
||||||
(setq missing '())
|
(setq missing '())
|
||||||
(foreach bname required-blocks
|
(foreach bname required-blocks
|
||||||
(setq datei (strcat block-pfad bname ".dxf"))
|
(setq datei (strcat block-pfad bname ".dwg"))
|
||||||
(if (not (findfile datei))
|
(if (not (findfile datei))
|
||||||
(setq missing (cons datei missing))
|
(setq missing (cons datei missing))
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ SSG_LIB
|
|||||||
│ │ ├── BTMT-Beladung → ILS_BTMT_Beladung
|
│ │ ├── BTMT-Beladung → ILS_BTMT_Beladung
|
||||||
│ │ └── BTMT-Entladung → ILS_BTMT_Entladung
|
│ │ └── BTMT-Entladung → ILS_BTMT_Entladung
|
||||||
│ ├── Foerderer
|
│ ├── Foerderer
|
||||||
│ │ ├── ETF Etagenfoerderer → ILS_ETF_Etagenfoerderer
|
|
||||||
│ │ ├── TEF Strecke → ILS_TEF_Strecke
|
│ │ ├── TEF Strecke → ILS_TEF_Strecke
|
||||||
│ │ ├── VarioFoerderer → FOERDERANLAGE
|
│ │ ├── VarioFoerderer → FOERDERANLAGE
|
||||||
│ │ ├── Kurven angetr. Aussen → ILS_K{90,60,30}{LA,RA}
|
│ │ ├── Kurven angetr. Aussen → ILS_K{90,60,30}{LA,RA}
|
||||||
|
|||||||
+215
-189
@@ -5,234 +5,281 @@
|
|||||||
Die SSG_LIB AutoLISP-Makros werden ueber einen zweistufigen Hybrid-Ansatz getestet:
|
Die SSG_LIB AutoLISP-Makros werden ueber einen zweistufigen Hybrid-Ansatz getestet:
|
||||||
|
|
||||||
1. **AutoLISP** (in BricsCAD): Liest JSON-Testfaelle, fuehrt die Funktionen aus,
|
1. **AutoLISP** (in BricsCAD): Liest JSON-Testfaelle, fuehrt die Funktionen aus,
|
||||||
schreibt Ergebnisse als JSON und DXF.
|
schreibt Ergebnisse als JSON und DXF/DWG.
|
||||||
2. **Python** (pytest + ezdxf): Validiert die Ergebnisse automatisch gegen
|
2. **Python** (pytest + ezdxf): Validiert die Ergebnisse automatisch gegen
|
||||||
erwartete Werte und optionale Referenz-DXFs.
|
erwartete Werte und optionale Referenzdaten.
|
||||||
|
|
||||||
```
|
```text
|
||||||
Python (pytest) AutoLISP (BricsCAD) Python (pytest)
|
Python (pytest) AutoLISP (BricsCAD) Python (pytest)
|
||||||
=============== ==================== ===============
|
=============== ==================== ===============
|
||||||
Testfall-Definitionen --> Ausfuehrung der --> Validierung:
|
Testfall-Definitionen --> Ausfuehrung der --> Validierung:
|
||||||
als JSON bereitstellen LISP-Funktionen - JSON-Ergebnisse
|
als JSON bereitstellen LISP-Funktionen - JSON-Ergebnisse
|
||||||
+ DXF + results.json - DXF-Geometrie
|
+ DXF/DWG + results.json - DXF-Geometrie
|
||||||
- Referenz-Vergleich
|
- Referenz-Vergleich
|
||||||
```
|
```
|
||||||
|
|
||||||
## Verzeichnisstruktur
|
## Verzeichnisstruktur
|
||||||
|
|
||||||
```
|
```text
|
||||||
tests/
|
tests/
|
||||||
├── testdata/ # JSON-Testfall-Definitionen (versioniert)
|
├── alltests.json # Zentrale Testregistry (welche Module + Speicherformat)
|
||||||
│ ├── kreisel_tests.json
|
├── test_run_all.lsp # C:SSG_RUN_ALL_TESTS - fuehrt alle Tests aus
|
||||||
│ ├── vario_tests.json
|
├── test_kreisel.lsp # C:TEST_KREISEL - Kreisel-Testrunner
|
||||||
│ └── omniflo_tests.json
|
├── test_foerderer.lsp # C:TEST_FOERDERER - Variofoerderer-Testrunner
|
||||||
├── reference/ # Abgenommene Referenz-DXFs (versioniert)
|
├── test_kseinaus.lsp # C:TEST_KSEINAUS - KreiselEinAus-Testrunner
|
||||||
│ └── kreisel_ref.dxf
|
├── test_omniflo.lsp # C:TEST_OMNIFLO - Omniflo-Testrunner
|
||||||
├── output/ # Generierte Ergebnisse (in .gitignore)
|
|
||||||
│ ├── kreisel_tests.dxf
|
|
||||||
│ └── kreisel_results.json
|
|
||||||
├── ssg_testrunner.lsp # LISP Test-Runner
|
|
||||||
├── conftest.py # pytest Fixtures
|
├── conftest.py # pytest Fixtures
|
||||||
├── test_kreisel.py # pytest Kreisel-Validierung
|
├── test_kreisel.py # pytest Kreisel-Validierung
|
||||||
├── test_vario.py # pytest Vario-Validierung
|
|
||||||
├── test_omniflo.py # pytest Omniflo-Validierung
|
├── test_omniflo.py # pytest Omniflo-Validierung
|
||||||
└── requirements.txt # Python-Abhaengigkeiten (ezdxf, pytest)
|
├── create_testbase.py # Hilfsskript (optional, i.d.R. nicht benoetigt)
|
||||||
|
├── requirements.txt # Python-Abhaengigkeiten (ezdxf, pytest)
|
||||||
|
├── testdata/ # JSON-Testfall-Definitionen (versioniert)
|
||||||
|
│ ├── kreisel_tests.json
|
||||||
|
│ ├── foerderer_tests.json
|
||||||
|
│ └── omniflo_tests.json
|
||||||
|
├── reference/ # Abgenommene Referenzdaten (versioniert)
|
||||||
|
│ └── omniflo_export_reference.csv
|
||||||
|
└── output/ # Generierte Ergebnisse (nicht in Git)
|
||||||
|
├── kreisel_results.json
|
||||||
|
├── kreisel_tests.dxf
|
||||||
|
├── foerderer_results.json
|
||||||
|
├── foerderer_tests.dwg
|
||||||
|
├── kseinaus_results.json
|
||||||
|
├── omniflo_results.json
|
||||||
|
├── omniflo_tests.dxf
|
||||||
|
└── omniflo_export.csv
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Testregistry (alltests.json)
|
||||||
|
|
||||||
|
Die Datei `tests/alltests.json` ist die zentrale Registry aller Testmodule.
|
||||||
|
`SSG_RUN_ALL_TESTS` liest sie beim Start — die Testliste ist nicht hartcodiert.
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{ "name": "kreisel", "save": "dxf", "module": "KreiselInsert" },
|
||||||
|
{ "name": "foerderer", "save": "dwg", "module": "VarioFoerderer" },
|
||||||
|
{ "name": "kseinaus", "save": null, "module": "VarioFoerderer" },
|
||||||
|
{ "name": "omniflo", "save": "dxf", "module": "OmniModulInsert" }
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
| Feld | Typ | Bedeutung |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `name` | String | Basisname des Testmoduls (Pflicht) |
|
||||||
|
| `save` | `"dxf"` / `"dwg"` / `null` | Speicherformat der Zeichnung |
|
||||||
|
| `module` | String | LISP-Modul (wird von ssg-ensure geladen) |
|
||||||
|
|
||||||
|
Aus dem `name` werden alle Dateinamen abgeleitet:
|
||||||
|
|
||||||
|
| Element | Schema | Beispiel (`kreisel`) |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| LISP-Datei | `tests/test_<name>.lsp` | `tests/test_kreisel.lsp` |
|
||||||
|
| BricsCAD-Befehl | `TEST_<NAME>` | `TEST_KREISEL` |
|
||||||
|
| Export-Funktion | `<name>:export-results` | `kreisel:export-results` |
|
||||||
|
| JSON-Ergebnis | `output/<name>_results.json` | `output/kreisel_results.json` |
|
||||||
|
| DXF/DWG-Datei | `output/<name>_tests.dxf/.dwg` | `output/kreisel_tests.dxf` |
|
||||||
|
|
||||||
## Schritt 1: Testfaelle definieren (JSON)
|
## Schritt 1: Testfaelle definieren (JSON)
|
||||||
|
|
||||||
Jedes Modul hat eine eigene JSON-Datei in `tests/testdata/`. Aufbau:
|
Jedes Modul hat eine eigene JSON-Datei in `tests/testdata/`. Format: **flaches JSON-Array**
|
||||||
|
(kompatibel mit `omni:load-json`). Kein Nesting, keine Wrapper-Objekte.
|
||||||
|
|
||||||
|
### Kreisel-Format (kreisel_tests.json)
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
[
|
||||||
"module": "Kreisel",
|
{
|
||||||
"version": "1.0",
|
"id": "KR_Kreuz_Q1_0Grad",
|
||||||
"description": "ILS Kreisel Testfaelle",
|
"function": "insert",
|
||||||
"tests": [
|
"x": 500, "y": 500, "z": 2500,
|
||||||
{
|
"abstand": 2000,
|
||||||
"id": "KR_Horiz_ObenUnten",
|
"rotation": 0.0,
|
||||||
"function": "draw-module",
|
"typ": "STANDARD",
|
||||||
"params": {
|
"expect_block_prefix": "KREISEL_",
|
||||||
"basepoint": [500.0, 5000.0, 2500.0],
|
"expect_hoehe": "2500",
|
||||||
"abstand": 4200.0,
|
"expect_kreiselart": "STANDARD"
|
||||||
"rotation": 270.0,
|
}
|
||||||
"attribs": {
|
]
|
||||||
"KREISELART": "STANDARD",
|
|
||||||
"NAME": "TEST_H_ObenUnten"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"expect": {
|
|
||||||
"attributes": {
|
|
||||||
"KREISELART": "STANDARD",
|
|
||||||
"DREHUNG": "270",
|
|
||||||
"ABSTAND": "4200"
|
|
||||||
},
|
|
||||||
"block_prefix": "KR_",
|
|
||||||
"min_entities": 6
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Felder
|
Felder:
|
||||||
|
|
||||||
| Feld | Beschreibung |
|
- `id` — Eindeutiger Testfall-Name
|
||||||
|---|---|
|
- `function` — `"insert"` oder `"connect"`
|
||||||
| `id` | Eindeutiger Testfall-Name |
|
- Eingabeparameter: `x`, `y`, `z`, `abstand`, `rotation`, `typ`
|
||||||
| `function` | Aufzurufende LISP-Funktion |
|
- `expect_*` — Erwartete Ergebniswerte (fuer Python-Validierung)
|
||||||
| `params` | Uebergabewerte an die Funktion |
|
|
||||||
| `expect.attributes` | Erwartete Block-Attribute nach Ausfuehrung |
|
|
||||||
| `expect.block_prefix` | Erwartetes Praefix des erzeugten Block-Namens |
|
|
||||||
| `expect.min_entities` | Mindestanzahl Entities im erzeugten Block |
|
|
||||||
|
|
||||||
## Schritt 2: LISP Test-Runner (ssg_testrunner.lsp)
|
### Foerderer-Format (foerderer_tests.json)
|
||||||
|
|
||||||
Der LISP Test-Runner liest die JSON-Testfaelle, fuehrt die Funktionen in
|
```json
|
||||||
BricsCAD aus und schreibt die Ergebnisse.
|
[
|
||||||
|
{ "y_abstand": 400 },
|
||||||
### Aufruf in BricsCAD
|
{
|
||||||
|
"test_id": "VF_Auf_0",
|
||||||
```
|
"richtung": "Auf",
|
||||||
Command: TESTRUN "kreisel"
|
"deltaL": 7000,
|
||||||
|
"deltaH": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
Der Befehl:
|
- Erster Eintrag (ohne `test_id`): Konfiguration (`y_abstand` zwischen Foerderern)
|
||||||
1. Liest `tests/testdata/kreisel_tests.json`
|
- Felder: `test_id`, `richtung` (`"Auf"` / `"Ab"`), `deltaL`, `deltaH`
|
||||||
2. Erstellt eine neue leere Zeichnung
|
- Ergebnisstatus: `GEBAUT`, `NICHT_GEBAUT`, `GEOMETRISCH_UNMOEGLICH`
|
||||||
3. Fuehrt fuer jeden Testfall die angegebene Funktion mit den Parametern aus
|
|
||||||
4. Sammelt Ergebnisse: Block-Handle, tatsaechliche Attribute, Insertionspunkt
|
### Omniflo-Format (omniflo_tests.json)
|
||||||
5. Schreibt `tests/output/kreisel_results.json`
|
|
||||||
6. Speichert die Zeichnung als `tests/output/kreisel_tests.dxf`
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "821104025",
|
||||||
|
"type": "bogen",
|
||||||
|
"sivasnr": "821104025",
|
||||||
|
"x": 219.4, "y": 223.06,
|
||||||
|
"hoehe": 2000,
|
||||||
|
"drehung": 0.0,
|
||||||
|
"description": "APB 110 R 550/22,5 – 84/522",
|
||||||
|
"row": "Boegen 22.5"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Schritt 2: LISP-Testrunner ausfuehren (BricsCAD)
|
||||||
|
|
||||||
|
### Alle Tests auf einmal
|
||||||
|
|
||||||
|
```lisp
|
||||||
|
(load (strcat (getenv "DXFMAKRO") "/tests/test_run_all.lsp"))
|
||||||
|
SSG_RUN_ALL_TESTS
|
||||||
|
```
|
||||||
|
|
||||||
|
`SSG_RUN_ALL_TESTS` liest `alltests.json` und fuehrt fuer jedes Modul aus:
|
||||||
|
|
||||||
|
1. Zeichnung leeren (ERASE ALL + PURGE x5)
|
||||||
|
2. `test_<name>.lsp` laden und `TEST_<NAME>` ausfuehren
|
||||||
|
3. JSON-Export: `<name>:export-results` aufrufen (immer)
|
||||||
|
4. Zeichnung speichern gemaess `save`-Feld (`"dxf"`, `"dwg"` oder kein Speichern)
|
||||||
|
5. Bei Fehler: weiter mit naechstem Test (Fehlerisolation)
|
||||||
|
|
||||||
|
### Einzeltest (z.B. nur Kreisel)
|
||||||
|
|
||||||
|
```lisp
|
||||||
|
(load (strcat (getenv "DXFMAKRO") "/tests/test_kreisel.lsp"))
|
||||||
|
TEST_KREISEL
|
||||||
|
(kreisel:export-results (strcat (getenv "DXFMAKRO") "/tests/output"))
|
||||||
|
```
|
||||||
|
|
||||||
### Ausgabe: results.json
|
### Ausgabe: results.json
|
||||||
|
|
||||||
```json
|
```json
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"test_id": "KR_Horiz_ObenUnten",
|
"test_id": "KR_Kreuz_Q1_0Grad",
|
||||||
"status": "executed",
|
"status": "GEBAUT",
|
||||||
"block_handle": "A3F",
|
"block_name": "KREISEL_STANDARD",
|
||||||
"block_name": "KR_STANDARD_01",
|
"insert_point": [500.0, 500.0, 2500.0],
|
||||||
"insert_point": [500.0, 5000.0, 2500.0],
|
"rotation": 0.0,
|
||||||
"rotation": 270.0,
|
"actual_kreiselart": "STANDARD",
|
||||||
"actual_attributes": {
|
"actual_hoehe": "2500"
|
||||||
"KREISELART": "STANDARD",
|
|
||||||
"DREHUNG": "270",
|
|
||||||
"ABSTAND": "4200",
|
|
||||||
"NAME": "TEST_H_ObenUnten"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Schritt 3: Python-Validierung (pytest)
|
## Schritt 3: Python-Validierung (pytest)
|
||||||
|
|
||||||
Die Python-Tests lesen `results.json` und die erzeugte DXF-Datei und pruefen:
|
```cmd
|
||||||
|
bin\run_tests.bat --runall
|
||||||
|
```
|
||||||
|
|
||||||
### 3a. Attribut-Pruefung (results.json)
|
Oder einzelnes Testmodul:
|
||||||
|
|
||||||
Vergleicht `actual_attributes` aus results.json gegen `expect.attributes`
|
```cmd
|
||||||
aus den Testdefinitionen. Keine BricsCAD-Instanz noetig.
|
bin\run_tests.bat --runall test_kreisel.py
|
||||||
|
```
|
||||||
|
|
||||||
### 3b. Geometrie-Pruefung (ezdxf)
|
### test_kreisel.py
|
||||||
|
|
||||||
Oeffnet die erzeugte DXF-Datei mit der Python-Bibliothek `ezdxf` und prueft:
|
| Klasse | Prueft |
|
||||||
|
| --- | --- |
|
||||||
|
| `TestKreiselAttributes` | Attribute (KREISELART, HOEHE), Block-Prefixe, Status |
|
||||||
|
| `TestKreiselGeometry` | DXF-Bloecke, Positionen, Kreis-Radien (400mm) |
|
||||||
|
| `TestKreiselReference` | Block-Anzahl und -Typen gegen Referenz-DXF |
|
||||||
|
|
||||||
- **Block-Existenz**: Alle erwarteten Bloecke im Modelspace vorhanden
|
### test_omniflo.py
|
||||||
- **Entity-Anzahl**: Mindestanzahl Entities pro Block
|
|
||||||
- **Kreisradien**: AN8/SP8-Kreise haben korrekten Radius (400mm)
|
|
||||||
- **Linienlaengen**: Tangenten haben korrekte Laenge (= Abstand)
|
|
||||||
- **Layer-Zuordnung**: Entities auf korrektem Layer
|
|
||||||
- **Insertionspunkte**: Bloecke an erwarteter Position
|
|
||||||
|
|
||||||
### 3c. Referenz-Vergleich
|
| Klasse | Prueft |
|
||||||
|
| --- | --- |
|
||||||
|
| `TestOmnifloExportUnit` | Mock-Export: Merkmale, Datentypen, Vollstaendigkeit (ohne BricsCAD) |
|
||||||
|
| `TestOmnifloExportCSV` | CSV aus BricsCAD: Header, Spalten, JSON-Merkmale |
|
||||||
|
|
||||||
Vergleicht die Ergebnis-DXF gegen eine abgenommene Referenz-DXF:
|
Tests, deren Eingabedaten fehlen (kein BricsCAD-Lauf), werden automatisch
|
||||||
|
uebersprungen (`pytest.skip`).
|
||||||
- Gleiche Anzahl Bloecke im Modelspace
|
|
||||||
- Gleiche Block-Typen
|
|
||||||
- Gleiche Attributwerte
|
|
||||||
|
|
||||||
## Schritt 4: Referenz-Management
|
## Schritt 4: Referenz-Management
|
||||||
|
|
||||||
### Neue Referenz erstellen (erster Lauf oder nach Aenderung)
|
```cmd
|
||||||
|
# Aktuelle Ergebnisse als neue Referenz speichern
|
||||||
```bash
|
bin\run_tests.bat --set-as-reference
|
||||||
# 1. Tests in BricsCAD ausfuehren
|
|
||||||
# Command: TESTRUN "kreisel"
|
|
||||||
|
|
||||||
# 2. Ergebnis-DXF visuell pruefen (in BricsCAD oeffnen)
|
|
||||||
|
|
||||||
# 3. Wenn OK: Als neue Referenz speichern
|
|
||||||
copy tests\output\kreisel_tests.dxf tests\reference\kreisel_ref.dxf
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Referenz aktualisieren
|
Kopiert alle Dateien aus `output/` nach `reference/`. Nur bei bestandenen Tests verwenden.
|
||||||
|
|
||||||
Wenn sich die LISP-Logik aendert und die neuen Ergebnisse korrekt sind:
|
## Modulspezifische Testfaelle
|
||||||
|
|
||||||
```bash
|
### Kreisel (kreisel_tests.json)
|
||||||
# 1. Tests in BricsCAD ausfuehren
|
|
||||||
# 2. Ergebnis visuell pruefen
|
|
||||||
# 3. Python-Tests zeigen Referenz-Abweichung:
|
|
||||||
pytest tests/test_kreisel.py -v
|
|
||||||
# FAILED test_block_count_matches_reference - 6 != 5
|
|
||||||
|
|
||||||
# 4. Neue Referenz speichern
|
| Test-ID | Beschreibung | Params |
|
||||||
copy tests\output\kreisel_tests.dxf tests\reference\kreisel_ref.dxf
|
| --- | --- | --- |
|
||||||
|
| KR_Kreuz_Q1_0Grad | Standard Kreisel, 0 Grad | rot=0, z=2500, abstand=2000 |
|
||||||
|
| KR_Kreuz_Q2_90Grad | Standard Kreisel, 90 Grad | rot=90, z=2500, abstand=3000 |
|
||||||
|
| KR_Kreuz_Q3_180Grad | Standard Kreisel, 180 Grad | rot=180, z=2500, abstand=4000 |
|
||||||
|
| KR_Kreuz_Q4_270Grad | Standard Kreisel, 270 Grad | rot=270, z=2500, abstand=5000 |
|
||||||
|
| KR_Schraeg_Q1_30Grad | Standard Kreisel, schraeg | rot=30, z=3000, abstand=3000 |
|
||||||
|
| KR_Pin_Q1_0Grad | Pin-Kreisel, 0 Grad | rot=0, typ=PIN, z=1500 |
|
||||||
|
| KR_Pin_Q1_90Grad | Pin-Kreisel, 90 Grad | rot=90, typ=PIN, z=1500 |
|
||||||
|
| KR_Pin_Q1_30Grad_Schraeg | Pin-Kreisel, schraeg | rot=30, typ=PIN, z=1500 |
|
||||||
|
|
||||||
# 5. Tests erneut ausfuehren - jetzt PASS
|
### Foerderer (foerderer_tests.json)
|
||||||
pytest tests/test_kreisel.py -v
|
|
||||||
```
|
|
||||||
|
|
||||||
## Ausfuehrung
|
| Test-ID | Richtung | deltaL | deltaH |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| VF_Auf_0 | Auf | 7000 | 0 |
|
||||||
|
| VF_Auf_1000 | Auf | 7000 | 1000 |
|
||||||
|
| VF_Auf_2000 | Auf | 7000 | 2000 |
|
||||||
|
| VF_Auf_3000 | Auf | 7000 | 3000 |
|
||||||
|
| VF_Auf_4000 | Auf | 7000 | 4000 |
|
||||||
|
| VF_Auf_5000 | Auf | 7000 | 5000 |
|
||||||
|
| VF_Ab_0 | Ab | 7000 | 0 (GEOMETRISCH_UNMOEGLICH) |
|
||||||
|
| VF_Ab_1000 | Ab | 7000 | 1000 |
|
||||||
|
| VF_Ab_2000 | Ab | 7000 | 2000 |
|
||||||
|
| VF_Ab_3000 | Ab | 7000 | 3000 |
|
||||||
|
| VF_Ab_4000 | Ab | 7000 | 4000 |
|
||||||
|
| VF_Ab_5000 | Ab | 7000 | 5000 |
|
||||||
|
|
||||||
### Kompletter Testlauf
|
### Omniflo (omniflo_tests.json)
|
||||||
|
|
||||||
```bash
|
Testfaelle basieren auf echten Sivas-Nummern (Boegen und Zusatzmodule).
|
||||||
# Umgebung setzen
|
Beispiele: `821104025`, `821104025+0_B10090`, `821104025+0_B10091`, ...
|
||||||
bin\setenv.bat
|
|
||||||
|
|
||||||
# 1. Testdaten-DXF erzeugen (Python, optional wenn Basis-DXF benoetigt)
|
|
||||||
python tests/create_testbase.py
|
|
||||||
|
|
||||||
# 2. BricsCAD starten und Tests ausfuehren
|
|
||||||
# In BricsCAD: TESTRUN "kreisel"
|
|
||||||
# In BricsCAD: TESTRUN "vario"
|
|
||||||
# In BricsCAD: TESTRUN "omniflo"
|
|
||||||
|
|
||||||
# 3. Python-Validierung
|
|
||||||
pytest tests/ -v
|
|
||||||
```
|
|
||||||
|
|
||||||
### Nur Python-Validierung (ohne BricsCAD)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Setzt voraus, dass output/ bereits erzeugt wurde
|
|
||||||
pytest tests/ -v
|
|
||||||
```
|
|
||||||
|
|
||||||
### Einzelnes Modul testen
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pytest tests/test_kreisel.py -v
|
|
||||||
```
|
|
||||||
|
|
||||||
## Umgebungsvariablen
|
## Umgebungsvariablen
|
||||||
|
|
||||||
| Variable | Pfad | Beschreibung |
|
Werden via `bin\setenv.bat` gesetzt. Fuer Tests relevant:
|
||||||
|---|---|---|
|
|
||||||
| `DXFM_TESTS` | `<DXFMAKRO>/tests` | Test-Wurzelverzeichnis |
|
| Variable | Beschreibung |
|
||||||
| `DXFM_TESTDATA` | `<DXFMAKRO>/tests/testdata` | JSON-Testdefinitionen |
|
| --- | --- |
|
||||||
| `DXFM_TESTOUT` | `<DXFMAKRO>/tests/output` | Generierte Ergebnisse |
|
| `DXFMAKRO` | Projektwurzel |
|
||||||
| `DXFM_TESTREF` | `<DXFMAKRO>/tests/reference` | Abgenommene Referenzen |
|
| `DXFM_TESTS` | tests/-Verzeichnis |
|
||||||
|
| `DXFM_TESTDATA` | testdata/-Verzeichnis |
|
||||||
|
| `DXFM_TESTOUT` | output/-Verzeichnis |
|
||||||
|
| `DXFM_TESTREF` | reference/-Verzeichnis |
|
||||||
|
| `DXFM_OMNIFLO` | Pfad zu Omniflo-DXF-Dateien |
|
||||||
|
|
||||||
## Abhaengigkeiten
|
## Abhaengigkeiten
|
||||||
|
|
||||||
### Python (tests/requirements.txt)
|
### Python (tests/requirements.txt)
|
||||||
|
|
||||||
```
|
```text
|
||||||
ezdxf>=1.0
|
ezdxf>=1.0
|
||||||
pytest>=7.0
|
pytest>=7.0
|
||||||
```
|
```
|
||||||
@@ -240,34 +287,13 @@ pytest>=7.0
|
|||||||
### AutoLISP
|
### AutoLISP
|
||||||
|
|
||||||
- SSG_LIB muss geladen sein (Menue per `_MENULOAD` eingerichtet, siehe CLAUDE.md)
|
- SSG_LIB muss geladen sein (Menue per `_MENULOAD` eingerichtet, siehe CLAUDE.md)
|
||||||
- `ssg_testrunner.lsp` wird manuell per `(load "...")` oder ueber das Menue geladen
|
- `test_run_all.lsp` laedt die einzelnen Testrunner automatisch
|
||||||
|
|
||||||
## Modulspezifische Testfaelle
|
## Neuen Test erstellen
|
||||||
|
|
||||||
### Kreisel (kreisel_tests.json)
|
1. **Testdaten**: `testdata/<modul>_tests.json` erstellen (flaches JSON-Array)
|
||||||
|
2. **LISP-Testrunner**: `test_<modul>.lsp` erstellen mit `c:TEST_<MODUL>` und `<modul>:export-results`
|
||||||
|
3. **Testregistry**: Eintrag in `alltests.json` hinzufuegen
|
||||||
|
4. **Python-Validierung** (optional): `test_<modul>.py` und Fixtures in `conftest.py`
|
||||||
|
|
||||||
| Test-ID | Beschreibung | Params |
|
Detailliertes Vorgehen und Codevorlagen: siehe `tests/README.md`.
|
||||||
|---|---|---|
|
|
||||||
| KR_Horiz_ObenUnten | Horizontaler Kreisel, oben nach unten | rot=270, art=STANDARD |
|
|
||||||
| KR_Horiz_UntenOben | Horizontaler Kreisel, unten nach oben | rot=90, art=PIN |
|
|
||||||
| KR_Vert_LinksRechts | Vertikaler Kreisel, links nach rechts | rot=0, art=PIN |
|
|
||||||
| KR_Vert_RechtsLinks | Vertikaler Kreisel, rechts nach links | rot=180, art=STANDARD |
|
|
||||||
| KR_Insert_Schraeg | Kreisel mit 10 Grad Drehung | rot=10, abstand=6000 |
|
|
||||||
|
|
||||||
### Vario (vario_tests.json)
|
|
||||||
|
|
||||||
| Test-ID | Beschreibung | Params |
|
|
||||||
|---|---|---|
|
|
||||||
| VF_Gerade_1Segment | Einzelnes gerades Segment | laenge=2000 |
|
|
||||||
| VF_Gerade_3Segmente | Drei gerade Segmente | laenge=6000 |
|
|
||||||
| VF_Gefaelle_Standard | Gefaellestrecke Standard | hoehe=500 |
|
|
||||||
| VF_Bogen_Links | Linksbogen | winkel=90 |
|
|
||||||
| VF_Bogen_Rechts | Rechtsbogen | winkel=-90 |
|
|
||||||
|
|
||||||
### Omniflo (omniflo_tests.json)
|
|
||||||
|
|
||||||
| Test-ID | Beschreibung | Params |
|
|
||||||
|---|---|---|
|
|
||||||
| OM_Bogen_90 | 90-Grad Bogen | winkel=90 |
|
|
||||||
| OM_Weiche_Links | Linksweiche | seite=L |
|
|
||||||
| OM_Weiche_Rechts | Rechtsweiche | seite=R |
|
|
||||||
|
|||||||
+60
-9
@@ -103,7 +103,18 @@ def build_kreisel_details(block):
|
|||||||
# --- Bekannte Bloecke ignorieren ---
|
# --- Bekannte Bloecke ignorieren ---
|
||||||
SKIP_BLOCKS = {"K1", "K2", "K3", "K4", "KS_EIN", "KS_AUS"}
|
SKIP_BLOCKS = {"K1", "K2", "K3", "K4", "KS_EIN", "KS_AUS"}
|
||||||
|
|
||||||
VARIO_BLOCKS = {
|
# Sivas-Nummern und Bezeichnungen je ILS-Elementtyp
|
||||||
|
ILS_SIVASNR = {
|
||||||
|
"kreisel": ("6200", "ILS 2.0 Kreisel"),
|
||||||
|
"eckrad": ("6210", "ILS 2.0 Eckrad"),
|
||||||
|
"zusatzmodul":("6215", "ILS 2.0 Zusatzmodul"),
|
||||||
|
"ils_weiche": ("6216", "ILS 2.0 Weichen"),
|
||||||
|
"strecke": ("6220", "ILS 2.0 Strecke - Module"),
|
||||||
|
"automation": ("6269", "ILS 2.0 Automation und Pneumatik - Gesamtanlage"),
|
||||||
|
}
|
||||||
|
|
||||||
|
# Strecken-Module: Blocknamen-Fragmente fuer Vario/Staustrecke-Elemente
|
||||||
|
STRECKE_BLOCKS = {
|
||||||
"AUS_Element_links", "EIN_Element_links",
|
"AUS_Element_links", "EIN_Element_links",
|
||||||
"Staustrecke_SP_1000_mm", "Staustrecke_Separator_SP_300_mm",
|
"Staustrecke_SP_1000_mm", "Staustrecke_Separator_SP_300_mm",
|
||||||
"Vario_Spannstation_SP_500mm", "Vario_Motorstation_SP_500mm",
|
"Vario_Spannstation_SP_500mm", "Vario_Motorstation_SP_500mm",
|
||||||
@@ -233,9 +244,14 @@ def process_blocks(blocks, lookup):
|
|||||||
counters["anzahl_streckengruppen"] = 1
|
counters["anzahl_streckengruppen"] = 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# --- VarioFoerderer ---
|
# --- ILS Eckrad ---
|
||||||
for vb in VARIO_BLOCKS:
|
if bname.startswith("ECKRAD_"):
|
||||||
if vb in bname:
|
counters["anzahl_eckraeder"] += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
# --- ILS Strecke-Module (Vario/Staustrecke) ---
|
||||||
|
for sb in STRECKE_BLOCKS:
|
||||||
|
if sb in bname:
|
||||||
counters["anzahl_variofoerderer"] += 1
|
counters["anzahl_variofoerderer"] += 1
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -286,10 +302,11 @@ def process_blocks(blocks, lookup):
|
|||||||
nr += 1
|
nr += 1
|
||||||
|
|
||||||
for block in kreisel_list:
|
for block in kreisel_list:
|
||||||
|
sivasnr, teileart = ILS_SIVASNR["kreisel"]
|
||||||
items.append({
|
items.append({
|
||||||
"nr": nr,
|
"nr": nr,
|
||||||
"teileart": "ILS 2.0 Kreisel",
|
"teileart": teileart,
|
||||||
"sivasnr": "6200",
|
"sivasnr": sivasnr,
|
||||||
"sivasnr_quoted": True,
|
"sivasnr_quoted": True,
|
||||||
"dispgruppe": 20,
|
"dispgruppe": 20,
|
||||||
"anzahl": 1,
|
"anzahl": 1,
|
||||||
@@ -299,8 +316,41 @@ def process_blocks(blocks, lookup):
|
|||||||
})
|
})
|
||||||
nr += 1
|
nr += 1
|
||||||
|
|
||||||
|
if counters["anzahl_eckraeder"] > 0:
|
||||||
|
sivasnr, teileart = ILS_SIVASNR["eckrad"]
|
||||||
|
items.append({
|
||||||
|
"nr": nr,
|
||||||
|
"teileart": teileart,
|
||||||
|
"sivasnr": sivasnr,
|
||||||
|
"sivasnr_quoted": True,
|
||||||
|
"dispgruppe": 20,
|
||||||
|
"anzahl": counters["anzahl_eckraeder"],
|
||||||
|
"laenge_mm": "",
|
||||||
|
"hoehe_m": "",
|
||||||
|
"details": {},
|
||||||
|
})
|
||||||
|
nr += 1
|
||||||
|
|
||||||
|
if counters["anzahl_variofoerderer"] > 0:
|
||||||
|
sivasnr, teileart = ILS_SIVASNR["strecke"]
|
||||||
|
items.append({
|
||||||
|
"nr": nr,
|
||||||
|
"teileart": teileart,
|
||||||
|
"sivasnr": sivasnr,
|
||||||
|
"sivasnr_quoted": True,
|
||||||
|
"dispgruppe": 20,
|
||||||
|
"anzahl": counters["anzahl_variofoerderer"],
|
||||||
|
"laenge_mm": "",
|
||||||
|
"hoehe_m": "",
|
||||||
|
"details": {},
|
||||||
|
})
|
||||||
|
nr += 1
|
||||||
|
|
||||||
# ILS Automation Summierungszeile (nur wenn ILS-Elemente vorhanden)
|
# ILS Automation Summierungszeile (nur wenn ILS-Elemente vorhanden)
|
||||||
if counters["anzahl_kreisel"] > 0 or counters["anzahl_variofoerderer"] > 0:
|
has_ils = (counters["anzahl_kreisel"] > 0
|
||||||
|
or counters["anzahl_eckraeder"] > 0
|
||||||
|
or counters["anzahl_variofoerderer"] > 0)
|
||||||
|
if has_ils:
|
||||||
automation_details = {
|
automation_details = {
|
||||||
"Anzahl Kreisel": counters["anzahl_kreisel"],
|
"Anzahl Kreisel": counters["anzahl_kreisel"],
|
||||||
"Anzahl Kreisel mit Pinband": counters["anzahl_kreisel_pinband"],
|
"Anzahl Kreisel mit Pinband": counters["anzahl_kreisel_pinband"],
|
||||||
@@ -323,10 +373,11 @@ def process_blocks(blocks, lookup):
|
|||||||
"Anzahl aller BTBeladung": counters["anzahl_btbeladung"],
|
"Anzahl aller BTBeladung": counters["anzahl_btbeladung"],
|
||||||
"Anzahl aller Abwurfstationen": counters["anzahl_abwurfstationen"],
|
"Anzahl aller Abwurfstationen": counters["anzahl_abwurfstationen"],
|
||||||
}
|
}
|
||||||
|
auto_sivasnr, auto_teileart = ILS_SIVASNR["automation"]
|
||||||
items.append({
|
items.append({
|
||||||
"nr": nr,
|
"nr": nr,
|
||||||
"teileart": "ILS 2.0 Automation",
|
"teileart": auto_teileart,
|
||||||
"sivasnr": "6270",
|
"sivasnr": auto_sivasnr,
|
||||||
"sivasnr_quoted": True,
|
"sivasnr_quoted": True,
|
||||||
"dispgruppe": 20,
|
"dispgruppe": 20,
|
||||||
"anzahl": 1,
|
"anzahl": 1,
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
[BTMT-Beladung]^C^C(ssg-ensure "SSG_LIB_Commands") ILS_BTMT_Beladung
|
[BTMT-Beladung]^C^C(ssg-ensure "SSG_LIB_Commands") ILS_BTMT_Beladung
|
||||||
[<-BTMT-Entladung]^C^C(ssg-ensure "SSG_LIB_Commands") ILS_BTMT_Entladung
|
[<-BTMT-Entladung]^C^C(ssg-ensure "SSG_LIB_Commands") ILS_BTMT_Entladung
|
||||||
[->Foerderer]
|
[->Foerderer]
|
||||||
[ETF Etagenfoerderer]^C^CI(ssg-ensure "SSG_LIB_Commands") LS_ETF_Etagenfoerderer
|
|
||||||
[Durch TEF angetriebene Strecke]^C^C(ssg-ensure "SSG_LIB_Commands") ILS_TEF_Strecke
|
[Durch TEF angetriebene Strecke]^C^C(ssg-ensure "SSG_LIB_Commands") ILS_TEF_Strecke
|
||||||
[VarioFoerderer]^C^CVarioFoerderer
|
[VarioFoerderer]^C^CVarioFoerderer
|
||||||
[EtageVarioFoerderer]^C^CETAGEVARIOFOERDERER
|
[EtageVarioFoerderer]^C^CETAGEVARIOFOERDERER
|
||||||
|
|||||||
@@ -36,6 +36,28 @@ def _load_json(path):
|
|||||||
return json.load(f)
|
return json.load(f)
|
||||||
|
|
||||||
|
|
||||||
|
# --- Foerderer Fixtures ---
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def foerderer_testdata():
|
||||||
|
"""Laedt die Foerderer-Testdefinitionen aus testdata/foerderer_tests.json."""
|
||||||
|
path = os.path.join(_testdata_dir(), "foerderer_tests.json")
|
||||||
|
data = _load_json(path)
|
||||||
|
return [t for t in data if "test_id" in t]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def foerderer_results():
|
||||||
|
"""Laedt die Foerderer-Ergebnisse aus output/foerderer_results.json."""
|
||||||
|
path = os.path.join(_output_dir(), "foerderer_results.json")
|
||||||
|
if not os.path.exists(path):
|
||||||
|
pytest.skip("foerderer_results.json nicht vorhanden - TEST_FOERDERER in BricsCAD ausfuehren")
|
||||||
|
data = _load_json(path)
|
||||||
|
if not data:
|
||||||
|
pytest.skip("foerderer_results.json ist leer")
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
# --- Omniflo Fixtures ---
|
# --- Omniflo Fixtures ---
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
Elementnummer;TeileArt;TeileId;Bezeichnung;Anzahl;Merkmale
|
||||||
|
1;"Omniflo Kurve";"0000";"OFBogen :1";1;{"Kurvenwinkel": 22.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104025"}
|
||||||
|
2;"Omniflo Kurve";"0000";"OFBogen :2";1;{"Kurvenwinkel": 22.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104025+0_B10090"}
|
||||||
|
3;"Omniflo Kurve";"0000";"OFBogen :3";1;{"Kurvenwinkel": 22.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104025+0_B10091"}
|
||||||
|
4;"Omniflo Kurve";"0000";"OFBogen :4";1;{"Kurvenwinkel": 45.0, "Radius": 400.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104021"}
|
||||||
|
5;"Omniflo Kurve";"0000";"OFBogen :5";1;{"Kurvenwinkel": 45.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104026"}
|
||||||
|
6;"Omniflo Kurve";"0000";"OFBogen :6";1;{"Kurvenwinkel": 45.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104026+0_B10071"}
|
||||||
|
7;"Omniflo Kurve";"0000";"OFBogen :7";1;{"Kurvenwinkel": 45.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104037"}
|
||||||
|
8;"Omniflo Kurve";"0000";"OFBogen :8";1;{"Kurvenwinkel": 45.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104029"}
|
||||||
|
9;"Omniflo Kurve";"0000";"OFBogen :9";1;{"Kurvenwinkel": 45.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104031"}
|
||||||
|
10;"Omniflo Kurve";"0000";"OFBogen :10";1;{"Kurvenwinkel": 45.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104031+0_B10060"}
|
||||||
|
11;"Omniflo Kurve";"0000";"OFBogen :11";1;{"Kurvenwinkel": 45.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104031+0_B10070"}
|
||||||
|
12;"Omniflo Kurve";"0000";"OFBogen :12";1;{"Kurvenwinkel": 67.5, "Radius": 400.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104024"}
|
||||||
|
13;"Omniflo Kurve";"0000";"OFBogen :13";1;{"Kurvenwinkel": 67.5, "Radius": 400.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104024+0_B10081"}
|
||||||
|
14;"Omniflo Kurve";"0000";"OFBogen :14";1;{"Kurvenwinkel": 67.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104027"}
|
||||||
|
15;"Omniflo Kurve";"0000";"OFBogen :15";1;{"Kurvenwinkel": 67.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104027+0_B10080"}
|
||||||
|
16;"Omniflo Kurve";"0000";"OFBogen :16";1;{"Kurvenwinkel": 67.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104028"}
|
||||||
|
17;"Omniflo Kurve";"0000";"OFBogen :17";1;{"Kurvenwinkel": 67.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104065"}
|
||||||
|
18;"Omniflo Kurve";"0000";"OFBogen :18";1;{"Kurvenwinkel": 90.0, "Radius": 400.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104022"}
|
||||||
|
19;"Omniflo Kurve";"0000";"OFBogen :19";1;{"Kurvenwinkel": 90.0, "Radius": 500.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104030"}
|
||||||
|
20;"Omniflo Kurve";"0000";"OFBogen :20";1;{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104033"}
|
||||||
|
21;"Omniflo Kurve";"0000";"OFBogen :21";1;{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104033+0_B10040"}
|
||||||
|
22;"Omniflo Kurve";"0000";"OFBogen :22";1;{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104033+0_B10050"}
|
||||||
|
23;"Omniflo Kurve";"0000";"OFBogen :23";1;{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104035"}
|
||||||
|
24;"Omniflo Kurve";"0000";"OFBogen :24";1;{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104041"}
|
||||||
|
25;"Omniflo Kurve";"0000";"OFBogen :25";1;{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104034"}
|
||||||
|
26;"Omniflo Kurve";"0000";"OFBogen :26";1;{"Kurvenwinkel": 90.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104066"}
|
||||||
|
27;"Omniflo Kurve";"0000";"OFBogen :27";1;{"Kurvenwinkel": 180.0, "Radius": 650.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104043"}
|
||||||
|
28;"Omniflo Weiche";"0000";"OFWeiche :1";1;{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342011"}
|
||||||
|
29;"Omniflo Weiche";"0000";"OFWeiche :2";1;{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342001"}
|
||||||
|
30;"Omniflo Weiche";"0000";"OFWeiche :3";1;{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342012"}
|
||||||
|
31;"Omniflo Weiche";"0000";"OFWeiche :4";1;{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342002"}
|
||||||
|
32;"Omniflo Weiche";"0000";"OFWeiche :1";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342100"}
|
||||||
|
33;"Omniflo Weiche";"0000";"OFWeiche :2";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342101"}
|
||||||
|
34;"Omniflo Weiche";"0000";"OFWeiche :1";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342200"}
|
||||||
|
35;"Omniflo Weiche";"0000";"OFWeiche :2";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342201"}
|
||||||
|
36;"Omniflo Weiche";"0000";"OFWeiche :5";1;{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372001"}
|
||||||
|
37;"Omniflo Weiche";"0000";"OFWeiche :6";1;{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372002"}
|
||||||
|
38;"Omniflo Weiche";"0000";"OFWeiche :7";1;{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372002+0_BG090090"}
|
||||||
|
39;"Omniflo Weiche";"0000";"OFWeiche :8";1;{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372004"}
|
||||||
|
40;"Omniflo Weiche";"0000";"OFWeiche :9";1;{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372005"}
|
||||||
|
41;"Omniflo Weiche";"0000";"OFWeiche :10";1;{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372005+0_BG090090"}
|
||||||
|
42;"Omniflo Weiche";"0000";"OFWeiche :11";1;{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372007"}
|
||||||
|
43;"Omniflo Weiche";"0000";"OFWeiche :12";1;{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372008"}
|
||||||
|
44;"Omniflo Weiche";"0000";"OFWeiche :13";1;{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372008+0_BG190090"}
|
||||||
|
45;"Omniflo Weiche";"0000";"OFWeiche :14";1;{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372010"}
|
||||||
|
46;"Omniflo Weiche";"0000";"OFWeiche :15";1;{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372011"}
|
||||||
|
47;"Omniflo Weiche";"0000";"OFWeiche :16";1;{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372011+0_BG190090"}
|
||||||
|
48;"Omniflo Weiche";"0000";"OFWeiche :17";1;{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372021"}
|
||||||
|
49;"Omniflo Weiche";"0000";"OFWeiche :18";1;{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372022"}
|
||||||
|
50;"Omniflo Weiche";"0000";"OFWeiche :19";1;{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372024"}
|
||||||
|
51;"Omniflo Weiche";"0000";"OFWeiche :20";1;{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372025"}
|
||||||
|
52;"Omniflo Weiche";"0000";"OFWeiche :21";1;{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372027"}
|
||||||
|
53;"Omniflo Weiche";"0000";"OFWeiche :22";1;{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372028"}
|
||||||
|
54;"Omniflo Weiche";"0000";"OFWeiche :23";1;{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372028+0_BG080090"}
|
||||||
|
55;"Omniflo Weiche";"0000";"OFWeiche :24";1;{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372030"}
|
||||||
|
56;"Omniflo Weiche";"0000";"OFWeiche :25";1;{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372031"}
|
||||||
|
57;"Omniflo Weiche";"0000";"OFWeiche :26";1;{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372031+0_BG080090"}
|
||||||
|
58;"Omniflo Weiche";"0000";"OFWeiche :27";1;{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372047"}
|
||||||
|
59;"Omniflo Weiche";"0000";"OFWeiche :28";1;{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372048"}
|
||||||
|
60;"Omniflo Weiche";"0000";"OFWeiche :29";1;{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372050"}
|
||||||
|
61;"Omniflo Weiche";"0000";"OFWeiche :30";1;{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372051"}
|
||||||
|
62;"Omniflo Weiche";"0000";"OFWeiche :3";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372100"}
|
||||||
|
63;"Omniflo Weiche";"0000";"OFWeiche :4";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372101"}
|
||||||
|
64;"Omniflo Weiche";"0000";"OFWeiche :5";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG090090+834372101"}
|
||||||
|
65;"Omniflo Weiche";"0000";"OFWeiche :6";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372101+0_BG090090"}
|
||||||
|
66;"Omniflo Weiche";"0000";"OFWeiche :7";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG090090+834372101+0_BG090090"}
|
||||||
|
67;"Omniflo Weiche";"0000";"OFWeiche :8";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372103"}
|
||||||
|
68;"Omniflo Weiche";"0000";"OFWeiche :9";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372104"}
|
||||||
|
69;"Omniflo Weiche";"0000";"OFWeiche :10";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG190090+834372104"}
|
||||||
|
70;"Omniflo Weiche";"0000";"OFWeiche :11";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372104+0_BG190090"}
|
||||||
|
71;"Omniflo Weiche";"0000";"OFWeiche :12";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG190090+834372104+0_BG190090"}
|
||||||
|
72;"Omniflo Weiche";"0000";"OFWeiche :13";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372106"}
|
||||||
|
73;"Omniflo Weiche";"0000";"OFWeiche :14";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372107"}
|
||||||
|
74;"Omniflo Weiche";"0000";"OFWeiche :15";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372109"}
|
||||||
|
75;"Omniflo Weiche";"0000";"OFWeiche :16";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372110"}
|
||||||
|
76;"Omniflo Weiche";"0000";"OFWeiche :17";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG080090+834372110"}
|
||||||
|
77;"Omniflo Weiche";"0000";"OFWeiche :18";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372110+0_BG080090"}
|
||||||
|
78;"Omniflo Weiche";"0000";"OFWeiche :19";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG080090+834372110+0_BG080090"}
|
||||||
|
79;"Omniflo Weiche";"0000";"OFWeiche :20";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372115"}
|
||||||
|
80;"Omniflo Weiche";"0000";"OFWeiche :21";1;{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372116"}
|
||||||
|
81;"Omniflo Weiche";"0000";"OFWeiche :3";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372200"}
|
||||||
|
82;"Omniflo Weiche";"0000";"OFWeiche :4";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372201"}
|
||||||
|
83;"Omniflo Weiche";"0000";"OFWeiche :5";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG090090+834372201"}
|
||||||
|
84;"Omniflo Weiche";"0000";"OFWeiche :6";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372201+0_BG090090"}
|
||||||
|
85;"Omniflo Weiche";"0000";"OFWeiche :7";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG090090+834372201+0_BG090090"}
|
||||||
|
86;"Omniflo Weiche";"0000";"OFWeiche :8";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372203"}
|
||||||
|
87;"Omniflo Weiche";"0000";"OFWeiche :9";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372204"}
|
||||||
|
88;"Omniflo Weiche";"0000";"OFWeiche :10";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG190090+834372204"}
|
||||||
|
89;"Omniflo Weiche";"0000";"OFWeiche :11";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372204+0_BG190090"}
|
||||||
|
90;"Omniflo Weiche";"0000";"OFWeiche :12";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG190090+834372204+0_BG190090"}
|
||||||
|
91;"Omniflo Weiche";"0000";"OFWeiche :13";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372206"}
|
||||||
|
92;"Omniflo Weiche";"0000";"OFWeiche :14";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372207"}
|
||||||
|
93;"Omniflo Weiche";"0000";"OFWeiche :15";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372209"}
|
||||||
|
94;"Omniflo Weiche";"0000";"OFWeiche :16";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372210"}
|
||||||
|
95;"Omniflo Weiche";"0000";"OFWeiche :17";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG080090+834372210"}
|
||||||
|
96;"Omniflo Weiche";"0000";"OFWeiche :18";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372210+0_BG080090"}
|
||||||
|
97;"Omniflo Weiche";"0000";"OFWeiche :19";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG080090+834372210+0_BG080090"}
|
||||||
|
98;"Omniflo Weiche";"0000";"OFWeiche :20";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372215"}
|
||||||
|
99;"Omniflo Weiche";"0000";"OFWeiche :21";1;{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372216"}
|
||||||
|
100;"Omniflo Weiche";"0000";"OFWeiche :1";1;{"Weichentyp": "Dreifachweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372400"}
|
||||||
|
101;"Omniflo Weiche";"0000";"OFWeiche :2";1;{"Weichentyp": "Dreifachweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372403"}
|
||||||
|
102;"Omniflo Weiche";"0000";"OFWeiche :3";1;{"Weichentyp": "Dreifachweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372404"}
|
||||||
|
103;"Omniflo Weiche";"0000";"OFWeiche :4";1;{"Weichentyp": "Dreifachweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG071090+834372404+0_BG071090"}
|
||||||
|
104;"Omniflo Weiche";"0000";"OFWeiche :5";1;{"Weichentyp": "Dreifachweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG071090+834372404"}
|
||||||
|
105;"Omniflo Weiche";"0000";"OFWeiche :6";1;{"Weichentyp": "Dreifachweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372404+0_BG071090"}
|
||||||
|
106;"Omniflo Weiche";"0000";"OFWeiche :1";1;{"Weichentyp": "Deltaweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372401"}
|
||||||
|
107;"Omniflo Weiche";"0000";"OFWeiche :1";1;{"Weichentyp": "Sternweiche", "Richtung": "3", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372420"}
|
||||||
|
Can't render this file because it contains an unexpected character in line 2 and column 42.
|
+69
-65
@@ -1,10 +1,9 @@
|
|||||||
;; ============================================================
|
;; ============================================================
|
||||||
;; test_foerderer.lsp - Automatischer Integrationstest fuer VarioFoerderer
|
;; test_foerderer.lsp - Automatischer Integrationstest fuer VarioFoerderer
|
||||||
;;
|
;;
|
||||||
;; Erzeugt 12 Variofoerderer (6x Auf, 6x Ab) mit deltaL=7000
|
;; Liest Testfaelle aus tests/testdata/foerderer_tests.json.
|
||||||
;; und verschiedenen Hoehenstufen. Speichert:
|
;; Speichert:
|
||||||
;; - tests/output/foerderer_results.json (Ergebnisse)
|
;; - tests/output/foerderer_results.json (Ergebnisse)
|
||||||
;; - tests/output/foerderer_tests.dwg (Zeichnung)
|
|
||||||
;;
|
;;
|
||||||
;; Voraussetzungen:
|
;; Voraussetzungen:
|
||||||
;; - SSG_LIB geladen (VarioFoerderer.lsp, ssg_core.lsp)
|
;; - SSG_LIB geladen (VarioFoerderer.lsp, ssg_core.lsp)
|
||||||
@@ -70,12 +69,13 @@
|
|||||||
;; ============================================================
|
;; ============================================================
|
||||||
;; C:TEST_FOERDERER - Hauptbefehl
|
;; C:TEST_FOERDERER - Hauptbefehl
|
||||||
;; ============================================================
|
;; ============================================================
|
||||||
(defun c:TEST_FOERDERER ( / deltaL deltaH richtung ergebnis
|
(defun c:TEST_FOERDERER ( / json-datei testdaten cfg tests
|
||||||
best-winkel L_GF L_VF
|
eintrag test-id richtung deltaL deltaH
|
||||||
y-offset hoehen-liste idx
|
ergebnis best-winkel L_GF L_VF
|
||||||
anz-gebaut anz-nicht-gebaut
|
y-offset y-abstand idx
|
||||||
results-list
|
anz-gebaut anz-nicht-gebaut results-list
|
||||||
test-id)
|
startpunkt vf-nummer hoehe-von hoehe-bis lastEnt
|
||||||
|
tests-out-dir old-dxfm-results)
|
||||||
|
|
||||||
;; Bibliothek initialisieren (laedt Block-Library und extrahiert Masse)
|
;; Bibliothek initialisieren (laedt Block-Library und extrahiert Masse)
|
||||||
(if (not *lib-initialized*)
|
(if (not *lib-initialized*)
|
||||||
@@ -87,8 +87,30 @@
|
|||||||
(setvar "ATTREQ" 0)
|
(setvar "ATTREQ" 0)
|
||||||
(setvar "ATTDIA" 0)
|
(setvar "ATTDIA" 0)
|
||||||
|
|
||||||
(setq deltaL 7000)
|
;; Testdaten aus JSON laden
|
||||||
(setq hoehen-liste '(0 1000 2000 3000 4000 5000))
|
(setq json-datei
|
||||||
|
(strcat (getenv "DXFMAKRO")
|
||||||
|
"\\tests\\testdata\\foerderer_tests.json"))
|
||||||
|
(setq testdaten (ssg-load-json json-datei))
|
||||||
|
(if (null testdaten)
|
||||||
|
(progn
|
||||||
|
(alert (strcat "Testdaten nicht gefunden:\n" json-datei))
|
||||||
|
(ssg-end)
|
||||||
|
(exit)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Konfiguration aus erstem Eintrag (ohne test_id)
|
||||||
|
(setq cfg (car testdaten))
|
||||||
|
(setq y-abstand (ssg-val cfg "y_abstand"))
|
||||||
|
(if (or (null y-abstand) (= y-abstand 0)) (setq y-abstand 400))
|
||||||
|
|
||||||
|
;; Nur Eintraege mit test_id sind Testfaelle
|
||||||
|
(setq tests
|
||||||
|
(vl-remove-if-not
|
||||||
|
'(lambda (e) (ssg-val e "test_id"))
|
||||||
|
testdaten))
|
||||||
|
|
||||||
(setq y-offset 0)
|
(setq y-offset 0)
|
||||||
(setq idx 0)
|
(setq idx 0)
|
||||||
(setq results-list '())
|
(setq results-list '())
|
||||||
@@ -99,66 +121,26 @@
|
|||||||
(princ "\n================================================================")
|
(princ "\n================================================================")
|
||||||
(princ "\n TEST_FOERDERER - Variofoerderer Integrationstest")
|
(princ "\n TEST_FOERDERER - Variofoerderer Integrationstest")
|
||||||
(princ "\n================================================================")
|
(princ "\n================================================================")
|
||||||
(princ (strcat "\n Distanz dL = " (rtos deltaL 2 0) " mm"))
|
(princ (strcat "\n Testdaten: " json-datei))
|
||||||
(princ "\n Hoehenstufen: 0, 1000, 2000, 3000, 4000, 5000 mm")
|
(princ (strcat "\n Testfaelle: " (itoa (length tests))))
|
||||||
(princ "\n Richtungen: Auf + Ab")
|
(princ (strcat "\n Y-Abstand: " (rtos y-abstand 2 0) " mm"))
|
||||||
(princ "\n================================================================")
|
(princ "\n================================================================")
|
||||||
|
|
||||||
;; ==========================================================
|
;; ==========================================================
|
||||||
;; TEIL 1: Aufwaerts-Tests (6 Foerderer)
|
;; Alle Testfaelle aus JSON ausfuehren
|
||||||
;; ==========================================================
|
;; ==========================================================
|
||||||
(foreach deltaH hoehen-liste
|
(foreach eintrag tests
|
||||||
|
(setq test-id (ssg-val eintrag "test_id"))
|
||||||
|
(setq richtung (ssg-val eintrag "richtung"))
|
||||||
|
(setq deltaL (float (ssg-val eintrag "deltaL")))
|
||||||
|
(setq deltaH (float (ssg-val eintrag "deltaH")))
|
||||||
(setq idx (1+ idx))
|
(setq idx (1+ idx))
|
||||||
(setq richtung "Auf")
|
|
||||||
(setq test-id (strcat "VF_Auf_" (rtos deltaH 2 0)))
|
|
||||||
|
|
||||||
(setq ergebnis (berechne-alle-winkel deltaL deltaH richtung))
|
;; Geometrisch unmoeglich: Ab mit deltaH=0
|
||||||
(setq best-winkel (car ergebnis))
|
(if (and (= richtung "Ab") (< deltaH 1))
|
||||||
(setq L_GF (cadr ergebnis))
|
|
||||||
(setq L_VF (caddr ergebnis))
|
|
||||||
|
|
||||||
(if (and best-winkel L_GF L_VF (> L_GF 0) (> L_VF 0))
|
|
||||||
(progn
|
|
||||||
(setq anz-gebaut (1+ anz-gebaut))
|
|
||||||
(princ (strcat "\n " (itoa idx) ". " test-id " -> GEBAUT "
|
|
||||||
(itoa best-winkel) " Grad L_GF=" (rtos L_GF 2 1)
|
|
||||||
" L_VF=" (rtos L_VF 2 1)))
|
|
||||||
|
|
||||||
(variofoerderer-einfuegen deltaL deltaH richtung best-winkel
|
|
||||||
(/ L_GF 2.0) (/ L_GF 2.0) L_VF
|
|
||||||
(list 0 y-offset 0) "links" idx 0)
|
|
||||||
|
|
||||||
(setq results-list (cons
|
|
||||||
(foerderer:test-result-json test-id richtung deltaL deltaH
|
|
||||||
"GEBAUT" best-winkel L_GF L_VF)
|
|
||||||
results-list))
|
|
||||||
)
|
|
||||||
(progn
|
|
||||||
(setq anz-nicht-gebaut (1+ anz-nicht-gebaut))
|
|
||||||
(princ (strcat "\n " (itoa idx) ". " test-id " -> NICHT_GEBAUT"))
|
|
||||||
|
|
||||||
(setq results-list (cons
|
|
||||||
(foerderer:test-result-json test-id richtung deltaL deltaH
|
|
||||||
"NICHT_GEBAUT" nil nil nil)
|
|
||||||
results-list))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(setq y-offset (- y-offset 200))
|
|
||||||
)
|
|
||||||
|
|
||||||
;; ==========================================================
|
|
||||||
;; TEIL 2: Abwaerts-Tests (6 Foerderer)
|
|
||||||
;; ==========================================================
|
|
||||||
(foreach deltaH hoehen-liste
|
|
||||||
(setq idx (1+ idx))
|
|
||||||
(setq richtung "Ab")
|
|
||||||
(setq test-id (strcat "VF_Ab_" (rtos deltaH 2 0)))
|
|
||||||
|
|
||||||
(if (< deltaH 1)
|
|
||||||
(progn
|
(progn
|
||||||
(setq anz-nicht-gebaut (1+ anz-nicht-gebaut))
|
(setq anz-nicht-gebaut (1+ anz-nicht-gebaut))
|
||||||
(princ (strcat "\n " (itoa idx) ". " test-id " -> GEOMETRISCH_UNMOEGLICH"))
|
(princ (strcat "\n " (itoa idx) ". " test-id " -> GEOMETRISCH_UNMOEGLICH"))
|
||||||
|
|
||||||
(setq results-list (cons
|
(setq results-list (cons
|
||||||
(foerderer:test-result-json test-id richtung deltaL deltaH
|
(foerderer:test-result-json test-id richtung deltaL deltaH
|
||||||
"GEOMETRISCH_UNMOEGLICH" nil nil nil)
|
"GEOMETRISCH_UNMOEGLICH" nil nil nil)
|
||||||
@@ -177,9 +159,17 @@
|
|||||||
(itoa best-winkel) " Grad L_GF=" (rtos L_GF 2 1)
|
(itoa best-winkel) " Grad L_GF=" (rtos L_GF 2 1)
|
||||||
" L_VF=" (rtos L_VF 2 1)))
|
" L_VF=" (rtos L_VF 2 1)))
|
||||||
|
|
||||||
|
(setq startpunkt (list 0 y-offset 0))
|
||||||
|
(setq vf-nummer idx)
|
||||||
|
(setq hoehe-von 0)
|
||||||
|
(setq hoehe-bis (if (= richtung "Auf") deltaH (- deltaH)))
|
||||||
|
(setq lastEnt (entlast))
|
||||||
(variofoerderer-einfuegen deltaL deltaH richtung best-winkel
|
(variofoerderer-einfuegen deltaL deltaH richtung best-winkel
|
||||||
(/ L_GF 2.0) (/ L_GF 2.0) L_VF
|
(/ L_GF 2.0) (/ L_GF 2.0) L_VF
|
||||||
(list 0 y-offset 0) "links" idx 0)
|
startpunkt "links")
|
||||||
|
(vf-block-erstellen "standard" "links" vf-nummer 0
|
||||||
|
hoehe-von hoehe-bis deltaH deltaL L_VF L_GF
|
||||||
|
richtung best-winkel startpunkt lastEnt)
|
||||||
|
|
||||||
(setq results-list (cons
|
(setq results-list (cons
|
||||||
(foerderer:test-result-json test-id richtung deltaL deltaH
|
(foerderer:test-result-json test-id richtung deltaL deltaH
|
||||||
@@ -189,7 +179,6 @@
|
|||||||
(progn
|
(progn
|
||||||
(setq anz-nicht-gebaut (1+ anz-nicht-gebaut))
|
(setq anz-nicht-gebaut (1+ anz-nicht-gebaut))
|
||||||
(princ (strcat "\n " (itoa idx) ". " test-id " -> NICHT_GEBAUT"))
|
(princ (strcat "\n " (itoa idx) ". " test-id " -> NICHT_GEBAUT"))
|
||||||
|
|
||||||
(setq results-list (cons
|
(setq results-list (cons
|
||||||
(foerderer:test-result-json test-id richtung deltaL deltaH
|
(foerderer:test-result-json test-id richtung deltaL deltaH
|
||||||
"NICHT_GEBAUT" nil nil nil)
|
"NICHT_GEBAUT" nil nil nil)
|
||||||
@@ -198,7 +187,7 @@
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
(setq y-offset (- y-offset 200))
|
(setq y-offset (- y-offset y-abstand))
|
||||||
)
|
)
|
||||||
|
|
||||||
;; ==========================================================
|
;; ==========================================================
|
||||||
@@ -212,6 +201,21 @@
|
|||||||
;; Ergebnisse in globaler Variable speichern
|
;; Ergebnisse in globaler Variable speichern
|
||||||
(setq *foerderer-test-results* (reverse results-list))
|
(setq *foerderer-test-results* (reverse results-list))
|
||||||
|
|
||||||
|
;; CSV- und Sivas-Export nach tests/output/
|
||||||
|
(setq tests-out-dir (strcat (getenv "DXFMAKRO") "/tests/output"))
|
||||||
|
(vl-mkdir tests-out-dir)
|
||||||
|
(setq old-dxfm-results (getenv "DXFM_RESULTS"))
|
||||||
|
(setenv "DXFM_RESULTS" tests-out-dir)
|
||||||
|
|
||||||
|
(princ "\n================================================================")
|
||||||
|
(princ "\n[TEST_FOERDERER] CSV-Export -> foerderer_export.csv")
|
||||||
|
(csv:run-export "FOERDERER_CSV" "export_csv.py" "foerderer_export.csv")
|
||||||
|
|
||||||
|
(princ "\n[TEST_FOERDERER] Sivas-Export -> foerderer_sivas.csv")
|
||||||
|
(csv:run-export "FOERDERER_SIVAS" "export_sivas.py" "foerderer_sivas.csv")
|
||||||
|
|
||||||
|
(setenv "DXFM_RESULTS" (if old-dxfm-results old-dxfm-results ""))
|
||||||
|
|
||||||
(ssg-end)
|
(ssg-end)
|
||||||
(princ "\n================================================================")
|
(princ "\n================================================================")
|
||||||
(princ "\n TEST_FOERDERER abgeschlossen.")
|
(princ "\n TEST_FOERDERER abgeschlossen.")
|
||||||
|
|||||||
@@ -0,0 +1,340 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
test_foerderer.py - Validiert VarioFoerderer Testergebnisse.
|
||||||
|
|
||||||
|
Prueft:
|
||||||
|
1. Status-Werte und Vollstaendigkeit (foerderer_results.json)
|
||||||
|
2. Mathematische Invarianten (Laengen, Winkel, Richtung)
|
||||||
|
3. Geometrisch unmoegliche Faelle
|
||||||
|
4. CSV-Export-Struktur (foerderer_export.csv, falls vorhanden)
|
||||||
|
5. Sivas-Export-Struktur (foerderer_sivas.csv, falls vorhanden)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import csv
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Hilfsfunktionen
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def _testdata_dir():
|
||||||
|
return os.getenv("DXFM_TESTDATA",
|
||||||
|
os.path.join(os.path.dirname(os.path.abspath(__file__)), "testdata"))
|
||||||
|
|
||||||
|
|
||||||
|
def _output_dir():
|
||||||
|
return os.getenv("DXFM_TESTOUT",
|
||||||
|
os.path.join(os.path.dirname(os.path.abspath(__file__)), "output"))
|
||||||
|
|
||||||
|
|
||||||
|
def _load_json(path):
|
||||||
|
with open(path, "r", encoding="utf-8") as f:
|
||||||
|
return json.load(f)
|
||||||
|
|
||||||
|
|
||||||
|
def _load_foerderer_results():
|
||||||
|
path = os.path.join(_output_dir(), "foerderer_results.json")
|
||||||
|
if not os.path.exists(path):
|
||||||
|
pytest.skip(
|
||||||
|
"foerderer_results.json nicht vorhanden - "
|
||||||
|
"TEST_FOERDERER in BricsCAD ausfuehren"
|
||||||
|
)
|
||||||
|
return _load_json(path)
|
||||||
|
|
||||||
|
|
||||||
|
def _load_foerderer_testdata():
|
||||||
|
path = os.path.join(_testdata_dir(), "foerderer_tests.json")
|
||||||
|
return _load_json(path)
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Klasse 1: Status und Vollstaendigkeit
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class TestFoerdererStatus:
|
||||||
|
"""Prueft Status-Werte und Vollstaendigkeit der Ergebnisse."""
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def setup(self):
|
||||||
|
self.results = _load_foerderer_results()
|
||||||
|
testdata = _load_foerderer_testdata()
|
||||||
|
self.tests = [t for t in testdata if "test_id" in t]
|
||||||
|
self.results_by_id = {r["test_id"]: r for r in self.results}
|
||||||
|
|
||||||
|
def test_alle_testfaelle_vorhanden(self):
|
||||||
|
"""Alle Testfaelle muessen in den Ergebnissen vorhanden sein."""
|
||||||
|
expected_ids = {t["test_id"] for t in self.tests}
|
||||||
|
result_ids = {r["test_id"] for r in self.results}
|
||||||
|
missing = expected_ids - result_ids
|
||||||
|
assert not missing, f"Fehlende Testfaelle in Ergebnissen: {missing}"
|
||||||
|
|
||||||
|
def test_status_werte_gueltig(self):
|
||||||
|
"""Status muss GEBAUT, NICHT_GEBAUT oder GEOMETRISCH_UNMOEGLICH sein."""
|
||||||
|
gueltige_status = {"GEBAUT", "NICHT_GEBAUT", "GEOMETRISCH_UNMOEGLICH"}
|
||||||
|
for r in self.results:
|
||||||
|
assert r["status"] in gueltige_status, (
|
||||||
|
f'{r["test_id"]}: Unbekannter Status "{r["status"]}"'
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_geometrisch_unmoeglich_ab_ohne_hoehe(self):
|
||||||
|
"""VF_Ab_0 (Abwaerts ohne Hoehenunterschied) muss GEOMETRISCH_UNMOEGLICH sein."""
|
||||||
|
r = self.results_by_id.get("VF_Ab_0")
|
||||||
|
assert r is not None, "VF_Ab_0 fehlt in den Ergebnissen"
|
||||||
|
assert r["status"] == "GEOMETRISCH_UNMOEGLICH", (
|
||||||
|
f'VF_Ab_0: erwartet GEOMETRISCH_UNMOEGLICH, ist "{r["status"]}"'
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_aufwaerts_flach_gebaut(self):
|
||||||
|
"""VF_Auf_0 (Aufwaerts, kein Hoehenunterschied) muss GEBAUT sein."""
|
||||||
|
r = self.results_by_id.get("VF_Auf_0")
|
||||||
|
assert r is not None, "VF_Auf_0 fehlt in den Ergebnissen"
|
||||||
|
assert r["status"] == "GEBAUT", (
|
||||||
|
f'VF_Auf_0: erwartet GEBAUT, ist "{r["status"]}"'
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_mindestens_ein_gebaut(self):
|
||||||
|
"""Mindestens ein Testfall muss GEBAUT sein."""
|
||||||
|
gebaut = [r for r in self.results if r["status"] == "GEBAUT"]
|
||||||
|
assert len(gebaut) > 0, "Kein einziger Foerderer konnte gebaut werden"
|
||||||
|
|
||||||
|
def test_richtung_vorhanden(self):
|
||||||
|
"""Jedes Ergebnis muss das Feld 'richtung' enthalten."""
|
||||||
|
for r in self.results:
|
||||||
|
assert "richtung" in r, f'{r["test_id"]}: Feld "richtung" fehlt'
|
||||||
|
assert r["richtung"] in ("Auf", "Ab"), (
|
||||||
|
f'{r["test_id"]}: Richtung "{r["richtung"]}" ist nicht "Auf" oder "Ab"'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Klasse 2: Mathematische Invarianten
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class TestFoerdererMathematik:
|
||||||
|
"""Prueft mathematische Korrektheit der berechneten Werte."""
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def setup(self):
|
||||||
|
self.results = _load_foerderer_results()
|
||||||
|
self.gebaut = [r for r in self.results if r["status"] == "GEBAUT"]
|
||||||
|
|
||||||
|
def test_gebaut_hat_winkel_und_laengen(self):
|
||||||
|
"""GEBAUT-Ergebnisse muessen winkel, L_GF und L_VF enthalten."""
|
||||||
|
for r in self.gebaut:
|
||||||
|
assert "winkel" in r, f'{r["test_id"]}: Feld "winkel" fehlt'
|
||||||
|
assert "L_GF" in r, f'{r["test_id"]}: Feld "L_GF" fehlt'
|
||||||
|
assert "L_VF" in r, f'{r["test_id"]}: Feld "L_VF" fehlt'
|
||||||
|
|
||||||
|
def test_laengen_positiv(self):
|
||||||
|
"""L_GF und L_VF muessen beide groesser als 0 sein."""
|
||||||
|
for r in self.gebaut:
|
||||||
|
assert r["L_GF"] > 0, (
|
||||||
|
f'{r["test_id"]}: L_GF={r["L_GF"]} muss > 0 sein'
|
||||||
|
)
|
||||||
|
assert r["L_VF"] > 0, (
|
||||||
|
f'{r["test_id"]}: L_VF={r["L_VF"]} muss > 0 sein'
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_winkel_gueltig(self):
|
||||||
|
"""Winkel muss aus dem festen Satz gueltiger Foerderer-Winkel stammen."""
|
||||||
|
gueltige_winkel = {9, 15, 21, 27, 33, 39, 45, 51}
|
||||||
|
for r in self.gebaut:
|
||||||
|
assert r["winkel"] in gueltige_winkel, (
|
||||||
|
f'{r["test_id"]}: Winkel={r["winkel"]} nicht in {sorted(gueltige_winkel)}'
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_aufwaerts_groesserer_deltaH_groesserer_winkel(self):
|
||||||
|
"""Aufwaerts: groesserer Hoehenunterschied erfordert groesseren oder gleichen Winkel."""
|
||||||
|
aufwaerts_gebaut = sorted(
|
||||||
|
[r for r in self.results if r["richtung"] == "Auf" and r["status"] == "GEBAUT"],
|
||||||
|
key=lambda r: r["deltaH"]
|
||||||
|
)
|
||||||
|
for i in range(1, len(aufwaerts_gebaut)):
|
||||||
|
prev = aufwaerts_gebaut[i - 1]
|
||||||
|
curr = aufwaerts_gebaut[i]
|
||||||
|
assert curr["winkel"] >= prev["winkel"], (
|
||||||
|
f'{curr["test_id"]}: Winkel={curr["winkel"]} < '
|
||||||
|
f'vorheriger Winkel={prev["winkel"]} bei groesserem deltaH'
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_kein_winkel_bei_nicht_gebaut(self):
|
||||||
|
"""NICHT_GEBAUT und GEOMETRISCH_UNMOEGLICH duerfen keinen Winkel haben."""
|
||||||
|
for r in self.results:
|
||||||
|
if r["status"] in ("NICHT_GEBAUT", "GEOMETRISCH_UNMOEGLICH"):
|
||||||
|
assert "winkel" not in r, (
|
||||||
|
f'{r["test_id"]}: Status={r["status"]} hat unerwartet Winkel'
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_deltaH_und_deltaL_vorhanden(self):
|
||||||
|
"""Alle Ergebnisse muessen deltaH und deltaL enthalten."""
|
||||||
|
for r in self.results:
|
||||||
|
assert "deltaH" in r, f'{r["test_id"]}: Feld "deltaH" fehlt'
|
||||||
|
assert "deltaL" in r, f'{r["test_id"]}: Feld "deltaL" fehlt'
|
||||||
|
assert r["deltaL"] > 0, f'{r["test_id"]}: deltaL muss > 0 sein'
|
||||||
|
assert r["deltaH"] >= 0, f'{r["test_id"]}: deltaH muss >= 0 sein'
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Klasse 3: CSV-Export-Pruefung (foerderer_export.csv)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class TestFoerdererExportCSV:
|
||||||
|
"""Prueft den CSV-Export aus BricsCAD (foerderer_export.csv)."""
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def setup(self):
|
||||||
|
csv_path = os.path.join(_output_dir(), "foerderer_export.csv")
|
||||||
|
if not os.path.exists(csv_path):
|
||||||
|
pytest.skip(
|
||||||
|
"foerderer_export.csv nicht vorhanden - "
|
||||||
|
"TEST_FOERDERER in BricsCAD ausfuehren (exportiert automatisch)"
|
||||||
|
)
|
||||||
|
self.rows = []
|
||||||
|
with open(csv_path, "r", encoding="utf-8") as f:
|
||||||
|
reader = csv.reader(f, delimiter=";")
|
||||||
|
self.header = next(reader)
|
||||||
|
for row in reader:
|
||||||
|
self.rows.append(row)
|
||||||
|
|
||||||
|
def test_header_felder(self):
|
||||||
|
"""CSV-Header muss korrekte Spaltenbezeichnungen haben."""
|
||||||
|
expected = ["Elementnummer", "TeileArt", "TeileId",
|
||||||
|
"Bezeichnung", "Anzahl", "Merkmale"]
|
||||||
|
for i, name in enumerate(expected):
|
||||||
|
assert self.header[i] == name, (
|
||||||
|
f"Header[{i}]: erwartet '{name}', ist '{self.header[i]}'"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_hat_eintraege(self):
|
||||||
|
"""CSV muss mindestens einen Dateneintrag enthalten."""
|
||||||
|
assert len(self.rows) > 0, "foerderer_export.csv enthaelt keine Daten"
|
||||||
|
|
||||||
|
def test_vario_teileart(self):
|
||||||
|
"""Alle Eintraege muessen TeileArt 'VarioFoerderer' haben."""
|
||||||
|
for i, row in enumerate(self.rows):
|
||||||
|
if len(row) < 2:
|
||||||
|
continue
|
||||||
|
assert row[1].strip('"') == "VarioFoerderer", (
|
||||||
|
f"Zeile {i + 2}: TeileArt='{row[1]}', erwartet 'VarioFoerderer'"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_anzahl_spalte_ist_eins(self):
|
||||||
|
"""Anzahl-Spalte muss fuer alle Zeilen '1' sein."""
|
||||||
|
for i, row in enumerate(self.rows):
|
||||||
|
if len(row) < 5:
|
||||||
|
continue
|
||||||
|
assert row[4] == "1", (
|
||||||
|
f"Zeile {i + 2}: Anzahl={row[4]}, erwartet 1"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_merkmale_sind_valides_json(self):
|
||||||
|
"""Merkmale-Spalte muss valides JSON enthalten."""
|
||||||
|
for i, row in enumerate(self.rows):
|
||||||
|
if len(row) < 6:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
json.loads(row[5])
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
pytest.fail(f"Zeile {i + 2}: Merkmale ist kein valides JSON: {e}")
|
||||||
|
|
||||||
|
def test_merkmale_felder(self):
|
||||||
|
"""Merkmale muessen alle Pflichtfelder enthalten."""
|
||||||
|
required = {"Typ", "Winkel", "DeltaH_mm", "DeltaL_mm",
|
||||||
|
"L_VF_m", "Hoehe_Von_mm", "Hoehe_Bis_mm"}
|
||||||
|
for i, row in enumerate(self.rows):
|
||||||
|
if len(row) < 6:
|
||||||
|
continue
|
||||||
|
merkmale = json.loads(row[5])
|
||||||
|
missing = required - set(merkmale.keys())
|
||||||
|
assert not missing, (
|
||||||
|
f"Zeile {i + 2}: Fehlende Merkmale-Felder: {missing}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_anzahl_csv_zeilen_entspricht_gebaut(self):
|
||||||
|
"""CSV-Zeilenanzahl muss Anzahl GEBAUT-Testfaellen entsprechen."""
|
||||||
|
results = _load_foerderer_results()
|
||||||
|
anzahl_gebaut = sum(1 for r in results if r["status"] == "GEBAUT")
|
||||||
|
assert len(self.rows) == anzahl_gebaut, (
|
||||||
|
f"CSV hat {len(self.rows)} Zeilen, "
|
||||||
|
f"erwartet {anzahl_gebaut} (Anzahl GEBAUT-Faelle)"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Klasse 4: Sivas-Export-Pruefung (foerderer_sivas.csv)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class TestFoerdererExportSivas:
|
||||||
|
"""Prueft den Sivas-Export aus BricsCAD (foerderer_sivas.csv)."""
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def setup(self):
|
||||||
|
csv_path = os.path.join(_output_dir(), "foerderer_sivas.csv")
|
||||||
|
if not os.path.exists(csv_path):
|
||||||
|
pytest.skip(
|
||||||
|
"foerderer_sivas.csv nicht vorhanden - "
|
||||||
|
"TEST_FOERDERER in BricsCAD ausfuehren (exportiert automatisch)"
|
||||||
|
)
|
||||||
|
self.rows = []
|
||||||
|
with open(csv_path, "r", encoding="utf-8") as f:
|
||||||
|
reader = csv.reader(f, delimiter=";")
|
||||||
|
self.header = next(reader)
|
||||||
|
for row in reader:
|
||||||
|
self.rows.append(row)
|
||||||
|
|
||||||
|
def test_header_felder(self):
|
||||||
|
"""Sivas-CSV-Header muss korrekte Spalten haben."""
|
||||||
|
expected = ["Nr", "TeileArt", "SivasNummer",
|
||||||
|
"Dispgruppe", "Anzahl", "Laenge[mm]", "Hoehe[m]", "details"]
|
||||||
|
for i, name in enumerate(expected):
|
||||||
|
assert self.header[i] == name, (
|
||||||
|
f"Header[{i}]: erwartet '{name}', ist '{self.header[i]}'"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_hat_eintraege(self):
|
||||||
|
"""Sivas-CSV muss mindestens einen Dateneintrag enthalten."""
|
||||||
|
assert len(self.rows) > 0, "foerderer_sivas.csv enthaelt keine Daten"
|
||||||
|
|
||||||
|
def test_strecke_zeile_vorhanden(self):
|
||||||
|
"""Eine Zeile mit TeileArt 'ILS 2.0 Strecke - Module' muss vorhanden sein."""
|
||||||
|
teilearten = [row[1].strip('"') for row in self.rows if len(row) >= 2]
|
||||||
|
assert "ILS 2.0 Strecke - Module" in teilearten, (
|
||||||
|
f"Keine Strecke-Zeile gefunden. Vorhandene: {teilearten}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_automation_zeile_vorhanden(self):
|
||||||
|
"""Eine ILS Automation Summierungszeile muss vorhanden sein."""
|
||||||
|
teilearten = [row[1].strip('"') for row in self.rows if len(row) >= 2]
|
||||||
|
assert "ILS 2.0 Automation und Pneumatik - Gesamtanlage" in teilearten, (
|
||||||
|
f"Keine Automation-Zeile gefunden. Vorhandene: {teilearten}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_details_sind_valides_json(self):
|
||||||
|
"""details-Spalte muss valides JSON enthalten."""
|
||||||
|
for i, row in enumerate(self.rows):
|
||||||
|
if len(row) < 8:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
json.loads(row[7])
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
pytest.fail(f"Zeile {i + 2}: details ist kein valides JSON: {e}")
|
||||||
|
|
||||||
|
def test_automation_details_felder(self):
|
||||||
|
"""Automation-Zeile muss Schluessel-Felder in details haben."""
|
||||||
|
required = {"Anzahl der einzelnen Variofoerderer",
|
||||||
|
"Laengen aller Variofoerderer",
|
||||||
|
"Anzahl aller Separatoren"}
|
||||||
|
for row in self.rows:
|
||||||
|
if len(row) < 8:
|
||||||
|
continue
|
||||||
|
if row[1].strip('"') == "ILS 2.0 Automation und Pneumatik - Gesamtanlage":
|
||||||
|
details = json.loads(row[7])
|
||||||
|
missing = required - set(details.keys())
|
||||||
|
assert not missing, (
|
||||||
|
f"Automation-details: fehlende Felder: {missing}"
|
||||||
|
)
|
||||||
|
break
|
||||||
Vendored
+77
@@ -0,0 +1,77 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"y_abstand": 400
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "VF_Auf_0",
|
||||||
|
"richtung": "Auf",
|
||||||
|
"deltaL": 7000,
|
||||||
|
"deltaH": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "VF_Auf_1000",
|
||||||
|
"richtung": "Auf",
|
||||||
|
"deltaL": 7000,
|
||||||
|
"deltaH": 1000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "VF_Auf_2000",
|
||||||
|
"richtung": "Auf",
|
||||||
|
"deltaL": 7000,
|
||||||
|
"deltaH": 2000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "VF_Auf_3000",
|
||||||
|
"richtung": "Auf",
|
||||||
|
"deltaL": 7000,
|
||||||
|
"deltaH": 3000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "VF_Auf_4000",
|
||||||
|
"richtung": "Auf",
|
||||||
|
"deltaL": 7000,
|
||||||
|
"deltaH": 4000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "VF_Auf_5000",
|
||||||
|
"richtung": "Auf",
|
||||||
|
"deltaL": 7000,
|
||||||
|
"deltaH": 5000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "VF_Ab_0",
|
||||||
|
"richtung": "Ab",
|
||||||
|
"deltaL": 7000,
|
||||||
|
"deltaH": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "VF_Ab_1000",
|
||||||
|
"richtung": "Ab",
|
||||||
|
"deltaL": 7000,
|
||||||
|
"deltaH": 1000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "VF_Ab_2000",
|
||||||
|
"richtung": "Ab",
|
||||||
|
"deltaL": 7000,
|
||||||
|
"deltaH": 2000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "VF_Ab_3000",
|
||||||
|
"richtung": "Ab",
|
||||||
|
"deltaL": 7000,
|
||||||
|
"deltaH": 3000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "VF_Ab_4000",
|
||||||
|
"richtung": "Ab",
|
||||||
|
"deltaL": 7000,
|
||||||
|
"deltaH": 4000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test_id": "VF_Ab_5000",
|
||||||
|
"richtung": "Ab",
|
||||||
|
"deltaL": 7000,
|
||||||
|
"deltaH": 5000
|
||||||
|
}
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user