Compare commits
21 Commits
c356b24fe9
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 2325316dd3 | |||
| 5bfda0abf6 | |||
| 200145eea7 | |||
| c29f13a4ae | |||
| e8c6b17ea9 | |||
| 85132193dd | |||
| 4aae9e153d | |||
| 855a874e4a | |||
| 829fe76d0f | |||
| ab415071c2 | |||
| c8760fb024 | |||
| 5f59433ac8 | |||
| 79ff6794db | |||
| 19282888ee | |||
| 4d09aee02b | |||
| b58e80b79f | |||
| e124272c13 | |||
| 586102cf00 | |||
| 7f81240559 | |||
| d9d398b6fd | |||
| 9a8f0ff374 |
@@ -0,0 +1,78 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## What this project does
|
||||||
|
|
||||||
|
`plant2dxf` reads a RuleDesigner CSV export describing all components of a plant/conveyor system (Kreisel, Gefällestrecke, VarioFörderer, Omniflo, etc.) and generates a DXF drawing of the plant by placing and assembling DXF blocks from library files. Positions come from the CSV's `Planquadrat` column (`X:<val> Y:<val>`, in mm); component-specific properties come from the `Merkmale` JSON column; connections between components come from `NachbarIds`.
|
||||||
|
|
||||||
|
Full functional documentation (CSV format, config format, per-element-type handler behavior, ezdxf usage patterns) lives in [doc/plant2dxf_dokumentation.md](doc/plant2dxf_dokumentation.md) — read it before making non-trivial changes to handler logic, it is much more detailed than this file.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
All commands are run via the `.bat` scripts in `bin/` (Windows only; this project has no `.sh` counterparts). Scripts call `setenv.bat` first, which sets `PROJECT`, `PROJECT_BIN`, `PROJECT_CFG`, `PROJECT_DOC`, `PROJECT_LIB`, `PROJECT_DATA`, `PROJECT_WORK`, `PROJECT_TEST`, `PROJECT_LOG` and creates missing `data/`, `work/`, `log/`, `testdata/` folders.
|
||||||
|
|
||||||
|
```bat
|
||||||
|
bin\install_py.bat REM create .venv and pip install lib/requirements.txt (no-op if .venv exists)
|
||||||
|
bin\manage_interpreter.bat activate REM activate .venv (used internally by other scripts)
|
||||||
|
bin\run_unittests.bat REM run all *_tests.py under lib\Elemente via unittest discover
|
||||||
|
bin\plant2dxf.bat -f <csv-datei> [-c shapes.cfg] [-l blocks.dxf] [-o output.dxf] [-v]
|
||||||
|
```
|
||||||
|
|
||||||
|
`run_unittests.bat` runs `python -m unittest discover -t "%PROJECT%" -s lib\Elemente -p "*_tests.py"` from the project root — tests must be discovered from repo root or the `lib.*` imports break. To run a single test file/case directly (with venv already active):
|
||||||
|
|
||||||
|
```bat
|
||||||
|
python -m unittest lib.Elemente.Kreisel_tests -v
|
||||||
|
python -m unittest lib.Elemente.Kreisel_tests.TestKreiselModell.test_from_merkmale -v
|
||||||
|
```
|
||||||
|
|
||||||
|
Dependencies (`lib/requirements.txt`): `ezdxf==1.4.1`, `svg.path==7.0`, `pydantic>=2.0.0`, plus `ruff` and `black` (line-length 88, target py312 — see `pyproject.toml`).
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Processing pipeline (`lib/plant2dxf.py`)
|
||||||
|
|
||||||
|
1. Load `cfg/shapes.cfg` and `cfg/allgemein.cfg`.
|
||||||
|
2. Create a new empty DXF document (R2018, millimeters).
|
||||||
|
3. `arbeiten_mit_csv.get_nachbar_information(csv_path)` does a full pre-pass over the CSV to build a neighbor map (`strecken_nachbarn`): for every Gefällestrecke/VarioFörderer it resolves which Kreisel/Eckrad/angetriebene Kurve/other VarioFörderer are attached via `NachbarIds`, and captures their rotation, height, position and drehrichtung. This neighbor map drives almost all the geometric decisions downstream.
|
||||||
|
4. Row-by-row over the CSV: parse `TeileArt`/`TeileId`/`Planquadrat`/`Merkmale`, resolve the block library file for that `TeileArt` from `allgemein.cfg` (cached per path so each library is read once), dispatch to a handler function named `handle_<teileart normalized>` (spaces/dots → underscores, lowercased — see `arbeiten_mit_csv.normalize_func_name`), and call it with a `HandlerContext` (`lib/handler_context.py`) bundling `msp`, `teileid`, `merkmale`, `x`, `y`, `doc`, `lib_doc`, `symbols`, `strecken_nachbarn`, `config`, `config_allgemein`.
|
||||||
|
5. Save the DXF to the output path.
|
||||||
|
|
||||||
|
Handler dispatch has special-cased overrides: any `TeileArt` starting with "Omniflo" or "TEF" is routed to `handle_omniflo` regardless of exact name, and "ILS 2.0 Kreisel*" variants all route to `handle_ils_2_0_kreisel`.
|
||||||
|
|
||||||
|
### Handler functions (`lib/plant2dxf.py`)
|
||||||
|
|
||||||
|
One `handle_*` function per `TeileArt`, e.g. `handle_ils_2_0_kreisel`, `handle_ils_2_0_gefaellestrecke`, `handle_ils_2_0_variofoerderer`, `handle_ils_2_0_eckrad`, `handle_ils_2_0_kurve_angetrieben`, `handle_bt___beladung`/`handle_bt___entladung`, `handle_omniflo`. Each handler:
|
||||||
|
- builds a Pydantic element object via `<ElementClass>.from_merkmale(...)` (in `lib/Elemente/`),
|
||||||
|
- inspects `ctx.strecken_nachbarn` to determine how many/which neighbors it's connected to (0, 1, or 2 Kreisel/Eckrad, direct-to-Kreisel vs. via-Stahlband, connected to an angetriebene Kurve needing a Motor-/Umlenkstation),
|
||||||
|
- builds a deterministic, parameter-encoded block name (e.g. `Ils_2.0_Gefaellestrecke_{laenge}_{hoehe}_{hat_umlenk}_{hat_motor}_{tefkurve}_...`) and only constructs the block geometry via `doc.blocks.new(...)` if that exact name doesn't already exist in `doc.blocks` — this is the project's block-deduplication/caching strategy, and reusing it correctly for any new variant is essential to avoid duplicate block definitions,
|
||||||
|
- inserts the resulting block (or raw lines for simple cases) into the modelspace with `msp.add_blockref(...)`.
|
||||||
|
|
||||||
|
This dispatch/handler structure — and especially the block-name-encodes-geometry-variant caching pattern — is the main thing to understand before adding a new `TeileArt` or modifying connection logic.
|
||||||
|
|
||||||
|
### Element classes (`lib/Elemente/`)
|
||||||
|
|
||||||
|
Pydantic models with geometry/business logic, one per component type: `Kreisel`, `Gefaellestrecke`, `VarioFoerderer`, `Angetriebene_Kurve`, `Eckrad`, `Bt_element`, `Omniflo`. Each has a `<Name>_tests.py` sibling with unittest cases (discovered by `run_unittests.bat`). `VarioFoerderer.py` and `Gefaellestrecke.py` contain the most complex logic (motor/Umlenkstation placement, AS/ES element insertion, rotation across one/two connected Kreisel) — see [doc/VarioFoerderer_Refactoring.md](doc/VarioFoerderer_Refactoring.md) for the design rationale (constants, enums, dataclasses extracted from what was previously an 820-line method).
|
||||||
|
|
||||||
|
### Helper modules (`lib/`)
|
||||||
|
|
||||||
|
- `arbeiten_mit_csv.py` — CSV parsing, `Planquadrat` coordinate extraction, `Merkmale` JSON parsing, the neighbor-analysis pass (`get_nachbar_information`), `TeileArt` → handler-name normalization.
|
||||||
|
- `block_methoden.py` — importing blocks from a library doc into the target doc, block rotation/mirroring (`turn_two_blocks_left`), reading insert color/layer from a library block, attribute helpers.
|
||||||
|
- `as_es_methoden.py` — AS-/ES-Element placement logic for Gefällestrecke (these depend on CSV height-comparison fields and Kreisel connection topology — flagged in the docs as needing review if RuleDesigner's CSV format changes).
|
||||||
|
- `handler_context.py` — the `HandlerContext` dataclass-like container passed to every handler, plus a `create_context_from_row` factory and rich `__str__`/`to_dict` for debugging.
|
||||||
|
- `utils.py` — `check_environment_var` (reads a required env var or exits) and `setup_logger` (timestamped file + console logger under `PROJECT_LOG`).
|
||||||
|
|
||||||
|
### Configuration (`cfg/`)
|
||||||
|
|
||||||
|
- `allgemein.cfg` — maps a `TeileArt`'s family (`[ILS]`, `[Omniflo]`, `[BT]`, `[TEF]`) to a block library filename under `data/block_libraries/`; also holds `[LOG]` format settings. Unmapped `TeileArt` falls back to `data/blocks.dxf`.
|
||||||
|
- `shapes.cfg` — one section per exact `TeileArt` string (must match the CSV column value exactly), listing library block names to place (`items`), their offsets/rotations relative to the computed position, and type-specific parameters (e.g. `asoffset`/`esoffset` for Gefällestrecke, `vario_abstand` for VarioFörderer, `winkel_*` angle constants, Omniflo Sivas-number overrides).
|
||||||
|
|
||||||
|
Both are read fresh per run; there's no schema validation beyond what `configparser` and the handler code assume, so a `TeileArt` typo silently falls through to "no handler found" (logged as a warning, row skipped) rather than erroring.
|
||||||
|
|
||||||
|
### Known fragility (documented in doc/plant2dxf_dokumentation.md)
|
||||||
|
|
||||||
|
The AS/ES-element and height-comparison logic in `as_es_methoden.py`, `lib/plant2dxf.py` (`handle_ils_2_0_gefaellestrecke`, `handle_ils_2_0_variofoerderer`), `lib/Elemente/Gefaellestrecke.py` (`rotation_mit_zwei_verbunden`), and `lib/Elemente/VarioFoerderer.py` (`vario_verbuden_am_kreisel`) all assume the current RuleDesigner CSV column set and semantics. If the CSV export format changes, these are the first places to check.
|
||||||
|
|
||||||
|
## Directories not under version control
|
||||||
|
|
||||||
|
`data/`, `work/`, `log/` are gitignored (generated/input working data, log files with timestamped names). `testdata/` holds committed CSV+DXF fixture pairs used for manual/reference comparison, separate from the `lib/Elemente/*_tests.py` unittest suite.
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
@echo off
|
||||||
|
CALL setenv.bat
|
||||||
|
|
||||||
|
echo ========================================
|
||||||
|
echo Creating all test DXF files from testdata
|
||||||
|
echo Output directory: %PROJECT_WORK%
|
||||||
|
echo ========================================
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM Track if any errors occurred
|
||||||
|
set ERRORS_OCCURRED=0
|
||||||
|
|
||||||
|
REM Iterate through all CSV files in testdata directory
|
||||||
|
for %%f in ("%PROJECT_TEST%\*.csv") do (
|
||||||
|
echo Processing: %%~nxf
|
||||||
|
CALL plant2dxf.bat -f "%%f" -o "%PROJECT_WORK%\%%~nf.dxf"
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo ERROR: Failed to process %%~nxf
|
||||||
|
echo.
|
||||||
|
set ERRORS_OCCURRED=1
|
||||||
|
) else (
|
||||||
|
echo SUCCESS: Created %%~nf.dxf in work folder
|
||||||
|
echo.
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
echo ========================================
|
||||||
|
if %ERRORS_OCCURRED%==1 (
|
||||||
|
echo Processing completed with ERRORS!
|
||||||
|
echo ========================================
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
) else (
|
||||||
|
echo All test DXF files processed successfully!
|
||||||
|
echo ========================================
|
||||||
|
pause
|
||||||
|
exit /b 0
|
||||||
|
)
|
||||||
+1
-1
@@ -7,4 +7,4 @@ REM Beispielaufruf mit Parametern:
|
|||||||
REM --in: Ordner mit .dxf-Dateien (optional. Standard: work/converted_dxfs)
|
REM --in: Ordner mit .dxf-Dateien (optional. Standard: work/converted_dxfs)
|
||||||
REM --name: Name der zu erzeugenden Bibliothek
|
REM --name: Name der zu erzeugenden Bibliothek
|
||||||
|
|
||||||
python %PROJECT_LIB%\dxf2lib.py %*
|
"%VIRTUAL_ENV%\Scripts\python.exe" %PROJECT_LIB%\dxf2lib.py %*
|
||||||
|
|||||||
+25
-21
@@ -1,30 +1,34 @@
|
|||||||
@echo off
|
@echo off
|
||||||
CALL setenv.bat
|
CALL setenv.bat
|
||||||
IF DEFINED NETWORK_INTERPRETER_PATH (
|
|
||||||
goto %~1_network
|
|
||||||
|
|
||||||
|
IF /I "%1"=="activate" GOTO activate
|
||||||
|
IF /I "%1"=="deactivate" GOTO deactivate
|
||||||
|
GOTO :eof
|
||||||
|
|
||||||
|
|
||||||
|
:activate
|
||||||
|
REM Interpreter wählen
|
||||||
|
IF DEFINED NETWORK_PYTHON (
|
||||||
|
SET PYTHON_EXE=%NETWORK_PYTHON%\python.exe
|
||||||
) ELSE (
|
) ELSE (
|
||||||
goto %~1_local
|
SET PYTHON_EXE=python
|
||||||
)
|
)
|
||||||
|
|
||||||
:activate_interpreter_local
|
REM venv sicherstellen
|
||||||
IF NOT EXIST %PROJECT%\.venv CALL %PROJECT_BIN%\install_py.bat
|
IF NOT EXIST "%PROJECT%\.venv" (
|
||||||
CALL %PROJECT%\.venv\Scripts\activate.bat
|
"%PYTHON_EXE%" -m venv "%PROJECT%\.venv"
|
||||||
goto :eof
|
)
|
||||||
|
|
||||||
:deactivate_interpreter_local
|
REM venv aktivieren
|
||||||
deactivate
|
CALL "%PROJECT%\.venv\Scripts\activate.bat"
|
||||||
goto :eof
|
|
||||||
|
|
||||||
:activate_interpreter_network
|
REM Interpreter festnageln
|
||||||
SET OLD_PATH=%PATH%
|
SET VIRTUAL_ENV_PYTHON=%PYTHON_EXE%
|
||||||
SET PATH=%NETWORK_INTERPRETER_PATH%;%PATH%
|
GOTO :eof
|
||||||
CALL %PROJECT%\.venv\Scripts\activate.bat
|
|
||||||
goto :eof
|
|
||||||
|
|
||||||
:deactivate_interpreter_network
|
|
||||||
SET PATH=%OLD_PATH%
|
:deactivate
|
||||||
SET OLD_PATH=
|
CALL "%PROJECT%\.venv\Scripts\deactivate.bat"
|
||||||
SET NETWORK_INTERPRETER_PATH=
|
SET VIRTUAL_ENV_PYTHON=
|
||||||
CALL %PROJECT%\.venv\Scripts\deactivate.bat
|
GOTO :eof
|
||||||
goto :eof
|
echo off
|
||||||
|
|||||||
+17
-3
@@ -1,4 +1,18 @@
|
|||||||
@echo off
|
@echo off
|
||||||
CALL manage_interpreter.bat activate_interpreter
|
CALL manage_interpreter.bat activate
|
||||||
python %PROJECT_LIB%\plant2dxf.py %*
|
if errorlevel 1 (
|
||||||
CALL manage_interpreter.bat deactivate_interpreter
|
echo ERROR: Failed to activate Python environment
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
cd /d "%PROJECT%"
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo ERROR: Failed to change to project directory: %PROJECT%
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
"%VIRTUAL_ENV%\Scripts\python.exe" -m lib.plant2dxf %*
|
||||||
|
set PYTHON_EXIT=%ERRORLEVEL%
|
||||||
|
|
||||||
|
CALL manage_interpreter.bat deactivate
|
||||||
|
exit /b %PYTHON_EXIT%
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
@echo off
|
||||||
|
CALL setenv.bat
|
||||||
|
|
||||||
|
echo ========================================
|
||||||
|
echo running all unittests in lib\Elemente
|
||||||
|
echo ========================================
|
||||||
|
echo.
|
||||||
|
CALL manage_interpreter.bat activate
|
||||||
|
if %ERRORLEVEL% NEQ 0 (
|
||||||
|
echo.
|
||||||
|
echo Failed to activate the Python interpreter!
|
||||||
|
pause
|
||||||
|
exit /B 1
|
||||||
|
)
|
||||||
|
echo Gefundene Testdateien:
|
||||||
|
for /f "delims=" %%f in ('dir /b "%PROJECT_LIB%\Elemente\*_tests.py" 2^>nul') do echo %%f
|
||||||
|
echo.
|
||||||
|
cd /d "%PROJECT%"
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo ERROR: Failed to change to project directory: %PROJECT%
|
||||||
|
CALL manage_interpreter.bat deactivate
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
"%VIRTUAL_ENV%\Scripts\python.exe" -m unittest discover -t "%PROJECT%" -s lib\Elemente -p "*_tests.py" -v
|
||||||
|
if %ERRORLEVEL% NEQ 0 (
|
||||||
|
echo.
|
||||||
|
echo Tests failed!
|
||||||
|
CALL manage_interpreter.bat deactivate
|
||||||
|
exit /B 1
|
||||||
|
) else (
|
||||||
|
echo.
|
||||||
|
echo All tests passed!
|
||||||
|
CALL manage_interpreter.bat deactivate
|
||||||
|
exit /B 0
|
||||||
|
)
|
||||||
|
|
||||||
@@ -19,6 +19,7 @@ if not exist %PROJECT%\log mkdir %PROJECT%\log
|
|||||||
if not exist %PROJECT%\testdata mkdir %PROJECT%\testdata
|
if not exist %PROJECT%\testdata mkdir %PROJECT%\testdata
|
||||||
|
|
||||||
set PATH=%PROJECT_BIN%;%PATH%
|
set PATH=%PROJECT_BIN%;%PATH%
|
||||||
|
REM set NETWORK_PYTHON=TO_BE_SET
|
||||||
|
|
||||||
|
|
||||||
popd
|
popd
|
||||||
|
|||||||
@@ -25,16 +25,19 @@ esoffset = 479.95
|
|||||||
Umlenkstation = 500.0, 0.0, 0.0
|
Umlenkstation = 500.0, 0.0, 0.0
|
||||||
Motorstation = 500.0, 0.0, 0.0
|
Motorstation = 500.0, 0.0, 0.0
|
||||||
vario_abstand = 66.5
|
vario_abstand = 66.5
|
||||||
|
|
||||||
[Ils 2.0 core winkel]
|
[Ils 2.0 core winkel]
|
||||||
winkel_boegen = 3
|
winkel_boegen = 3
|
||||||
winkel_motor = 3.0
|
winkel_motor = 3.0
|
||||||
winkel_umlenk = 3.0
|
winkel_umlenk = 3.0
|
||||||
winkel_as = 3.0
|
winkel_as = 3.0
|
||||||
winkel_es = 3.0
|
winkel_es = 3.0
|
||||||
|
|
||||||
[Omniflo]
|
[Omniflo]
|
||||||
OFgeradesivas = 821106002
|
OFgeradesivas = 821106002
|
||||||
Tefgeradesivas = 0_B10030
|
Tefgeradesivas = 0_B10030
|
||||||
OFfoerderer = 2
|
OFfoerderer = 2
|
||||||
|
|
||||||
[Scanner_Stoper_namen]
|
[Scanner_Stoper_namen]
|
||||||
Omniflo_stopper = 827062022
|
Omniflo_stopper = 827062022
|
||||||
Omniflo_scanner = _DUMMY_SCANNER
|
Omniflo_scanner = _DUMMY_SCANNER
|
||||||
|
|||||||
+35623
-36239
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,7 @@ Aufgrund möglicher Änderungen im CSV-Dateiformat von RuleDesigner müssen in Z
|
|||||||
|
|
||||||
Die Logik zur Bestimmung und Platzierung von AS- und ES-Elementen bei Gefällestrecken und Vario-Förderern basiert auf dem aktuellen CSV-Format. Bei Änderungen der Datenstruktur oder der verfügbaren Informationen müssen folgende Methoden in `as_es_methoden.py` überprüft und angepasst werden:
|
Die Logik zur Bestimmung und Platzierung von AS- und ES-Elementen bei Gefällestrecken und Vario-Förderern basiert auf dem aktuellen CSV-Format. Bei Änderungen der Datenstruktur oder der verfügbaren Informationen müssen folgende Methoden in `as_es_methoden.py` überprüft und angepasst werden:
|
||||||
|
|
||||||
- `erstellung_gefaelle_block_verbunenden_am_einen()`: Erstellt AS/ES-Elemente für Gefällestrecken, die mit einem Kreisel verbunden sind
|
- `erstellung_gefaelle_block_verbunden_an_einen()`: Erstellt AS/ES-Elemente für Gefällestrecken, die mit einem Kreisel verbunden sind
|
||||||
- `gefaellegerade_erstellung()`: Erstellt AS/ES-Elemente für Gefällestrecken, die mit zwei Kreiseln verbunden sind
|
- `gefaellegerade_erstellung()`: Erstellt AS/ES-Elemente für Gefällestrecken, die mit zwei Kreiseln verbunden sind
|
||||||
- `am_kreisel_direct_verbunden()`: Prüft, ob eine Gefällestrecke/Vario-Förderer direkt mit einem Kreisel verbunden ist (ohne Stahlband)
|
- `am_kreisel_direct_verbunden()`: Prüft, ob eine Gefällestrecke/Vario-Förderer direkt mit einem Kreisel verbunden ist (ohne Stahlband)
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ Die Höhenvergleiche zur Bestimmung der Verbindungsart zwischen Gefällestrecken
|
|||||||
- `handle_ils_2_0_gefaellestrecke()`: Haupt-Handler für Gefällestrecken
|
- `handle_ils_2_0_gefaellestrecke()`: Haupt-Handler für Gefällestrecken
|
||||||
- `handle_ils_2_0_variofoerderer()`: Haupt-Handler für Vario-Förderer
|
- `handle_ils_2_0_variofoerderer()`: Haupt-Handler für Vario-Förderer
|
||||||
|
|
||||||
**Gefällestrecke-Methoden (`lib/Elemente/Gefaehllestrecke.py`):**
|
**Gefällestrecke-Methoden (`lib/Elemente/Gefaellestrecke.py`):**
|
||||||
|
|
||||||
- `rotation_mit_zwei_verbunden()`: Berechnet Rotation bei Verbindung mit zwei Kreiseln (verwendet Höhenvergleiche)
|
- `rotation_mit_zwei_verbunden()`: Berechnet Rotation bei Verbindung mit zwei Kreiseln (verwendet Höhenvergleiche)
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ Die Höhenvergleiche zur Bestimmung der Verbindungsart zwischen Gefällestrecken
|
|||||||
**Betroffene Dateien:**
|
**Betroffene Dateien:**
|
||||||
- `lib/as_es_methoden.py`: AS/ES-Element-Berechnungen
|
- `lib/as_es_methoden.py`: AS/ES-Element-Berechnungen
|
||||||
- `lib/plant2dxf.py`: Handler-Funktionen für Gefällestrecken und Vario-Förderer
|
- `lib/plant2dxf.py`: Handler-Funktionen für Gefällestrecken und Vario-Förderer
|
||||||
- `lib/Elemente/Gefaehllestrecke.py`: Höhenvergleiche und Verbindungslogik
|
- `lib/Elemente/Gefaellestrecke.py`: Höhenvergleiche und Verbindungslogik
|
||||||
- `lib/Elemente/VarioFoerderer.py`: Höhenvergleiche und Verbindungslogik
|
- `lib/Elemente/VarioFoerderer.py`: Höhenvergleiche und Verbindungslogik
|
||||||
|
|
||||||
## Übersicht
|
## Übersicht
|
||||||
@@ -505,7 +505,7 @@ msp.add_blockref(blockname, (x, y, z), dxfattribs={"rotation": rotation, "layer"
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
msp.add_blockref("ILS_2.0_Gefaellestrecke_8200_2000_UZS_higher",
|
msp.add_blockref("ILS_2.0_Gefaellestrecke_8200_2000_UZS_higher",
|
||||||
(x, y, hoehe_gefaehlle),
|
(x, y, hoehe_gefaelle),
|
||||||
dxfattribs={"rotation": rotation, "layer": "6-SP"})
|
dxfattribs={"rotation": rotation, "layer": "6-SP"})
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -536,13 +536,13 @@ if blockname not in doc.blocks:
|
|||||||
**Beispiel:**
|
**Beispiel:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
blockname = f"Ils_2.0_Gefaellestrecke_{laenge}_{hoehe_gefaehlle}_{hat_motor_0}_{hat_umlenk_0}"
|
blockname = f"Ils_2.0_Gefaellestrecke_{laenge}_{hoehe_gefaelle}_{hat_motor_0}_{hat_umlenk_0}"
|
||||||
if blockname not in doc.blocks:
|
if blockname not in doc.blocks:
|
||||||
block = doc.blocks.new(name=blockname, base_point=(0, 0, 0))
|
block = doc.blocks.new(name=blockname, base_point=(0, 0, 0))
|
||||||
# Füge Komponenten zum Block hinzu
|
# Füge Komponenten zum Block hinzu
|
||||||
block.add_blockref("Vario_Motorstation_500mm", (0, 0, 0))
|
block.add_blockref("Vario_Motorstation_500mm", (0, 0, 0))
|
||||||
line = Line.new(dxfattribs={"start": start, "end": ende})
|
line = Line.new(dxfattribs={"start": start, "end": ende})
|
||||||
line.translate(-x, -y, -hoehe_gefaehlle)
|
line.translate(-x, -y, -hoehe_gefaelle)
|
||||||
block.add_entity(line)
|
block.add_entity(line)
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -733,11 +733,11 @@ Die Methode `hat_motor_umlenk_station()` prüft, ob eine Gefällestrecke eine Mo
|
|||||||
|
|
||||||
**Höhen-basierte Bestimmung:**
|
**Höhen-basierte Bestimmung:**
|
||||||
|
|
||||||
- Wenn `upper_hoehe_gefaehlle > lower_hoehe_gefaehlle`:
|
- Wenn `upper_hoehe_gefaelle > lower_hoehe_gefaelle`:
|
||||||
- Wenn `vario_hoehe_0` oder `vario_hoehe_1 == upper_hoehe_gefaehlle` → `hat_motor_0 = True`
|
- Wenn `vario_hoehe_0` oder `vario_hoehe_1 == upper_hoehe_gefaelle` → `hat_motor_0 = True`
|
||||||
- Sonst → `hat_umlenk_0 = True`
|
- Sonst → `hat_umlenk_0 = True`
|
||||||
- Wenn `upper_hoehe_gefaehlle < lower_hoehe_gefaehlle`:
|
- Wenn `upper_hoehe_gefaelle < lower_hoehe_gefaelle`:
|
||||||
- Wenn `vario_hoehe_0` oder `vario_hoehe_1 == lower_hoehe_gefaehlle` → `hat_motor_0 = True`
|
- Wenn `vario_hoehe_0` oder `vario_hoehe_1 == lower_hoehe_gefaelle` → `hat_motor_0 = True`
|
||||||
- Sonst → `hat_umlenk_0 = True`
|
- Sonst → `hat_umlenk_0 = True`
|
||||||
|
|
||||||
**Rotations-basierte Bestimmung (bei gleicher Höhe):**
|
**Rotations-basierte Bestimmung (bei gleicher Höhe):**
|
||||||
@@ -797,7 +797,7 @@ Die Methode `ein_motor_oder_eine_umlenk()` erstellt die Motor- oder Umlenkstatio
|
|||||||
Der Blockname wird dynamisch generiert:
|
Der Blockname wird dynamisch generiert:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
Ils_2.0_Gefaellestrecke_{laenge}_{hoehe_gefaehlle}_{hat_umlenk_0}_{hat_motor_0}_{tefkurve_0}_{umlenk_gerade}_{motor_gerade}
|
Ils_2.0_Gefaellestrecke_{laenge}_{hoehe_gefaelle}_{hat_umlenk_0}_{hat_motor_0}_{tefkurve_0}_{umlenk_gerade}_{motor_gerade}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 4. Block-Erstellung
|
#### 4. Block-Erstellung
|
||||||
@@ -825,19 +825,19 @@ dy = halbe_laenge * math.cos(0) # dy = halbe_laenge (da cos(0) = 1)
|
|||||||
**Rechts-Version:**
|
**Rechts-Version:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
Vario_Foerderer_{winkel}_{voerder_richtung}_{laenge}_{hoehe_vario}_rechts_{motor_vorhanden}_{umlenk_vorhanden}_{gefaelle}_{gefahellewinkel}
|
Vario_Foerderer_{winkel}_{foerder_richtung}_{laenge}_{hoehe_vario}_rechts_{motor_vorhanden}_{umlenk_vorhanden}_{gefaelle}_{gefahellewinkel}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Links-Version:**
|
**Links-Version:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
Vario_Foerderer_{winkel}_{voerder_richtung}_{laenge}_{hoehe_vario}_links_{motor_vorhanden}_{umlenk_vorhanden}_{gefaelle}_{gefahellewinkel}
|
Vario_Foerderer_{winkel}_{foerder_richtung}_{laenge}_{hoehe_vario}_links_{motor_vorhanden}_{umlenk_vorhanden}_{gefaelle}_{gefahellewinkel}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Parameter:**
|
**Parameter:**
|
||||||
|
|
||||||
- `winkel`: Winkel des Förderers (z.B. 3, 6, 9)
|
- `winkel`: Winkel des Förderers (z.B. 3, 6, 9)
|
||||||
- `voerder_richtung`: Auf, Ab oder Horizontal
|
- `foerder_richtung`: Auf, Ab oder Horizontal
|
||||||
- `laenge`: Länge in mm
|
- `laenge`: Länge in mm
|
||||||
- `hoehe_vario`: Mittlere Höhe ((h0 + h1) / 2)
|
- `hoehe_vario`: Mittlere Höhe ((h0 + h1) / 2)
|
||||||
- `motor_vorhanden`: True/False
|
- `motor_vorhanden`: True/False
|
||||||
@@ -874,7 +874,7 @@ Vario_Foerderer_{winkel}_{voerder_richtung}_{laenge}_{hoehe_vario}_links_{motor_
|
|||||||
foerderer, doc, lib_doc, config,
|
foerderer, doc, lib_doc, config,
|
||||||
block, block_name_links,
|
block, block_name_links,
|
||||||
start, ende,
|
start, ende,
|
||||||
voerder_richtung,
|
foerder_richtung,
|
||||||
winkel_VP_offset_vorne, # None, da keine Verbindung
|
winkel_VP_offset_vorne, # None, da keine Verbindung
|
||||||
winkel_VP_offset_hinten # None, da keine Verbindung
|
winkel_VP_offset_hinten # None, da keine Verbindung
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,18 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Angetriebene_Kurve — Modell für angetriebene Kurven.
|
||||||
|
|
||||||
|
Refactoring-Änderungen:
|
||||||
|
- antrieb-Property Side-Effect entfernt: Normalisierung "Aussen"→"außen" etc.
|
||||||
|
wird nun beim Erstellen durch @field_validator erledigt
|
||||||
|
- antrieb-Property ist jetzt ein reiner read-only Getter
|
||||||
|
"""
|
||||||
from pydantic import BaseModel, Field, field_validator
|
from pydantic import BaseModel, Field, field_validator
|
||||||
|
|
||||||
|
|
||||||
class Angetriebene_Kurve(BaseModel):
|
class Angetriebene_Kurve(BaseModel):
|
||||||
|
"""Modell für eine angetriebene Kurve."""
|
||||||
|
|
||||||
teileid: str
|
teileid: str
|
||||||
x: float
|
x: float
|
||||||
y: float
|
y: float
|
||||||
@@ -9,21 +20,52 @@ class Angetriebene_Kurve(BaseModel):
|
|||||||
hoehe0: float = Field(default=0.0, description="Hoehe Anfang der Kurve")
|
hoehe0: float = Field(default=0.0, description="Hoehe Anfang der Kurve")
|
||||||
hoehe1: float = Field(default=0.0, description="Hoehe Ende der Kurve")
|
hoehe1: float = Field(default=0.0, description="Hoehe Ende der Kurve")
|
||||||
kurvenrichtung: str = Field(description="Kurvenrichtung der Kurve")
|
kurvenrichtung: str = Field(description="Kurvenrichtung der Kurve")
|
||||||
antriebNebenStrecke: str =Field(description="wo die Angetriebene Strecke ist abhängig von der kurvenrichtung")
|
antriebNebenStrecke: str = Field(
|
||||||
|
description="wo die Angetriebene Strecke ist abhängig von der kurvenrichtung"
|
||||||
|
)
|
||||||
winkel: int = Field(description="Der Winkel der Kurve")
|
winkel: int = Field(description="Der Winkel der Kurve")
|
||||||
|
|
||||||
|
@field_validator("antriebNebenStrecke", mode="before")
|
||||||
|
@classmethod
|
||||||
|
def normalize_antrieb(cls, v):
|
||||||
|
"""
|
||||||
|
Normalisiert die Antrieb-Bezeichnung beim Erstellen.
|
||||||
|
|
||||||
|
Konvertiert englische/gemischte Schreibvarianten in
|
||||||
|
die konsistente deutsche Kleinbuchstaben-Form.
|
||||||
|
|
||||||
|
"Aussen" → "außen", "Innen" → "innen"
|
||||||
|
"""
|
||||||
|
if isinstance(v, str):
|
||||||
|
mapping = {"Aussen": "außen", "Innen": "innen"}
|
||||||
|
return mapping.get(v, v)
|
||||||
|
return v
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def antrieb(self):
|
def antrieb(self) -> str:
|
||||||
if self.antriebNebenStrecke == "Aussen":
|
"""Antrieb-Seite (read-only, normalisiert beim Erstellen)."""
|
||||||
self.antriebNebenStrecke = "außen"
|
|
||||||
elif self.antriebNebenStrecke == "Innen":
|
|
||||||
self.antriebNebenStrecke = "innen"
|
|
||||||
return self.antriebNebenStrecke
|
return self.antriebNebenStrecke
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hight_zwischen(self):
|
def hight_zwischen(self):
|
||||||
return ((self.hoehe0 + self.hoehe1) /2)
|
"""Mittlere Höhe zwischen hoehe0 und hoehe1."""
|
||||||
|
return (self.hoehe0 + self.hoehe1) / 2
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_merkmale(cls, teileid: str, x: float, y: float, merkmale: dict) -> 'Angetriebene_Kurve':
|
def from_merkmale(
|
||||||
|
cls, teileid: str, x: float, y: float, merkmale: dict
|
||||||
|
) -> "Angetriebene_Kurve":
|
||||||
|
"""
|
||||||
|
Erstellt Angetriebene_Kurve aus einem Merkmale-Dictionary.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
teileid: Teile-Identifikator
|
||||||
|
x, y: Koordinaten in mm
|
||||||
|
merkmale: Dictionary mit Eigenschaftswerten
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Angetriebene_Kurve-Instanz
|
||||||
|
"""
|
||||||
hoehe0 = float(merkmale.get("Höhe Anfang")) * 1000
|
hoehe0 = float(merkmale.get("Höhe Anfang")) * 1000
|
||||||
hoehe1 = float(merkmale.get("Höhe Ende")) * 1000
|
hoehe1 = float(merkmale.get("Höhe Ende")) * 1000
|
||||||
winkel = int(merkmale.get("Kurvenwinkel"))
|
winkel = int(merkmale.get("Kurvenwinkel"))
|
||||||
@@ -31,7 +73,7 @@ class Angetriebene_Kurve(BaseModel):
|
|||||||
antriebNebenstrecke = merkmale.get("AntriebNebenStrecke")
|
antriebNebenstrecke = merkmale.get("AntriebNebenStrecke")
|
||||||
try:
|
try:
|
||||||
drehung = float(merkmale.get("Drehung"))
|
drehung = float(merkmale.get("Drehung"))
|
||||||
except Exception as e:
|
except (TypeError, ValueError):
|
||||||
drehung = 0.0
|
drehung = 0.0
|
||||||
|
|
||||||
return cls(
|
return cls(
|
||||||
@@ -43,6 +85,5 @@ class Angetriebene_Kurve(BaseModel):
|
|||||||
hoehe1=hoehe1,
|
hoehe1=hoehe1,
|
||||||
kurvenrichtung=kurvenrichtung,
|
kurvenrichtung=kurvenrichtung,
|
||||||
antriebNebenStrecke=antriebNebenstrecke,
|
antriebNebenStrecke=antriebNebenstrecke,
|
||||||
winkel = winkel
|
winkel=winkel,
|
||||||
|
|
||||||
)
|
)
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Unit-Tests für Angetriebene_Kurve (Refactored)
|
||||||
|
"""
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from .Angetriebene_Kurve import Angetriebene_Kurve
|
||||||
|
|
||||||
|
|
||||||
|
class TestAngetriebeneKurveModell(unittest.TestCase):
|
||||||
|
"""Tests für das Angetriebene_Kurve Modell."""
|
||||||
|
|
||||||
|
def test_from_merkmale(self):
|
||||||
|
merkmale = {
|
||||||
|
"Höhe Anfang": "1.5",
|
||||||
|
"Höhe Ende": "2.0",
|
||||||
|
"Kurvenwinkel": "90",
|
||||||
|
"Kurvenrichtung": "links",
|
||||||
|
"AntriebNebenStrecke": "außen",
|
||||||
|
"Drehung": "-270",
|
||||||
|
}
|
||||||
|
obj = Angetriebene_Kurve.from_merkmale("AK-001", 100.0, 200.0, merkmale)
|
||||||
|
self.assertEqual(obj.teileid, "AK-001")
|
||||||
|
self.assertEqual(obj.hoehe0, 1500.0)
|
||||||
|
self.assertEqual(obj.hoehe1, 2000.0)
|
||||||
|
self.assertEqual(obj.winkel, 90)
|
||||||
|
self.assertEqual(obj.kurvenrichtung, "links")
|
||||||
|
self.assertEqual(obj.drehung, -270.0)
|
||||||
|
|
||||||
|
def test_from_merkmale_drehung_fehlend(self):
|
||||||
|
merkmale = {
|
||||||
|
"Höhe Anfang": "1.0",
|
||||||
|
"Höhe Ende": "1.0",
|
||||||
|
"Kurvenwinkel": "45",
|
||||||
|
"Kurvenrichtung": "rechts",
|
||||||
|
"AntriebNebenStrecke": "innen",
|
||||||
|
}
|
||||||
|
obj = Angetriebene_Kurve.from_merkmale("AK-002", 0.0, 0.0, merkmale)
|
||||||
|
self.assertEqual(obj.drehung, 0.0) # None → default
|
||||||
|
|
||||||
|
|
||||||
|
class TestAntriebNormalisierung(unittest.TestCase):
|
||||||
|
"""Tests für die field_validator Normalisierung von antriebNebenStrecke."""
|
||||||
|
|
||||||
|
def test_aussen_normalisiert(self):
|
||||||
|
"""'Aussen' wird beim Erstellen zu 'außen' normalisiert."""
|
||||||
|
obj = Angetriebene_Kurve(
|
||||||
|
teileid="T", x=0, y=0, kurvenrichtung="links",
|
||||||
|
antriebNebenStrecke="Aussen", winkel=90,
|
||||||
|
)
|
||||||
|
self.assertEqual(obj.antriebNebenStrecke, "außen")
|
||||||
|
self.assertEqual(obj.antrieb, "außen")
|
||||||
|
|
||||||
|
def test_innen_normalisiert(self):
|
||||||
|
"""'Innen' wird beim Erstellen zu 'innen' normalisiert."""
|
||||||
|
obj = Angetriebene_Kurve(
|
||||||
|
teileid="T", x=0, y=0, kurvenrichtung="rechts",
|
||||||
|
antriebNebenStrecke="Innen", winkel=45,
|
||||||
|
)
|
||||||
|
self.assertEqual(obj.antriebNebenStrecke, "innen")
|
||||||
|
self.assertEqual(obj.antrieb, "innen")
|
||||||
|
|
||||||
|
def test_bereits_normalisiert_bleibt(self):
|
||||||
|
"""Bereits normalisierte Werte bleiben unverändert."""
|
||||||
|
obj = Angetriebene_Kurve(
|
||||||
|
teileid="T", x=0, y=0, kurvenrichtung="links",
|
||||||
|
antriebNebenStrecke="außen", winkel=90,
|
||||||
|
)
|
||||||
|
self.assertEqual(obj.antriebNebenStrecke, "außen")
|
||||||
|
|
||||||
|
def test_unbekannter_wert_bleibt(self):
|
||||||
|
"""Unbekannte Werte werden nicht verändert."""
|
||||||
|
obj = Angetriebene_Kurve(
|
||||||
|
teileid="T", x=0, y=0, kurvenrichtung="links",
|
||||||
|
antriebNebenStrecke="custom_wert", winkel=90,
|
||||||
|
)
|
||||||
|
self.assertEqual(obj.antriebNebenStrecke, "custom_wert")
|
||||||
|
|
||||||
|
def test_antrieb_property_read_only(self):
|
||||||
|
"""antrieb Property gibt den normierten Wert zurück ohne Side-Effect."""
|
||||||
|
obj = Angetriebene_Kurve(
|
||||||
|
teileid="T", x=0, y=0, kurvenrichtung="links",
|
||||||
|
antriebNebenStrecke="Aussen", winkel=90,
|
||||||
|
)
|
||||||
|
# Mehrfacher Zugriff ändert nichts
|
||||||
|
_ = obj.antrieb
|
||||||
|
_ = obj.antrieb
|
||||||
|
self.assertEqual(obj.antrieb, "außen")
|
||||||
|
|
||||||
|
|
||||||
|
class TestHightZwischen(unittest.TestCase):
|
||||||
|
"""Tests für hight_zwischen Property."""
|
||||||
|
|
||||||
|
def test_mittlere_hoehe(self):
|
||||||
|
obj = Angetriebene_Kurve(
|
||||||
|
teileid="T", x=0, y=0, kurvenrichtung="links",
|
||||||
|
antriebNebenStrecke="außen", winkel=90,
|
||||||
|
hoehe0=1000, hoehe1=3000,
|
||||||
|
)
|
||||||
|
self.assertEqual(obj.hight_zwischen, 2000.0)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
@@ -1,14 +1,19 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
from pydantic import BaseModel, Field, field_validator
|
from pydantic import BaseModel, Field, field_validator
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
class Bt_element(BaseModel):
|
class Bt_element(BaseModel):
|
||||||
"""Das sind beide BTMT Elemente"""
|
"""Das sind beide BTMT Elemente"""
|
||||||
|
|
||||||
teileid: str
|
teileid: str
|
||||||
drehung: Optional[float] = Field(default=0.0, description="Rotation des Elements")
|
drehung: Optional[float] = Field(default=0.0, description="Rotation des Elements")
|
||||||
hoehe: Optional[float] = Field(default=0.0, description="Hoehe des Elements")
|
hoehe: Optional[float] = Field(default=0.0, description="Hoehe des Elements")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_merkmale(cls, teileid: str, x: float, y: float, merkmale: dict) -> 'Bt_element':
|
def from_merkmale(
|
||||||
|
cls, teileid: str, x: float, y: float, merkmale: dict
|
||||||
|
) -> "Bt_element":
|
||||||
try:
|
try:
|
||||||
hoehe = float(merkmale.get("Höhe in Meter"))
|
hoehe = float(merkmale.get("Höhe in Meter"))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -18,10 +23,4 @@ class Bt_element(BaseModel):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
drehung = 0.0
|
drehung = 0.0
|
||||||
|
|
||||||
return cls(
|
return cls(teileid=teileid, x=x, y=y, hoehe=hoehe, drehung=drehung)
|
||||||
teileid = teileid,
|
|
||||||
x = x,
|
|
||||||
y = y,
|
|
||||||
hoehe = hoehe,
|
|
||||||
drehung = drehung
|
|
||||||
)
|
|
||||||
|
|||||||
+134
-34
@@ -1,48 +1,148 @@
|
|||||||
from pydantic import BaseModel, Field, field_validator
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Eckrad — Modell und Erstellungsfunktionen für Eckrad-Komponenten.
|
||||||
|
|
||||||
|
Refactoring-Änderungen:
|
||||||
|
- Hartkodierte Block-Namen durch Konstanten (BLOCK_AN8, BLOCK_RICHTUNGSPFEIL, etc.) ersetzt
|
||||||
|
- @staticmethod auf erstellung_eckrad_richtung
|
||||||
|
- 3x try/except in from_merkmale vereinfacht: drehrichtung braucht kein try/except (dict.get wirft nie)
|
||||||
|
- drehung wird nun korrekt an den Konstruktor übergeben (war vorher gelesen aber nicht weitergegeben)
|
||||||
|
- Hinweis: Modell hat keine x/y-Felder, diese werden von Pydantic ignoriert
|
||||||
|
"""
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
import block_methoden
|
|
||||||
RADIUS = 400
|
from lib import block_methoden
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# KONSTANTEN
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
RADIUS = 400 # Radius der Eckrad-Kreise (mm)
|
||||||
|
BLOCK_AN8 = "AN8" # Grundform-Block für Eckrad
|
||||||
|
BLOCK_RICHTUNGSPFEIL = "Richtungspfeil" # Richtungsanzeiger-Block
|
||||||
|
BLOCK_ECKRAD_UZS = "eckrad_UZS" # Eckrad-Block im Uhrzeigersinn
|
||||||
|
BLOCK_ECKRAD_GUZS = "eckrad_GUZS" # Eckrad-Block gegen Uhrzeigersinn
|
||||||
|
RICHTUNGSPFEIL_OFFSET = 200 # Versatz der Richtungspfeile vom Zentrum (mm)
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# HILFSFUNKTIONEN
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
def _safe_float(value, default=0.0):
|
||||||
|
"""
|
||||||
|
Konvertiert einen Wert zu float mit Fallback.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: Zu konvertierender Wert (kann None sein)
|
||||||
|
default: Rückgabewert bei Fehler
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Float-Wert oder default
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if value is None:
|
||||||
|
return default
|
||||||
|
return float(value)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# ECKRAD KLASSE
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
|
||||||
class Eckrad(BaseModel):
|
class Eckrad(BaseModel):
|
||||||
|
"""Modell für Eckrad-Komponenten."""
|
||||||
|
|
||||||
teileid: str
|
teileid: str
|
||||||
drehung: Optional[float] = Field(default=0.0, description="Rotation des Elements")
|
drehung: Optional[float] = Field(default=0.0, description="Rotation des Elements")
|
||||||
hoehe: Optional[float] = Field(default=0.0, description="Hoehe des Elements")
|
hoehe: Optional[float] = Field(default=0.0, description="Hoehe des Elements")
|
||||||
drehrichtung: Optional [str] =Field(default=None,description="Richtung des Eckrads")
|
drehrichtung: Optional[str] = Field(
|
||||||
|
default=None, description="Richtung des Eckrads"
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_merkmale(cls, teileid: str, x: float, y: float, merkmale: dict) -> 'Eckrad':
|
def from_merkmale(
|
||||||
try:
|
cls, teileid: str, x: float, y: float, merkmale: dict
|
||||||
hoehe = float(merkmale.get("Höhe in Meter")) * 1000
|
) -> "Eckrad":
|
||||||
except Exception as e:
|
"""
|
||||||
hoehe = 0.0
|
Erstellt Eckrad aus einem Merkmale-Dictionary.
|
||||||
try:
|
|
||||||
drehung = float(merkmale.get("Drehung"))
|
Args:
|
||||||
except Exception as e:
|
teileid: Teile-Identifikator
|
||||||
drehung = 0.0
|
x, y: Koordinaten (werden vom Modell nicht gespeichert)
|
||||||
try:
|
merkmale: Dictionary mit Eigenschaftswerten
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Eckrad-Instanz
|
||||||
|
"""
|
||||||
|
hoehe = _safe_float(merkmale.get("Höhe in Meter"), 0.0) * 1000
|
||||||
|
drehung = _safe_float(merkmale.get("Drehung"), 0.0)
|
||||||
|
# dict.get() wirft keine Ausnahme — kein try/except nötig
|
||||||
drehrichtung = merkmale.get("Drehrichtung")
|
drehrichtung = merkmale.get("Drehrichtung")
|
||||||
except Exception as e:
|
|
||||||
drehrichtung = None
|
|
||||||
return cls(
|
return cls(
|
||||||
teileid=teileid,
|
teileid=teileid,
|
||||||
x = x,
|
|
||||||
y = y,
|
|
||||||
hoehe=hoehe,
|
hoehe=hoehe,
|
||||||
drehrichtung = drehrichtung
|
drehung=drehung,
|
||||||
|
drehrichtung=drehrichtung,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def erstellung_eckrad_richtung(merkmale, doc, lib_doc):
|
def erstellung_eckrad_richtung(merkmale, doc, lib_doc):
|
||||||
block_methoden.import_block("AN8",lib_doc,doc)
|
"""
|
||||||
block_methoden.import_block("Richtungspfeil",lib_doc,doc)
|
Erstellt Eckrad-Blöcke mit Richtungspfeilen (UZS und GUZS).
|
||||||
eckrad_rechts = "eckrad_UZS"
|
|
||||||
eckrad_links = "eckrad_GUZS"
|
Erstellt bei Bedarf neue Blöcke für beide Drehrichtungen,
|
||||||
|
jeder mit dem AN8-Grundform-Block und zwei Richtungspfeilen.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
merkmale: Dictionary mit "Höhe in m"
|
||||||
|
doc: DXF-Dokument
|
||||||
|
lib_doc: Bibliotheks-Dokument
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(eckrad_rechts, eckrad_links, hight): Blocknamen und Höhe in mm
|
||||||
|
"""
|
||||||
|
block_methoden.import_block(BLOCK_AN8, lib_doc, doc)
|
||||||
|
block_methoden.import_block(BLOCK_RICHTUNGSPFEIL, lib_doc, doc)
|
||||||
|
|
||||||
hight = float(merkmale.get("Höhe in m")) * 1000
|
hight = float(merkmale.get("Höhe in m")) * 1000
|
||||||
# Erstellung der Richtungung Blöcke der Eckrads
|
|
||||||
if eckrad_rechts not in doc.blocks:
|
# Blöcke nur erstellen wenn noch nicht vorhanden
|
||||||
block_rechts = doc.blocks.new(name= eckrad_rechts,base_point=(0,0,0))
|
if BLOCK_ECKRAD_UZS not in doc.blocks:
|
||||||
block_links = doc.blocks.new(name= eckrad_links,base_point=(0,0,0))
|
block_rechts = doc.blocks.new(name=BLOCK_ECKRAD_UZS, base_point=(0, 0, 0))
|
||||||
block_rechts.add_blockref("AN8",(0,0,0))
|
block_links = doc.blocks.new(name=BLOCK_ECKRAD_GUZS, base_point=(0, 0, 0))
|
||||||
block_links.add_blockref("AN8",(0,0,0))
|
|
||||||
block_rechts.add_blockref("Richtungspfeil",(0+200,0+ RADIUS,0))
|
# Grundform für beide
|
||||||
block_rechts.add_blockref("Richtungspfeil",(0-200,0- RADIUS,0),dxfattribs={"rotation": 180})
|
block_rechts.add_blockref(BLOCK_AN8, (0, 0, 0))
|
||||||
block_links.add_blockref("Richtungspfeil",(0+200,0- RADIUS,0))
|
block_links.add_blockref(BLOCK_AN8, (0, 0, 0))
|
||||||
block_links.add_blockref("Richtungspfeil",(0-200,0+ RADIUS,0),dxfattribs={"rotation": 180})
|
|
||||||
return eckrad_rechts,eckrad_links,hight
|
# UZS: Pfeile bei (+offset, +RADIUS) und (-offset, -RADIUS)
|
||||||
|
block_rechts.add_blockref(
|
||||||
|
BLOCK_RICHTUNGSPFEIL,
|
||||||
|
(RICHTUNGSPFEIL_OFFSET, RADIUS, 0),
|
||||||
|
)
|
||||||
|
block_rechts.add_blockref(
|
||||||
|
BLOCK_RICHTUNGSPFEIL,
|
||||||
|
(-RICHTUNGSPFEIL_OFFSET, -RADIUS, 0),
|
||||||
|
dxfattribs={"rotation": 180},
|
||||||
|
)
|
||||||
|
|
||||||
|
# GUZS: Pfeile bei (+offset, -RADIUS) und (-offset, +RADIUS)
|
||||||
|
block_links.add_blockref(
|
||||||
|
BLOCK_RICHTUNGSPFEIL,
|
||||||
|
(RICHTUNGSPFEIL_OFFSET, -RADIUS, 0),
|
||||||
|
)
|
||||||
|
block_links.add_blockref(
|
||||||
|
BLOCK_RICHTUNGSPFEIL,
|
||||||
|
(-RICHTUNGSPFEIL_OFFSET, RADIUS, 0),
|
||||||
|
dxfattribs={"rotation": 180},
|
||||||
|
)
|
||||||
|
|
||||||
|
return BLOCK_ECKRAD_UZS, BLOCK_ECKRAD_GUZS, hight
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Unit-Tests für Eckrad (Refactored)
|
||||||
|
"""
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from .Eckrad import Eckrad, _safe_float, BLOCK_AN8, BLOCK_ECKRAD_UZS, BLOCK_ECKRAD_GUZS, RADIUS
|
||||||
|
|
||||||
|
|
||||||
|
class TestSafeFloat(unittest.TestCase):
|
||||||
|
"""Tests für Eckrad _safe_float."""
|
||||||
|
|
||||||
|
def test_normaler_wert(self):
|
||||||
|
self.assertEqual(_safe_float("2.5"), 2.5)
|
||||||
|
|
||||||
|
def test_none_default(self):
|
||||||
|
self.assertEqual(_safe_float(None, 99.0), 99.0)
|
||||||
|
|
||||||
|
def test_ungueltig_default(self):
|
||||||
|
self.assertEqual(_safe_float("abc", 0.0), 0.0)
|
||||||
|
|
||||||
|
|
||||||
|
class TestEckradModell(unittest.TestCase):
|
||||||
|
"""Tests für das Eckrad Modell."""
|
||||||
|
|
||||||
|
def test_from_merkmale_vollstaendig(self):
|
||||||
|
merkmale = {
|
||||||
|
"Höhe in Meter": "3.5",
|
||||||
|
"Drehung": "45",
|
||||||
|
"Drehrichtung": "UZS",
|
||||||
|
}
|
||||||
|
obj = Eckrad.from_merkmale("E-001", 100.0, 200.0, merkmale)
|
||||||
|
self.assertEqual(obj.teileid, "E-001")
|
||||||
|
self.assertEqual(obj.hoehe, 3500.0) # 3.5 * 1000
|
||||||
|
self.assertEqual(obj.drehung, 45.0)
|
||||||
|
self.assertEqual(obj.drehrichtung, "UZS")
|
||||||
|
|
||||||
|
def test_from_merkmale_fehlende_hoehe(self):
|
||||||
|
merkmale = {"Drehung": "90", "Drehrichtung": None}
|
||||||
|
obj = Eckrad.from_merkmale("E-002", 0.0, 0.0, merkmale)
|
||||||
|
self.assertEqual(obj.hoehe, 0.0) # None → default 0
|
||||||
|
|
||||||
|
def test_from_merkmale_fehlende_drehung(self):
|
||||||
|
merkmale = {"Höhe in Meter": "1.0"}
|
||||||
|
obj = Eckrad.from_merkmale("E-003", 0.0, 0.0, merkmale)
|
||||||
|
self.assertEqual(obj.drehung, 0.0) # None → default 0
|
||||||
|
|
||||||
|
def test_drehrichtung_ohne_try_except(self):
|
||||||
|
# drehrichtung = merkmale.get("Drehrichtung") wirft nie
|
||||||
|
merkmale = {"Höhe in Meter": "1.0", "Drehung": "0"}
|
||||||
|
obj = Eckrad.from_merkmale("E-004", 0.0, 0.0, merkmale)
|
||||||
|
self.assertIsNone(obj.drehrichtung)
|
||||||
|
|
||||||
|
|
||||||
|
class TestEckradKonstanten(unittest.TestCase):
|
||||||
|
"""Tests für Eckrad-Konstanten."""
|
||||||
|
|
||||||
|
def test_block_namen(self):
|
||||||
|
self.assertEqual(BLOCK_AN8, "AN8")
|
||||||
|
self.assertEqual(BLOCK_ECKRAD_UZS, "eckrad_UZS")
|
||||||
|
self.assertEqual(BLOCK_ECKRAD_GUZS, "eckrad_GUZS")
|
||||||
|
|
||||||
|
def test_radius(self):
|
||||||
|
self.assertEqual(RADIUS, 400)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
@@ -1,304 +0,0 @@
|
|||||||
|
|
||||||
from pydantic import BaseModel, Field, field_validator
|
|
||||||
import re
|
|
||||||
import plant2dxf
|
|
||||||
import math
|
|
||||||
from ezdxf.math import Matrix44
|
|
||||||
import block_methoden
|
|
||||||
|
|
||||||
|
|
||||||
class Gefaellestrecke(BaseModel):
|
|
||||||
teileid: str
|
|
||||||
x: float = Field(description="X-Koordinate des Foerder-Zentrums")
|
|
||||||
y: float = Field(description="Y-Koordinate des Foerder-Zentrums")
|
|
||||||
laenge:float = Field(description = "Länge des Förderers")
|
|
||||||
h0: float = Field(description="Höhe Unten in Merkmale")
|
|
||||||
h1: float = Field(description="Höhe Oben in Merkmale")
|
|
||||||
drehung: float = Field(default=0.0, description="Drehung an z achse")
|
|
||||||
anzahl_scanner: int = Field(default=0, description="Anzahl der Scanner")
|
|
||||||
anzahl_separatoren: int = Field(default=0, description="Anzahl der Separatoren")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def hight_zwischen(self):
|
|
||||||
return ((self.h0 + self.h1) /2)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_merkmale(cls, teileid: str, x: float, y: float, merkmale: dict) -> 'Gefaellestrecke':
|
|
||||||
h0 = float(merkmale.get("Höhe unten")) * 1000
|
|
||||||
h1 = float(merkmale.get("Höhe oben")) * 1000
|
|
||||||
laenge = float(merkmale.get("Länge in Meter")) * 1000
|
|
||||||
return cls(
|
|
||||||
teileid = teileid,
|
|
||||||
laenge = laenge,
|
|
||||||
x = x,
|
|
||||||
y = y,
|
|
||||||
h0 = h0,
|
|
||||||
h1 =h1,
|
|
||||||
drehung = float(merkmale.get("Drehung")),
|
|
||||||
anzahl_scanner = int(merkmale.get("Anzahl der Scanner")),
|
|
||||||
anzahl_separatoren = int(merkmale.get("Anzahl der Separatoren"))
|
|
||||||
)
|
|
||||||
def erstehlung_von_gefalle_ohne_aussnahmen(msp, x, y, upper_hoehe_gefaehlle, lower_hoehe_gefaehlle, halbe_laenge, winkel):
|
|
||||||
dx = halbe_laenge *math.sin(winkel * -1)
|
|
||||||
dy = halbe_laenge * math.cos(winkel)
|
|
||||||
start = x +dx, y + dy,upper_hoehe_gefaehlle
|
|
||||||
ende = x -dx, y - dy,lower_hoehe_gefaehlle
|
|
||||||
line =msp.add_line(start,ende)
|
|
||||||
line.dxf.layer = "6-SP"
|
|
||||||
def rotation_mit_zwei_verbunden(gefaellestrecke_nachbarn,richtung2, richtung0, am_kreisel, kreisel_verbunden, hight_position):
|
|
||||||
drehung0 =gefaellestrecke_nachbarn.get("Drehung0")
|
|
||||||
drehung1 = gefaellestrecke_nachbarn.get("Drehung1")
|
|
||||||
x0_kreisel = float(gefaellestrecke_nachbarn.get("x0"))
|
|
||||||
y0_kreisel = float(gefaellestrecke_nachbarn.get("y0"))
|
|
||||||
x1_kreisel = float(gefaellestrecke_nachbarn.get("x1"))
|
|
||||||
y1_kreisel = float(gefaellestrecke_nachbarn.get("y1"))
|
|
||||||
|
|
||||||
if richtung2 == "DEFAULT":
|
|
||||||
if richtung0 == "Vertikal":
|
|
||||||
if x0_kreisel < x1_kreisel:
|
|
||||||
position = hight_position + "_links"
|
|
||||||
else:
|
|
||||||
position = hight_position + "_rechts"
|
|
||||||
else:
|
|
||||||
if y0_kreisel > y1_kreisel:
|
|
||||||
position = hight_position + "_higher"
|
|
||||||
else:
|
|
||||||
position = hight_position + "_lower"
|
|
||||||
|
|
||||||
if richtung0 == "Vertikal":
|
|
||||||
if position == "lower_rechts" or position == "higher_links":
|
|
||||||
gefaelle = "links"
|
|
||||||
else:
|
|
||||||
gefaelle = "rechts"
|
|
||||||
elif richtung0 == "Horizontal":
|
|
||||||
if position == "lower_lower" or position == "higher_higher":
|
|
||||||
gefaelle = "oben"
|
|
||||||
else:
|
|
||||||
gefaelle = "unten"
|
|
||||||
# vertausch der drehung und der höhe für die namens gebung des blockes
|
|
||||||
if (position == "higher_rechts" or position == "lower_rechts" or position=="higher_lower" or position== "lower_lower") and drehung0 != drehung1 and am_kreisel == 0:
|
|
||||||
drehung_2 = drehung0
|
|
||||||
drehung0 = drehung1
|
|
||||||
drehung1= drehung_2
|
|
||||||
if hight_position == "higher":
|
|
||||||
hight_position = "lower"
|
|
||||||
else:
|
|
||||||
hight_position = "higher"
|
|
||||||
|
|
||||||
# austausch der werte damit immer davon ausgehen dass der 1 kreisel in unserer Liste am Kreisel verbuden ist
|
|
||||||
if kreisel_verbunden == 1 and am_kreisel ==2:
|
|
||||||
am_kreisel == 1
|
|
||||||
drehung_2 = drehung0
|
|
||||||
drehung0 = drehung1
|
|
||||||
drehung1= drehung_2
|
|
||||||
if hight_position == "higher":
|
|
||||||
hight_position = "lower"
|
|
||||||
else:
|
|
||||||
hight_position = "higher"
|
|
||||||
else:
|
|
||||||
if richtung2 == "Vertikal":
|
|
||||||
if x0_kreisel < x1_kreisel:
|
|
||||||
position = hight_position + "_links"
|
|
||||||
else:
|
|
||||||
position = hight_position + "_rechts"
|
|
||||||
else:
|
|
||||||
if y0_kreisel > y1_kreisel:
|
|
||||||
position = hight_position + "_higher"
|
|
||||||
else:
|
|
||||||
position = hight_position + "_lower"
|
|
||||||
|
|
||||||
if richtung2 == "Vertikal":
|
|
||||||
if position == "lower_rechts" or position == "higher_links":
|
|
||||||
gefaelle = "links"
|
|
||||||
else:
|
|
||||||
gefaelle = "rechts"
|
|
||||||
elif richtung2 == "Horizontal":
|
|
||||||
if position == "lower_lower" or position == "higher_higher":
|
|
||||||
gefaelle = "oben"
|
|
||||||
else:
|
|
||||||
gefaelle = "unten"
|
|
||||||
# austausch der werte damit immer davon ausgehen dass der 1 kreisel in unserer Liste am Kreisel verbuden ist
|
|
||||||
if am_kreisel == 2:
|
|
||||||
am_kreisel = 1
|
|
||||||
drehung_2 = drehung0
|
|
||||||
drehung0 = drehung1
|
|
||||||
drehung1= drehung_2
|
|
||||||
if hight_position == "higher":
|
|
||||||
hight_position = "lower"
|
|
||||||
else:
|
|
||||||
hight_position = "higher"
|
|
||||||
# Erstellung der Rotation
|
|
||||||
if gefaelle == "oben":
|
|
||||||
rotation = 0
|
|
||||||
elif gefaelle == "unten" :
|
|
||||||
rotation = 180
|
|
||||||
elif gefaelle == "links" :
|
|
||||||
rotation = 90
|
|
||||||
elif gefaelle == "rechts" :
|
|
||||||
rotation = 270
|
|
||||||
return rotation,drehung0,drehung1,hight_position
|
|
||||||
def ein_motor_oder_eine_umlenk(x, y,start,ende, doc, lib_doc, hoehe_gefaehlle, block_Vario_Umlenkstation_500mm, block_Vario_Motorstation_500mm, blockname_motor_links, blockname_umlenk_links, hat_motor_0, hat_umlenk_0, tefkurve_0, block,umlenk_gerade,motor_gerade):
|
|
||||||
|
|
||||||
block_Vario_Bogen_auf = (f"Vario_Bogen_auf_3°")
|
|
||||||
block_Vario_Bogen_ab = (f"Vario_Bogen_ab_3°")
|
|
||||||
block_Vario_Bogen_auf_links = (f"Vario_Bogen_auf_3°") + "_links"
|
|
||||||
block_Vario_Bogen_ab_links = (f"Vario_Bogen_ab_3°") + "_links"
|
|
||||||
auf_attrib = block_methoden.import_block(block_Vario_Bogen_auf,lib_doc,doc)
|
|
||||||
ab_attrib = block_methoden.import_block(block_Vario_Bogen_ab,lib_doc,doc)
|
|
||||||
Vario_Bogen_auf_Delta_SP_0 = list(float(att)for att in re.split(r"[;,]", auf_attrib["DELTA_SP_0"]))
|
|
||||||
Vario_Bogen_auf_Delta_SP_1 = list(float(att) for att in re.split(r"[;,]", auf_attrib["DELTA_SP_1"]))
|
|
||||||
Vario_Bogen_ab_Delta_SP_0 = list(float(att) for att in re.split(r"[;,]", ab_attrib["DELTA_SP_0"]))
|
|
||||||
Vario_Bogen_ab_Delta_SP_1 = list(float(att) for att in re.split(r"[;,]", ab_attrib["DELTA_SP_1"]))
|
|
||||||
for i, wert in enumerate(Vario_Bogen_auf_Delta_SP_0):
|
|
||||||
if wert < 0:
|
|
||||||
Vario_Bogen_auf_Delta_SP_0[i] = abs(wert)
|
|
||||||
for i, wert in enumerate(Vario_Bogen_auf_Delta_SP_1):
|
|
||||||
if wert< 0:
|
|
||||||
Vario_Bogen_auf_Delta_SP_1[i] = abs(wert)
|
|
||||||
for i, wert in enumerate(Vario_Bogen_ab_Delta_SP_0):
|
|
||||||
if wert< 0:
|
|
||||||
Vario_Bogen_ab_Delta_SP_0[i] = abs(wert)
|
|
||||||
for i, wert in enumerate(Vario_Bogen_ab_Delta_SP_1):
|
|
||||||
if wert< 0:
|
|
||||||
Vario_Bogen_ab_Delta_SP_1[i] = abs(wert)
|
|
||||||
block_methoden.turn_two_blocks_left(doc, block_Vario_Bogen_auf, block_Vario_Bogen_ab, block_Vario_Bogen_ab_links, block_Vario_Bogen_auf_links)
|
|
||||||
if hat_motor_0 == True:
|
|
||||||
if tefkurve_0 == "links":
|
|
||||||
if motor_gerade == False:
|
|
||||||
block.add_blockref(block_Vario_Bogen_ab_links,(start[0]-x,start[1]-Vario_Bogen_ab_Delta_SP_0[0]-y,start[2]- Vario_Bogen_ab_Delta_SP_0[2]-hoehe_gefaehlle),dxfattribs={"rotation": 270})
|
|
||||||
start = [start[0],start[1]-Vario_Bogen_ab_Delta_SP_0[0]- Vario_Bogen_ab_Delta_SP_1[0],start[2]-Vario_Bogen_ab_Delta_SP_0[2]- Vario_Bogen_ab_Delta_SP_1[2]]
|
|
||||||
block.add_blockref(blockname_motor_links, (start[0]-x,start[1] - 250* math.cos(math.radians(3))-y,start[2] - 250* math.sin(math.radians(3))-hoehe_gefaehlle),dxfattribs={"rotation": 270})
|
|
||||||
start[1]= start[1] - 500* math.cos(math.radians(3))
|
|
||||||
start[2] = start[2] - 500* math.sin(math.radians(3))
|
|
||||||
else:
|
|
||||||
block.add_blockref("Vario_Motorstation_500mm_links", (start[0]-x,start[1] -250 -y,start[2] -hoehe_gefaehlle),dxfattribs={"rotation": 270})
|
|
||||||
start[1]= start[1] - 500
|
|
||||||
|
|
||||||
else:
|
|
||||||
if motor_gerade == False:
|
|
||||||
block.add_blockref(block_Vario_Bogen_ab,(start[0]-x,start[1]-Vario_Bogen_ab_Delta_SP_0[0]-y,start[2]- Vario_Bogen_ab_Delta_SP_0[2]-hoehe_gefaehlle),dxfattribs={"rotation": 270})
|
|
||||||
start = [start[0],start[1]-Vario_Bogen_ab_Delta_SP_0[0]- Vario_Bogen_ab_Delta_SP_1[0],start[2]-Vario_Bogen_ab_Delta_SP_0[2]- Vario_Bogen_ab_Delta_SP_1[2]]
|
|
||||||
block.add_blockref(block_Vario_Motorstation_500mm, (start[0]-x,start[1] - 250* math.cos(math.radians(3))-y,start[2] - 250* math.sin(math.radians(3))-hoehe_gefaehlle),dxfattribs={"rotation": 270})
|
|
||||||
start[1]= start[1] - 500* math.cos(math.radians(3))
|
|
||||||
start[2] = start[2] - 500* math.sin(math.radians(3))
|
|
||||||
else:
|
|
||||||
block.add_blockref("Vario_Motorstation_500mm", (start[0]-x,start[1]- 250 -y,start[2] -hoehe_gefaehlle),dxfattribs={"rotation": 270})
|
|
||||||
start[1]= start[1] - 500
|
|
||||||
|
|
||||||
if hat_umlenk_0 == True:
|
|
||||||
if tefkurve_0 == "links":
|
|
||||||
if umlenk_gerade == False:
|
|
||||||
block.add_blockref(block_Vario_Bogen_auf,(ende[0]-x,ende[1]+Vario_Bogen_auf_Delta_SP_0[0]-y,ende[2] + Vario_Bogen_auf_Delta_SP_0[2]-hoehe_gefaehlle),dxfattribs={"rotation": 90})
|
|
||||||
ende = [ende[0],ende[1]+ Vario_Bogen_auf_Delta_SP_0[0]+ Vario_Bogen_auf_Delta_SP_1[0],ende[2]+Vario_Bogen_auf_Delta_SP_0[2]+ Vario_Bogen_auf_Delta_SP_1[2]]
|
|
||||||
block.add_blockref(blockname_umlenk_links, (ende[0]-x,ende[1] + 250* math.cos(math.radians(3))-y,ende[2] + 250* math.sin(math.radians(3))-hoehe_gefaehlle),dxfattribs={"rotation": 270})
|
|
||||||
|
|
||||||
ende [1]= ende[1] + 500* math.cos(math.radians(3))
|
|
||||||
ende[2] = ende[2] + 500* math.sin(math.radians(3))
|
|
||||||
else:
|
|
||||||
block.add_blockref("Vario_Umlenkstation_500mm_links", (ende[0]-x,ende[1] + 250-y,ende[2] -hoehe_gefaehlle),dxfattribs={"rotation": 270})
|
|
||||||
ende [1]= ende[1] + 500
|
|
||||||
|
|
||||||
else:
|
|
||||||
if umlenk_gerade == False:
|
|
||||||
block.add_blockref(block_Vario_Bogen_auf_links,(ende[0]-x,ende[1]+Vario_Bogen_auf_Delta_SP_0[0]-y,ende[2] + Vario_Bogen_auf_Delta_SP_0[2]-hoehe_gefaehlle),dxfattribs={"rotation": 90})
|
|
||||||
ende = [ende[0],ende[1]+ Vario_Bogen_auf_Delta_SP_0[0]+ Vario_Bogen_auf_Delta_SP_1[0],ende[2]+Vario_Bogen_auf_Delta_SP_0[2]+ Vario_Bogen_auf_Delta_SP_1[2]]
|
|
||||||
block.add_blockref(block_Vario_Umlenkstation_500mm, (ende[0]-x,ende[1] + 250* math.cos(math.radians(3))-y,ende[2] + 250* math.sin(math.radians(3))-hoehe_gefaehlle),dxfattribs={"rotation": 270})
|
|
||||||
ende [1]= ende[1] + 500* math.cos(math.radians(3))
|
|
||||||
ende[2] = ende[2] + 500* math.sin(math.radians(3))
|
|
||||||
else:
|
|
||||||
block.add_blockref("Vario_Umlenkstation_500mm", (ende[0]-x,ende[1] + 250-y,ende[2] -hoehe_gefaehlle),dxfattribs={"rotation": 270})
|
|
||||||
ende [1]= ende[1] + 500
|
|
||||||
return start,ende
|
|
||||||
def hat_motor_umlenk_station (gefaelle_objekt, gefaellestrecke_nachbarn):
|
|
||||||
hat_motor_0 = None
|
|
||||||
hat_motor_1 = None
|
|
||||||
hat_umlenk_0 = None
|
|
||||||
hat_umlenk_1 = None
|
|
||||||
tefkurve_0 = None
|
|
||||||
tefkurve_1 = None
|
|
||||||
umlenk_gerade = False
|
|
||||||
motor_gerade = False
|
|
||||||
upper_hoehe_gefaehlle = gefaelle_objekt.h1
|
|
||||||
lower_hoehe_gefaehlle = gefaelle_objekt.h0
|
|
||||||
rotation = gefaelle_objekt.drehung
|
|
||||||
x = gefaelle_objekt.x
|
|
||||||
y = gefaelle_objekt.y
|
|
||||||
|
|
||||||
if "Kurvenrichtung" in gefaellestrecke_nachbarn:
|
|
||||||
vario_hoehe_0 = float(gefaellestrecke_nachbarn.get("vario_hoehe_0"))
|
|
||||||
vario_hoehe_1 = float(gefaellestrecke_nachbarn.get("vario_hoehe_1"))
|
|
||||||
kurvenrichtung = gefaellestrecke_nachbarn.get("Kurvenrichtung")
|
|
||||||
tefkurve_0 = gefaellestrecke_nachbarn.get("Tefkurve")
|
|
||||||
x_angetrieben = gefaellestrecke_nachbarn.get("X_angetrieben")
|
|
||||||
y_angetrieben = gefaellestrecke_nachbarn.get("Y_angetrieben")
|
|
||||||
x_angetrieben_1 = gefaellestrecke_nachbarn.get("X_angetrieben_1")
|
|
||||||
y_angetrieben_1 = gefaellestrecke_nachbarn.get("Y_angetrieben_1")
|
|
||||||
if (kurvenrichtung == "links" and tefkurve_0 == "außen") or kurvenrichtung == "rechts" and tefkurve_0 == "innen":
|
|
||||||
tefkurve_0 = "rechts"
|
|
||||||
else:
|
|
||||||
tefkurve_0 = "links"
|
|
||||||
|
|
||||||
if upper_hoehe_gefaehlle > lower_hoehe_gefaehlle:
|
|
||||||
if vario_hoehe_0 == upper_hoehe_gefaehlle or vario_hoehe_1 == upper_hoehe_gefaehlle:
|
|
||||||
hat_motor_0 = True
|
|
||||||
else:
|
|
||||||
hat_umlenk_0 = True
|
|
||||||
elif upper_hoehe_gefaehlle < lower_hoehe_gefaehlle:
|
|
||||||
if vario_hoehe_0 == lower_hoehe_gefaehlle or vario_hoehe_1 == lower_hoehe_gefaehlle:
|
|
||||||
hat_motor_0 = True
|
|
||||||
else:
|
|
||||||
hat_umlenk_0 = True
|
|
||||||
else:
|
|
||||||
rotation_zwischen = rotation
|
|
||||||
if rotation_zwischen == 0.0:
|
|
||||||
rotation_zwischen = -360.0
|
|
||||||
if (((-360.0<= rotation_zwischen< -270.0)and y > y_angetrieben) or ((-90.0< rotation< 0.0)and y > y_angetrieben) or
|
|
||||||
((-270.0< rotation_zwischen< -90.0)and y < y_angetrieben) or
|
|
||||||
(rotation == -90.0 and x < x_angetrieben) or ((rotation == -270.0)and x<x_angetrieben)):
|
|
||||||
hat_umlenk_0 = True
|
|
||||||
umlenk_gerade = True
|
|
||||||
else:
|
|
||||||
hat_motor_0 = True
|
|
||||||
motor_gerade = True
|
|
||||||
|
|
||||||
if "Kurvenrichtung_1" in gefaellestrecke_nachbarn:
|
|
||||||
vario_hoehe_0_1 = float(gefaellestrecke_nachbarn.get("vario_hoehe_0_1"))
|
|
||||||
vario_hoehe_1_1 = float(gefaellestrecke_nachbarn.get("vario_hoehe_1_1"))
|
|
||||||
kurvenrichtung_1 = gefaellestrecke_nachbarn.get("Kurvenrichtung_1")
|
|
||||||
tefkurve_1 = gefaellestrecke_nachbarn.get("Tefkurve_1")
|
|
||||||
if (kurvenrichtung_1 == "links" and tefkurve_1 == "außen") or kurvenrichtung_1 == "rechts" and tefkurve_1 == "innen":
|
|
||||||
tefkurve_1 = "rechts"
|
|
||||||
else:
|
|
||||||
tefkurve_1 = "links"
|
|
||||||
if upper_hoehe_gefaehlle > lower_hoehe_gefaehlle:
|
|
||||||
if vario_hoehe_0_1 == upper_hoehe_gefaehlle or vario_hoehe_1_1 == upper_hoehe_gefaehlle:
|
|
||||||
hat_motor_1 = True
|
|
||||||
else:
|
|
||||||
hat_umlenk_1 = True
|
|
||||||
elif upper_hoehe_gefaehlle < lower_hoehe_gefaehlle:
|
|
||||||
if vario_hoehe_0_1 == lower_hoehe_gefaehlle or vario_hoehe_1_1 == lower_hoehe_gefaehlle:
|
|
||||||
hat_motor_1 = True
|
|
||||||
else:
|
|
||||||
hat_umlenk_1 = True
|
|
||||||
else:
|
|
||||||
rotation_zwischen = rotation
|
|
||||||
if rotation_zwischen == 0.0:
|
|
||||||
rotation_zwischen = -360.0
|
|
||||||
if (((-360.0<= rotation_zwischen< -270.0)and y > y_angetrieben_1) or ((-90.0< rotation< 0.0)and y > y_angetrieben_1) or
|
|
||||||
((-270.0< rotation_zwischen< -90.0)and y < y_angetrieben_1) or
|
|
||||||
(rotation == -90.0 and x < x_angetrieben_1) or ((rotation == -270.0)and x<x_angetrieben_1)):
|
|
||||||
hat_umlenk_1 = True
|
|
||||||
umlenk_gerade = True
|
|
||||||
else:
|
|
||||||
hat_motor_1 = True
|
|
||||||
motor_gerade = True
|
|
||||||
hat_zusatz ={}
|
|
||||||
hat_zusatz["hat_motor_0"] = hat_motor_0
|
|
||||||
hat_zusatz["hat_motor_1"] = hat_motor_1
|
|
||||||
hat_zusatz["hat_umlenk_0"] = hat_umlenk_0
|
|
||||||
hat_zusatz["hat_umlenk_1"] = hat_umlenk_1
|
|
||||||
hat_zusatz["tefkurve_0"] = tefkurve_0
|
|
||||||
hat_zusatz["tefkurve_1"] = tefkurve_1
|
|
||||||
hat_zusatz["umlenk_gerade"] = umlenk_gerade
|
|
||||||
hat_zusatz["motor_gerade"] = motor_gerade
|
|
||||||
return hat_zusatz
|
|
||||||
@@ -0,0 +1,621 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Gefaellestrecke — Modell und Hilfsfunktionen für Gefällestrecken.
|
||||||
|
|
||||||
|
Enthält das Pydantic-Modell und statische Methoden zur Erstellung
|
||||||
|
von DXF-Geometrie für Gefällestrecken zwischen Fördererkomponenten.
|
||||||
|
|
||||||
|
Refactoring-Änderungen:
|
||||||
|
- @staticmethod auf alle Methoden, die self nicht nutzen
|
||||||
|
- Bug fix Zeile 112: am_kreisel == 1 → am_kreisel = 1
|
||||||
|
- Duplizierte Logik (Zeilen 69–90 vs 121–141) in _bestimme_position/_bestimme_gefaelle extrahiert
|
||||||
|
- rotation_mit_zwei_verbunden aufgeteilt in Hilfsfunktionen
|
||||||
|
- hat_motor_umlenk_station aufgeteilt: _pruefe_motor_umlenk_an_kurve, _bestimme_tefkurve
|
||||||
|
- ein_motor_oder_eine_umlenk aufgeteilt: _add_station_mit_bogen, _add_station_gerade
|
||||||
|
- Magic Numbers durch Konstanten ersetzt
|
||||||
|
- Dokumentation hinzugefügt
|
||||||
|
"""
|
||||||
|
import math
|
||||||
|
import re
|
||||||
|
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
from lib import block_methoden
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# KONSTANTEN
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
ROTATION_MAP = {"oben": 0, "unten": 180, "links": 90, "rechts": 270}
|
||||||
|
"""Zuordnung von Gefälle-Richtung zu Rotationswinkel in Grad."""
|
||||||
|
|
||||||
|
LAYER_SP = "6-SP"
|
||||||
|
"""DXF-Layer für Seitenprofile."""
|
||||||
|
|
||||||
|
WINKEL_3_GRAD = 3
|
||||||
|
"""Standard-Bogenwinkel in Grad."""
|
||||||
|
|
||||||
|
STATIONS_LAENGE = 500
|
||||||
|
"""Länge einer Motor-/Umlenkstation in mm."""
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# HILFSFUNKTIONEN
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
def _bestimme_position(richtung, x0_kreisel, x1_kreisel, y0_kreisel, y1_kreisel, hight_position):
|
||||||
|
"""
|
||||||
|
Bestimmt die relative Position basierend auf Richtung und Kreiselkoordinaten.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
richtung: "Vertikal" oder "Horizontal"
|
||||||
|
x0_kreisel, y0_kreisel: Koordinaten erstes Kreisel
|
||||||
|
x1_kreisel, y1_kreisel: Koordinaten zweites Kreisel
|
||||||
|
hight_position: "higher" oder "lower"
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Position-String z.B. "higher_links", "lower_rechts"
|
||||||
|
"""
|
||||||
|
if richtung == "Vertikal":
|
||||||
|
suffix = "_links" if x0_kreisel < x1_kreisel else "_rechts"
|
||||||
|
else:
|
||||||
|
suffix = "_higher" if y0_kreisel > y1_kreisel else "_lower"
|
||||||
|
return hight_position + suffix
|
||||||
|
|
||||||
|
|
||||||
|
def _bestimme_gefaelle(richtung, position):
|
||||||
|
"""
|
||||||
|
Bestimmt die Gefälle-Richtung basierend auf Richtung und Position.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
richtung: "Vertikal" oder "Horizontal"
|
||||||
|
position: Position-String (z.B. "lower_rechts")
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Gefälle-Richtung: "links", "rechts", "oben" oder "unten"
|
||||||
|
"""
|
||||||
|
if richtung == "Vertikal":
|
||||||
|
return "links" if position in ("lower_rechts", "higher_links") else "rechts"
|
||||||
|
elif richtung == "Horizontal":
|
||||||
|
return "oben" if position in ("lower_lower", "higher_higher") else "unten"
|
||||||
|
return "links" # Fallback für unbekannte Richtung
|
||||||
|
|
||||||
|
|
||||||
|
def _tausche_drehungen_und_hoehe(drehung0, drehung1, hight_position):
|
||||||
|
"""
|
||||||
|
Tauscht Drehungen und invertiert die Höhe-Position.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(neue_drehung0, neue_drehung1, neue_hight_position)
|
||||||
|
"""
|
||||||
|
neue_hight = "lower" if hight_position == "higher" else "higher"
|
||||||
|
return drehung1, drehung0, neue_hight
|
||||||
|
|
||||||
|
|
||||||
|
def _bestimme_tefkurve(kurvenrichtung, tefkurve):
|
||||||
|
"""
|
||||||
|
Bestimmt die effektive Tefkurve-Richtung aus Kurvenrichtung und Tefkurve.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
kurvenrichtung: "links" oder "rechts"
|
||||||
|
tefkurve: "außen" oder "innen"
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
"rechts" oder "links"
|
||||||
|
"""
|
||||||
|
if (kurvenrichtung == "links" and tefkurve == "außen") or (
|
||||||
|
kurvenrichtung == "rechts" and tefkurve == "innen"
|
||||||
|
):
|
||||||
|
return "rechts"
|
||||||
|
return "links"
|
||||||
|
|
||||||
|
|
||||||
|
def _ist_umlenk_position(rotation, x, y, x_angetrieben, y_angetrieben):
|
||||||
|
"""
|
||||||
|
Prüft ob die Position eine Umlenkposition ist (gleiche-Höhe-Fall).
|
||||||
|
|
||||||
|
Basiert auf Rotationswinkel und relativer Position zur angetriebenen Strecke.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
rotation: Drehung in Grad
|
||||||
|
x, y: Position des Gefällestreckens
|
||||||
|
x_angetrieben, y_angetrieben: Position der angetriebenen Strecke
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True wenn Umlenkposition, sonst False (Motorposition)
|
||||||
|
"""
|
||||||
|
rotation_zwischen = rotation if rotation != 0.0 else -360.0
|
||||||
|
return (
|
||||||
|
((-360.0 <= rotation_zwischen < -270.0) and y > y_angetrieben)
|
||||||
|
or ((-90.0 < rotation < 0.0) and y > y_angetrieben)
|
||||||
|
or ((-270.0 < rotation_zwischen < -90.0) and y < y_angetrieben)
|
||||||
|
or (rotation == -90.0 and x < x_angetrieben)
|
||||||
|
or (rotation == -270.0 and x < x_angetrieben)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _normalize_deltas(*delta_lists):
|
||||||
|
"""Setzt negative Werte in Delta-Listen auf positiv."""
|
||||||
|
for delta_list in delta_lists:
|
||||||
|
for i, val in enumerate(delta_list):
|
||||||
|
if val < 0:
|
||||||
|
delta_list[i] = abs(val)
|
||||||
|
|
||||||
|
|
||||||
|
def _laedt_bogen_deltas(block_name, lib_doc, doc):
|
||||||
|
"""
|
||||||
|
Lädt Bogen-Delta-Attribute und normalisiert negative Werte.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
block_name: Name des Bogen-Blocks
|
||||||
|
lib_doc: Bibliotheks-Dokument
|
||||||
|
doc: Ziel-Dokument
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict mit DELTA_SP_0 und DELTA_SP_1 als normalisierten Listen
|
||||||
|
"""
|
||||||
|
attrib = block_methoden.import_block(block_name, lib_doc, doc)
|
||||||
|
deltas = {}
|
||||||
|
for key in ("DELTA_SP_0", "DELTA_SP_1"):
|
||||||
|
values = [float(v) for v in re.split(r"[;,]", attrib[key])]
|
||||||
|
deltas[key] = [abs(v) if v < 0 else v for v in values]
|
||||||
|
return deltas
|
||||||
|
|
||||||
|
|
||||||
|
def _add_station_mit_bogen(
|
||||||
|
block, bogen_block, station_block, position, x, y, hoehe,
|
||||||
|
deltas_0, deltas_1, vorzeichen, rotation_bogen
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Fügt Station mit Bogen-Übergang hinzu.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
block: DXF-Block zum Hinzufügen
|
||||||
|
bogen_block: Blockname des Bogens
|
||||||
|
station_block: Blockname der Station
|
||||||
|
position: [x, y, z] aktuelle Position
|
||||||
|
x, y: Offset-Koordinaten
|
||||||
|
hoehe: Höhe des Gefälles
|
||||||
|
deltas_0, deltas_1: Delta-Werte des Bogens [x, y, z]
|
||||||
|
vorzeichen: -1 für Motor (Anfang), +1 für Umlenk (Ende)
|
||||||
|
rotation_bogen: Rotation des Bogenblocks
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Neue Position nach Station-Platzierung
|
||||||
|
"""
|
||||||
|
v = vorzeichen
|
||||||
|
# Bogen hinzufügen
|
||||||
|
block.add_blockref(
|
||||||
|
bogen_block,
|
||||||
|
(position[0] - x, position[1] + v * deltas_0[0] - y, position[2] + v * deltas_0[2] - hoehe),
|
||||||
|
dxfattribs={"rotation": rotation_bogen},
|
||||||
|
)
|
||||||
|
# Position nach Bogen aktualisieren
|
||||||
|
new_pos = [
|
||||||
|
position[0],
|
||||||
|
position[1] + v * (deltas_0[0] + deltas_1[0]),
|
||||||
|
position[2] + v * (deltas_0[2] + deltas_1[2]),
|
||||||
|
]
|
||||||
|
# Station hinzufügen
|
||||||
|
winkel_rad = math.radians(WINKEL_3_GRAD)
|
||||||
|
block.add_blockref(
|
||||||
|
station_block,
|
||||||
|
(
|
||||||
|
new_pos[0] - x,
|
||||||
|
new_pos[1] + v * (STATIONS_LAENGE / 2) * math.cos(winkel_rad) - y,
|
||||||
|
new_pos[2] + v * (STATIONS_LAENGE / 2) * math.sin(winkel_rad) - hoehe,
|
||||||
|
),
|
||||||
|
dxfattribs={"rotation": 270},
|
||||||
|
)
|
||||||
|
new_pos[1] += v * STATIONS_LAENGE * math.cos(winkel_rad)
|
||||||
|
new_pos[2] += v * STATIONS_LAENGE * math.sin(winkel_rad)
|
||||||
|
return new_pos
|
||||||
|
|
||||||
|
|
||||||
|
def _add_station_gerade(block, station_block, position, x, y, hoehe, vorzeichen):
|
||||||
|
"""
|
||||||
|
Fügt Station ohne Bogen (gerade) hinzu.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
block: DXF-Block zum Hinzufügen
|
||||||
|
station_block: Blockname der Station
|
||||||
|
position: [x, y, z] aktuelle Position
|
||||||
|
x, y: Offset-Koordinaten
|
||||||
|
hoehe: Höhe des Gefälles
|
||||||
|
vorzeichen: -1 für Motor, +1 für Umlenk
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Neue Position nach Station-Platzierung
|
||||||
|
"""
|
||||||
|
v = vorzeichen
|
||||||
|
block.add_blockref(
|
||||||
|
station_block,
|
||||||
|
(position[0] - x, position[1] + v * (STATIONS_LAENGE / 2) - y, position[2] - hoehe),
|
||||||
|
dxfattribs={"rotation": 270},
|
||||||
|
)
|
||||||
|
new_pos = list(position)
|
||||||
|
new_pos[1] += v * STATIONS_LAENGE
|
||||||
|
return new_pos
|
||||||
|
|
||||||
|
|
||||||
|
def _pruefe_motor_umlenk_an_kurve(
|
||||||
|
upper_hoehe, lower_hoehe, vario_hoehe_0, vario_hoehe_1,
|
||||||
|
rotation, x, y, x_angetrieben, y_angetrieben
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Prüft ob Motor oder Umlenk an einer Kurve benötigt wird.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
upper_hoehe: Obere Höhe des Gefällestreckens
|
||||||
|
lower_hoehe: Untere Höhe des Gefällestreckens
|
||||||
|
vario_hoehe_0, vario_hoehe_1: Höhen der Nachbarn
|
||||||
|
rotation: Drehung in Grad
|
||||||
|
x, y: Position des Gefällestreckens
|
||||||
|
x_angetrieben, y_angetrieben: Position der angetriebenen Strecke
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(hat_motor, hat_umlenk, ist_gerade)
|
||||||
|
"""
|
||||||
|
if upper_hoehe > lower_hoehe:
|
||||||
|
if vario_hoehe_0 == upper_hoehe or vario_hoehe_1 == upper_hoehe:
|
||||||
|
return True, False, False
|
||||||
|
return False, True, False
|
||||||
|
elif upper_hoehe < lower_hoehe:
|
||||||
|
if vario_hoehe_0 == lower_hoehe or vario_hoehe_1 == lower_hoehe:
|
||||||
|
return True, False, False
|
||||||
|
return False, True, False
|
||||||
|
else: # Gleiche Höhe → Positionsbasierte Bestimmung
|
||||||
|
ist_umlenk = _ist_umlenk_position(rotation, x, y, x_angetrieben, y_angetrieben)
|
||||||
|
if ist_umlenk:
|
||||||
|
return False, True, True
|
||||||
|
return True, False, True
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# GEFAELLESTRECKE KLASSE
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
class Gefaellestrecke(BaseModel):
|
||||||
|
"""Modell für Gefällestrecken zwischen Fördererkomponenten."""
|
||||||
|
|
||||||
|
teileid: str
|
||||||
|
x: float = Field(description="X-Koordinate des Foerder-Zentrums")
|
||||||
|
y: float = Field(description="Y-Koordinate des Foerder-Zentrums")
|
||||||
|
laenge: float = Field(description="Länge des Förderers")
|
||||||
|
h0: float = Field(description="Höhe Unten in Merkmale")
|
||||||
|
h1: float = Field(description="Höhe Oben in Merkmale")
|
||||||
|
drehung: float = Field(default=0.0, description="Drehung an z achse")
|
||||||
|
anzahl_scanner: int = Field(default=0, description="Anzahl der Scanner")
|
||||||
|
anzahl_separatoren: int = Field(default=0, description="Anzahl der Separatoren")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def hight_zwischen(self):
|
||||||
|
"""Mittlere Höhe zwischen h0 und h1."""
|
||||||
|
return (self.h0 + self.h1) / 2
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_merkmale(
|
||||||
|
cls, teileid: str, x: float, y: float, merkmale: dict
|
||||||
|
) -> "Gefaellestrecke":
|
||||||
|
"""
|
||||||
|
Erstellt ein Gefaellestrecke-Objekt aus einem Merkmale-Dictionary.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
teileid: Teile-Identifikator
|
||||||
|
x, y: Koordinaten in mm
|
||||||
|
merkmale: Dictionary mit Eigenschaftswerten
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Gefaellestrecke-Instanz
|
||||||
|
"""
|
||||||
|
h0 = float(merkmale.get("Höhe unten")) * 1000
|
||||||
|
h1 = float(merkmale.get("Höhe oben")) * 1000
|
||||||
|
laenge = float(merkmale.get("Länge in Meter")) * 1000
|
||||||
|
return cls(
|
||||||
|
teileid=teileid,
|
||||||
|
laenge=laenge,
|
||||||
|
x=x,
|
||||||
|
y=y,
|
||||||
|
h0=h0,
|
||||||
|
h1=h1,
|
||||||
|
drehung=float(merkmale.get("Drehung")),
|
||||||
|
anzahl_scanner=int(merkmale.get("Anzahl der Scanner")),
|
||||||
|
anzahl_separatoren=int(merkmale.get("Anzahl der Separatoren")),
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def erstehlung_von_gefalle_ohne_aussnahmen(
|
||||||
|
msp, x, y, upper_hoehe_gefaelle, lower_hoehe_gefaelle, halbe_laenge, winkel
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Zeichnet eine Gefällelinie ohne Motor-/Umlenk-Ausnahmen.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
msp: DXF-Modelspace
|
||||||
|
x, y: Zentrum der Gefällelinie
|
||||||
|
upper_hoehe_gefaelle: Höhe am oberen Ende
|
||||||
|
lower_hoehe_gefaelle: Höhe am unteren Ende
|
||||||
|
halbe_laenge: Halbe Länge der Strecke
|
||||||
|
winkel: Rotationswinkel
|
||||||
|
"""
|
||||||
|
dx = halbe_laenge * math.sin(winkel * -1)
|
||||||
|
dy = halbe_laenge * math.cos(winkel)
|
||||||
|
start = x + dx, y + dy, upper_hoehe_gefaelle
|
||||||
|
ende = x - dx, y - dy, lower_hoehe_gefaelle
|
||||||
|
line = msp.add_line(start, ende)
|
||||||
|
line.dxf.layer = LAYER_SP
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def rotation_mit_zwei_verbunden(
|
||||||
|
gefaellestrecke_nachbarn,
|
||||||
|
richtung2,
|
||||||
|
richtung0,
|
||||||
|
am_kreisel,
|
||||||
|
kreisel_verbunden,
|
||||||
|
hight_position,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Berechnet Rotation wenn zwei Kreise verbunden sind.
|
||||||
|
|
||||||
|
Bestimmt die Gefälle-Richtung und passt Drehungen an,
|
||||||
|
damit der 1. Kreisel in der Liste konsistent am Kreisel verbunden ist.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gefaellestrecke_nachbarn: Dict mit Drehungen und Kreisel-Positionen
|
||||||
|
richtung2: Richtung des zweiten Kreisels ("DEFAULT", "Vertikal", "Horizontal")
|
||||||
|
richtung0: Richtung des ersten Kreisels
|
||||||
|
am_kreisel: Kreisel-Index (0, 1 oder 2)
|
||||||
|
kreisel_verbunden: Anzahl verbundener Kreisel
|
||||||
|
hight_position: "higher" oder "lower"
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(rotation, drehung0, drehung1, hight_position)
|
||||||
|
"""
|
||||||
|
drehung0 = gefaellestrecke_nachbarn.get("Drehung0")
|
||||||
|
drehung1 = gefaellestrecke_nachbarn.get("Drehung1")
|
||||||
|
x0_kreisel = float(gefaellestrecke_nachbarn.get("x0"))
|
||||||
|
y0_kreisel = float(gefaellestrecke_nachbarn.get("y0"))
|
||||||
|
x1_kreisel = float(gefaellestrecke_nachbarn.get("x1"))
|
||||||
|
y1_kreisel = float(gefaellestrecke_nachbarn.get("y1"))
|
||||||
|
|
||||||
|
# DEFAULT → richtung0 verwenden, sonst richtung2
|
||||||
|
effektive_richtung = richtung0 if richtung2 == "DEFAULT" else richtung2
|
||||||
|
|
||||||
|
# Einheitliche Position- und Gefälle-Bestimmung (eliminiert Duplikation)
|
||||||
|
position = _bestimme_position(
|
||||||
|
effektive_richtung, x0_kreisel, x1_kreisel, y0_kreisel, y1_kreisel, hight_position
|
||||||
|
)
|
||||||
|
gefaelle = _bestimme_gefaelle(effektive_richtung, position)
|
||||||
|
|
||||||
|
if richtung2 == "DEFAULT":
|
||||||
|
# Vertausch wenn Position rechts/lower und Drehungen verschieden
|
||||||
|
if (
|
||||||
|
position in ("higher_rechts", "lower_rechts", "higher_lower", "lower_lower")
|
||||||
|
and drehung0 != drehung1
|
||||||
|
and am_kreisel == 0
|
||||||
|
):
|
||||||
|
drehung0, drehung1, hight_position = _tausche_drehungen_und_hoehe(
|
||||||
|
drehung0, drehung1, hight_position
|
||||||
|
)
|
||||||
|
|
||||||
|
# Austausch damit der 1. Kreisel in der Liste am Kreisel verbunden ist
|
||||||
|
if kreisel_verbunden == 1 and am_kreisel == 2:
|
||||||
|
am_kreisel = 1 # BUG FIX: war "am_kreisel == 1" (Vergleich statt Zuweisung)
|
||||||
|
drehung0, drehung1, hight_position = _tausche_drehungen_und_hoehe(
|
||||||
|
drehung0, drehung1, hight_position
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Austausch wenn am_kreisel == 2
|
||||||
|
if am_kreisel == 2:
|
||||||
|
am_kreisel = 1
|
||||||
|
drehung0, drehung1, hight_position = _tausche_drehungen_und_hoehe(
|
||||||
|
drehung0, drehung1, hight_position
|
||||||
|
)
|
||||||
|
|
||||||
|
rotation = ROTATION_MAP[gefaelle]
|
||||||
|
return rotation, drehung0, drehung1, hight_position
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def ein_motor_oder_eine_umlenk(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
start,
|
||||||
|
ende,
|
||||||
|
doc,
|
||||||
|
lib_doc,
|
||||||
|
hoehe_gefaelle,
|
||||||
|
block_Vario_Umlenkstation_500mm,
|
||||||
|
block_Vario_Motorstation_500mm,
|
||||||
|
blockname_motor_links,
|
||||||
|
blockname_umlenk_links,
|
||||||
|
hat_motor_0,
|
||||||
|
hat_umlenk_0,
|
||||||
|
tefkurve_0,
|
||||||
|
block,
|
||||||
|
umlenk_gerade,
|
||||||
|
motor_gerade,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Platziert Motor- und/oder Umlenkstation mit optionalen Bögen.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
x, y: Zentrum des Förderers
|
||||||
|
start, ende: Start-/End-Punkt der Gefällelinie
|
||||||
|
doc, lib_doc: DXF-Dokumente
|
||||||
|
hoehe_gefaelle: Höhe der Gefällelinie
|
||||||
|
block_Vario_Umlenkstation_500mm: Block-Name Umlenkstation rechts
|
||||||
|
block_Vario_Motorstation_500mm: Block-Name Motorstation rechts
|
||||||
|
blockname_motor_links: Block-Name Motorstation links
|
||||||
|
blockname_umlenk_links: Block-Name Umlenkstation links
|
||||||
|
hat_motor_0, hat_umlenk_0: Ob Motor/Umlenk vorhanden
|
||||||
|
tefkurve_0: "links" oder "rechts"
|
||||||
|
block: DXF-Block zum Hinzufügen
|
||||||
|
umlenk_gerade, motor_gerade: Ob Station gerade (keine Bögen)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(start, ende) nach Platzierung
|
||||||
|
"""
|
||||||
|
# Bogen-Blöcke laden und Deltas extrahieren
|
||||||
|
block_Vario_Bogen_auf = "Vario_Bogen_auf_3°"
|
||||||
|
block_Vario_Bogen_ab = "Vario_Bogen_ab_3°"
|
||||||
|
block_Vario_Bogen_auf_links = block_Vario_Bogen_auf + "_links"
|
||||||
|
block_Vario_Bogen_ab_links = block_Vario_Bogen_ab + "_links"
|
||||||
|
|
||||||
|
ab_deltas = _laedt_bogen_deltas(block_Vario_Bogen_ab, lib_doc, doc)
|
||||||
|
auf_deltas = _laedt_bogen_deltas(block_Vario_Bogen_auf, lib_doc, doc)
|
||||||
|
|
||||||
|
block_methoden.turn_two_blocks_left(
|
||||||
|
doc,
|
||||||
|
block_Vario_Bogen_auf,
|
||||||
|
block_Vario_Bogen_ab,
|
||||||
|
block_Vario_Bogen_ab_links,
|
||||||
|
block_Vario_Bogen_auf_links,
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Motor-Station ---
|
||||||
|
if hat_motor_0:
|
||||||
|
ist_links = (tefkurve_0 == "links")
|
||||||
|
# Motor: tefkurve "links" → bogen_links + station_links
|
||||||
|
bogen_motor = block_Vario_Bogen_ab_links if ist_links else block_Vario_Bogen_ab
|
||||||
|
station_motor = blockname_motor_links if ist_links else block_Vario_Motorstation_500mm
|
||||||
|
station_motor_gerade = (
|
||||||
|
"Vario_Motorstation_500mm_links" if ist_links else "Vario_Motorstation_500mm"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not motor_gerade:
|
||||||
|
start = _add_station_mit_bogen(
|
||||||
|
block, bogen_motor, station_motor, start,
|
||||||
|
x, y, hoehe_gefaelle,
|
||||||
|
ab_deltas["DELTA_SP_0"], ab_deltas["DELTA_SP_1"],
|
||||||
|
vorzeichen=-1, rotation_bogen=270,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
start = _add_station_gerade(
|
||||||
|
block, station_motor_gerade, start,
|
||||||
|
x, y, hoehe_gefaelle, vorzeichen=-1,
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Umlenk-Station ---
|
||||||
|
if hat_umlenk_0:
|
||||||
|
ist_links = (tefkurve_0 == "links")
|
||||||
|
# Umlenk: Bogen-Blockname ist INVERTIERT relativ zu tefkurve
|
||||||
|
bogen_umlenk = block_Vario_Bogen_auf if ist_links else block_Vario_Bogen_auf_links
|
||||||
|
station_umlenk = blockname_umlenk_links if ist_links else block_Vario_Umlenkstation_500mm
|
||||||
|
station_umlenk_gerade = (
|
||||||
|
"Vario_Umlenkstation_500mm_links" if ist_links else "Vario_Umlenkstation_500mm"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not umlenk_gerade:
|
||||||
|
ende = _add_station_mit_bogen(
|
||||||
|
block, bogen_umlenk, station_umlenk, ende,
|
||||||
|
x, y, hoehe_gefaelle,
|
||||||
|
auf_deltas["DELTA_SP_0"], auf_deltas["DELTA_SP_1"],
|
||||||
|
vorzeichen=+1, rotation_bogen=90,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
ende = _add_station_gerade(
|
||||||
|
block, station_umlenk_gerade, ende,
|
||||||
|
x, y, hoehe_gefaelle, vorzeichen=+1,
|
||||||
|
)
|
||||||
|
|
||||||
|
return start, ende
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def hat_motor_umlenk_station(gefaelle_objekt, gefaellestrecke_nachbarn):
|
||||||
|
"""
|
||||||
|
Analysiert Nachbar-Daten und bestimmt Motor-/Umlenkstation-Zuordnung.
|
||||||
|
|
||||||
|
Untersucht ob an jedem Ende der Gefällelinie eine Motorstation
|
||||||
|
oder eine Umlenkstation angeschlossen ist.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gefaelle_objekt: Gefaellestrecke-Instanz mit h0, h1, drehung, x, y
|
||||||
|
gefaellestrecke_nachbarn: Dict mit Kurven- und Höhen-Informationen
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict mit hat_motor_0/1, hat_umlenk_0/1, tefkurve_0/1,
|
||||||
|
umlenk_gerade, motor_gerade
|
||||||
|
"""
|
||||||
|
hat_motor_0 = None
|
||||||
|
hat_motor_1 = None
|
||||||
|
hat_umlenk_0 = None
|
||||||
|
hat_umlenk_1 = None
|
||||||
|
tefkurve_0 = None
|
||||||
|
tefkurve_1 = None
|
||||||
|
umlenk_gerade = False
|
||||||
|
motor_gerade = False
|
||||||
|
upper_hoehe_gefaelle = gefaelle_objekt.h1
|
||||||
|
lower_hoehe_gefaelle = gefaelle_objekt.h0
|
||||||
|
rotation = gefaelle_objekt.drehung
|
||||||
|
x = gefaelle_objekt.x
|
||||||
|
y = gefaelle_objekt.y
|
||||||
|
|
||||||
|
if "Kurvenrichtung" not in gefaellestrecke_nachbarn:
|
||||||
|
return {
|
||||||
|
"hat_motor_0": hat_motor_0,
|
||||||
|
"hat_motor_1": hat_motor_1,
|
||||||
|
"hat_umlenk_0": hat_umlenk_0,
|
||||||
|
"hat_umlenk_1": hat_umlenk_1,
|
||||||
|
"tefkurve_0": tefkurve_0,
|
||||||
|
"tefkurve_1": tefkurve_1,
|
||||||
|
"umlenk_gerade": umlenk_gerade,
|
||||||
|
"motor_gerade": motor_gerade,
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Erster Nachbar ---
|
||||||
|
vario_hoehe_0 = float(gefaellestrecke_nachbarn.get("vario_hoehe_0"))
|
||||||
|
vario_hoehe_1 = float(gefaellestrecke_nachbarn.get("vario_hoehe_1"))
|
||||||
|
kurvenrichtung = gefaellestrecke_nachbarn.get("Kurvenrichtung")
|
||||||
|
tefkurve_0 = gefaellestrecke_nachbarn.get("Tefkurve")
|
||||||
|
x_angetrieben = gefaellestrecke_nachbarn.get("X_angetrieben")
|
||||||
|
y_angetrieben = gefaellestrecke_nachbarn.get("Y_angetrieben")
|
||||||
|
|
||||||
|
tefkurve_0 = _bestimme_tefkurve(kurvenrichtung, tefkurve_0)
|
||||||
|
|
||||||
|
hat_motor_0, hat_umlenk_0, ist_gerade_0 = _pruefe_motor_umlenk_an_kurve(
|
||||||
|
upper_hoehe_gefaelle, lower_hoehe_gefaelle,
|
||||||
|
vario_hoehe_0, vario_hoehe_1,
|
||||||
|
rotation, x, y, x_angetrieben, y_angetrieben,
|
||||||
|
)
|
||||||
|
# Gerade-Flag nur setzen im gleiche-Höhe-Fall
|
||||||
|
if ist_gerade_0:
|
||||||
|
if hat_umlenk_0:
|
||||||
|
umlenk_gerade = True
|
||||||
|
if hat_motor_0:
|
||||||
|
motor_gerade = True
|
||||||
|
|
||||||
|
# --- Zweiter Nachbar (falls vorhanden) ---
|
||||||
|
if "Kurvenrichtung_1" in gefaellestrecke_nachbarn:
|
||||||
|
vario_hoehe_0_1 = float(gefaellestrecke_nachbarn.get("vario_hoehe_0_1"))
|
||||||
|
vario_hoehe_1_1 = float(gefaellestrecke_nachbarn.get("vario_hoehe_1_1"))
|
||||||
|
kurvenrichtung_1 = gefaellestrecke_nachbarn.get("Kurvenrichtung_1")
|
||||||
|
tefkurve_1 = gefaellestrecke_nachbarn.get("Tefkurve_1")
|
||||||
|
x_angetrieben_1 = gefaellestrecke_nachbarn.get("X_angetrieben_1")
|
||||||
|
y_angetrieben_1 = gefaellestrecke_nachbarn.get("Y_angetrieben_1")
|
||||||
|
|
||||||
|
tefkurve_1 = _bestimme_tefkurve(kurvenrichtung_1, tefkurve_1)
|
||||||
|
|
||||||
|
hat_motor_1, hat_umlenk_1, ist_gerade_1 = _pruefe_motor_umlenk_an_kurve(
|
||||||
|
upper_hoehe_gefaelle, lower_hoehe_gefaelle,
|
||||||
|
vario_hoehe_0_1, vario_hoehe_1_1,
|
||||||
|
rotation, x, y, x_angetrieben_1, y_angetrieben_1,
|
||||||
|
)
|
||||||
|
if ist_gerade_1:
|
||||||
|
if hat_umlenk_1:
|
||||||
|
umlenk_gerade = True
|
||||||
|
if hat_motor_1:
|
||||||
|
motor_gerade = True
|
||||||
|
|
||||||
|
return {
|
||||||
|
"hat_motor_0": hat_motor_0,
|
||||||
|
"hat_motor_1": hat_motor_1,
|
||||||
|
"hat_umlenk_0": hat_umlenk_0,
|
||||||
|
"hat_umlenk_1": hat_umlenk_1,
|
||||||
|
"tefkurve_0": tefkurve_0,
|
||||||
|
"tefkurve_1": tefkurve_1,
|
||||||
|
"umlenk_gerade": umlenk_gerade,
|
||||||
|
"motor_gerade": motor_gerade,
|
||||||
|
}
|
||||||
@@ -0,0 +1,238 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Unit-Tests für Gefaellestrecke (Refactored)
|
||||||
|
"""
|
||||||
|
import unittest
|
||||||
|
import math
|
||||||
|
|
||||||
|
from .Gefaellestrecke import (
|
||||||
|
Gefaellestrecke,
|
||||||
|
ROTATION_MAP,
|
||||||
|
_bestimme_position,
|
||||||
|
_bestimme_gefaelle,
|
||||||
|
_tausche_drehungen_und_hoehe,
|
||||||
|
_bestimme_tefkurve,
|
||||||
|
_ist_umlenk_position,
|
||||||
|
_pruefe_motor_umlenk_an_kurve,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestGefaellestreckeModell(unittest.TestCase):
|
||||||
|
"""Tests für das Gefaellestrecke Pydantic-Modell."""
|
||||||
|
|
||||||
|
def test_from_merkmale(self):
|
||||||
|
merkmale = {
|
||||||
|
"Höhe unten": "1.5",
|
||||||
|
"Höhe oben": "2.0",
|
||||||
|
"Länge in Meter": "5.0",
|
||||||
|
"Drehung": "-90",
|
||||||
|
"Anzahl der Scanner": "2",
|
||||||
|
"Anzahl der Separatoren": "1",
|
||||||
|
}
|
||||||
|
obj = Gefaellestrecke.from_merkmale("TEST-001", 100.0, 200.0, merkmale)
|
||||||
|
self.assertEqual(obj.teileid, "TEST-001")
|
||||||
|
self.assertEqual(obj.h0, 1500.0)
|
||||||
|
self.assertEqual(obj.h1, 2000.0)
|
||||||
|
self.assertEqual(obj.laenge, 5000.0)
|
||||||
|
self.assertEqual(obj.drehung, -90.0)
|
||||||
|
self.assertEqual(obj.anzahl_scanner, 2)
|
||||||
|
self.assertEqual(obj.anzahl_separatoren, 1)
|
||||||
|
|
||||||
|
def test_hight_zwischen(self):
|
||||||
|
obj = Gefaellestrecke(teileid="T", x=0, y=0, laenge=1000, h0=1000, h1=3000)
|
||||||
|
self.assertEqual(obj.hight_zwischen, 2000.0)
|
||||||
|
|
||||||
|
|
||||||
|
class TestBestimmePosition(unittest.TestCase):
|
||||||
|
"""Tests für _bestimme_position Hilfsfunktion."""
|
||||||
|
|
||||||
|
def test_vertikal_links(self):
|
||||||
|
# x0 < x1 → "_links"
|
||||||
|
result = _bestimme_position("Vertikal", 100, 200, 0, 0, "higher")
|
||||||
|
self.assertEqual(result, "higher_links")
|
||||||
|
|
||||||
|
def test_vertikal_rechts(self):
|
||||||
|
# x0 > x1 → "_rechts"
|
||||||
|
result = _bestimme_position("Vertikal", 300, 200, 0, 0, "lower")
|
||||||
|
self.assertEqual(result, "lower_rechts")
|
||||||
|
|
||||||
|
def test_horizontal_higher(self):
|
||||||
|
# y0 > y1 → "_higher"
|
||||||
|
result = _bestimme_position("Horizontal", 0, 0, 500, 100, "higher")
|
||||||
|
self.assertEqual(result, "higher_higher")
|
||||||
|
|
||||||
|
def test_horizontal_lower(self):
|
||||||
|
# y0 < y1 → "_lower"
|
||||||
|
result = _bestimme_position("Horizontal", 0, 0, 50, 500, "lower")
|
||||||
|
self.assertEqual(result, "lower_lower")
|
||||||
|
|
||||||
|
|
||||||
|
class TestBestimmeGefaelle(unittest.TestCase):
|
||||||
|
"""Tests für _bestimme_gefaelle Hilfsfunktion."""
|
||||||
|
|
||||||
|
def test_vertikal_links(self):
|
||||||
|
self.assertEqual(_bestimme_gefaelle("Vertikal", "lower_rechts"), "links")
|
||||||
|
self.assertEqual(_bestimme_gefaelle("Vertikal", "higher_links"), "links")
|
||||||
|
|
||||||
|
def test_vertikal_rechts(self):
|
||||||
|
self.assertEqual(_bestimme_gefaelle("Vertikal", "higher_rechts"), "rechts")
|
||||||
|
self.assertEqual(_bestimme_gefaelle("Vertikal", "lower_links"), "rechts")
|
||||||
|
|
||||||
|
def test_horizontal_oben(self):
|
||||||
|
self.assertEqual(_bestimme_gefaelle("Horizontal", "lower_lower"), "oben")
|
||||||
|
self.assertEqual(_bestimme_gefaelle("Horizontal", "higher_higher"), "oben")
|
||||||
|
|
||||||
|
def test_horizontal_unten(self):
|
||||||
|
self.assertEqual(_bestimme_gefaelle("Horizontal", "higher_lower"), "unten")
|
||||||
|
self.assertEqual(_bestimme_gefaelle("Horizontal", "lower_higher"), "unten")
|
||||||
|
|
||||||
|
|
||||||
|
class TestTauscheDrehungen(unittest.TestCase):
|
||||||
|
"""Tests für _tausche_drehungen_und_hoehe."""
|
||||||
|
|
||||||
|
def test_tausch_drehungen(self):
|
||||||
|
d0, d1, h = _tausche_drehungen_und_hoehe(10, 20, "higher")
|
||||||
|
self.assertEqual(d0, 20)
|
||||||
|
self.assertEqual(d1, 10)
|
||||||
|
self.assertEqual(h, "lower")
|
||||||
|
|
||||||
|
def test_tausch_invert_hoehe(self):
|
||||||
|
_, _, h = _tausche_drehungen_und_hoehe(0, 0, "lower")
|
||||||
|
self.assertEqual(h, "higher")
|
||||||
|
|
||||||
|
|
||||||
|
class TestBestimmeeTefkurve(unittest.TestCase):
|
||||||
|
"""Tests für _bestimme_tefkurve."""
|
||||||
|
|
||||||
|
def test_links_aussen_ist_rechts(self):
|
||||||
|
self.assertEqual(_bestimme_tefkurve("links", "außen"), "rechts")
|
||||||
|
|
||||||
|
def test_rechts_innen_ist_rechts(self):
|
||||||
|
self.assertEqual(_bestimme_tefkurve("rechts", "innen"), "rechts")
|
||||||
|
|
||||||
|
def test_links_innen_ist_links(self):
|
||||||
|
self.assertEqual(_bestimme_tefkurve("links", "innen"), "links")
|
||||||
|
|
||||||
|
def test_rechts_aussen_ist_links(self):
|
||||||
|
self.assertEqual(_bestimme_tefkurve("rechts", "außen"), "links")
|
||||||
|
|
||||||
|
|
||||||
|
class TestIstUmlenkPosition(unittest.TestCase):
|
||||||
|
"""Tests für _ist_umlenk_position."""
|
||||||
|
|
||||||
|
def test_rotation_minus90_x_kleiner(self):
|
||||||
|
# rotation == -90 und x < x_angetrieben → True (Umlenk)
|
||||||
|
self.assertTrue(_ist_umlenk_position(-90.0, 50, 100, 200, 100))
|
||||||
|
|
||||||
|
def test_rotation_minus90_x_groesser(self):
|
||||||
|
# rotation == -90 und x >= x_angetrieben → False (Motor)
|
||||||
|
self.assertFalse(_ist_umlenk_position(-90.0, 300, 100, 200, 100))
|
||||||
|
|
||||||
|
def test_rotation_0_wird_minus360(self):
|
||||||
|
# rotation == 0 → rotation_zwischen = -360
|
||||||
|
# -360 <= -360 < -270 und y > y_angetrieben → True
|
||||||
|
self.assertTrue(_ist_umlenk_position(0.0, 100, 500, 100, 100))
|
||||||
|
|
||||||
|
|
||||||
|
class TestPruefeMotorUmlenkAnKurve(unittest.TestCase):
|
||||||
|
"""Tests für _pruefe_motor_umlenk_an_kurve."""
|
||||||
|
|
||||||
|
def test_upper_hoeher_motor_passend(self):
|
||||||
|
# upper > lower, vario_hoehe_0 == upper → Motor
|
||||||
|
hat_motor, hat_umlenk, ist_gerade = _pruefe_motor_umlenk_an_kurve(
|
||||||
|
2000, 1000, 2000, 1500, 0, 0, 0, 0, 0
|
||||||
|
)
|
||||||
|
self.assertTrue(hat_motor)
|
||||||
|
self.assertFalse(hat_umlenk)
|
||||||
|
self.assertFalse(ist_gerade)
|
||||||
|
|
||||||
|
def test_upper_hoeher_umlenk(self):
|
||||||
|
# upper > lower, keine Höhe passt → Umlenk
|
||||||
|
hat_motor, hat_umlenk, ist_gerade = _pruefe_motor_umlenk_an_kurve(
|
||||||
|
2000, 1000, 1500, 1200, 0, 0, 0, 0, 0
|
||||||
|
)
|
||||||
|
self.assertFalse(hat_motor)
|
||||||
|
self.assertTrue(hat_umlenk)
|
||||||
|
self.assertFalse(ist_gerade)
|
||||||
|
|
||||||
|
def test_lower_hoeher_motor(self):
|
||||||
|
# upper < lower, vario_hoehe_1 == lower → Motor
|
||||||
|
hat_motor, hat_umlenk, ist_gerade = _pruefe_motor_umlenk_an_kurve(
|
||||||
|
1000, 2000, 1500, 2000, 0, 0, 0, 0, 0
|
||||||
|
)
|
||||||
|
self.assertTrue(hat_motor)
|
||||||
|
self.assertFalse(hat_umlenk)
|
||||||
|
|
||||||
|
def test_gleiche_hoehe_umlenk_position(self):
|
||||||
|
# gleiche Höhe, Umlenkposition → Umlenk gerade
|
||||||
|
hat_motor, hat_umlenk, ist_gerade = _pruefe_motor_umlenk_an_kurve(
|
||||||
|
1000, 1000, 800, 900, -90.0, 50, 100, 200, 100
|
||||||
|
)
|
||||||
|
self.assertFalse(hat_motor)
|
||||||
|
self.assertTrue(hat_umlenk)
|
||||||
|
self.assertTrue(ist_gerade)
|
||||||
|
|
||||||
|
def test_gleiche_hoehe_motor_position(self):
|
||||||
|
# gleiche Höhe, keine Umlenkposition → Motor gerade
|
||||||
|
hat_motor, hat_umlenk, ist_gerade = _pruefe_motor_umlenk_an_kurve(
|
||||||
|
1000, 1000, 800, 900, -90.0, 300, 100, 200, 100
|
||||||
|
)
|
||||||
|
self.assertTrue(hat_motor)
|
||||||
|
self.assertFalse(hat_umlenk)
|
||||||
|
self.assertTrue(ist_gerade)
|
||||||
|
|
||||||
|
|
||||||
|
class TestRotationMap(unittest.TestCase):
|
||||||
|
"""Tests für ROTATION_MAP Konstante."""
|
||||||
|
|
||||||
|
def test_alle_richtungen(self):
|
||||||
|
self.assertEqual(ROTATION_MAP["oben"], 0)
|
||||||
|
self.assertEqual(ROTATION_MAP["unten"], 180)
|
||||||
|
self.assertEqual(ROTATION_MAP["links"], 90)
|
||||||
|
self.assertEqual(ROTATION_MAP["rechts"], 270)
|
||||||
|
|
||||||
|
|
||||||
|
class TestRotationMitZweiVerbunden(unittest.TestCase):
|
||||||
|
"""Tests für rotation_mit_zwei_verbunden (Bug-Fix Zeile 112 getestet)."""
|
||||||
|
|
||||||
|
def _nachbarn(self):
|
||||||
|
return {
|
||||||
|
"Drehung0": 90, "Drehung1": 180,
|
||||||
|
"x0": "100", "y0": "200", "x1": "300", "y1": "400",
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_default_richtung_vertikal(self):
|
||||||
|
# richtung2 == "DEFAULT", richtung0 == "Vertikal"
|
||||||
|
# x0(100) < x1(300) → "_links", position="higher_links"
|
||||||
|
# gefaelle="links" → rotation=90
|
||||||
|
rotation, d0, d1, hp = Gefaellestrecke.rotation_mit_zwei_verbunden(
|
||||||
|
self._nachbarn(), "DEFAULT", "Vertikal", 0, 0, "higher"
|
||||||
|
)
|
||||||
|
self.assertEqual(rotation, 90)
|
||||||
|
|
||||||
|
def test_nicht_default_richtung_horizontal(self):
|
||||||
|
# richtung2 != "DEFAULT", richtung2 == "Horizontal"
|
||||||
|
# y0(200) < y1(400) → "_lower", position="higher_lower"
|
||||||
|
# gefaelle="unten" → rotation=180
|
||||||
|
rotation, _, _, _ = Gefaellestrecke.rotation_mit_zwei_verbunden(
|
||||||
|
self._nachbarn(), "Horizontal", "Vertikal", 0, 0, "higher"
|
||||||
|
)
|
||||||
|
self.assertEqual(rotation, 180)
|
||||||
|
|
||||||
|
def test_bug_fix_am_kreisel_zuweisung(self):
|
||||||
|
# kreisel_verbunden=1, am_kreisel=2 → muss tauschen (Bug fix: war ==)
|
||||||
|
nachbarn = self._nachbarn()
|
||||||
|
# Drehungen verschieden damit Tausch sichtbar
|
||||||
|
nachbarn["Drehung0"] = 45
|
||||||
|
nachbarn["Drehung1"] = 135
|
||||||
|
rotation, d0, d1, hp = Gefaellestrecke.rotation_mit_zwei_verbunden(
|
||||||
|
nachbarn, "DEFAULT", "Vertikal", 2, 1, "higher"
|
||||||
|
)
|
||||||
|
# Drehungen sollten getauscht sein
|
||||||
|
self.assertEqual(d0, 135)
|
||||||
|
self.assertEqual(d1, 45)
|
||||||
|
self.assertEqual(hp, "lower")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
+170
-79
@@ -1,29 +1,87 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Kreisel — Modell und Zeichenfunktionen für Kreisel-Komponenten.
|
||||||
|
|
||||||
|
Refactoring-Änderungen:
|
||||||
|
- Pin-Zeichenlogik (4x copy-paste für 0°/90°/180°/270°) durch PIN_OFFSETS-Lookup-Tabelle ersetzt
|
||||||
|
- @staticmethod auf draw_kreisel_lines und draw_kreisel_drehrichtung_markierung
|
||||||
|
- Magic Number 50 durch benanntes Constant PIN_OFFSET ersetzt
|
||||||
|
- Richtungspfeil-Import aus Loop herausgezogen (war 6x idempotent aufgerufen)
|
||||||
|
- Unused variable bref entfernt
|
||||||
|
"""
|
||||||
|
import math
|
||||||
|
|
||||||
from ezdxf.entities import Line
|
from ezdxf.entities import Line
|
||||||
import math
|
|
||||||
from pydantic import BaseModel, Field, field_validator
|
from pydantic import BaseModel, Field, field_validator
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
import plant2dxf
|
|
||||||
import block_methoden
|
|
||||||
|
|
||||||
|
from lib import block_methoden
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# KONSTANTEN
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
ATTR_TAG = "TeileId" # Attributtag im Block
|
ATTR_TAG = "TeileId" # Attributtag im Block
|
||||||
RADIUS = 400 # Radius der Kreiselkreise (mm)
|
RADIUS = 400 # Radius der Kreiselkreise (mm)
|
||||||
|
PIN_OFFSET = 50 # Offset für Pin-Bereichsmarkierung (mm)
|
||||||
|
|
||||||
|
# Pin-Bereichs-Offsets pro Drehung: (p1a_dx, p1a_dy, p1b_dx, p1b_dy, p2a_dx, p2a_dy, p2b_dx, p2b_dy)
|
||||||
|
# Berechnet aus dem manuell kodierten Original für 0°/90°/180°/270°
|
||||||
|
PIN_OFFSETS = {
|
||||||
|
0.0: (
|
||||||
|
-(RADIUS + PIN_OFFSET), +PIN_OFFSET,
|
||||||
|
-(RADIUS + PIN_OFFSET), -PIN_OFFSET,
|
||||||
|
+(RADIUS + PIN_OFFSET), +PIN_OFFSET,
|
||||||
|
+(RADIUS + PIN_OFFSET), -PIN_OFFSET,
|
||||||
|
),
|
||||||
|
180.0: (
|
||||||
|
+(RADIUS + PIN_OFFSET), -PIN_OFFSET,
|
||||||
|
+(RADIUS + PIN_OFFSET), +PIN_OFFSET,
|
||||||
|
-(RADIUS + PIN_OFFSET), -PIN_OFFSET,
|
||||||
|
-(RADIUS + PIN_OFFSET), +PIN_OFFSET,
|
||||||
|
),
|
||||||
|
90.0: (
|
||||||
|
+PIN_OFFSET, +(RADIUS - PIN_OFFSET),
|
||||||
|
-PIN_OFFSET, +(RADIUS - PIN_OFFSET),
|
||||||
|
+PIN_OFFSET, -(RADIUS - PIN_OFFSET),
|
||||||
|
-PIN_OFFSET, -(RADIUS - PIN_OFFSET),
|
||||||
|
),
|
||||||
|
270.0: (
|
||||||
|
-PIN_OFFSET, -(RADIUS - PIN_OFFSET),
|
||||||
|
+PIN_OFFSET, -(RADIUS - PIN_OFFSET),
|
||||||
|
-PIN_OFFSET, +(RADIUS - PIN_OFFSET),
|
||||||
|
+PIN_OFFSET, +(RADIUS - PIN_OFFSET),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# KREISEL KLASSE
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
|
||||||
class Kreisel(BaseModel):
|
class Kreisel(BaseModel):
|
||||||
"""Pydantic-Modell für Kreisel-Komponenten."""
|
"""Pydantic-Modell für Kreisel-Komponenten."""
|
||||||
|
|
||||||
teileid: str
|
teileid: str
|
||||||
x: float = Field(description="X-Koordinate des Kreisel-Zentrums")
|
x: float = Field(description="X-Koordinate des Kreisel-Zentrums")
|
||||||
y: float = Field(description="Y-Koordinate des Kreisel-Zentrums")
|
y: float = Field(description="Y-Koordinate des Kreisel-Zentrums")
|
||||||
hoehe: float = Field(description="Höhe in mm")
|
hoehe: float = Field(description="Höhe in mm")
|
||||||
drehung: float = Field(default=0.0, description="Drehung/Winkel in Grad")
|
drehung: float = Field(default=0.0, description="Drehung/Winkel in Grad")
|
||||||
drehrichtung: Optional[str] = Field(default=None, description="Drehrichtung: UZS oder GUZS")
|
drehrichtung: Optional[str] = Field(
|
||||||
abstand: float = Field(default=20000.0, description="Abstand zwischen Kreiselachsen in mm")
|
default=None, description="Drehrichtung: UZS oder GUZS"
|
||||||
kreiselart: Optional[str] = Field(default=None, description="Kreiselart, z.B. 'Pin'")
|
)
|
||||||
|
abstand: float = Field(
|
||||||
|
default=20000.0, description="Abstand zwischen Kreiselachsen in mm"
|
||||||
|
)
|
||||||
|
kreiselart: Optional[str] = Field(
|
||||||
|
default=None, description="Kreiselart, z.B. 'Pin'"
|
||||||
|
)
|
||||||
anzahl_scanner: float = Field(default=0.0, description="Anzahl der Scanner")
|
anzahl_scanner: float = Field(default=0.0, description="Anzahl der Scanner")
|
||||||
anzahl_separatoren: float = Field(default=0.0, description="Anzahl der Separatoren")
|
anzahl_separatoren: float = Field(default=0.0, description="Anzahl der Separatoren")
|
||||||
|
|
||||||
@field_validator('abstand')
|
@field_validator("abstand")
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate_abstand(cls, v):
|
def validate_abstand(cls, v):
|
||||||
"""Konvertiert Abstand von Meter zu mm, falls nötig."""
|
"""Konvertiert Abstand von Meter zu mm, falls nötig."""
|
||||||
@@ -35,7 +93,7 @@ class Kreisel(BaseModel):
|
|||||||
v = 10000.0 # Fallback 10 m
|
v = 10000.0 # Fallback 10 m
|
||||||
return v
|
return v
|
||||||
|
|
||||||
@field_validator('hoehe')
|
@field_validator("hoehe")
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate_hoehe(cls, v):
|
def validate_hoehe(cls, v):
|
||||||
"""Konvertiert Höhe von Meter zu mm, falls nötig."""
|
"""Konvertiert Höhe von Meter zu mm, falls nötig."""
|
||||||
@@ -63,7 +121,6 @@ class Kreisel(BaseModel):
|
|||||||
@property
|
@property
|
||||||
def richtung_rad(self) -> float:
|
def richtung_rad(self) -> float:
|
||||||
"""Richtung in Radianten (für am_kreisel_direct_verbunden)."""
|
"""Richtung in Radianten (für am_kreisel_direct_verbunden)."""
|
||||||
# Wird aus drehung abgeleitet oder separat gesetzt
|
|
||||||
return math.radians(self.drehung)
|
return math.radians(self.drehung)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -86,7 +143,9 @@ class Kreisel(BaseModel):
|
|||||||
return self.hoehe
|
return self.hoehe
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_merkmale(cls, teileid: str, x: float, y: float, merkmale: dict) -> 'Kreisel':
|
def from_merkmale(
|
||||||
|
cls, teileid: str, x: float, y: float, merkmale: dict
|
||||||
|
) -> "Kreisel":
|
||||||
"""Erstellt ein Kreisel-Objekt aus einem merkmale-Dictionary."""
|
"""Erstellt ein Kreisel-Objekt aus einem merkmale-Dictionary."""
|
||||||
hoehe_m = merkmale.get("Höhe in m", "0").replace(",", ".")
|
hoehe_m = merkmale.get("Höhe in m", "0").replace(",", ".")
|
||||||
try:
|
try:
|
||||||
@@ -94,7 +153,9 @@ class Kreisel(BaseModel):
|
|||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
hoehe = 0.0
|
hoehe = 0.0
|
||||||
|
|
||||||
abstand_m = merkmale.get("Abstand (Kreiselachse A - Kreiselachse) in Meter", "20").replace(",", ".")
|
abstand_m = merkmale.get(
|
||||||
|
"Abstand (Kreiselachse A - Kreiselachse) in Meter", "20"
|
||||||
|
).replace(",", ".")
|
||||||
try:
|
try:
|
||||||
abstand = float(abstand_m) * 1000
|
abstand = float(abstand_m) * 1000
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
@@ -125,14 +186,25 @@ class Kreisel(BaseModel):
|
|||||||
abstand=abstand,
|
abstand=abstand,
|
||||||
kreiselart=merkmale.get("Kreiselart"),
|
kreiselart=merkmale.get("Kreiselart"),
|
||||||
anzahl_scanner=anzahl_scanner,
|
anzahl_scanner=anzahl_scanner,
|
||||||
anzahl_separatoren=anzahl_separatoren
|
anzahl_separatoren=anzahl_separatoren,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def draw_kreisel_lines(msp, pos1, pos2, kreisel):
|
def draw_kreisel_lines(msp, pos1, pos2, kreisel):
|
||||||
"""Zeichnet tangentiale Linien zwischen zwei Kreiselblöcken, unabhängig vom Winkel."""
|
"""
|
||||||
|
Zeichnet tangentiale Linien zwischen zwei Kreiselblöcken, unabhängig vom Winkel.
|
||||||
|
|
||||||
|
Für Pin-Kreisel werden zusätzlich Pinbereichs-Begrenzungslinien gezeichnet,
|
||||||
|
die sich basierend auf der Drehung (0°/90°/180°/270°) verschieben.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
msp: DXF-Modelspace
|
||||||
|
pos1, pos2: Positionen der beiden Kreisel-Blöcke (x, y, z)
|
||||||
|
kreisel: Kreisel-Instanz
|
||||||
|
"""
|
||||||
rotation = kreisel.drehung
|
rotation = kreisel.drehung
|
||||||
x1, y1, z1 = pos1
|
x1, y1, z1 = pos1
|
||||||
x2, y2, z1 = pos2
|
x2, y2, _ = pos2 # z identisch für beide Blöcke
|
||||||
# Verbindungsvektor
|
# Verbindungsvektor
|
||||||
dx = x2 - x1
|
dx = x2 - x1
|
||||||
dy = y2 - y1
|
dy = y2 - y1
|
||||||
@@ -141,7 +213,6 @@ class Kreisel(BaseModel):
|
|||||||
if length == 0:
|
if length == 0:
|
||||||
return # keine Linie bei identischen Punkten
|
return # keine Linie bei identischen Punkten
|
||||||
# Normalenvektor (senkrecht, normiert, Länge = RADIUS)
|
# Normalenvektor (senkrecht, normiert, Länge = RADIUS)
|
||||||
|
|
||||||
nx = -dy / length * RADIUS
|
nx = -dy / length * RADIUS
|
||||||
ny = dx / length * RADIUS
|
ny = dx / length * RADIUS
|
||||||
# Tangentialpunkte
|
# Tangentialpunkte
|
||||||
@@ -149,54 +220,50 @@ class Kreisel(BaseModel):
|
|||||||
p1b = (x1 - nx, y1 - ny, z1)
|
p1b = (x1 - nx, y1 - ny, z1)
|
||||||
p2a = (x2 + nx, y2 + ny, z1)
|
p2a = (x2 + nx, y2 + ny, z1)
|
||||||
p2b = (x2 - nx, y2 - ny, z1)
|
p2b = (x2 - nx, y2 - ny, z1)
|
||||||
if kreisel.kreiselart == "Pin":
|
|
||||||
if rotation == 0.0:
|
|
||||||
p1a2 = p1a[0] - RADIUS - 50, p1a[1] + 50, z1
|
|
||||||
p1b2 = p1b[0] - RADIUS - 50, p1b[1] - 50, z1
|
|
||||||
p2a2 = p2a[0] + RADIUS + 50, p2a[1] + 50, z1
|
|
||||||
p2b2 = p2b[0] + RADIUS + 50, p2b[1] - 50, z1
|
|
||||||
Line1 = Line.new(dxfattribs={"start": p1a2,"end": p2a2,"layer": "Pinbereich"})
|
|
||||||
Line2 = Line.new(dxfattribs={"start": p1b2,"end": p2b2,"layer": "Pinbereich"})
|
|
||||||
msp.add_entity(Line1)
|
|
||||||
msp.add_entity(Line2)
|
|
||||||
elif rotation == 180.0:
|
|
||||||
p1a2 = p1a[0] + RADIUS + 50, p1a[1] - 50, z1
|
|
||||||
p1b2 = p1b[0] + RADIUS + 50, p1b[1] + 50, z1
|
|
||||||
p2a2 = p2a[0] - RADIUS - 50, p2a[1] - 50, z1
|
|
||||||
p2b2 = p2b[0] - RADIUS - 50, p2b[1] + 50, z1
|
|
||||||
Line1 = Line.new(dxfattribs={"start": p1a2,"end": p2a2,"layer": "Pinbereich"})
|
|
||||||
Line2 = Line.new(dxfattribs={"start": p1b2,"end": p2b2,"layer": "Pinbereich"})
|
|
||||||
msp.add_entity(Line1)
|
|
||||||
msp.add_entity(Line2)
|
|
||||||
elif rotation == 90.0:
|
|
||||||
p1a2 = p1a[0] + 50, p1a[1] - 50 + RADIUS , z1
|
|
||||||
p1b2 = p1b[0] - 50, p1b[1] - 50 + RADIUS, z1
|
|
||||||
p2a2 = p2a[0] + 50, p2a[1] + 50 - RADIUS, z1
|
|
||||||
p2b2 = p2b[0] - 50, p2b[1] + 50 - RADIUS, z1
|
|
||||||
Line1 = Line.new(dxfattribs={"start": p1a2,"end": p2a2,"layer": "Pinbereich"})
|
|
||||||
Line2 = Line.new(dxfattribs={"start": p1b2,"end": p2b2,"layer": "Pinbereich"})
|
|
||||||
msp.add_entity(Line1)
|
|
||||||
msp.add_entity(Line2)
|
|
||||||
elif rotation == 270.0:
|
|
||||||
p1a2 = p1a[0] - 50, p1a[1] + 50 - RADIUS , z1
|
|
||||||
p1b2 = p1b[0] + 50, p1b[1] + 50 - RADIUS, z1
|
|
||||||
p2a2 = p2a[0] - 50, p2a[1] - 50 + RADIUS, z1
|
|
||||||
p2b2 = p2b[0] + 50, p2b[1] - 50 + RADIUS, z1
|
|
||||||
Line1 = Line.new(dxfattribs={"start": p1a2,"end": p2a2,"layer": "Pinbereich"})
|
|
||||||
Line2 = Line.new(dxfattribs={"start": p1b2,"end": p2b2,"layer": "Pinbereich"})
|
|
||||||
msp.add_entity(Line1)
|
|
||||||
msp.add_entity(Line2)
|
|
||||||
|
|
||||||
# Linien zeichnen
|
# Pin-Bereichsmarkierung (Lookup-Tabelle statt 4x copy-paste)
|
||||||
|
if kreisel.kreiselart == "Pin" and rotation in PIN_OFFSETS:
|
||||||
|
offsets = PIN_OFFSETS[rotation]
|
||||||
|
points = [p1a, p1b, p2a, p2b]
|
||||||
|
adjusted = [
|
||||||
|
(p[0] + offsets[i * 2], p[1] + offsets[i * 2 + 1], z1)
|
||||||
|
for i, p in enumerate(points)
|
||||||
|
]
|
||||||
|
p1a2, p1b2, p2a2, p2b2 = adjusted
|
||||||
|
msp.add_entity(Line.new(
|
||||||
|
dxfattribs={"start": p1a2, "end": p2a2, "layer": "Pinbereich"}
|
||||||
|
))
|
||||||
|
msp.add_entity(Line.new(
|
||||||
|
dxfattribs={"start": p1b2, "end": p2b2, "layer": "Pinbereich"}
|
||||||
|
))
|
||||||
|
|
||||||
|
# Hauptlinien zeichnen
|
||||||
msp.add_line(p1a, p2a)
|
msp.add_line(p1a, p2a)
|
||||||
msp.add_line(p1b, p2b)
|
msp.add_line(p1b, p2b)
|
||||||
|
|
||||||
def draw_kreisel_drehrichtung_markierung(msp, pos1, pos2, kreisel, lib_doc, doc, verbose):
|
@staticmethod
|
||||||
|
def draw_kreisel_drehrichtung_markierung(
|
||||||
|
msp, pos1, pos2, kreisel, lib_doc, doc, verbose
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Zeichnet Richtungspfeile für die Drehrichtung eines Kreisels.
|
||||||
|
|
||||||
|
Platziert 3 Pfeile auf der oberen und 3 auf der unteren Tangentiallinie,
|
||||||
|
mit invertierter Richtung zwischen oben und unten.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
msp: DXF-Modelspace
|
||||||
|
pos1, pos2: Positionen der beiden Kreisel-Blöcke
|
||||||
|
kreisel: Kreisel-Instanz
|
||||||
|
lib_doc: Bibliotheks-Dokument
|
||||||
|
doc: DXF-Dokument
|
||||||
|
verbose: Ob Debug-Ausgabe aktiviert ist
|
||||||
|
"""
|
||||||
drehrichtung = (kreisel.drehrichtung or "").upper()
|
drehrichtung = (kreisel.drehrichtung or "").upper()
|
||||||
if drehrichtung not in ("UZS", "GUZS"):
|
if drehrichtung not in ("UZS", "GUZS"):
|
||||||
return
|
return
|
||||||
x1, y1, z1 = pos1
|
x1, y1, z1 = pos1
|
||||||
x2, y2,z2 = pos2
|
x2, y2, _ = pos2
|
||||||
dx = x2 - x1
|
dx = x2 - x1
|
||||||
dy = y2 - y1
|
dy = y2 - y1
|
||||||
length = math.hypot(dx, dy)
|
length = math.hypot(dx, dy)
|
||||||
@@ -205,35 +272,59 @@ class Kreisel(BaseModel):
|
|||||||
# Normalenvektor (senkrecht, normiert, Länge = RADIUS)
|
# Normalenvektor (senkrecht, normiert, Länge = RADIUS)
|
||||||
nx = -dy / length * RADIUS
|
nx = -dy / length * RADIUS
|
||||||
ny = dx / length * RADIUS
|
ny = dx / length * RADIUS
|
||||||
# Obere Linie
|
# Obere und untere Tangentiallinien
|
||||||
p1_oben = (x1 + nx, y1 + ny)
|
p1_oben = (x1 + nx, y1 + ny)
|
||||||
p2_oben = (x2 + nx, y2 + ny)
|
p2_oben = (x2 + nx, y2 + ny)
|
||||||
# Untere Linie
|
|
||||||
p1_unten = (x1 - nx, y1 - ny)
|
p1_unten = (x1 - nx, y1 - ny)
|
||||||
p2_unten = (x2 - nx, y2 - ny)
|
p2_unten = (x2 - nx, y2 - ny)
|
||||||
# S-LP auf oberer Linie (Drehrichtung wie angegeben)
|
|
||||||
|
# Richtungspfeil einmal importieren (nicht 6x in der Schleife)
|
||||||
|
block_methoden.import_block("Richtungspfeil", lib_doc, doc)
|
||||||
|
blockref_layer, color = block_methoden.get_insert_color_layer(lib_doc, "Richtungspfeil")
|
||||||
|
|
||||||
|
# Obere Linie: Drehrichtung wie angegeben
|
||||||
|
Kreisel._place_richtungspfeile(
|
||||||
|
msp, p1_oben, p2_oben, z1, drehrichtung,
|
||||||
|
invert=False, blockref_layer=blockref_layer,
|
||||||
|
verbose=verbose, label="oben",
|
||||||
|
)
|
||||||
|
# Untere Linie: Drehrichtung invertiert
|
||||||
|
Kreisel._place_richtungspfeile(
|
||||||
|
msp, p1_unten, p2_unten, z1, drehrichtung,
|
||||||
|
invert=True, blockref_layer=blockref_layer,
|
||||||
|
verbose=verbose, label="unten",
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _place_richtungspfeile(msp, p1, p2, z, drehrichtung, invert, blockref_layer, verbose, label):
|
||||||
|
"""
|
||||||
|
Platziert 3 Richtungspfeile entlang einer Tangentiallinie.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
msp: DXF-Modelspace
|
||||||
|
p1, p2: Start-/End-Punkt der Linie (x, y)
|
||||||
|
z: Z-Koordinate
|
||||||
|
drehrichtung: "UZS" oder "GUZS"
|
||||||
|
invert: Ob die Richtung invertiert werden soll
|
||||||
|
blockref_layer: Layer für den Block-Reference
|
||||||
|
verbose: Ob Debug-Ausgabe aktiviert ist
|
||||||
|
label: "oben" oder "unten" für Logging
|
||||||
|
"""
|
||||||
for i in range(1, 4):
|
for i in range(1, 4):
|
||||||
t = i / 4 # 1/4, 2/4, 3/4
|
t = i / 4 # 1/4, 2/4, 3/4
|
||||||
px = p1_oben[0] + t * (p2_oben[0] - p1_oben[0])
|
px = p1[0] + t * (p2[0] - p1[0])
|
||||||
py = p1_oben[1] + t * (p2_oben[1] - p1_oben[1])
|
py = p1[1] + t * (p2[1] - p1[1])
|
||||||
rotation = math.degrees(math.atan2(p2_oben[1] - p1_oben[1], p2_oben[0] - p1_oben[0]))
|
rotation = math.degrees(math.atan2(p2[1] - p1[1], p2[0] - p1[0]))
|
||||||
if drehrichtung == "GUZS":
|
# Obere Linie: GUZS invertiert; Untere Linie: UZS invertiert
|
||||||
|
should_invert = (drehrichtung == "GUZS" and not invert) or (drehrichtung == "UZS" and invert)
|
||||||
|
if should_invert:
|
||||||
rotation += 180
|
rotation += 180
|
||||||
block_methoden.import_block("Richtungspfeil", lib_doc, doc)
|
msp.add_blockref(
|
||||||
blockref_layer, color = block_methoden.get_insert_color_layer(lib_doc, "Richtungspfeil")
|
"Richtungspfeil",
|
||||||
bref = msp.add_blockref("Richtungspfeil", (px, py,z1), dxfattribs={"rotation": rotation,"layer": blockref_layer})
|
(px, py, z),
|
||||||
|
dxfattribs={"rotation": rotation, "layer": blockref_layer},
|
||||||
|
)
|
||||||
if verbose:
|
if verbose:
|
||||||
print(f"[INFO] Drehrichtung '{drehrichtung}': Richtungspfeil oben bei ({px:.1f}, {py:.1f}), rot={rotation:.1f}")
|
print(
|
||||||
# S-LP auf unterer Linie (Drehrichtung invertiert)
|
f"[INFO] Drehrichtung '{drehrichtung}': Richtungspfeil {label} bei ({px:.1f}, {py:.1f}), rot={rotation:.1f}"
|
||||||
for i in range(1, 4):
|
)
|
||||||
t = i / 4
|
|
||||||
px = p1_unten[0] + t * (p2_unten[0] - p1_unten[0])
|
|
||||||
py = p1_unten[1] + t * (p2_unten[1] - p1_unten[1])
|
|
||||||
rotation = math.degrees(math.atan2(p2_unten[1] - p1_unten[1], p2_unten[0] - p1_unten[0]))
|
|
||||||
if drehrichtung == "UZS":
|
|
||||||
rotation += 180
|
|
||||||
block_methoden.import_block("Richtungspfeil", lib_doc, doc)
|
|
||||||
blockref_layer, color = block_methoden.get_insert_color_layer( lib_doc, "Richtungspfeil")
|
|
||||||
bref = msp.add_blockref("Richtungspfeil", (px, py, z1), dxfattribs={"rotation": rotation , "layer": blockref_layer})
|
|
||||||
if verbose:
|
|
||||||
print(f"[INFO] Drehrichtung '{drehrichtung}':Richtungspfeil unten bei ({px:.1f}, {py:.1f}), rot={rotation:.1f}")
|
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Unit-Tests für Kreisel (Refactored)
|
||||||
|
"""
|
||||||
|
import unittest
|
||||||
|
import math
|
||||||
|
|
||||||
|
from .Kreisel import Kreisel, RADIUS, PIN_OFFSET, PIN_OFFSETS
|
||||||
|
|
||||||
|
|
||||||
|
class TestKreiselModell(unittest.TestCase):
|
||||||
|
"""Tests für das Kreisel Pydantic-Modell."""
|
||||||
|
|
||||||
|
def test_from_merkmale(self):
|
||||||
|
merkmale = {
|
||||||
|
"Höhe in m": "2,5", # Komma-Format
|
||||||
|
"Abstand (Kreiselachse A - Kreiselachse) in Meter": "15",
|
||||||
|
"Drehung": "90",
|
||||||
|
"Drehrichtung": "UZS",
|
||||||
|
"Kreiselart": "Pin",
|
||||||
|
"Anzahl der Scanner": "1",
|
||||||
|
"Anzahl der Separatoren": "0",
|
||||||
|
}
|
||||||
|
obj = Kreisel.from_merkmale("K-001", 1000.0, 2000.0, merkmale)
|
||||||
|
self.assertEqual(obj.teileid, "K-001")
|
||||||
|
self.assertEqual(obj.hoehe, 2500.0) # 2.5 * 1000
|
||||||
|
self.assertEqual(obj.abstand, 15000.0) # 15 * 1000
|
||||||
|
self.assertEqual(obj.drehung, 90.0)
|
||||||
|
self.assertEqual(obj.drehrichtung, "UZS")
|
||||||
|
self.assertEqual(obj.kreiselart, "Pin")
|
||||||
|
|
||||||
|
def test_halbabstand(self):
|
||||||
|
obj = Kreisel(teileid="K", x=0, y=0, hoehe=0, abstand=10000)
|
||||||
|
self.assertEqual(obj.halbabstand, 5000.0)
|
||||||
|
|
||||||
|
def test_pos1_pos2_bei_90_grad(self):
|
||||||
|
obj = Kreisel(teileid="K", x=1000, y=1000, hoehe=500, abstand=2000, drehung=90)
|
||||||
|
# Bei 90° → winkel_rad = radians(90) → cos=0, sin=1
|
||||||
|
# pos1 = (x - halbabstand*cos, y - halbabstand*sin, z) = (1000-0, 1000-1000, 500)
|
||||||
|
self.assertAlmostEqual(obj.pos1[0], 1000.0, places=3)
|
||||||
|
self.assertAlmostEqual(obj.pos1[1], 0.0, places=3)
|
||||||
|
# pos2 = (x + halbabstand*cos, y + halbabstand*sin, z) = (1000+0, 1000+1000, 500)
|
||||||
|
self.assertAlmostEqual(obj.pos2[0], 1000.0, places=3)
|
||||||
|
self.assertAlmostEqual(obj.pos2[1], 2000.0, places=3)
|
||||||
|
|
||||||
|
|
||||||
|
class TestPinOffsets(unittest.TestCase):
|
||||||
|
"""Tests für die PIN_OFFSETS Lookup-Tabelle."""
|
||||||
|
|
||||||
|
def test_alle_rotationen_vorhanden(self):
|
||||||
|
for rotation in (0.0, 90.0, 180.0, 270.0):
|
||||||
|
self.assertIn(rotation, PIN_OFFSETS)
|
||||||
|
|
||||||
|
def test_offset_laenge(self):
|
||||||
|
# Jeder Eintrag muss 8 Werte haben (4 Punkte × 2 Koordinaten)
|
||||||
|
for rotation, offsets in PIN_OFFSETS.items():
|
||||||
|
self.assertEqual(len(offsets), 8, f"Rotation {rotation}: erwartet 8 Offsets")
|
||||||
|
|
||||||
|
def test_rotation_0_p1a_offset(self):
|
||||||
|
# p1a bei 0°: (-(RADIUS+PIN_OFFSET), +PIN_OFFSET)
|
||||||
|
offsets = PIN_OFFSETS[0.0]
|
||||||
|
self.assertEqual(offsets[0], -(RADIUS + PIN_OFFSET))
|
||||||
|
self.assertEqual(offsets[1], +PIN_OFFSET)
|
||||||
|
|
||||||
|
def test_rotation_90_p2b_offset(self):
|
||||||
|
# p2b bei 90°: (-PIN_OFFSET, -(RADIUS-PIN_OFFSET))
|
||||||
|
offsets = PIN_OFFSETS[90.0]
|
||||||
|
self.assertEqual(offsets[6], -PIN_OFFSET)
|
||||||
|
self.assertEqual(offsets[7], -(RADIUS - PIN_OFFSET))
|
||||||
|
|
||||||
|
def test_rotation_180_symmetrie_zu_0(self):
|
||||||
|
# 180° ist X-Spiegelung von 0° mit Y-Inversion
|
||||||
|
off_0 = PIN_OFFSETS[0.0]
|
||||||
|
off_180 = PIN_OFFSETS[180.0]
|
||||||
|
# p1a bei 0°: (-(R+O), +O) → p1a bei 180°: (+(R+O), -O)
|
||||||
|
self.assertEqual(off_180[0], -off_0[0])
|
||||||
|
self.assertEqual(off_180[1], -off_0[1])
|
||||||
|
|
||||||
|
|
||||||
|
class TestKreiselKonstanten(unittest.TestCase):
|
||||||
|
"""Tests für Kreisel-Konstanten."""
|
||||||
|
|
||||||
|
def test_radius_wert(self):
|
||||||
|
self.assertEqual(RADIUS, 400)
|
||||||
|
|
||||||
|
def test_pin_offset_wert(self):
|
||||||
|
self.assertEqual(PIN_OFFSET, 50)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
+132
-52
@@ -1,11 +1,77 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Omniflo — Modell und Erstellungsfunktionen für Omniflo-Kettenförderer.
|
||||||
|
|
||||||
|
Refactoring-Änderungen:
|
||||||
|
- 8x try/except-Boilerplate durch _safe_float/_safe_int Hilfsfunktionen ersetzt
|
||||||
|
- @staticmethod auf Omniflo_geraden_erstellung und omniflo_foerdererstellung
|
||||||
|
- Bug fix: omniflo_foerdererstellung nutzte rotation (Grad) statt winkel_rad in sin/cos
|
||||||
|
- Duplizierte dx/dy-Berechnung vereinheitlicht
|
||||||
|
"""
|
||||||
|
import math
|
||||||
|
|
||||||
from ezdxf.entities import Line
|
from ezdxf.entities import Line
|
||||||
import math
|
from pydantic import BaseModel, Field
|
||||||
from pydantic import BaseModel, Field, field_validator
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
import plant2dxf
|
|
||||||
import block_methoden
|
from lib import block_methoden
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# HILFSFUNKTIONEN
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
def _safe_float(value, default=0.0):
|
||||||
|
"""
|
||||||
|
Konvertiert einen Wert zu float mit Fallback.
|
||||||
|
|
||||||
|
Behandelt automatisch Komma-als-Dezimaltrennzeichen (z.B. "3,5" → 3.5).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: Zu konvertierender Wert (str, int, float oder None)
|
||||||
|
default: Rückgabewert bei Konvertierungsfehler
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Float-Wert oder default
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if value is None:
|
||||||
|
return default
|
||||||
|
if isinstance(value, str):
|
||||||
|
value = value.replace(",", ".")
|
||||||
|
return float(value)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
def _safe_int(value, default=0):
|
||||||
|
"""
|
||||||
|
Konvertiert einen Wert zu int mit Fallback (über float-Zwischenschritt).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: Zu konvertierender Wert
|
||||||
|
default: Rückgabewert bei Konvertierungsfehler
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Int-Wert oder default
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if value is None:
|
||||||
|
return default
|
||||||
|
return int(float(value))
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# OMNIFLO KLASSE
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
|
||||||
class Omniflo(BaseModel):
|
class Omniflo(BaseModel):
|
||||||
|
"""Modell für Omniflo-Kettenförderer."""
|
||||||
|
|
||||||
teileid: str
|
teileid: str
|
||||||
x: float
|
x: float
|
||||||
y: float
|
y: float
|
||||||
@@ -16,62 +82,64 @@ class Omniflo(BaseModel):
|
|||||||
h0: Optional[float] = Field(default=0.0, description="Höhe unten im CSV")
|
h0: Optional[float] = Field(default=0.0, description="Höhe unten im CSV")
|
||||||
h1: Optional[float] = Field(default=0.0, description="Höhe Oben im CSV")
|
h1: Optional[float] = Field(default=0.0, description="Höhe Oben im CSV")
|
||||||
anzahl_scanner: Optional[int] = Field(default=0, description="Anzahl der Scanner")
|
anzahl_scanner: Optional[int] = Field(default=0, description="Anzahl der Scanner")
|
||||||
anzahl_stopper: Optional [int] = Field(default=0, description="Anzahl der Separatoren")
|
anzahl_stopper: Optional[int] = Field(
|
||||||
|
default=0, description="Anzahl der Separatoren"
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hight_zwischen(self):
|
def hight_zwischen(self):
|
||||||
return ((self.h0 + self.h1) /2)
|
"""Mittlere Höhe zwischen h0 und h1."""
|
||||||
|
return (self.h0 + self.h1) / 2
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_merkmale(cls, teileid, x, y, merkmale):
|
def from_merkmale(cls, teileid, x, y, merkmale):
|
||||||
sivasnummer = merkmale.get("SivasNummer")
|
"""
|
||||||
try:
|
Erstellt Omniflo aus einem Merkmale-Dictionary.
|
||||||
laenge = float(merkmale.get("Länge in Meter", "0").replace(",", ".")) * 1000 # Meter → mm
|
|
||||||
except Exception:
|
Verwendet _safe_float/_safe_int für robuste Konvertierung
|
||||||
laenge = 0
|
statt 8x wiederholtem try/except-Muster.
|
||||||
try:
|
|
||||||
winkel = float(merkmale.get("Drehung"))
|
Args:
|
||||||
except Exception:
|
teileid: Teile-Identifikator
|
||||||
winkel = 0.0
|
x, y: Koordinaten in mm
|
||||||
try:
|
merkmale: Dictionary mit Eigenschaftswerten
|
||||||
hoehe = float(merkmale.get("Höhe"))
|
|
||||||
except Exception:
|
Returns:
|
||||||
hoehe = 0.0
|
Omniflo-Instanz
|
||||||
try:
|
"""
|
||||||
h0 = float(merkmale.get("Höhe unten"))
|
|
||||||
except Exception:
|
|
||||||
h0 = 0.0
|
|
||||||
try:
|
|
||||||
h1 = float(merkmale.get("Höhe oben"))
|
|
||||||
except Exception:
|
|
||||||
h1 = 0.0
|
|
||||||
try:
|
|
||||||
anzahl_scanner = float(merkmale.get("Anzahl der Scanner", "0"))
|
|
||||||
except Exception:
|
|
||||||
anzahl_scanner = 0
|
|
||||||
try:
|
|
||||||
anzahl_separatoren = float(merkmale.get("Anzahl der Separatoren", "0"))
|
|
||||||
except Exception:
|
|
||||||
anzahl_separatoren = 0
|
|
||||||
return cls(
|
return cls(
|
||||||
teileid=teileid,
|
teileid=teileid,
|
||||||
x=x,
|
x=x,
|
||||||
y=y,
|
y=y,
|
||||||
sivasnummer = sivasnummer,
|
sivasnummer=merkmale.get("SivasNummer"),
|
||||||
laenge = laenge,
|
laenge=_safe_float(merkmale.get("Länge in Meter"), 0.0) * 1000, # Meter → mm
|
||||||
drehung = winkel,
|
drehung=_safe_float(merkmale.get("Drehung"), 0.0),
|
||||||
hoehe = hoehe,
|
hoehe=_safe_float(merkmale.get("Höhe"), 0.0),
|
||||||
h0 = h0,
|
h0=_safe_float(merkmale.get("Höhe unten"), 0.0),
|
||||||
h1 = h1,
|
h1=_safe_float(merkmale.get("Höhe oben"), 0.0),
|
||||||
anzahl_scanner = anzahl_scanner,
|
anzahl_scanner=_safe_int(merkmale.get("Anzahl der Scanner"), 0),
|
||||||
anzahl_stopper = anzahl_separatoren
|
anzahl_stopper=_safe_int(merkmale.get("Anzahl der Separatoren"), 0),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def Omniflo_geraden_erstellung(msp, doc, tefsivas, omniflo_objekt):
|
def Omniflo_geraden_erstellung(msp, doc, tefsivas, omniflo_objekt):
|
||||||
"""Erstellung der Tef gerade und Omniflo gerade"""
|
"""
|
||||||
|
Erstellung der Tef gerade und Omniflo gerade.
|
||||||
|
|
||||||
|
Zeichnet eine Linie zwischen Start- und Endpunkt basierend auf
|
||||||
|
Länge und Drehung des Omniflo-Objekts.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
msp: DXF-Modelspace
|
||||||
|
doc: DXF-Dokument
|
||||||
|
tefsivas: Sivas-Nummer der Tef-Strecke
|
||||||
|
omniflo_objekt: Omniflo-Instanz
|
||||||
|
"""
|
||||||
winkel_rad = math.radians(omniflo_objekt.drehung)
|
winkel_rad = math.radians(omniflo_objekt.drehung)
|
||||||
halbe_laenge = omniflo_objekt.laenge / 2
|
halbe_laenge = omniflo_objekt.laenge / 2
|
||||||
x = omniflo_objekt.x
|
x = omniflo_objekt.x
|
||||||
y = omniflo_objekt.y
|
y = omniflo_objekt.y
|
||||||
# Man muss bei sin -1 machen wegen des links koordinaten system
|
# Koordinatensystem: sin mit -1 wegen links-Koordinatensystem
|
||||||
dx = halbe_laenge * math.sin(winkel_rad * -1)
|
dx = halbe_laenge * math.sin(winkel_rad * -1)
|
||||||
dy = halbe_laenge * math.cos(winkel_rad)
|
dy = halbe_laenge * math.cos(winkel_rad)
|
||||||
start = (x + dx, y + dy, omniflo_objekt.h1)
|
start = (x + dx, y + dy, omniflo_objekt.h1)
|
||||||
@@ -85,8 +153,18 @@ class Omniflo(BaseModel):
|
|||||||
linie.dxf.layer = "F-1"
|
linie.dxf.layer = "F-1"
|
||||||
else:
|
else:
|
||||||
linie.dxf.layer = "A-2"
|
linie.dxf.layer = "A-2"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def omniflo_foerdererstellung(msp, doc, lib_doc, omniflo_objekt):
|
def omniflo_foerdererstellung(msp, doc, lib_doc, omniflo_objekt):
|
||||||
""""Erstellung des Kettenförderers aktuell nur grundriss"""
|
"""
|
||||||
|
Erstellung des Kettenförderers (aktuell nur Grundriss).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
msp: DXF-Modelspace
|
||||||
|
doc: DXF-Dokument
|
||||||
|
lib_doc: Bibliotheks-Dokument
|
||||||
|
omniflo_objekt: Omniflo-Instanz
|
||||||
|
"""
|
||||||
block_methoden.import_block("bogen1", lib_doc, doc)
|
block_methoden.import_block("bogen1", lib_doc, doc)
|
||||||
block_methoden.import_block("bogen2", lib_doc, doc)
|
block_methoden.import_block("bogen2", lib_doc, doc)
|
||||||
x = omniflo_objekt.x
|
x = omniflo_objekt.x
|
||||||
@@ -96,12 +174,13 @@ class Omniflo(BaseModel):
|
|||||||
h0 = omniflo_objekt.h0
|
h0 = omniflo_objekt.h0
|
||||||
h1 = omniflo_objekt.h1
|
h1 = omniflo_objekt.h1
|
||||||
h_zwischen = omniflo_objekt.hight_zwischen
|
h_zwischen = omniflo_objekt.hight_zwischen
|
||||||
blockname = (f"OF_Förderer_{laenge}_{h_zwischen}")
|
blockname = f"OF_Förderer_{laenge}_{h_zwischen}"
|
||||||
winkel_rad = math.radians(rotation)
|
winkel_rad = math.radians(rotation)
|
||||||
halbe_laenge = laenge / 2
|
halbe_laenge = laenge / 2
|
||||||
# Man muss bei sin -1 machen wegen des links koordinaten system
|
# BUG FIX: war `math.sin(rotation * -1)` — rotation ist in Grad!
|
||||||
dx = halbe_laenge * math.sin(rotation * -1)
|
# Muss winkel_rad (Radianten) verwenden wie in Omniflo_geraden_erstellung
|
||||||
dy = halbe_laenge * math.cos(rotation)
|
dx = halbe_laenge * math.sin(winkel_rad * -1)
|
||||||
|
dy = halbe_laenge * math.cos(winkel_rad)
|
||||||
start = (x + dx, y + dy, h1)
|
start = (x + dx, y + dy, h1)
|
||||||
ende = (x - dx, y - dy, h0)
|
ende = (x - dx, y - dy, h0)
|
||||||
if blockname not in doc.blocks:
|
if blockname not in doc.blocks:
|
||||||
@@ -112,5 +191,6 @@ class Omniflo(BaseModel):
|
|||||||
copy = line.copy()
|
copy = line.copy()
|
||||||
copy.translate(-x, -y, -h_zwischen)
|
copy.translate(-x, -y, -h_zwischen)
|
||||||
block.add_entity(copy)
|
block.add_entity(copy)
|
||||||
msp.add_blockref(blockname,(x,y,h_zwischen),dxfattribs={"rotation": rotation})
|
msp.add_blockref(
|
||||||
|
blockname, (x, y, h_zwischen), dxfattribs={"rotation": rotation}
|
||||||
|
)
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Unit-Tests für Omniflo (Refactored)
|
||||||
|
"""
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from .Omniflo import Omniflo, _safe_float, _safe_int
|
||||||
|
|
||||||
|
|
||||||
|
class TestSafeFloat(unittest.TestCase):
|
||||||
|
"""Tests für _safe_float Hilfsfunktion."""
|
||||||
|
|
||||||
|
def test_normaler_string(self):
|
||||||
|
self.assertEqual(_safe_float("3.14"), 3.14)
|
||||||
|
|
||||||
|
def test_komma_als_dezimaltrenner(self):
|
||||||
|
self.assertEqual(_safe_float("3,14"), 3.14)
|
||||||
|
|
||||||
|
def test_none_gibt_default(self):
|
||||||
|
self.assertEqual(_safe_float(None, 42.0), 42.0)
|
||||||
|
|
||||||
|
def test_ungueltiger_string_gibt_default(self):
|
||||||
|
self.assertEqual(_safe_float("abc", 1.0), 1.0)
|
||||||
|
|
||||||
|
def test_int_input(self):
|
||||||
|
self.assertEqual(_safe_float(5), 5.0)
|
||||||
|
|
||||||
|
def test_float_input(self):
|
||||||
|
self.assertEqual(_safe_float(2.5), 2.5)
|
||||||
|
|
||||||
|
|
||||||
|
class TestSafeInt(unittest.TestCase):
|
||||||
|
"""Tests für _safe_int Hilfsfunktion."""
|
||||||
|
|
||||||
|
def test_normaler_string(self):
|
||||||
|
self.assertEqual(_safe_int("3"), 3)
|
||||||
|
|
||||||
|
def test_float_string_wird_getruncated(self):
|
||||||
|
self.assertEqual(_safe_int("3.7"), 3)
|
||||||
|
|
||||||
|
def test_none_gibt_default(self):
|
||||||
|
self.assertEqual(_safe_int(None, 7), 7)
|
||||||
|
|
||||||
|
def test_ungueltiger_string(self):
|
||||||
|
self.assertEqual(_safe_int("xyz", 0), 0)
|
||||||
|
|
||||||
|
|
||||||
|
class TestOmnifloModell(unittest.TestCase):
|
||||||
|
"""Tests für das Omniflo Modell."""
|
||||||
|
|
||||||
|
def test_from_merkmale_vollstaendig(self):
|
||||||
|
merkmale = {
|
||||||
|
"SivasNummer": "SV-123",
|
||||||
|
"Länge in Meter": "10,5", # Komma-Format
|
||||||
|
"Drehung": "-180",
|
||||||
|
"Höhe": "3.0",
|
||||||
|
"Höhe unten": "1.0",
|
||||||
|
"Höhe oben": "2.0",
|
||||||
|
"Anzahl der Scanner": "2",
|
||||||
|
"Anzahl der Separatoren": "1",
|
||||||
|
}
|
||||||
|
obj = Omniflo.from_merkmale("TEST-001", 50.0, 60.0, merkmale)
|
||||||
|
self.assertEqual(obj.teileid, "TEST-001")
|
||||||
|
self.assertEqual(obj.sivasnummer, "SV-123")
|
||||||
|
self.assertAlmostEqual(obj.laenge, 10500.0) # 10.5 * 1000
|
||||||
|
self.assertEqual(obj.drehung, -180.0)
|
||||||
|
self.assertEqual(obj.hoehe, 3.0)
|
||||||
|
self.assertEqual(obj.h0, 1.0)
|
||||||
|
self.assertEqual(obj.h1, 2.0)
|
||||||
|
self.assertEqual(obj.anzahl_scanner, 2)
|
||||||
|
self.assertEqual(obj.anzahl_stopper, 1)
|
||||||
|
|
||||||
|
def test_from_merkmale_fehlende_werte(self):
|
||||||
|
# Fehlende optionale Felder → defaults
|
||||||
|
merkmale = {
|
||||||
|
"SivasNummer": "SV-001",
|
||||||
|
}
|
||||||
|
obj = Omniflo.from_merkmale("TEST-002", 0.0, 0.0, merkmale)
|
||||||
|
self.assertEqual(obj.laenge, 0.0) # None * 1000 → default 0 * 1000
|
||||||
|
self.assertEqual(obj.drehung, 0.0)
|
||||||
|
self.assertEqual(obj.hoehe, 0.0)
|
||||||
|
|
||||||
|
def test_hight_zwischen(self):
|
||||||
|
merkmale = {
|
||||||
|
"SivasNummer": "SV-001",
|
||||||
|
"Höhe unten": "1.0",
|
||||||
|
"Höhe oben": "3.0",
|
||||||
|
}
|
||||||
|
obj = Omniflo.from_merkmale("TEST-003", 0.0, 0.0, merkmale)
|
||||||
|
self.assertEqual(obj.hight_zwischen, 2.0)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
+1140
-684
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,284 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Unit-Tests für VarioFoerderer (Refactored)
|
||||||
|
|
||||||
|
Diese Tests können direkt in der Library-Methode verwendet werden
|
||||||
|
oder als separate Test-Datei ausgeführt werden.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import math
|
||||||
|
from unittest.mock import Mock, MagicMock
|
||||||
|
from .VarioFoerderer import (
|
||||||
|
VarioFoerderer,
|
||||||
|
Foerderrichtung,
|
||||||
|
MotorUmlenkConfig,
|
||||||
|
BogenDeltas,
|
||||||
|
OffsetResult,
|
||||||
|
_parse_delta_attribute,
|
||||||
|
_calculate_offset_with_rotation,
|
||||||
|
_is_es_as_element,
|
||||||
|
horizontale_ausrichtung,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestMotorUmlenkConfig(unittest.TestCase):
|
||||||
|
"""Tests für MotorUmlenkConfig Dataclass"""
|
||||||
|
|
||||||
|
def test_motor_offset_berechnung(self):
|
||||||
|
"""Test: Motor-Offset-Berechnung"""
|
||||||
|
config = MotorUmlenkConfig(
|
||||||
|
winkel_motor=45.0,
|
||||||
|
winkel_umlenk=30.0,
|
||||||
|
umlenk_laenge=(100.0, 50.0),
|
||||||
|
motor_laenge=(80.0, 40.0),
|
||||||
|
vario_abstand=25.0
|
||||||
|
)
|
||||||
|
|
||||||
|
# Motor-Offsets
|
||||||
|
expected_motor_x = 100.0 * math.cos(math.radians(45.0))
|
||||||
|
expected_motor_z = 100.0 * math.sin(math.radians(45.0))
|
||||||
|
|
||||||
|
self.assertAlmostEqual(config.motor_offset_x, expected_motor_x, places=5)
|
||||||
|
self.assertAlmostEqual(config.motor_offset_z, expected_motor_z, places=5)
|
||||||
|
|
||||||
|
def test_umlenk_offset_berechnung(self):
|
||||||
|
"""Test: Umlenk-Offset-Berechnung"""
|
||||||
|
config = MotorUmlenkConfig(
|
||||||
|
winkel_motor=45.0,
|
||||||
|
winkel_umlenk=30.0,
|
||||||
|
umlenk_laenge=(100.0, 50.0),
|
||||||
|
motor_laenge=(80.0, 40.0),
|
||||||
|
vario_abstand=25.0
|
||||||
|
)
|
||||||
|
|
||||||
|
# Umlenk-Offsets
|
||||||
|
expected_umlenk_x = 80.0 * math.cos(math.radians(30.0))
|
||||||
|
expected_umlenk_z = 80.0 * math.sin(math.radians(30.0))
|
||||||
|
|
||||||
|
self.assertAlmostEqual(config.umlenk_offset_x, expected_umlenk_x, places=5)
|
||||||
|
self.assertAlmostEqual(config.umlenk_offset_z, expected_umlenk_z, places=5)
|
||||||
|
|
||||||
|
|
||||||
|
class TestBogenDeltas(unittest.TestCase):
|
||||||
|
"""Tests für BogenDeltas Dataclass"""
|
||||||
|
|
||||||
|
def test_normalize_negative_values(self):
|
||||||
|
"""Test: Normalisierung negativer Werte"""
|
||||||
|
deltas = BogenDeltas(
|
||||||
|
SP_0=[-10.0, -20.0, 5.0],
|
||||||
|
SP_1=[15.0, -25.0, 10.0],
|
||||||
|
VP_0=[-5.0, 8.0, -3.0],
|
||||||
|
VP_1=[12.0, -15.0, 7.0]
|
||||||
|
)
|
||||||
|
|
||||||
|
deltas.normalize_negative_values()
|
||||||
|
|
||||||
|
# X und Y (Index 0 und 1) sollen positiv sein, Z (Index 2) unverändert
|
||||||
|
self.assertEqual(deltas.SP_0, [10.0, 20.0, 5.0])
|
||||||
|
self.assertEqual(deltas.SP_1, [15.0, 25.0, 10.0])
|
||||||
|
self.assertEqual(deltas.VP_0, [5.0, 8.0, -3.0])
|
||||||
|
self.assertEqual(deltas.VP_1, [12.0, 15.0, 7.0])
|
||||||
|
|
||||||
|
|
||||||
|
class TestVarioFoerderer(unittest.TestCase):
|
||||||
|
"""Tests für VarioFoerderer Modell"""
|
||||||
|
|
||||||
|
def test_from_merkmale(self):
|
||||||
|
"""Test: VarioFoerderer aus Merkmale-Dict erstellen"""
|
||||||
|
merkmale = {
|
||||||
|
"Höhe Anfang": "1.5",
|
||||||
|
"Höhe Ende": "2.0",
|
||||||
|
"Länge in Meter": "5.0",
|
||||||
|
"Winkel": "6",
|
||||||
|
"Motorstation_hinten": True,
|
||||||
|
"Spannstation_vorn": False,
|
||||||
|
"Drehung": "-90",
|
||||||
|
"Förderrichtung": "Auf",
|
||||||
|
"Anzahl der Scanner": "2",
|
||||||
|
"Anzahl der Separatoren": "3",
|
||||||
|
}
|
||||||
|
|
||||||
|
foerderer = VarioFoerderer.from_merkmale("TEST-001", 100.0, 200.0, merkmale)
|
||||||
|
|
||||||
|
self.assertEqual(foerderer.teileid, "TEST-001")
|
||||||
|
self.assertEqual(foerderer.x, 100.0)
|
||||||
|
self.assertEqual(foerderer.y, 200.0)
|
||||||
|
self.assertEqual(foerderer.h0, 1500.0) # 1.5 * 1000
|
||||||
|
self.assertEqual(foerderer.h1, 2000.0) # 2.0 * 1000
|
||||||
|
self.assertEqual(foerderer.laenge, 5000.0) # 5.0 * 1000
|
||||||
|
self.assertEqual(foerderer.winkel, 6.0)
|
||||||
|
self.assertTrue(foerderer.hat_motor)
|
||||||
|
self.assertFalse(foerderer.hat_umlenk)
|
||||||
|
self.assertEqual(foerderer.drehung, -90.0)
|
||||||
|
self.assertEqual(foerderer.foerderer_richtung, "Auf")
|
||||||
|
self.assertEqual(foerderer.anzahl_scanner, 2)
|
||||||
|
self.assertEqual(foerderer.anzahl_separatoren, 3)
|
||||||
|
|
||||||
|
def test_hight_zwischen(self):
|
||||||
|
"""Test: Berechnung der mittleren Höhe"""
|
||||||
|
merkmale = {
|
||||||
|
"Höhe Anfang": "1.0",
|
||||||
|
"Höhe Ende": "3.0",
|
||||||
|
"Länge in Meter": "1.0",
|
||||||
|
"Winkel": "3",
|
||||||
|
"Motorstation_hinten": False,
|
||||||
|
"Spannstation_vorn": False,
|
||||||
|
"Drehung": "0",
|
||||||
|
"Förderrichtung": "Auf",
|
||||||
|
"Anzahl der Scanner": "0",
|
||||||
|
"Anzahl der Separatoren": "0",
|
||||||
|
}
|
||||||
|
|
||||||
|
foerderer = VarioFoerderer.from_merkmale("TEST-002", 0, 0, merkmale)
|
||||||
|
expected_height = (1000.0 + 3000.0) / 2 # (h0 + h1) / 2
|
||||||
|
|
||||||
|
self.assertEqual(foerderer.hight_zwischen, expected_height)
|
||||||
|
|
||||||
|
|
||||||
|
class TestHilfsfunktionen(unittest.TestCase):
|
||||||
|
"""Tests für generische Hilfsfunktionen"""
|
||||||
|
|
||||||
|
def test_parse_delta_attribute(self):
|
||||||
|
"""Test: Delta-Attribut parsen"""
|
||||||
|
attrib_dict = {
|
||||||
|
"DELTA_SP_0": "10.5;20.3;-5.7",
|
||||||
|
"DELTA_VP_1": "15.2,25.8,-8.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
result_sp = _parse_delta_attribute(attrib_dict, "DELTA_SP_0")
|
||||||
|
result_vp = _parse_delta_attribute(attrib_dict, "DELTA_VP_1")
|
||||||
|
|
||||||
|
self.assertEqual(result_sp, [10.5, 20.3, -5.7])
|
||||||
|
self.assertEqual(result_vp, [15.2, 25.8, -8.1])
|
||||||
|
|
||||||
|
def test_calculate_offset_with_rotation(self):
|
||||||
|
"""Test: Offset-Berechnung mit Rotation"""
|
||||||
|
SP = [10.0, 5.0, 8.0]
|
||||||
|
VP = [2.0, 5.0, 3.0]
|
||||||
|
winkel = 45.0
|
||||||
|
|
||||||
|
result = _calculate_offset_with_rotation(SP, VP, winkel)
|
||||||
|
|
||||||
|
# Erwartete Werte berechnen
|
||||||
|
rad = math.radians(45.0)
|
||||||
|
expected_x = (SP[0] - VP[0]) * math.cos(rad) + (SP[2] - VP[2]) * math.sin(rad)
|
||||||
|
expected_y = VP[1]
|
||||||
|
expected_z = -(SP[0] - VP[0]) * math.sin(rad) + (SP[2] - VP[2]) * math.cos(rad)
|
||||||
|
|
||||||
|
self.assertAlmostEqual(result[0], expected_x, places=5)
|
||||||
|
self.assertAlmostEqual(result[1], expected_y, places=5)
|
||||||
|
self.assertAlmostEqual(result[2], expected_z, places=5)
|
||||||
|
|
||||||
|
def test_is_es_as_element_true(self):
|
||||||
|
"""Test: ES/AS-Element erkennen"""
|
||||||
|
entity = Mock()
|
||||||
|
entity.dxftype.return_value = "INSERT"
|
||||||
|
entity.dxf.name = "200000146_ES-Element_90_rechts_modified"
|
||||||
|
|
||||||
|
self.assertTrue(_is_es_as_element(entity))
|
||||||
|
|
||||||
|
def test_is_es_as_element_false(self):
|
||||||
|
"""Test: Kein ES/AS-Element"""
|
||||||
|
entity = Mock()
|
||||||
|
entity.dxftype.return_value = "INSERT"
|
||||||
|
entity.dxf.name = "Vario_Bogen_auf_12°"
|
||||||
|
|
||||||
|
self.assertFalse(_is_es_as_element(entity))
|
||||||
|
|
||||||
|
def test_is_es_as_element_not_insert(self):
|
||||||
|
"""Test: Kein INSERT-Entity"""
|
||||||
|
entity = Mock()
|
||||||
|
entity.dxftype.return_value = "LINE"
|
||||||
|
|
||||||
|
self.assertFalse(_is_es_as_element(entity))
|
||||||
|
|
||||||
|
|
||||||
|
class TestHorizontaleAusrichtung(unittest.TestCase):
|
||||||
|
"""Tests für horizontale_ausrichtung Funktion"""
|
||||||
|
|
||||||
|
def test_horizontal_rotation_0(self):
|
||||||
|
"""Test: Horizontale Ausrichtung bei Rotation 0°"""
|
||||||
|
merkmale = {
|
||||||
|
"Höhe Anfang": "1.0",
|
||||||
|
"Höhe Ende": "1.0",
|
||||||
|
"Länge in Meter": "1.0",
|
||||||
|
"Winkel": "3",
|
||||||
|
"Motorstation_hinten": False,
|
||||||
|
"Spannstation_vorn": False,
|
||||||
|
"Drehung": "0",
|
||||||
|
"Förderrichtung": "Horizontal",
|
||||||
|
"Anzahl der Scanner": "0",
|
||||||
|
"Anzahl der Separatoren": "0",
|
||||||
|
}
|
||||||
|
|
||||||
|
foerderer = VarioFoerderer.from_merkmale("TEST", 100.0, 200.0, merkmale)
|
||||||
|
|
||||||
|
# Förderer ist über Kreisel (y > y_kreisel)
|
||||||
|
result = horizontale_ausrichtung(foerderer, 100.0, 100.0)
|
||||||
|
self.assertEqual(result, "unten_drehung_0_or_-90")
|
||||||
|
|
||||||
|
# Förderer ist unter Kreisel (y < y_kreisel)
|
||||||
|
result = horizontale_ausrichtung(foerderer, 100.0, 300.0)
|
||||||
|
self.assertEqual(result, "oben_drehung_0_or_-90")
|
||||||
|
|
||||||
|
def test_nicht_horizontal(self):
|
||||||
|
"""Test: Nicht-horizontale Förderer geben 'None' zurück"""
|
||||||
|
merkmale = {
|
||||||
|
"Höhe Anfang": "1.0",
|
||||||
|
"Höhe Ende": "2.0",
|
||||||
|
"Länge in Meter": "1.0",
|
||||||
|
"Winkel": "6",
|
||||||
|
"Motorstation_hinten": False,
|
||||||
|
"Spannstation_vorn": False,
|
||||||
|
"Drehung": "0",
|
||||||
|
"Förderrichtung": "Auf",
|
||||||
|
"Anzahl der Scanner": "0",
|
||||||
|
"Anzahl der Separatoren": "0",
|
||||||
|
}
|
||||||
|
|
||||||
|
foerderer = VarioFoerderer.from_merkmale("TEST", 100.0, 200.0, merkmale)
|
||||||
|
result = horizontale_ausrichtung(foerderer, 100.0, 100.0)
|
||||||
|
|
||||||
|
self.assertEqual(result, "None")
|
||||||
|
|
||||||
|
|
||||||
|
class TestFoerderrichtungEnum(unittest.TestCase):
|
||||||
|
"""Tests für Foerderrichtung Enum"""
|
||||||
|
|
||||||
|
def test_enum_werte(self):
|
||||||
|
"""Test: Enum-Werte sind korrekt"""
|
||||||
|
self.assertEqual(Foerderrichtung.AUF.value, "Auf")
|
||||||
|
self.assertEqual(Foerderrichtung.AB.value, "Ab")
|
||||||
|
self.assertEqual(Foerderrichtung.HORIZONTAL.value, "Horizontal")
|
||||||
|
|
||||||
|
def test_enum_vergleich(self):
|
||||||
|
"""Test: Enum-Vergleich funktioniert"""
|
||||||
|
richtung = "Auf"
|
||||||
|
self.assertEqual(richtung, Foerderrichtung.AUF.value)
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Test-Runner
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
def run_tests():
|
||||||
|
"""Führt alle Unit-Tests aus"""
|
||||||
|
loader = unittest.TestLoader()
|
||||||
|
suite = loader.loadTestsFromModule(__import__(__name__))
|
||||||
|
runner = unittest.TextTestRunner(verbosity=2)
|
||||||
|
result = runner.run(suite)
|
||||||
|
|
||||||
|
print("\n" + "="*70)
|
||||||
|
print(f"Tests durchgeführt: {result.testsRun}")
|
||||||
|
print(f"Erfolgreich: {result.testsRun - len(result.failures) - len(result.errors)}")
|
||||||
|
print(f"Fehlgeschlagen: {len(result.failures)}")
|
||||||
|
print(f"Errors: {len(result.errors)}")
|
||||||
|
print("="*70)
|
||||||
|
|
||||||
|
return result.wasSuccessful()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
success = run_tests()
|
||||||
|
exit(0 if success else 1)
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import csv
|
import csv
|
||||||
@@ -5,8 +6,8 @@ import json
|
|||||||
import re
|
import re
|
||||||
import configparser
|
import configparser
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from utils import check_environment_var, setup_logger
|
from lib.utils import check_environment_var, setup_logger
|
||||||
from Elemente import Kreisel, VarioFoerderer,Gefaehllestrecke,Angetriebene_Kurve,Bt_element,Omniflo, Eckrad
|
from lib.Elemente import Kreisel, VarioFoerderer,Gefaellestrecke,Angetriebene_Kurve,Bt_element,Omniflo, Eckrad
|
||||||
# --------------------------------------------------------- CFG-Leser für shapes.cfg
|
# --------------------------------------------------------- CFG-Leser für shapes.cfg
|
||||||
def get_shape_cfg(teileart, cfg_path, logger=None):
|
def get_shape_cfg(teileart, cfg_path, logger=None):
|
||||||
parser = configparser.ConfigParser()
|
parser = configparser.ConfigParser()
|
||||||
|
|||||||
+637
-228
File diff suppressed because it is too large
Load Diff
+63
-19
@@ -1,24 +1,35 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
import math
|
import math
|
||||||
import plant2dxf
|
from lib import plant2dxf
|
||||||
from ezdxf import units
|
from ezdxf import units
|
||||||
from ezdxf.entities import Line
|
from ezdxf.entities import Line
|
||||||
from ezdxf.addons import importer
|
from ezdxf.addons import importer
|
||||||
from ezdxf.math import Matrix44, X_AXIS, Y_AXIS, Z_AXIS
|
from ezdxf.math import Matrix44, X_AXIS, Y_AXIS, Z_AXIS
|
||||||
|
|
||||||
|
|
||||||
def dreh_block(block_name: str, to_doc, lib_doc, winkel):
|
def dreh_block(block_name: str, to_doc, lib_doc, winkel):
|
||||||
"""Nimmt ein schon importierten Block und erstellt einen neuen der an der y_axis oder x_axis gedreht wird
|
"""Nimmt ein schon importierten Block und erstellt einen neuen der an der y_axis oder x_axis gedreht wird"""
|
||||||
"""
|
|
||||||
dreh_block_name = block_name + f"_{math.degrees(winkel)}"
|
dreh_block_name = block_name + f"_{math.degrees(winkel)}"
|
||||||
layer, color = get_insert_color_layer(lib_doc, block_name)
|
layer, color = get_insert_color_layer(lib_doc, block_name)
|
||||||
if (dreh_block_name in to_doc.blocks):
|
if dreh_block_name in to_doc.blocks:
|
||||||
return dreh_block_name
|
return dreh_block_name
|
||||||
block_zwischen = to_doc.blocks.new(name=block_name + f"zwischenschrit_{winkel}", base_point=(0,0,0))
|
block_zwischen = to_doc.blocks.new(
|
||||||
|
name=block_name + f"zwischenschrit_{winkel}", base_point=(0, 0, 0)
|
||||||
|
)
|
||||||
block = to_doc.blocks.new(name=dreh_block_name, base_point=(0, 0, 0))
|
block = to_doc.blocks.new(name=dreh_block_name, base_point=(0, 0, 0))
|
||||||
if block_name == "200000146_ES-Element_90_rechts" or block_name =="400102632_ES-Element_90_links" or block_name =="200000241_AS-Element_90_rechts" or block_name =="200000217_AS-Element_90_links":
|
if (
|
||||||
|
block_name == "200000146_ES-Element_90_rechts"
|
||||||
|
or block_name == "400102632_ES-Element_90_links"
|
||||||
|
or block_name == "200000241_AS-Element_90_rechts"
|
||||||
|
or block_name == "200000217_AS-Element_90_links"
|
||||||
|
):
|
||||||
rotation_matrix = Matrix44.axis_rotate(X_AXIS, winkel)
|
rotation_matrix = Matrix44.axis_rotate(X_AXIS, winkel)
|
||||||
else:
|
else:
|
||||||
rotation_matrix = Matrix44.axis_rotate(Y_AXIS, winkel)
|
rotation_matrix = Matrix44.axis_rotate(Y_AXIS, winkel)
|
||||||
|
|
||||||
block_zwischen.add_blockref(block_name,(0,0,0),dxfattribs={"layer":layer,"color": color})
|
block_zwischen.add_blockref(
|
||||||
|
block_name, (0, 0, 0), dxfattribs={"layer": layer, "color": color}
|
||||||
|
)
|
||||||
for e in block_zwischen:
|
for e in block_zwischen:
|
||||||
copy = e.copy()
|
copy = e.copy()
|
||||||
copy.transform(rotation_matrix)
|
copy.transform(rotation_matrix)
|
||||||
@@ -33,7 +44,7 @@ def import_block(block_name: str, from_doc, to_doc, winkel = None) -> None:
|
|||||||
- Stellt sicher, dass benutzte Layer im Ziel existieren (mit Eigenschaften)
|
- Stellt sicher, dass benutzte Layer im Ziel existieren (mit Eigenschaften)
|
||||||
- Übernimmt Basispunkt und Block-Layer, falls vorhanden
|
- Übernimmt Basispunkt und Block-Layer, falls vorhanden
|
||||||
"""
|
"""
|
||||||
msp2 = from_doc.modelspace()
|
|
||||||
src = from_doc.blocks[block_name]
|
src = from_doc.blocks[block_name]
|
||||||
att_def = {}
|
att_def = {}
|
||||||
if block_name == "Pinbereich":
|
if block_name == "Pinbereich":
|
||||||
@@ -41,7 +52,7 @@ def import_block(block_name: str, from_doc, to_doc, winkel = None) -> None:
|
|||||||
|
|
||||||
# Alle Linientypen importieren
|
# Alle Linientypen importieren
|
||||||
imp.import_table("linetypes")
|
imp.import_table("linetypes")
|
||||||
if ((block_name in to_doc.blocks)):
|
if block_name in to_doc.blocks:
|
||||||
# speichern der attdef elemente in eine Liste falks diese verhanden sind und gibt diese zurück
|
# speichern der attdef elemente in eine Liste falks diese verhanden sind und gibt diese zurück
|
||||||
for ent in src:
|
for ent in src:
|
||||||
copy = ent.copy()
|
copy = ent.copy()
|
||||||
@@ -100,6 +111,7 @@ def import_block(block_name: str, from_doc, to_doc, winkel = None) -> None:
|
|||||||
if att_def != {}:
|
if att_def != {}:
|
||||||
return att_def
|
return att_def
|
||||||
|
|
||||||
|
|
||||||
def get_insert_color_layer(lib_doc, blockname):
|
def get_insert_color_layer(lib_doc, blockname):
|
||||||
"""Gibt den Layer und die Color für den Jeweiligen block in der Libary datei zurück"""
|
"""Gibt den Layer und die Color für den Jeweiligen block in der Libary datei zurück"""
|
||||||
msp_lib = lib_doc.modelspace()
|
msp_lib = lib_doc.modelspace()
|
||||||
@@ -110,6 +122,8 @@ def get_insert_color_layer(lib_doc, blockname):
|
|||||||
color = insert.dxf.color
|
color = insert.dxf.color
|
||||||
layer = insert.dxf.layer
|
layer = insert.dxf.layer
|
||||||
return layer, color
|
return layer, color
|
||||||
|
|
||||||
|
|
||||||
def rotatate_and_left_motor_umlenk(doc, lib_doc, config):
|
def rotatate_and_left_motor_umlenk(doc, lib_doc, config):
|
||||||
motor_rotation = float(config.get("Ils 2.0 core winkel", "winkel_motor"))
|
motor_rotation = float(config.get("Ils 2.0 core winkel", "winkel_motor"))
|
||||||
umlenk_rotation = float(config.get("Ils 2.0 core winkel", "winkel_umlenk"))
|
umlenk_rotation = float(config.get("Ils 2.0 core winkel", "winkel_umlenk"))
|
||||||
@@ -119,21 +133,51 @@ def rotatate_and_left_motor_umlenk(doc, lib_doc,config):
|
|||||||
blockname_umlenk_links = block_Vario_Umlenkstation_500mm + "_links"
|
blockname_umlenk_links = block_Vario_Umlenkstation_500mm + "_links"
|
||||||
import_block(block_Vario_Umlenkstation_500mm, lib_doc, doc)
|
import_block(block_Vario_Umlenkstation_500mm, lib_doc, doc)
|
||||||
import_block(block_Vario_Motorstation_500mm, lib_doc, doc)
|
import_block(block_Vario_Motorstation_500mm, lib_doc, doc)
|
||||||
turn_two_blocks_left(doc, block_Vario_Umlenkstation_500mm, block_Vario_Motorstation_500mm, blockname_motor_links, blockname_umlenk_links)
|
turn_two_blocks_left(
|
||||||
|
doc,
|
||||||
|
block_Vario_Umlenkstation_500mm,
|
||||||
|
block_Vario_Motorstation_500mm,
|
||||||
|
blockname_motor_links,
|
||||||
|
blockname_umlenk_links,
|
||||||
|
)
|
||||||
|
|
||||||
block_Vario_Umlenkstation_500mm =dreh_block(block_Vario_Umlenkstation_500mm,doc,lib_doc,math.radians(umlenk_rotation))
|
block_Vario_Umlenkstation_500mm = dreh_block(
|
||||||
block_Vario_Motorstation_500mm =dreh_block(block_Vario_Motorstation_500mm,doc,lib_doc,math.radians(motor_rotation))
|
block_Vario_Umlenkstation_500mm, doc, lib_doc, math.radians(umlenk_rotation)
|
||||||
blockname_motor_links =dreh_block(blockname_motor_links,doc,lib_doc,math.radians(umlenk_rotation))
|
)
|
||||||
blockname_umlenk_links =dreh_block(blockname_umlenk_links,doc,lib_doc,math.radians(motor_rotation))
|
block_Vario_Motorstation_500mm = dreh_block(
|
||||||
return block_Vario_Umlenkstation_500mm,block_Vario_Motorstation_500mm,blockname_motor_links,blockname_umlenk_links
|
block_Vario_Motorstation_500mm, doc, lib_doc, math.radians(motor_rotation)
|
||||||
|
)
|
||||||
|
blockname_motor_links = dreh_block(
|
||||||
|
blockname_motor_links, doc, lib_doc, math.radians(umlenk_rotation)
|
||||||
|
)
|
||||||
|
blockname_umlenk_links = dreh_block(
|
||||||
|
blockname_umlenk_links, doc, lib_doc, math.radians(motor_rotation)
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
block_Vario_Umlenkstation_500mm,
|
||||||
|
block_Vario_Motorstation_500mm,
|
||||||
|
blockname_motor_links,
|
||||||
|
blockname_umlenk_links,
|
||||||
|
)
|
||||||
|
|
||||||
def turn_two_blocks_left(doc, block_1_name_zwischen, block_2_name_zwischen, block_2_left_name, block_1_left_name):
|
|
||||||
|
def turn_two_blocks_left(
|
||||||
|
doc,
|
||||||
|
block_1_name_zwischen,
|
||||||
|
block_2_name_zwischen,
|
||||||
|
block_2_left_name,
|
||||||
|
block_1_left_name,
|
||||||
|
):
|
||||||
blockname1 = block_1_name_zwischen
|
blockname1 = block_1_name_zwischen
|
||||||
blockname2 = block_2_name_zwischen
|
blockname2 = block_2_name_zwischen
|
||||||
if block_2_left_name not in doc.blocks:
|
if block_2_left_name not in doc.blocks:
|
||||||
matrix = Matrix44.scale(1, -1, 1)
|
matrix = Matrix44.scale(1, -1, 1)
|
||||||
block1_zwischen = doc.blocks.new(name=block_1_name_zwischen + "zwischenschrit", base_point=(0,0,0))
|
block1_zwischen = doc.blocks.new(
|
||||||
block2_zwischen = doc.blocks.new(name=block_2_name_zwischen + "zwischenschrit", base_point=(0,0,0))
|
name=block_1_name_zwischen + "zwischenschrit", base_point=(0, 0, 0)
|
||||||
|
)
|
||||||
|
block2_zwischen = doc.blocks.new(
|
||||||
|
name=block_2_name_zwischen + "zwischenschrit", base_point=(0, 0, 0)
|
||||||
|
)
|
||||||
block_2 = doc.blocks.new(name=block_2_left_name, base_point=(0, 0, 0))
|
block_2 = doc.blocks.new(name=block_2_left_name, base_point=(0, 0, 0))
|
||||||
block_1_left_name = doc.blocks.new(name=block_1_left_name, base_point=(0, 0, 0))
|
block_1_left_name = doc.blocks.new(name=block_1_left_name, base_point=(0, 0, 0))
|
||||||
block1_zwischen.add_blockref(blockname1, (0, 0, 0))
|
block1_zwischen.add_blockref(blockname1, (0, 0, 0))
|
||||||
@@ -148,8 +192,8 @@ def turn_two_blocks_left(doc, block_1_name_zwischen, block_2_name_zwischen, bloc
|
|||||||
copy.transform(matrix)
|
copy.transform(matrix)
|
||||||
block_1_left_name.add_entity(copy)
|
block_1_left_name.add_entity(copy)
|
||||||
|
|
||||||
def add_attributes_to_block(block, attributes):
|
|
||||||
|
|
||||||
|
def add_attributes_to_block(block, attributes):
|
||||||
"""
|
"""
|
||||||
Fügt einem bestehenden ezdxf-Block Attribut-Definitionen hinzu.
|
Fügt einem bestehenden ezdxf-Block Attribut-Definitionen hinzu.
|
||||||
|
|
||||||
|
|||||||
+153
-78
@@ -1,15 +1,16 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
import os
|
import os
|
||||||
import ezdxf
|
import ezdxf
|
||||||
from ezdxf.math import Matrix44, Vec3, BoundingBox, Vec2
|
from ezdxf.math import Matrix44, Vec3, BoundingBox, Vec2
|
||||||
import math
|
import math
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
import shutil
|
|
||||||
import configparser
|
import configparser
|
||||||
from utils import check_environment_var, setup_logger
|
from utils import check_environment_var, setup_logger
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
||||||
def create_block_library(input_dir, output_file, config, logger=None):
|
def create_block_library(input_dir, output_file, config, logger=None):
|
||||||
"""
|
"""
|
||||||
Erstellt eine DXF-Block-Bibliothek aus einzelnen DXF-Dateien.
|
Erstellt eine DXF-Block-Bibliothek aus einzelnen DXF-Dateien.
|
||||||
@@ -84,17 +85,16 @@ def create_block_library(input_dir, output_file, config, logger=None):
|
|||||||
for attrib in insert.attribs:
|
for attrib in insert.attribs:
|
||||||
att_def[attrib.dxf.tag] = attrib.dxf.text
|
att_def[attrib.dxf.tag] = attrib.dxf.text
|
||||||
|
|
||||||
|
|
||||||
for e in entities:
|
for e in entities:
|
||||||
if e.dxftype() in allowed_types:
|
if e.dxftype() in allowed_types:
|
||||||
filtered_entities.append(e)
|
filtered_entities.append(e)
|
||||||
else:
|
else:
|
||||||
logger.info(f"{e.dxftype()} is nicht in der erlaubten Liste. Diese befindet sich in {filename}")
|
logger.info(
|
||||||
|
f"{e.dxftype()} is nicht in der erlaubten Liste. Diese befindet sich in {filename}"
|
||||||
|
)
|
||||||
|
|
||||||
entities = filtered_entities
|
entities = filtered_entities
|
||||||
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_msg = f"Fehler beim Lesen von {filename}: {e}"
|
error_msg = f"Fehler beim Lesen von {filename}: {e}"
|
||||||
if logger:
|
if logger:
|
||||||
@@ -106,7 +106,9 @@ def create_block_library(input_dir, output_file, config, logger=None):
|
|||||||
|
|
||||||
# Sicherstellen, dass die im Quell-DXF verwendeten Layer im Zieldokument existieren
|
# Sicherstellen, dass die im Quell-DXF verwendeten Layer im Zieldokument existieren
|
||||||
try:
|
try:
|
||||||
used_layer_names = {e.dxf.layer for e in entities if hasattr(e.dxf, "layer")}
|
used_layer_names = {
|
||||||
|
e.dxf.layer for e in entities if hasattr(e.dxf, "layer")
|
||||||
|
}
|
||||||
for layer_name in used_layer_names:
|
for layer_name in used_layer_names:
|
||||||
if layer_name and layer_name not in doc.layers:
|
if layer_name and layer_name not in doc.layers:
|
||||||
try:
|
try:
|
||||||
@@ -123,7 +125,9 @@ def create_block_library(input_dir, output_file, config, logger=None):
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
boundingbox, ausdehnung, center = calculate_block_bounding_box(filtered_entities, doc,src_doc, filename,config)
|
boundingbox, ausdehnung, center = calculate_block_bounding_box(
|
||||||
|
filtered_entities, doc, src_doc, filename, config
|
||||||
|
)
|
||||||
if center is None:
|
if center is None:
|
||||||
error_msg = f"Keine gültige Geometrie in {filename}"
|
error_msg = f"Keine gültige Geometrie in {filename}"
|
||||||
if logger:
|
if logger:
|
||||||
@@ -146,7 +150,6 @@ def create_block_library(input_dir, output_file, config, logger=None):
|
|||||||
# Platzierung in Reihen und Spalten
|
# Platzierung in Reihen und Spalten
|
||||||
# Attribut-Definition (ATTDEF) hinzufügen
|
# Attribut-Definition (ATTDEF) hinzufügen
|
||||||
|
|
||||||
|
|
||||||
# Blockreferenz-Layer bestimmen
|
# Blockreferenz-Layer bestimmen
|
||||||
blockref_layer = None
|
blockref_layer = None
|
||||||
try:
|
try:
|
||||||
@@ -186,9 +189,15 @@ def create_block_library(input_dir, output_file, config, logger=None):
|
|||||||
blockref_layer = None
|
blockref_layer = None
|
||||||
section = "dxf2lib"
|
section = "dxf2lib"
|
||||||
text_height = get_cfg_value(section, "text_height", DEFAULTS["text_height"])
|
text_height = get_cfg_value(section, "text_height", DEFAULTS["text_height"])
|
||||||
extra_block_space_x = get_cfg_value(section, "extra_block_space_x", DEFAULTS["extra_block_space_x"])
|
extra_block_space_x = get_cfg_value(
|
||||||
blocks_per_row = get_cfg_value(section, "blocks_per_row", DEFAULTS["blocks_per_row"])
|
section, "extra_block_space_x", DEFAULTS["extra_block_space_x"]
|
||||||
extra_text_space_y = get_cfg_value(section, "extra_text_space_y", DEFAULTS["extra_text_space_y"])
|
)
|
||||||
|
blocks_per_row = get_cfg_value(
|
||||||
|
section, "blocks_per_row", DEFAULTS["blocks_per_row"]
|
||||||
|
)
|
||||||
|
extra_text_space_y = get_cfg_value(
|
||||||
|
section, "extra_text_space_y", DEFAULTS["extra_text_space_y"]
|
||||||
|
)
|
||||||
|
|
||||||
ausdehnung_x, ausdehung_y = ausdehnung[0], ausdehnung[1]
|
ausdehnung_x, ausdehung_y = ausdehnung[0], ausdehnung[1]
|
||||||
|
|
||||||
@@ -199,7 +208,9 @@ def create_block_library(input_dir, output_file, config, logger=None):
|
|||||||
x_offset += max_blockspacing_x
|
x_offset += max_blockspacing_x
|
||||||
# Blockreferenz mit optionalem Layer einfügen (Entity-Layer bleiben erhalten)
|
# Blockreferenz mit optionalem Layer einfügen (Entity-Layer bleiben erhalten)
|
||||||
if blockref_layer:
|
if blockref_layer:
|
||||||
test =msp.add_blockref(name, insert=(x_offset, y_offset), dxfattribs={"layer": blockref_layer})
|
test = msp.add_blockref(
|
||||||
|
name, insert=(x_offset, y_offset), dxfattribs={"layer": blockref_layer}
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
test = msp.add_blockref(name, insert=(x_offset, y_offset))
|
test = msp.add_blockref(name, insert=(x_offset, y_offset))
|
||||||
# Text mit Blocknamen über dem Block
|
# Text mit Blocknamen über dem Block
|
||||||
@@ -215,7 +226,16 @@ def create_block_library(input_dir, output_file, config, logger=None):
|
|||||||
a.is_invisible = True
|
a.is_invisible = True
|
||||||
# Werte aus Config holen (Block: [dxf2lib])
|
# Werte aus Config holen (Block: [dxf2lib])
|
||||||
|
|
||||||
msp.add_text(name, dxfattribs={'height': text_height, 'insert': (x_offset -ausdehnung_x/2 , y_offset + ausdehung_y/2 + extra_text_space_y)})
|
msp.add_text(
|
||||||
|
name,
|
||||||
|
dxfattribs={
|
||||||
|
"height": text_height,
|
||||||
|
"insert": (
|
||||||
|
x_offset - ausdehnung_x / 2,
|
||||||
|
y_offset + ausdehung_y / 2 + extra_text_space_y,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
processed_files.append(filename)
|
processed_files.append(filename)
|
||||||
blocks_in_row += 1
|
blocks_in_row += 1
|
||||||
@@ -234,7 +254,9 @@ def create_block_library(input_dir, output_file, config, logger=None):
|
|||||||
logger.info(f"Fehlerhafte Dateien: {len(error_files)}")
|
logger.info(f"Fehlerhafte Dateien: {len(error_files)}")
|
||||||
|
|
||||||
if error_files:
|
if error_files:
|
||||||
logger.warning(f"{len(error_files)} Dateien konnten nicht verarbeitet werden:")
|
logger.warning(
|
||||||
|
f"{len(error_files)} Dateien konnten nicht verarbeitet werden:"
|
||||||
|
)
|
||||||
for filename, error_msg in error_files:
|
for filename, error_msg in error_files:
|
||||||
logger.error(f"{filename}: {error_msg}")
|
logger.error(f"{filename}: {error_msg}")
|
||||||
else:
|
else:
|
||||||
@@ -245,7 +267,9 @@ def create_block_library(input_dir, output_file, config, logger=None):
|
|||||||
print(f"Fehlerhafte Dateien: {len(error_files)}")
|
print(f"Fehlerhafte Dateien: {len(error_files)}")
|
||||||
|
|
||||||
if error_files:
|
if error_files:
|
||||||
print(f"Warnung: {len(error_files)} Dateien konnten nicht verarbeitet werden.")
|
print(
|
||||||
|
f"Warnung: {len(error_files)} Dateien konnten nicht verarbeitet werden."
|
||||||
|
)
|
||||||
|
|
||||||
output_dir = output_file.parent
|
output_dir = output_file.parent
|
||||||
if not output_dir.exists():
|
if not output_dir.exists():
|
||||||
@@ -267,7 +291,9 @@ def copy_entity(logger, error_files, filename, e, center):
|
|||||||
return cp
|
return cp
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
error_msg = f"Fehler beim Verarbeiten von Entity {e.dxftype()} in {filename}: {err}"
|
error_msg = (
|
||||||
|
f"Fehler beim Verarbeiten von Entity {e.dxftype()} in {filename}: {err}"
|
||||||
|
)
|
||||||
if logger:
|
if logger:
|
||||||
logger.error(error_msg)
|
logger.error(error_msg)
|
||||||
else:
|
else:
|
||||||
@@ -276,15 +302,15 @@ def copy_entity(logger, error_files, filename, e, center):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Standardwerte (falls nicht in der Config)
|
# Standardwerte (falls nicht in der Config)
|
||||||
DEFAULTS = {
|
DEFAULTS = {
|
||||||
"text_height": 20, # Schriftgröße des Texts (in DXF-Einheiten)
|
"text_height": 20, # Schriftgröße des Texts (in DXF-Einheiten)
|
||||||
"blocks_per_row": 20, # Anzahl Blöcke pro Zeile im Raster
|
"blocks_per_row": 20, # Anzahl Blöcke pro Zeile im Raster
|
||||||
"extra_block_space_x": 50, # Extra Platz damit sich Blöcke nicht überlappen
|
"extra_block_space_x": 50, # Extra Platz damit sich Blöcke nicht überlappen
|
||||||
"extra_text_space_y" : 50 # Abstand der Überschrift über dem Symbol
|
"extra_text_space_y": 50, # Abstand der Überschrift über dem Symbol
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_cfg_value(section, key, fallback):
|
def get_cfg_value(section, key, fallback):
|
||||||
try:
|
try:
|
||||||
return int(config.get(section, key))
|
return int(config.get(section, key))
|
||||||
@@ -292,9 +318,9 @@ def get_cfg_value(section, key, fallback):
|
|||||||
return fallback
|
return fallback
|
||||||
|
|
||||||
|
|
||||||
|
def convert_dxf_to_block_with_inserts(
|
||||||
|
input_filename, output_filename, block_name="CONVERTED_BLOCK"
|
||||||
def convert_dxf_to_block_with_inserts(input_filename, output_filename, block_name="CONVERTED_BLOCK"):
|
):
|
||||||
"""
|
"""
|
||||||
Konvertiert alle Entities einer DXF-Datei in einen neuen Block
|
Konvertiert alle Entities einer DXF-Datei in einen neuen Block
|
||||||
INSERTs werden als Referenzen beibehalten (nicht explodiert)
|
INSERTs werden als Referenzen beibehalten (nicht explodiert)
|
||||||
@@ -305,8 +331,8 @@ def convert_dxf_to_block_with_inserts(input_filename, output_filename, block_nam
|
|||||||
print(f"Lade DXF-Datei: {input_filename}")
|
print(f"Lade DXF-Datei: {input_filename}")
|
||||||
|
|
||||||
# Neue Ausgabe-DXF erstellen
|
# Neue Ausgabe-DXF erstellen
|
||||||
output_doc = ezdxf.new('R2010')
|
output_doc = ezdxf.new("R2010")
|
||||||
output_doc.header['$INSUNITS'] = 4 # Millimeter
|
output_doc.header["$INSUNITS"] = 4 # Millimeter
|
||||||
|
|
||||||
# Zuerst alle Block-Definitionen kopieren
|
# Zuerst alle Block-Definitionen kopieren
|
||||||
copied_blocks = copy_block_definitions(input_doc, output_doc)
|
copied_blocks = copy_block_definitions(input_doc, output_doc)
|
||||||
@@ -322,7 +348,7 @@ def convert_dxf_to_block_with_inserts(input_filename, output_filename, block_nam
|
|||||||
insert_count = 0
|
insert_count = 0
|
||||||
|
|
||||||
for entity in msp:
|
for entity in msp:
|
||||||
if entity.dxftype() == 'INSERT':
|
if entity.dxftype() == "INSERT":
|
||||||
# INSERT direkt kopieren (nicht explodieren)
|
# INSERT direkt kopieren (nicht explodieren)
|
||||||
copy_entity_to_block(entity, new_block)
|
copy_entity_to_block(entity, new_block)
|
||||||
insert_count += 1
|
insert_count += 1
|
||||||
@@ -373,7 +399,7 @@ def copy_block_definitions(source_doc, target_doc):
|
|||||||
|
|
||||||
for block_name in source_doc.blocks:
|
for block_name in source_doc.blocks:
|
||||||
# Standard-Blöcke (MODEL_SPACE, PAPER_SPACE) überspringen
|
# Standard-Blöcke (MODEL_SPACE, PAPER_SPACE) überspringen
|
||||||
if block_name.startswith('*'):
|
if block_name.startswith("*"):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
source_block = source_doc.blocks[block_name]
|
source_block = source_doc.blocks[block_name]
|
||||||
@@ -407,11 +433,16 @@ def calculate_block_bounding_box(block, doc, src_doc, filename,config):
|
|||||||
if entity_bbox and entity_bbox.has_data:
|
if entity_bbox and entity_bbox.has_data:
|
||||||
bbox.extend(entity_bbox)
|
bbox.extend(entity_bbox)
|
||||||
|
|
||||||
|
return (
|
||||||
return bbox, (bbox.extmax.x - bbox.extmin.x, bbox.extmax.y - bbox.extmin.y), bbox.center
|
bbox,
|
||||||
|
(bbox.extmax.x - bbox.extmin.x, bbox.extmax.y - bbox.extmin.y),
|
||||||
|
bbox.center,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _bbox_from_virtual_entities(entity, doc, src_doc, filename, config, transform_matrix=None):
|
def _bbox_from_virtual_entities(
|
||||||
|
entity, doc, src_doc, filename, config, transform_matrix=None
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Nutzt virtual_entities(), um komplexe Objekte (z.B. SURFACE) in
|
Nutzt virtual_entities(), um komplexe Objekte (z.B. SURFACE) in
|
||||||
auswertbare Geometrie zu zerlegen und darauf eine Bounding Box zu
|
auswertbare Geometrie zu zerlegen und darauf eine Bounding Box zu
|
||||||
@@ -440,7 +471,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
|
|||||||
|
|
||||||
bbox = BoundingBox()
|
bbox = BoundingBox()
|
||||||
try:
|
try:
|
||||||
if e.dxftype() == 'LINE':
|
if e.dxftype() == "LINE":
|
||||||
start = Vec3(e.dxf.start)
|
start = Vec3(e.dxf.start)
|
||||||
end = Vec3(e.dxf.end)
|
end = Vec3(e.dxf.end)
|
||||||
if transform_matrix:
|
if transform_matrix:
|
||||||
@@ -449,7 +480,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
|
|||||||
bbox.extend([start])
|
bbox.extend([start])
|
||||||
bbox.extend([end])
|
bbox.extend([end])
|
||||||
|
|
||||||
elif e.dxftype() == 'CIRCLE':
|
elif e.dxftype() == "CIRCLE":
|
||||||
# Kreis durch Punktabtastung (robust bei Transformationen)
|
# Kreis durch Punktabtastung (robust bei Transformationen)
|
||||||
center = Vec3(e.dxf.center)
|
center = Vec3(e.dxf.center)
|
||||||
radius = float(e.dxf.radius)
|
radius = float(e.dxf.radius)
|
||||||
@@ -465,7 +496,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
|
|||||||
if points:
|
if points:
|
||||||
bbox.extend(points)
|
bbox.extend(points)
|
||||||
|
|
||||||
elif e.dxftype() == 'ARC':
|
elif e.dxftype() == "ARC":
|
||||||
# Bogen durch Punktabtastung zwischen Start- und Endwinkel
|
# Bogen durch Punktabtastung zwischen Start- und Endwinkel
|
||||||
center = Vec3(e.dxf.center)
|
center = Vec3(e.dxf.center)
|
||||||
radius = float(e.dxf.radius)
|
radius = float(e.dxf.radius)
|
||||||
@@ -496,7 +527,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
|
|||||||
if points:
|
if points:
|
||||||
bbox.extend(points)
|
bbox.extend(points)
|
||||||
|
|
||||||
elif e.dxftype() == 'LWPOLYLINE':
|
elif e.dxftype() == "LWPOLYLINE":
|
||||||
# Nutze virtuelle Entities (Linien/Bögen), inkl. Bulge-Unterstützung
|
# Nutze virtuelle Entities (Linien/Bögen), inkl. Bulge-Unterstützung
|
||||||
ve_bbox = _bbox_from_virtual_entities(
|
ve_bbox = _bbox_from_virtual_entities(
|
||||||
e, doc, src_doc, filename, config, transform_matrix
|
e, doc, src_doc, filename, config, transform_matrix
|
||||||
@@ -504,7 +535,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
|
|||||||
if ve_bbox.has_data:
|
if ve_bbox.has_data:
|
||||||
bbox.extend(ve_bbox)
|
bbox.extend(ve_bbox)
|
||||||
|
|
||||||
elif e.dxftype() == 'POLYLINE':
|
elif e.dxftype() == "POLYLINE":
|
||||||
# 2D/3D Polylines ebenfalls über virtuelle Entities
|
# 2D/3D Polylines ebenfalls über virtuelle Entities
|
||||||
ve_bbox = _bbox_from_virtual_entities(
|
ve_bbox = _bbox_from_virtual_entities(
|
||||||
e, doc, src_doc, filename, config, transform_matrix
|
e, doc, src_doc, filename, config, transform_matrix
|
||||||
@@ -512,7 +543,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
|
|||||||
if ve_bbox.has_data:
|
if ve_bbox.has_data:
|
||||||
bbox.extend(ve_bbox)
|
bbox.extend(ve_bbox)
|
||||||
|
|
||||||
elif e.dxftype() == '3DFACE':
|
elif e.dxftype() == "3DFACE":
|
||||||
# 3DFace: direkte Eckpunkte verwenden
|
# 3DFace: direkte Eckpunkte verwenden
|
||||||
pts = []
|
pts = []
|
||||||
try:
|
try:
|
||||||
@@ -527,7 +558,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
|
|||||||
if pts:
|
if pts:
|
||||||
bbox.extend(pts)
|
bbox.extend(pts)
|
||||||
|
|
||||||
elif e.dxftype() in {'MESH', 'POLYFACE', 'POLYFACEMESH'}:
|
elif e.dxftype() in {"MESH", "POLYFACE", "POLYFACEMESH"}:
|
||||||
# Mesh/Polyface über virtuelle Geometrie auswerten
|
# Mesh/Polyface über virtuelle Geometrie auswerten
|
||||||
ve_bbox = _bbox_from_virtual_entities(
|
ve_bbox = _bbox_from_virtual_entities(
|
||||||
e, doc, src_doc, filename, config, transform_matrix
|
e, doc, src_doc, filename, config, transform_matrix
|
||||||
@@ -535,7 +566,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
|
|||||||
if ve_bbox.has_data:
|
if ve_bbox.has_data:
|
||||||
bbox.extend(ve_bbox)
|
bbox.extend(ve_bbox)
|
||||||
|
|
||||||
elif e.dxftype() == 'SPLINE':
|
elif e.dxftype() == "SPLINE":
|
||||||
# Approximation der Spline-Kurve
|
# Approximation der Spline-Kurve
|
||||||
try:
|
try:
|
||||||
pts = list(e.approximate(60))
|
pts = list(e.approximate(60))
|
||||||
@@ -557,18 +588,20 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
|
|||||||
if sampled:
|
if sampled:
|
||||||
bbox.extend(sampled)
|
bbox.extend(sampled)
|
||||||
|
|
||||||
elif e.dxftype() == 'ATTDEF':
|
elif e.dxftype() == "ATTDEF":
|
||||||
|
|
||||||
insert_point = Vec3(e.dxf.insert)
|
insert_point = Vec3(e.dxf.insert)
|
||||||
if transform_matrix:
|
if transform_matrix:
|
||||||
insert_point = transform_matrix.transform(insert_point)
|
insert_point = transform_matrix.transform(insert_point)
|
||||||
elif e.dxftype() == 'TEXT':
|
elif e.dxftype() == "TEXT":
|
||||||
insert_point = Vec3(e.dxf.insert)
|
insert_point = Vec3(e.dxf.insert)
|
||||||
height = float(getattr(e.dxf, "height", 1.0))
|
height = float(getattr(e.dxf, "height", 1.0))
|
||||||
width_factor = float(getattr(e.dxf, "width", 1.0))
|
width_factor = float(getattr(e.dxf, "width", 1.0))
|
||||||
rotation = math.radians(getattr(e.dxf, "rotation", 0.0))
|
rotation = math.radians(getattr(e.dxf, "rotation", 0.0))
|
||||||
text_content = getattr(e.dxf, "text", "") or ""
|
text_content = getattr(e.dxf, "text", "") or ""
|
||||||
est_width = max(len(text_content) * height * 0.6 * width_factor, height * 0.5)
|
est_width = max(
|
||||||
|
len(text_content) * height * 0.6 * width_factor, height * 0.5
|
||||||
|
)
|
||||||
corners = [
|
corners = [
|
||||||
insert_point,
|
insert_point,
|
||||||
insert_point + Vec3(est_width, 0, 0),
|
insert_point + Vec3(est_width, 0, 0),
|
||||||
@@ -590,7 +623,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
|
|||||||
pt = transform_matrix.transform(pt)
|
pt = transform_matrix.transform(pt)
|
||||||
bbox.extend([pt])
|
bbox.extend([pt])
|
||||||
|
|
||||||
elif e.dxftype() == 'MTEXT':
|
elif e.dxftype() == "MTEXT":
|
||||||
insert_point = Vec3(e.dxf.insert)
|
insert_point = Vec3(e.dxf.insert)
|
||||||
char_height = float(getattr(e.dxf, "char_height", 1.0))
|
char_height = float(getattr(e.dxf, "char_height", 1.0))
|
||||||
width = float(getattr(e.dxf, "width", 0.0))
|
width = float(getattr(e.dxf, "width", 0.0))
|
||||||
@@ -610,7 +643,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
|
|||||||
pt = transform_matrix.transform(pt)
|
pt = transform_matrix.transform(pt)
|
||||||
bbox.extend([pt])
|
bbox.extend([pt])
|
||||||
|
|
||||||
elif e.dxftype() == 'REGION':
|
elif e.dxftype() == "REGION":
|
||||||
# Region: Begrenzungsgeometrie über virtual_entities()
|
# Region: Begrenzungsgeometrie über virtual_entities()
|
||||||
ve_bbox = _bbox_from_virtual_entities(
|
ve_bbox = _bbox_from_virtual_entities(
|
||||||
e, doc, src_doc, filename, config, transform_matrix
|
e, doc, src_doc, filename, config, transform_matrix
|
||||||
@@ -618,7 +651,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
|
|||||||
if ve_bbox.has_data:
|
if ve_bbox.has_data:
|
||||||
bbox.extend(ve_bbox)
|
bbox.extend(ve_bbox)
|
||||||
|
|
||||||
elif e.dxftype().endswith('SURFACE'):
|
elif e.dxftype().endswith("SURFACE"):
|
||||||
# Viele Surface-Typen liefern ihre Proxy-Geometrie über virtual_entities()
|
# Viele Surface-Typen liefern ihre Proxy-Geometrie über virtual_entities()
|
||||||
ve_bbox = _bbox_from_virtual_entities(
|
ve_bbox = _bbox_from_virtual_entities(
|
||||||
e, doc, src_doc, filename, config, transform_matrix
|
e, doc, src_doc, filename, config, transform_matrix
|
||||||
@@ -626,24 +659,36 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
|
|||||||
if ve_bbox.has_data:
|
if ve_bbox.has_data:
|
||||||
bbox.extend(ve_bbox)
|
bbox.extend(ve_bbox)
|
||||||
|
|
||||||
elif e.dxftype() == 'INSERT':
|
elif e.dxftype() == "INSERT":
|
||||||
# INSERT: Block-Inhalt mit Transformation berücksichtigen
|
# INSERT: Block-Inhalt mit Transformation berücksichtigen
|
||||||
insert_bbox = calculate_insert_bounding_box(e, doc,src_doc,filename,config, transform_matrix)
|
insert_bbox = calculate_insert_bounding_box(
|
||||||
if insert_bbox and insert_bbox.has_data and e.dxf.layer not in config.get("dxf2lib","automation_layer"):
|
e, doc, src_doc, filename, config, transform_matrix
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
insert_bbox
|
||||||
|
and insert_bbox.has_data
|
||||||
|
and e.dxf.layer not in config.get("dxf2lib", "automation_layer")
|
||||||
|
):
|
||||||
bbox.extend(insert_bbox)
|
bbox.extend(insert_bbox)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Fehler bei Bounding Box Berechnung für {e.dxftype()}: {e}")
|
print(f"Fehler bei Bounding Box Berechnung für {e.dxftype()}: {e}")
|
||||||
|
|
||||||
|
|
||||||
return bbox
|
return bbox
|
||||||
|
|
||||||
|
|
||||||
def extract_scaling(matrix):
|
def extract_scaling(matrix):
|
||||||
sx = math.sqrt(matrix[0, 0] ** 2 + matrix[0, 1] ** 2 + matrix[0, 2] ** 2)
|
sx = math.sqrt(matrix[0, 0] ** 2 + matrix[0, 1] ** 2 + matrix[0, 2] ** 2)
|
||||||
sy = math.sqrt(matrix[1, 0] ** 2 + matrix[1, 1] ** 2 + matrix[1, 2] ** 2)
|
sy = math.sqrt(matrix[1, 0] ** 2 + matrix[1, 1] ** 2 + matrix[1, 2] ** 2)
|
||||||
return sx, sy,
|
return (
|
||||||
|
sx,
|
||||||
|
sy,
|
||||||
|
)
|
||||||
|
|
||||||
def calculate_insert_bounding_box(insert_entity, doc,src_doc,filename,config,parent_transform=None):
|
|
||||||
|
def calculate_insert_bounding_box(
|
||||||
|
insert_entity, doc, src_doc, filename, config, parent_transform=None
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Berechnet die Bounding Box eines INSERTs inklusive Block-Inhalt
|
Berechnet die Bounding Box eines INSERTs inklusive Block-Inhalt
|
||||||
"""
|
"""
|
||||||
@@ -667,7 +712,6 @@ def calculate_insert_bounding_box(insert_entity, doc,src_doc,filename,config,par
|
|||||||
|
|
||||||
block_def = src_blk
|
block_def = src_blk
|
||||||
|
|
||||||
|
|
||||||
# Transformation der INSERT-Entity berechnen
|
# Transformation der INSERT-Entity berechnen
|
||||||
insert_transform = get_insert_transform_matrix(insert_entity)
|
insert_transform = get_insert_transform_matrix(insert_entity)
|
||||||
|
|
||||||
@@ -682,7 +726,9 @@ def calculate_insert_bounding_box(insert_entity, doc,src_doc,filename,config,par
|
|||||||
|
|
||||||
for block_entity in block_def:
|
for block_entity in block_def:
|
||||||
|
|
||||||
entity_bbox= get_entity_bounding_box(block_entity, doc,src_doc,filename, config,combined_transform)
|
entity_bbox = get_entity_bounding_box(
|
||||||
|
block_entity, doc, src_doc, filename, config, combined_transform
|
||||||
|
)
|
||||||
if entity_bbox and entity_bbox.has_data:
|
if entity_bbox and entity_bbox.has_data:
|
||||||
if new_insert:
|
if new_insert:
|
||||||
dst_blk.add_entity(block_entity.copy())
|
dst_blk.add_entity(block_entity.copy())
|
||||||
@@ -703,18 +749,18 @@ def get_insert_transform_matrix(insert_entity):
|
|||||||
insert_point = Vec3(insert_entity.dxf.insert)
|
insert_point = Vec3(insert_entity.dxf.insert)
|
||||||
|
|
||||||
# Skalierung
|
# Skalierung
|
||||||
xscale = getattr(insert_entity.dxf, 'xscale', 1.0)
|
xscale = getattr(insert_entity.dxf, "xscale", 1.0)
|
||||||
yscale = getattr(insert_entity.dxf, 'yscale', 1.0)
|
yscale = getattr(insert_entity.dxf, "yscale", 1.0)
|
||||||
zscale = getattr(insert_entity.dxf, 'zscale', 1.0)
|
zscale = getattr(insert_entity.dxf, "zscale", 1.0)
|
||||||
|
|
||||||
# Rotation (in Radiant umwandeln)
|
# Rotation (in Radiant umwandeln)
|
||||||
rotation = math.radians(getattr(insert_entity.dxf, 'rotation', 0.0))
|
rotation = math.radians(getattr(insert_entity.dxf, "rotation", 0.0))
|
||||||
|
|
||||||
# Transformationsmatrix erstellen
|
# Transformationsmatrix erstellen
|
||||||
matrix = Matrix44.chain(
|
matrix = Matrix44.chain(
|
||||||
Matrix44.scale(xscale, yscale, zscale),
|
Matrix44.scale(xscale, yscale, zscale),
|
||||||
Matrix44.z_rotate(rotation),
|
Matrix44.z_rotate(rotation),
|
||||||
Matrix44.translate(insert_point.x, insert_point.y, insert_point.z)
|
Matrix44.translate(insert_point.x, insert_point.y, insert_point.z),
|
||||||
)
|
)
|
||||||
|
|
||||||
return matrix
|
return matrix
|
||||||
@@ -759,11 +805,14 @@ def add_bounding_box_to_modelspace(msp, bbox, centered=False):
|
|||||||
(right, bottom),
|
(right, bottom),
|
||||||
(right, top),
|
(right, top),
|
||||||
(left, top),
|
(left, top),
|
||||||
(left, bottom)
|
(left, bottom),
|
||||||
]
|
]
|
||||||
# Roter Punkt in der Mitte
|
# Roter Punkt in der Mitte
|
||||||
msp.add_circle(center=(0.0, 0.0), radius=max(0.5, min(width, height) * 0.01),
|
msp.add_circle(
|
||||||
dxfattribs={"layer": "BOUNDING_BOX", "color": 1})
|
center=(0.0, 0.0),
|
||||||
|
radius=max(0.5, min(width, height) * 0.01),
|
||||||
|
dxfattribs={"layer": "BOUNDING_BOX", "color": 1},
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# Ursprüngliche, nicht-zentrierte Bounding Box
|
# Ursprüngliche, nicht-zentrierte Bounding Box
|
||||||
bbox_points = [
|
bbox_points = [
|
||||||
@@ -771,7 +820,7 @@ def add_bounding_box_to_modelspace(msp, bbox, centered=False):
|
|||||||
(max_pt.x, min_pt.y),
|
(max_pt.x, min_pt.y),
|
||||||
(max_pt.x, max_pt.y),
|
(max_pt.x, max_pt.y),
|
||||||
(min_pt.x, max_pt.y),
|
(min_pt.x, max_pt.y),
|
||||||
(min_pt.x, min_pt.y)
|
(min_pt.x, min_pt.y),
|
||||||
]
|
]
|
||||||
|
|
||||||
bbox_poly = msp.add_lwpolyline(bbox_points)
|
bbox_poly = msp.add_lwpolyline(bbox_points)
|
||||||
@@ -779,13 +828,23 @@ def add_bounding_box_to_modelspace(msp, bbox, centered=False):
|
|||||||
bbox_poly.dxf.color = 1 # Rot
|
bbox_poly.dxf.color = 1 # Rot
|
||||||
|
|
||||||
# Text mit Abmessungen
|
# Text mit Abmessungen
|
||||||
text_pos = Vec3(bbox_points[0][0], (bbox_points[2][1] if centered else max_pt.y) + 5, 0)
|
text_pos = Vec3(
|
||||||
msp.add_text(f"Breite: {width:.2f} mm", height=3,
|
bbox_points[0][0], (bbox_points[2][1] if centered else max_pt.y) + 5, 0
|
||||||
dxfattribs={'insert': text_pos, 'layer': "BOUNDING_BOX", 'color': 1})
|
)
|
||||||
|
msp.add_text(
|
||||||
|
f"Breite: {width:.2f} mm",
|
||||||
|
height=3,
|
||||||
|
dxfattribs={"insert": text_pos, "layer": "BOUNDING_BOX", "color": 1},
|
||||||
|
)
|
||||||
|
|
||||||
text_pos2 = Vec3(bbox_points[0][0], (bbox_points[2][1] if centered else max_pt.y) + 10, 0)
|
text_pos2 = Vec3(
|
||||||
msp.add_text(f"Höhe: {height:.2f} mm", height=3,
|
bbox_points[0][0], (bbox_points[2][1] if centered else max_pt.y) + 10, 0
|
||||||
dxfattribs={'insert': text_pos2, 'layer': "BOUNDING_BOX", 'color': 1})
|
)
|
||||||
|
msp.add_text(
|
||||||
|
f"Höhe: {height:.2f} mm",
|
||||||
|
height=3,
|
||||||
|
dxfattribs={"insert": text_pos2, "layer": "BOUNDING_BOX", "color": 1},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def format_bounding_box(bbox):
|
def format_bounding_box(bbox):
|
||||||
@@ -801,9 +860,11 @@ def format_bounding_box(bbox):
|
|||||||
height = max_pt.y - min_pt.y
|
height = max_pt.y - min_pt.y
|
||||||
depth = max_pt.z - min_pt.z
|
depth = max_pt.z - min_pt.z
|
||||||
|
|
||||||
return (f"Min: ({min_pt.x:.2f}, {min_pt.y:.2f}, {min_pt.z:.2f}) "
|
return (
|
||||||
|
f"Min: ({min_pt.x:.2f}, {min_pt.y:.2f}, {min_pt.z:.2f}) "
|
||||||
f"Max: ({max_pt.x:.2f}, {max_pt.y:.2f}, {max_pt.z:.2f}) "
|
f"Max: ({max_pt.x:.2f}, {max_pt.y:.2f}, {max_pt.z:.2f}) "
|
||||||
f"Größe: {width:.2f} × {height:.2f} × {depth:.2f} mm")
|
f"Größe: {width:.2f} × {height:.2f} × {depth:.2f} mm"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def analyze_source_dxf_with_blocks(filename):
|
def analyze_source_dxf_with_blocks(filename):
|
||||||
@@ -824,16 +885,16 @@ def analyze_source_dxf_with_blocks(filename):
|
|||||||
entity_type = entity.dxftype()
|
entity_type = entity.dxftype()
|
||||||
entity_types[entity_type] = entity_types.get(entity_type, 0) + 1
|
entity_types[entity_type] = entity_types.get(entity_type, 0) + 1
|
||||||
|
|
||||||
layer = getattr(entity.dxf, 'layer', '0')
|
layer = getattr(entity.dxf, "layer", "0")
|
||||||
layer_count[layer] = layer_count.get(layer, 0) + 1
|
layer_count[layer] = layer_count.get(layer, 0) + 1
|
||||||
|
|
||||||
if entity_type == 'INSERT':
|
if entity_type == "INSERT":
|
||||||
block_name = entity.dxf.name
|
block_name = entity.dxf.name
|
||||||
insert_blocks[block_name] = insert_blocks.get(block_name, 0) + 1
|
insert_blocks[block_name] = insert_blocks.get(block_name, 0) + 1
|
||||||
|
|
||||||
# Block-Definitionen analysieren
|
# Block-Definitionen analysieren
|
||||||
for block_name in doc.blocks:
|
for block_name in doc.blocks:
|
||||||
if not block_name.startswith('*'): # Keine Standard-Blöcke
|
if not block_name.startswith("*"): # Keine Standard-Blöcke
|
||||||
block_def = doc.blocks[block_name]
|
block_def = doc.blocks[block_name]
|
||||||
entity_count = len(list(block_def))
|
entity_count = len(list(block_def))
|
||||||
block_definitions[block_name] = entity_count
|
block_definitions[block_name] = entity_count
|
||||||
@@ -864,11 +925,21 @@ def analyze_source_dxf_with_blocks(filename):
|
|||||||
print(f"Fehler bei der Analyse: {e}")
|
print(f"Fehler bei der Analyse: {e}")
|
||||||
return {}, {}, {}, {}
|
return {}, {}, {}, {}
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Argumentparser für Kommandozeilenoptionen
|
# Argumentparser für Kommandozeilenoptionen
|
||||||
parser = argparse.ArgumentParser(description="SVG/XML zu DXF Konverter")
|
parser = argparse.ArgumentParser(description="SVG/XML zu DXF Konverter")
|
||||||
parser.add_argument('-i', '--input', type=str, help='Input-Verzeichnis mit SVG/XML-Dateien')
|
parser.add_argument(
|
||||||
parser.add_argument('-n', '--name', required=False, type=str, help='Name der zu erzeugenden Bibliothek (optional, wird sonst abgefragt)', default="test")
|
"-i", "--input", type=str, help="Input-Verzeichnis mit SVG/XML-Dateien"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-n",
|
||||||
|
"--name",
|
||||||
|
required=False,
|
||||||
|
type=str,
|
||||||
|
help="Name der zu erzeugenden Bibliothek (optional, wird sonst abgefragt)",
|
||||||
|
default="test",
|
||||||
|
)
|
||||||
|
|
||||||
if len(sys.argv) == 2 and sys.argv[1] in ("-h", "--help"):
|
if len(sys.argv) == 2 and sys.argv[1] in ("-h", "--help"):
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
@@ -877,7 +948,9 @@ if __name__ == "__main__":
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if not args.name:
|
if not args.name:
|
||||||
args.name = input("Bitte Namen der zu erzeugenden Bibliothek eingeben: ").strip()
|
args.name = input(
|
||||||
|
"Bitte Namen der zu erzeugenden Bibliothek eingeben: "
|
||||||
|
).strip()
|
||||||
if not args.name:
|
if not args.name:
|
||||||
print("Fehler: Kein Name angegeben. Beende.")
|
print("Fehler: Kein Name angegeben. Beende.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@@ -890,7 +963,9 @@ if __name__ == "__main__":
|
|||||||
INPUT_DIR = check_environment_var("PROJECT_DATA") / "omniflo"
|
INPUT_DIR = check_environment_var("PROJECT_DATA") / "omniflo"
|
||||||
print(f"Kein Input-Verzeichnis angegeben, verwende Standard: {INPUT_DIR} \n")
|
print(f"Kein Input-Verzeichnis angegeben, verwende Standard: {INPUT_DIR} \n")
|
||||||
|
|
||||||
OUTPUT_FILE = check_environment_var("PROJECT_DATA") / "block_libraries" / f"{args.name}.dxf"
|
OUTPUT_FILE = (
|
||||||
|
check_environment_var("PROJECT_DATA") / "block_libraries" / f"{args.name}.dxf"
|
||||||
|
)
|
||||||
|
|
||||||
# Prüfe und erstelle log-Verzeichnis falls nötig
|
# Prüfe und erstelle log-Verzeichnis falls nötig
|
||||||
log_dir = check_environment_var("PROJECT_LOG")
|
log_dir = check_environment_var("PROJECT_LOG")
|
||||||
@@ -899,9 +974,9 @@ if __name__ == "__main__":
|
|||||||
print(f"Log-Verzeichnis erstellt: {log_dir}")
|
print(f"Log-Verzeichnis erstellt: {log_dir}")
|
||||||
|
|
||||||
# Logger Setup
|
# Logger Setup
|
||||||
log_file = Path(os.environ['PROJECT_LOG']) / 'dxf2lib.log'
|
log_file = Path(os.environ["PROJECT_LOG"]) / "dxf2lib.log"
|
||||||
file_handler = logging.FileHandler(str(log_file), 'a', 'utf-8')
|
file_handler = logging.FileHandler(str(log_file), "a", "utf-8")
|
||||||
logger = setup_logger(log_dir, name='dxf2lib')
|
logger = setup_logger(log_dir, name="dxf2lib")
|
||||||
logger.info("=== DXF2LIB Verarbeitung gestartet ===")
|
logger.info("=== DXF2LIB Verarbeitung gestartet ===")
|
||||||
logger.info(f"Input-Verzeichnis: {INPUT_DIR}")
|
logger.info(f"Input-Verzeichnis: {INPUT_DIR}")
|
||||||
logger.info(f"Output-Datei: {OUTPUT_FILE}")
|
logger.info(f"Output-Datei: {OUTPUT_FILE}")
|
||||||
|
|||||||
@@ -0,0 +1,215 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Handler Context für DXF-Elementgenerierung.
|
||||||
|
Vereinfacht die Aufrufe der handle-Funktionen und bietet Debug-Unterstützung.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class HandlerContext:
|
||||||
|
"""
|
||||||
|
Kontextobjekt für Handler-Funktionsaufrufe.
|
||||||
|
|
||||||
|
Speichert alle Parameter für handle-Funktionen und bietet:
|
||||||
|
- Vereinfachte Aufrufe
|
||||||
|
- Schöne String-Repräsentation für Debugging
|
||||||
|
- Einfachen Zugriff auf alle Parameter
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
msp,
|
||||||
|
teileid,
|
||||||
|
merkmale,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
doc,
|
||||||
|
lib_doc,
|
||||||
|
verbose=False,
|
||||||
|
symbols=None,
|
||||||
|
strecken_nachbarn=None,
|
||||||
|
config=None,
|
||||||
|
config_allgemein=None,
|
||||||
|
):
|
||||||
|
self.msp = msp
|
||||||
|
self.teileid = teileid
|
||||||
|
self.merkmale = merkmale if merkmale is not None else {}
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
self.doc = doc
|
||||||
|
self.lib_doc = lib_doc
|
||||||
|
self.verbose = verbose
|
||||||
|
self.symbols = symbols if symbols is not None else []
|
||||||
|
self.strecken_nachbarn = (
|
||||||
|
strecken_nachbarn if strecken_nachbarn is not None else []
|
||||||
|
)
|
||||||
|
self.config = config
|
||||||
|
self.config_allgemein = config_allgemein
|
||||||
|
|
||||||
|
def call(self, handler_func):
|
||||||
|
"""
|
||||||
|
Ruft eine Handler-Funktion mit allen gespeicherten Parametern auf.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
handler_func: Die Handler-Funktion (z.B. handle_ils_2_0_kreisel)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Rückgabewert der Handler-Funktion
|
||||||
|
"""
|
||||||
|
return handler_func(
|
||||||
|
self.msp,
|
||||||
|
self.teileid,
|
||||||
|
self.merkmale,
|
||||||
|
self.x,
|
||||||
|
self.y,
|
||||||
|
self.doc,
|
||||||
|
self.lib_doc,
|
||||||
|
self.verbose,
|
||||||
|
self.symbols,
|
||||||
|
self.strecken_nachbarn,
|
||||||
|
self.config,
|
||||||
|
self.config_allgemein,
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""String-Repräsentation für Debugging."""
|
||||||
|
lines = [
|
||||||
|
"=" * 80,
|
||||||
|
"HandlerContext:",
|
||||||
|
"=" * 80,
|
||||||
|
f"TeileId: {self.teileid}",
|
||||||
|
f"Position: x={self.x:.2f}, y={self.y:.2f}",
|
||||||
|
f"Verbose: {self.verbose}",
|
||||||
|
"-" * 80,
|
||||||
|
"Merkmale:",
|
||||||
|
]
|
||||||
|
|
||||||
|
if self.merkmale:
|
||||||
|
for key, value in self.merkmale.items():
|
||||||
|
lines.append(f" {key:20s}: {value}")
|
||||||
|
else:
|
||||||
|
lines.append(" (keine)")
|
||||||
|
|
||||||
|
lines.append("-" * 80)
|
||||||
|
lines.append(f"Symbols: {len(self.symbols)} Einträge")
|
||||||
|
if self.symbols:
|
||||||
|
for i, sym in enumerate(self.symbols, 1):
|
||||||
|
lines.append(f" [{i}] {sym}")
|
||||||
|
|
||||||
|
lines.append("-" * 80)
|
||||||
|
lines.append(f"Nachbarn: {len(self.strecken_nachbarn)} Einträge")
|
||||||
|
|
||||||
|
lines.append("-" * 80)
|
||||||
|
lines.append(f"doc: {type(self.doc).__name__}")
|
||||||
|
lines.append(
|
||||||
|
f"lib_doc: {type(self.lib_doc).__name__ if self.lib_doc else 'None'}"
|
||||||
|
)
|
||||||
|
lines.append(f"msp: {type(self.msp).__name__}")
|
||||||
|
lines.append(f"config: {'vorhanden' if self.config else 'None'}")
|
||||||
|
lines.append(f"config_allg: {'vorhanden' if self.config_allgemein else 'None'}")
|
||||||
|
lines.append("=" * 80)
|
||||||
|
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
"""Kurze Repräsentation."""
|
||||||
|
return (
|
||||||
|
f"HandlerContext(teileid={self.teileid!r}, "
|
||||||
|
f"x={self.x:.2f}, y={self.y:.2f}, "
|
||||||
|
f"merkmale={len(self.merkmale)} items)"
|
||||||
|
)
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
"""
|
||||||
|
Gibt alle Parameter als Dictionary zurück (ohne Objekt-Referenzen).
|
||||||
|
Nützlich für Logging oder Serialisierung.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"teileid": self.teileid,
|
||||||
|
"x": self.x,
|
||||||
|
"y": self.y,
|
||||||
|
"verbose": self.verbose,
|
||||||
|
"merkmale": self.merkmale.copy(),
|
||||||
|
"symbols_count": len(self.symbols),
|
||||||
|
"symbols": self.symbols,
|
||||||
|
"nachbarn_count": len(self.strecken_nachbarn),
|
||||||
|
"has_config": self.config is not None,
|
||||||
|
"has_config_allgemein": self.config_allgemein is not None,
|
||||||
|
"has_lib_doc": self.lib_doc is not None,
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def position(self):
|
||||||
|
"""Gibt Position als Tuple zurück."""
|
||||||
|
return (self.x, self.y)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_library(self):
|
||||||
|
"""Prüft, ob eine Bibliothek verfügbar ist."""
|
||||||
|
return self.lib_doc is not None
|
||||||
|
|
||||||
|
def get_merkmal(self, key, default=None):
|
||||||
|
"""
|
||||||
|
Holt ein Merkmal mit Fallback-Wert.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
key: Merkmal-Schlüssel
|
||||||
|
default: Standardwert, falls Merkmal nicht existiert
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Merkmalwert oder default
|
||||||
|
"""
|
||||||
|
return self.merkmale.get(key, default)
|
||||||
|
|
||||||
|
|
||||||
|
def create_context_from_row(
|
||||||
|
row,
|
||||||
|
msp,
|
||||||
|
doc,
|
||||||
|
lib_doc,
|
||||||
|
strecken_nachbarn,
|
||||||
|
config,
|
||||||
|
config_allgemein,
|
||||||
|
symbols=None,
|
||||||
|
verbose=False,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Factory-Funktion: Erstellt HandlerContext aus einer CSV-Zeile.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
row: Dictionary mit CSV-Daten
|
||||||
|
msp: Modelspace
|
||||||
|
doc: DXF-Dokument
|
||||||
|
lib_doc: Bibliotheks-Dokument
|
||||||
|
strecken_nachbarn: Liste der Nachbarn
|
||||||
|
config: Config-Parser
|
||||||
|
config_allgemein: Allgemeine Config
|
||||||
|
symbols: Symbol-Liste (optional)
|
||||||
|
verbose: Debug-Modus (optional)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
HandlerContext-Instanz
|
||||||
|
"""
|
||||||
|
from arbeiten_mit_csv import parse_merkmale, extract_coords
|
||||||
|
|
||||||
|
bezeichner = row["Bezeichnung"].strip()
|
||||||
|
teileid = row["TeileId"].strip()
|
||||||
|
planquadrat = row["Planquadrat"]
|
||||||
|
merkmale = parse_merkmale(row.get("Merkmale", ""))
|
||||||
|
merkmale["bezeichner"] = bezeichner
|
||||||
|
|
||||||
|
x, y = extract_coords(planquadrat)
|
||||||
|
|
||||||
|
return HandlerContext(
|
||||||
|
msp=msp,
|
||||||
|
teileid=teileid,
|
||||||
|
merkmale=merkmale,
|
||||||
|
x=x,
|
||||||
|
y=y,
|
||||||
|
doc=doc,
|
||||||
|
lib_doc=lib_doc,
|
||||||
|
verbose=verbose,
|
||||||
|
symbols=symbols if symbols is not None else [],
|
||||||
|
strecken_nachbarn=strecken_nachbarn,
|
||||||
|
config=config,
|
||||||
|
config_allgemein=config_allgemein,
|
||||||
|
)
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
import ezdxf
|
import ezdxf
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@@ -7,7 +8,7 @@ def inspect_blocks(dxf_path):
|
|||||||
print(f"Datei: {dxf_path}")
|
print(f"Datei: {dxf_path}")
|
||||||
print("Gefundene Blöcke und Attribute:\n")
|
print("Gefundene Blöcke und Attribute:\n")
|
||||||
for block in doc.blocks:
|
for block in doc.blocks:
|
||||||
if block.name.startswith('*'): # Überspringe anonyme/Standardblöcke
|
if block.name.startswith("*"): # Überspringe anonyme/Standardblöcke
|
||||||
continue
|
continue
|
||||||
print(f"Block: {block.name}")
|
print(f"Block: {block.name}")
|
||||||
attribs = [e for e in block if e.dxftype() == "ATTDEF"]
|
attribs = [e for e in block if e.dxftype() == "ATTDEF"]
|
||||||
|
|||||||
+1056
-321
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,4 @@
|
|||||||
|
ruff==0.14.14
|
||||||
|
black==26.1.0
|
||||||
|
pydantic==2.12.5
|
||||||
ezdxf==1.4.1
|
ezdxf==1.4.1
|
||||||
svg.path==7.0
|
|
||||||
pydantic>=2.0.0
|
|
||||||
+197
-51
@@ -1,9 +1,11 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
import unittest
|
import unittest
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import difflib
|
import difflib
|
||||||
from utils import check_environment_var, setup_logger
|
from utils import check_environment_var, setup_logger
|
||||||
import plant2dxf
|
import plant2dxf
|
||||||
|
|
||||||
|
|
||||||
class TestDXFGeometry(unittest.TestCase):
|
class TestDXFGeometry(unittest.TestCase):
|
||||||
testordner_path = Path(check_environment_var("PROJECT_TEST"))
|
testordner_path = Path(check_environment_var("PROJECT_TEST"))
|
||||||
lib_path = Path(check_environment_var("PROJECT_DATA"))
|
lib_path = Path(check_environment_var("PROJECT_DATA"))
|
||||||
@@ -13,7 +15,25 @@ class TestDXFGeometry(unittest.TestCase):
|
|||||||
cfg_path = config_dir / "shapes.cfg"
|
cfg_path = config_dir / "shapes.cfg"
|
||||||
allgemein_cfg_path = config_dir / "allgemein.cfg"
|
allgemein_cfg_path = config_dir / "allgemein.cfg"
|
||||||
|
|
||||||
GEOM_CODES = {"0", "8", "10", "20", "30", "11", "21", "31", "41", "42", "43", "70", "71", "72", "73", "74", "75"}
|
GEOM_CODES = {
|
||||||
|
"0",
|
||||||
|
"8",
|
||||||
|
"10",
|
||||||
|
"20",
|
||||||
|
"30",
|
||||||
|
"11",
|
||||||
|
"21",
|
||||||
|
"31",
|
||||||
|
"41",
|
||||||
|
"42",
|
||||||
|
"43",
|
||||||
|
"70",
|
||||||
|
"71",
|
||||||
|
"72",
|
||||||
|
"73",
|
||||||
|
"74",
|
||||||
|
"75",
|
||||||
|
}
|
||||||
|
|
||||||
def extract_geometry_lines(self, file_path):
|
def extract_geometry_lines(self, file_path):
|
||||||
"""
|
"""
|
||||||
@@ -39,125 +59,251 @@ class TestDXFGeometry(unittest.TestCase):
|
|||||||
geom1 = self.extract_geometry_lines(file1)
|
geom1 = self.extract_geometry_lines(file1)
|
||||||
geom2 = self.extract_geometry_lines(file2)
|
geom2 = self.extract_geometry_lines(file2)
|
||||||
if geom1 != geom2:
|
if geom1 != geom2:
|
||||||
diff = "".join(difflib.unified_diff(geom1, geom2, fromfile=str(file1), tofile=str(file2)))
|
diff = "".join(
|
||||||
|
difflib.unified_diff(
|
||||||
|
geom1, geom2, fromfile=str(file1), tofile=str(file2)
|
||||||
|
)
|
||||||
|
)
|
||||||
raise AssertionError(f"Geometrische Daten unterscheiden sich:\n{diff}")
|
raise AssertionError(f"Geometrische Daten unterscheiden sich:\n{diff}")
|
||||||
|
|
||||||
def test_omniflobogen_dxf_file(self):
|
def test_omniflobogen_dxf_file(self):
|
||||||
omniflo_bogen = "omniflo_bogen"
|
omniflo_bogen = "omniflo_bogen"
|
||||||
omniflo_bogen_csv = self.testordner_path / f"{omniflo_bogen}.csv"
|
omniflo_bogen_csv = self.testordner_path / f"{omniflo_bogen}.csv"
|
||||||
omniflo_bogen_dxf = f"{omniflo_bogen}.dxf"
|
omniflo_bogen_dxf = f"{omniflo_bogen}.dxf"
|
||||||
omniflo_bogen_jason = self.work_dir / f"{omniflo_bogen}.jason"
|
omniflo_bogen_json = self.work_dir / f"{omniflo_bogen}.json"
|
||||||
omniflo_bogen_output = self.work_dir / omniflo_bogen_dxf
|
omniflo_bogen_output = self.work_dir / omniflo_bogen_dxf
|
||||||
omniflo_bogen_reference = self.testordner_path / omniflo_bogen_dxf
|
omniflo_bogen_reference = self.testordner_path / omniflo_bogen_dxf
|
||||||
plant2dxf.main(omniflo_bogen_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, omniflo_bogen_output,omniflo_bogen_jason)
|
plant2dxf.main(
|
||||||
|
omniflo_bogen_csv,
|
||||||
|
self.default_lib_path,
|
||||||
|
self.cfg_path,
|
||||||
|
self.allgemein_cfg_path,
|
||||||
|
omniflo_bogen_output,
|
||||||
|
omniflo_bogen_json,
|
||||||
|
)
|
||||||
self.assert_dxf_geometry_equal(omniflo_bogen_output, omniflo_bogen_reference)
|
self.assert_dxf_geometry_equal(omniflo_bogen_output, omniflo_bogen_reference)
|
||||||
|
|
||||||
def test_weiche_90_dxf_file(self):
|
def test_weiche_90_dxf_file(self):
|
||||||
weiche_90 = "weiche_90"
|
weiche_90 = "weiche_90"
|
||||||
weiche_90_csv = self.testordner_path / f"{weiche_90}.csv"
|
weiche_90_csv = self.testordner_path / f"{weiche_90}.csv"
|
||||||
weiche_90_dxf = f"{weiche_90}.dxf"
|
weiche_90_dxf = f"{weiche_90}.dxf"
|
||||||
weiche_90_jason = self.work_dir /f"{weiche_90}.jason"
|
weiche_90_json = self.work_dir / f"{weiche_90}.json"
|
||||||
weiche_90_output = self.work_dir / weiche_90_dxf
|
weiche_90_output = self.work_dir / weiche_90_dxf
|
||||||
weiche_90_reference = self.testordner_path / weiche_90_dxf
|
weiche_90_reference = self.testordner_path / weiche_90_dxf
|
||||||
plant2dxf.main(weiche_90_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, weiche_90_output,weiche_90_jason)
|
plant2dxf.main(
|
||||||
|
weiche_90_csv,
|
||||||
|
self.default_lib_path,
|
||||||
|
self.cfg_path,
|
||||||
|
self.allgemein_cfg_path,
|
||||||
|
weiche_90_output,
|
||||||
|
weiche_90_json,
|
||||||
|
)
|
||||||
self.assert_dxf_geometry_equal(weiche_90_output, weiche_90_reference)
|
self.assert_dxf_geometry_equal(weiche_90_output, weiche_90_reference)
|
||||||
|
|
||||||
def test_weiche_45_simple_dxf_file(self):
|
def test_weiche_45_simple_dxf_file(self):
|
||||||
weiche_45_simple = "weiche_45_simple"
|
weiche_45_simple = "weiche_45_simple"
|
||||||
weiche_45_simple_csv = self.testordner_path / f"{weiche_45_simple}.csv"
|
weiche_45_simple_csv = self.testordner_path / f"{weiche_45_simple}.csv"
|
||||||
weiche_45_simple_dxf = f"{weiche_45_simple}.dxf"
|
weiche_45_simple_dxf = f"{weiche_45_simple}.dxf"
|
||||||
weiche_45_simple_jason = self.work_dir/ f"{weiche_45_simple}.jason"
|
weiche_45_simple_json = self.work_dir / f"{weiche_45_simple}.json"
|
||||||
weiche_45_simple_output = self.work_dir / weiche_45_simple_dxf
|
weiche_45_simple_output = self.work_dir / weiche_45_simple_dxf
|
||||||
weiche_45_simple_reference = self.testordner_path / weiche_45_simple_dxf
|
weiche_45_simple_reference = self.testordner_path / weiche_45_simple_dxf
|
||||||
plant2dxf.main(weiche_45_simple_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, weiche_45_simple_output,weiche_45_simple_jason)
|
plant2dxf.main(
|
||||||
self.assert_dxf_geometry_equal(weiche_45_simple_output, weiche_45_simple_reference)
|
weiche_45_simple_csv,
|
||||||
|
self.default_lib_path,
|
||||||
|
self.cfg_path,
|
||||||
|
self.allgemein_cfg_path,
|
||||||
|
weiche_45_simple_output,
|
||||||
|
weiche_45_simple_json,
|
||||||
|
)
|
||||||
|
self.assert_dxf_geometry_equal(
|
||||||
|
weiche_45_simple_output, weiche_45_simple_reference
|
||||||
|
)
|
||||||
|
|
||||||
def test_weiche_45_doppel_dxf_file(self):
|
def test_weiche_45_doppel_dxf_file(self):
|
||||||
weiche_45_doppel = "weiche_45_doppel"
|
weiche_45_doppel = "weiche_45_doppel"
|
||||||
weiche_45_doppel_csv = self.testordner_path / f"{weiche_45_doppel}.csv"
|
weiche_45_doppel_csv = self.testordner_path / f"{weiche_45_doppel}.csv"
|
||||||
weiche_45_doppel_dxf = f"{weiche_45_doppel}.dxf"
|
weiche_45_doppel_dxf = f"{weiche_45_doppel}.dxf"
|
||||||
weiche_45_doppel_jason = self.work_dir /f"{weiche_45_doppel}.jason"
|
weiche_45_doppel_json = self.work_dir / f"{weiche_45_doppel}.json"
|
||||||
weiche_45_doppel_output = self.work_dir / weiche_45_doppel_dxf
|
weiche_45_doppel_output = self.work_dir / weiche_45_doppel_dxf
|
||||||
weiche_45_doppel_reference = self.testordner_path / weiche_45_doppel_dxf
|
weiche_45_doppel_reference = self.testordner_path / weiche_45_doppel_dxf
|
||||||
plant2dxf.main(weiche_45_doppel_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, weiche_45_doppel_output,weiche_45_doppel_jason)
|
plant2dxf.main(
|
||||||
self.assert_dxf_geometry_equal(weiche_45_doppel_output, weiche_45_doppel_reference)
|
weiche_45_doppel_csv,
|
||||||
|
self.default_lib_path,
|
||||||
|
self.cfg_path,
|
||||||
|
self.allgemein_cfg_path,
|
||||||
|
weiche_45_doppel_output,
|
||||||
|
weiche_45_doppel_json,
|
||||||
|
)
|
||||||
|
self.assert_dxf_geometry_equal(
|
||||||
|
weiche_45_doppel_output, weiche_45_doppel_reference
|
||||||
|
)
|
||||||
|
|
||||||
def test_weiche_45_dreiwege_dxf_file(self):
|
def test_weiche_45_dreiwege_dxf_file(self):
|
||||||
weiche_45_dreiwege = "weiche_45_dreiwege"
|
weiche_45_dreiwege = "weiche_45_dreiwege"
|
||||||
weiche_45_dreiwege_csv = self.testordner_path / f"{weiche_45_dreiwege}.csv"
|
weiche_45_dreiwege_csv = self.testordner_path / f"{weiche_45_dreiwege}.csv"
|
||||||
weiche_45_dreiwege_dxf = f"{weiche_45_dreiwege}.dxf"
|
weiche_45_dreiwege_dxf = f"{weiche_45_dreiwege}.dxf"
|
||||||
weiche_45_dreiwege_jason = self.work_dir /f"{weiche_45_dreiwege}.jason"
|
weiche_45_dreiwege_json = self.work_dir / f"{weiche_45_dreiwege}.json"
|
||||||
weiche_45_dreiwege_output = self.work_dir / weiche_45_dreiwege_dxf
|
weiche_45_dreiwege_output = self.work_dir / weiche_45_dreiwege_dxf
|
||||||
weiche_45_dreiwege_reference = self.testordner_path / weiche_45_dreiwege_dxf
|
weiche_45_dreiwege_reference = self.testordner_path / weiche_45_dreiwege_dxf
|
||||||
plant2dxf.main(weiche_45_dreiwege_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, weiche_45_dreiwege_output,weiche_45_dreiwege_jason)
|
plant2dxf.main(
|
||||||
self.assert_dxf_geometry_equal(weiche_45_dreiwege_output, weiche_45_dreiwege_reference)
|
weiche_45_dreiwege_csv,
|
||||||
|
self.default_lib_path,
|
||||||
|
self.cfg_path,
|
||||||
|
self.allgemein_cfg_path,
|
||||||
|
weiche_45_dreiwege_output,
|
||||||
|
weiche_45_dreiwege_json,
|
||||||
|
)
|
||||||
|
self.assert_dxf_geometry_equal(
|
||||||
|
weiche_45_dreiwege_output, weiche_45_dreiwege_reference
|
||||||
|
)
|
||||||
|
|
||||||
def test_weichenkoerper_dxf_file(self):
|
def test_weichenkoerper_dxf_file(self):
|
||||||
weichenkoerper = "weichenkoerper"
|
weichenkoerper = "weichenkoerper"
|
||||||
weichenkoerper_csv = self.testordner_path / f"{weichenkoerper}.csv"
|
weichenkoerper_csv = self.testordner_path / f"{weichenkoerper}.csv"
|
||||||
weichenkoerper_dxf = f"{weichenkoerper}.dxf"
|
weichenkoerper_dxf = f"{weichenkoerper}.dxf"
|
||||||
weichenkoerper_jason = self.work_dir /f"{weichenkoerper}.jason"
|
weichenkoerper_json = self.work_dir / f"{weichenkoerper}.json"
|
||||||
weichenkoerper_output = self.work_dir / weichenkoerper_dxf
|
weichenkoerper_output = self.work_dir / weichenkoerper_dxf
|
||||||
weichenkoerper_reference = self.testordner_path / weichenkoerper_dxf
|
weichenkoerper_reference = self.testordner_path / weichenkoerper_dxf
|
||||||
plant2dxf.main(weichenkoerper_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, weichenkoerper_output,weichenkoerper_jason)
|
plant2dxf.main(
|
||||||
|
weichenkoerper_csv,
|
||||||
|
self.default_lib_path,
|
||||||
|
self.cfg_path,
|
||||||
|
self.allgemein_cfg_path,
|
||||||
|
weichenkoerper_output,
|
||||||
|
weichenkoerper_json,
|
||||||
|
)
|
||||||
self.assert_dxf_geometry_equal(weichenkoerper_output, weichenkoerper_reference)
|
self.assert_dxf_geometry_equal(weichenkoerper_output, weichenkoerper_reference)
|
||||||
|
|
||||||
def test_weichenkombination_dxf_file(self):
|
def test_weichenkombination_dxf_file(self):
|
||||||
weichenkombination = "weichenkombination"
|
weichenkombination = "weichenkombination"
|
||||||
weichenkombination_csv = self.testordner_path / f"{weichenkombination}.csv"
|
weichenkombination_csv = self.testordner_path / f"{weichenkombination}.csv"
|
||||||
weichenkombination_dxf = f"{weichenkombination}.dxf"
|
weichenkombination_dxf = f"{weichenkombination}.dxf"
|
||||||
weichenkombination_jason = self.work_dir /f"{weichenkombination}.jason"
|
weichenkombination_json = self.work_dir / f"{weichenkombination}.json"
|
||||||
weichenkombination_output = self.work_dir / weichenkombination_dxf
|
weichenkombination_output = self.work_dir / weichenkombination_dxf
|
||||||
weichenkombination_reference = self.testordner_path / weichenkombination_dxf
|
weichenkombination_reference = self.testordner_path / weichenkombination_dxf
|
||||||
plant2dxf.main(weichenkombination_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, weichenkombination_output,weichenkombination_jason)
|
plant2dxf.main(
|
||||||
self.assert_dxf_geometry_equal(weichenkombination_output, weichenkombination_reference)
|
weichenkombination_csv,
|
||||||
|
self.default_lib_path,
|
||||||
|
self.cfg_path,
|
||||||
|
self.allgemein_cfg_path,
|
||||||
|
weichenkombination_output,
|
||||||
|
weichenkombination_json,
|
||||||
|
)
|
||||||
|
self.assert_dxf_geometry_equal(
|
||||||
|
weichenkombination_output, weichenkombination_reference
|
||||||
|
)
|
||||||
|
|
||||||
def test_gefaelle_dxf_file(self):
|
def test_gefaelle_dxf_file(self):
|
||||||
gefaelle = "gefaelle"
|
gefaelle = "gefaelle"
|
||||||
gefaelle_csv = self.testordner_path / f"{gefaelle}.csv"
|
gefaelle_csv = self.testordner_path / f"{gefaelle}.csv"
|
||||||
gefaelle_dxf = f"{gefaelle}.dxf"
|
gefaelle_dxf = f"{gefaelle}.dxf"
|
||||||
gefaelle_jason = self.work_dir /f"{gefaelle}.jason"
|
gefaelle_json = self.work_dir / f"{gefaelle}.json"
|
||||||
weichenkombination_output = self.work_dir / gefaelle_dxf
|
weichenkombination_output = self.work_dir / gefaelle_dxf
|
||||||
weichenkombination_reference = self.testordner_path / gefaelle_dxf
|
weichenkombination_reference = self.testordner_path / gefaelle_dxf
|
||||||
plant2dxf.main(gefaelle_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, weichenkombination_output,gefaelle_jason)
|
plant2dxf.main(
|
||||||
self.assert_dxf_geometry_equal(weichenkombination_output, weichenkombination_reference)
|
gefaelle_csv,
|
||||||
|
self.default_lib_path,
|
||||||
|
self.cfg_path,
|
||||||
|
self.allgemein_cfg_path,
|
||||||
|
weichenkombination_output,
|
||||||
|
gefaelle_json,
|
||||||
|
)
|
||||||
|
self.assert_dxf_geometry_equal(
|
||||||
|
weichenkombination_output, weichenkombination_reference
|
||||||
|
)
|
||||||
|
|
||||||
def test_gefaelle_ausnahme_gleiche_orientierung_dxf_file(self):
|
def test_gefaelle_ausnahme_gleiche_orientierung_dxf_file(self):
|
||||||
gefaelle_ausnahme_gleiche_orientierung= "gefaelle_ausnahme_gleiche_orientierung"
|
gefaelle_ausnahme_gleiche_orientierung = (
|
||||||
gefaelle_ausnahme_gleiche_orientierung_csv = self.testordner_path / f"{gefaelle_ausnahme_gleiche_orientierung}.csv"
|
"gefaelle_ausnahme_gleiche_orientierung"
|
||||||
gefaelle_ausnahme_gleiche_orientierung_dxf = f"{gefaelle_ausnahme_gleiche_orientierung}.dxf"
|
)
|
||||||
gefaelle_ausnahme_gleiche_orientierung_jason = self.work_dir /f"{gefaelle_ausnahme_gleiche_orientierung}.jason"
|
gefaelle_ausnahme_gleiche_orientierung_csv = (
|
||||||
gefaelle_ausnahme_gleiche_orientierung_output = self.work_dir / gefaelle_ausnahme_gleiche_orientierung_dxf
|
self.testordner_path / f"{gefaelle_ausnahme_gleiche_orientierung}.csv"
|
||||||
gefaelle_ausnahme_gleiche_orientierung_reference = self.testordner_path / gefaelle_ausnahme_gleiche_orientierung_dxf
|
)
|
||||||
plant2dxf.main(gefaelle_ausnahme_gleiche_orientierung_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, gefaelle_ausnahme_gleiche_orientierung_output,gefaelle_ausnahme_gleiche_orientierung_jason)
|
gefaelle_ausnahme_gleiche_orientierung_dxf = (
|
||||||
self.assert_dxf_geometry_equal(gefaelle_ausnahme_gleiche_orientierung_output, gefaelle_ausnahme_gleiche_orientierung_reference)
|
f"{gefaelle_ausnahme_gleiche_orientierung}.dxf"
|
||||||
|
)
|
||||||
|
gefaelle_ausnahme_gleiche_orientierung_json = (
|
||||||
|
self.work_dir / f"{gefaelle_ausnahme_gleiche_orientierung}.json"
|
||||||
|
)
|
||||||
|
gefaelle_ausnahme_gleiche_orientierung_output = (
|
||||||
|
self.work_dir / gefaelle_ausnahme_gleiche_orientierung_dxf
|
||||||
|
)
|
||||||
|
gefaelle_ausnahme_gleiche_orientierung_reference = (
|
||||||
|
self.testordner_path / gefaelle_ausnahme_gleiche_orientierung_dxf
|
||||||
|
)
|
||||||
|
plant2dxf.main(
|
||||||
|
gefaelle_ausnahme_gleiche_orientierung_csv,
|
||||||
|
self.default_lib_path,
|
||||||
|
self.cfg_path,
|
||||||
|
self.allgemein_cfg_path,
|
||||||
|
gefaelle_ausnahme_gleiche_orientierung_output,
|
||||||
|
gefaelle_ausnahme_gleiche_orientierung_json,
|
||||||
|
)
|
||||||
|
self.assert_dxf_geometry_equal(
|
||||||
|
gefaelle_ausnahme_gleiche_orientierung_output,
|
||||||
|
gefaelle_ausnahme_gleiche_orientierung_reference,
|
||||||
|
)
|
||||||
|
|
||||||
def test_gefaelle_ausnahme_unterschiedlich_orientierung_dxf_file(self):
|
def test_gefaelle_ausnahme_unterschiedlich_orientierung_dxf_file(self):
|
||||||
gefaelle_ausnahme_unterschiedlich_orientierung= "gefaelle_ausnahme_unterschiedlich_orientierung"
|
gefaelle_ausnahme_unterschiedlich_orientierung = (
|
||||||
gefaelle_ausnahme_unterschiedlich_orientierung_csv = self.testordner_path / f"{gefaelle_ausnahme_unterschiedlich_orientierung}.csv"
|
"gefaelle_ausnahme_unterschiedlich_orientierung"
|
||||||
gefaelle_ausnahme_unterschiedlich_orientierung_dxf = f"{gefaelle_ausnahme_unterschiedlich_orientierung}.dxf"
|
)
|
||||||
gefaelle_ausnahme_unterschiedlich_orientierung_jason = self.work_dir /f"{gefaelle_ausnahme_unterschiedlich_orientierung}.jason"
|
gefaelle_ausnahme_unterschiedlich_orientierung_csv = (
|
||||||
gefaelle_ausnahme_unterschiedlich_orientierung_output = self.work_dir / gefaelle_ausnahme_unterschiedlich_orientierung_dxf
|
self.testordner_path
|
||||||
gefaelle_ausnahme_unterschiedlich_orientierung_reference = self.testordner_path / gefaelle_ausnahme_unterschiedlich_orientierung_dxf
|
/ f"{gefaelle_ausnahme_unterschiedlich_orientierung}.csv"
|
||||||
plant2dxf.main(gefaelle_ausnahme_unterschiedlich_orientierung_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, gefaelle_ausnahme_unterschiedlich_orientierung_output,gefaelle_ausnahme_unterschiedlich_orientierung_jason)
|
)
|
||||||
self.assert_dxf_geometry_equal(gefaelle_ausnahme_unterschiedlich_orientierung_output, gefaelle_ausnahme_unterschiedlich_orientierung_reference)
|
gefaelle_ausnahme_unterschiedlich_orientierung_dxf = (
|
||||||
|
f"{gefaelle_ausnahme_unterschiedlich_orientierung}.dxf"
|
||||||
|
)
|
||||||
|
gefaelle_ausnahme_unterschiedlich_orientierung_json = (
|
||||||
|
self.work_dir / f"{gefaelle_ausnahme_unterschiedlich_orientierung}.json"
|
||||||
|
)
|
||||||
|
gefaelle_ausnahme_unterschiedlich_orientierung_output = (
|
||||||
|
self.work_dir / gefaelle_ausnahme_unterschiedlich_orientierung_dxf
|
||||||
|
)
|
||||||
|
gefaelle_ausnahme_unterschiedlich_orientierung_reference = (
|
||||||
|
self.testordner_path / gefaelle_ausnahme_unterschiedlich_orientierung_dxf
|
||||||
|
)
|
||||||
|
plant2dxf.main(
|
||||||
|
gefaelle_ausnahme_unterschiedlich_orientierung_csv,
|
||||||
|
self.default_lib_path,
|
||||||
|
self.cfg_path,
|
||||||
|
self.allgemein_cfg_path,
|
||||||
|
gefaelle_ausnahme_unterschiedlich_orientierung_output,
|
||||||
|
gefaelle_ausnahme_unterschiedlich_orientierung_json,
|
||||||
|
)
|
||||||
|
self.assert_dxf_geometry_equal(
|
||||||
|
gefaelle_ausnahme_unterschiedlich_orientierung_output,
|
||||||
|
gefaelle_ausnahme_unterschiedlich_orientierung_reference,
|
||||||
|
)
|
||||||
|
|
||||||
def test_gefaelle_einzeln_verbunden_dxf_file(self):
|
def test_gefaelle_einzeln_verbunden_dxf_file(self):
|
||||||
gefaelle_einzeln_verbunden = "gefaelle_einzeln_verbunden"
|
gefaelle_einzeln_verbunden = "gefaelle_einzeln_verbunden"
|
||||||
gefaelle_einzeln_verbunden_csv = self.testordner_path / f"{gefaelle_einzeln_verbunden}.csv"
|
gefaelle_einzeln_verbunden_csv = (
|
||||||
|
self.testordner_path / f"{gefaelle_einzeln_verbunden}.csv"
|
||||||
|
)
|
||||||
gefaelle_einzeln_verbunden_dxf = f"{gefaelle_einzeln_verbunden}.dxf"
|
gefaelle_einzeln_verbunden_dxf = f"{gefaelle_einzeln_verbunden}.dxf"
|
||||||
gefaelle_einzeln_verbunden_jason = self.work_dir /f"{gefaelle_einzeln_verbunden}.jason"
|
gefaelle_einzeln_verbunden_json = (
|
||||||
gefaelle_einzeln_verbunden_output = self.work_dir / gefaelle_einzeln_verbunden_dxf
|
self.work_dir / f"{gefaelle_einzeln_verbunden}.json"
|
||||||
gefaelle_einzeln_verbunden_reference = self.testordner_path / gefaelle_einzeln_verbunden_dxf
|
)
|
||||||
plant2dxf.main(gefaelle_einzeln_verbunden_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, gefaelle_einzeln_verbunden_output,gefaelle_einzeln_verbunden_jason)
|
gefaelle_einzeln_verbunden_output = (
|
||||||
self.assert_dxf_geometry_equal(gefaelle_einzeln_verbunden_output, gefaelle_einzeln_verbunden_reference)
|
self.work_dir / gefaelle_einzeln_verbunden_dxf
|
||||||
|
)
|
||||||
|
gefaelle_einzeln_verbunden_reference = (
|
||||||
|
self.testordner_path / gefaelle_einzeln_verbunden_dxf
|
||||||
|
)
|
||||||
|
plant2dxf.main(
|
||||||
|
gefaelle_einzeln_verbunden_csv,
|
||||||
|
self.default_lib_path,
|
||||||
|
self.cfg_path,
|
||||||
|
self.allgemein_cfg_path,
|
||||||
|
gefaelle_einzeln_verbunden_output,
|
||||||
|
gefaelle_einzeln_verbunden_json,
|
||||||
|
)
|
||||||
|
self.assert_dxf_geometry_equal(
|
||||||
|
gefaelle_einzeln_verbunden_output, gefaelle_einzeln_verbunden_reference
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+5
-3
@@ -1,3 +1,4 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
@@ -14,7 +15,7 @@ def check_environment_var(env_str: str) -> Path:
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def setup_logger(log_dir: Path, name: str = 'app') -> logging.Logger:
|
def setup_logger(log_dir: Path, name: str = "app") -> logging.Logger:
|
||||||
"""
|
"""
|
||||||
Erstellt und konfiguriert einen Logger, der sowohl in eine Datei als auch auf die Konsole schreibt.
|
Erstellt und konfiguriert einen Logger, der sowohl in eine Datei als auch auf die Konsole schreibt.
|
||||||
Die Logdatei erhält einen Zeitstempel im Namen und ist UTF-8 kodiert.
|
Die Logdatei erhält einen Zeitstempel im Namen und ist UTF-8 kodiert.
|
||||||
@@ -26,6 +27,7 @@ def setup_logger(log_dir: Path, name: str = 'app') -> logging.Logger:
|
|||||||
logging.Logger: Konfigurierter Logger
|
logging.Logger: Konfigurierter Logger
|
||||||
"""
|
"""
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
logger = logging.getLogger(name)
|
logger = logging.getLogger(name)
|
||||||
logger.setLevel(logging.INFO)
|
logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
@@ -38,7 +40,7 @@ def setup_logger(log_dir: Path, name: str = 'app') -> logging.Logger:
|
|||||||
|
|
||||||
# Logdatei mit Zeitstempel im Namen erzeugen
|
# Logdatei mit Zeitstempel im Namen erzeugen
|
||||||
log_file = log_dir / f"{name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
|
log_file = log_dir / f"{name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
|
||||||
file_handler = logging.FileHandler(log_file, encoding='utf-8')
|
file_handler = logging.FileHandler(log_file, encoding="utf-8")
|
||||||
file_handler.setLevel(logging.INFO)
|
file_handler.setLevel(logging.INFO)
|
||||||
|
|
||||||
# Handler für die Konsole
|
# Handler für die Konsole
|
||||||
@@ -46,7 +48,7 @@ def setup_logger(log_dir: Path, name: str = 'app') -> logging.Logger:
|
|||||||
console_handler.setLevel(logging.INFO)
|
console_handler.setLevel(logging.INFO)
|
||||||
|
|
||||||
# Einheitliches Log-Format definieren
|
# Einheitliches Log-Format definieren
|
||||||
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
|
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
|
||||||
file_handler.setFormatter(formatter)
|
file_handler.setFormatter(formatter)
|
||||||
console_handler.setFormatter(formatter)
|
console_handler.setFormatter(formatter)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
[tool.black]
|
||||||
|
line-length = 88
|
||||||
|
target-version = ["py312"]
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
line-length = 88
|
||||||
|
select = ["E", "F", "I"]
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"[python]": {
|
||||||
|
"editor.defaultFormatter": "ms-python.black-formatter",
|
||||||
|
"editor.formatOnSave": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"ruff.enable": true,
|
||||||
|
"ruff.fixOnSave": true,
|
||||||
|
"ruff.organizeImports": true
|
||||||
|
}
|
||||||
Vendored
+6854
-1132
File diff suppressed because it is too large
Load Diff
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
Fehlen:
|
||||||
|
ILS Vario Förderer Test.
|
||||||
|
- Benötigt alle Test wie bei Gevälleststrecke + unterschedlche Winkel Berechnung mit Gefällestrecke und Berechnung ohne Motor und Umlenk vor allem bei winkel 0 und winkel 3 bei einem ab förderer + Verbindung mit Kreisel
|
||||||
|
Ils angetriebene Kurve(Vario kurve)
|
||||||
|
verbinding mit Gefällestrecke
|
||||||
|
Ils Kurve(Gefällekurve)
|
||||||
|
- Dimensionen und dxf Blöcke sind noch nicht richtig weshalb es hier noch keine Test gibt's
|
||||||
Vendored
+5854
-132
File diff suppressed because it is too large
Load Diff
Vendored
+10470
-4748
File diff suppressed because it is too large
Load Diff
Vendored
+5878
-156
File diff suppressed because it is too large
Load Diff
Vendored
+12413
-6691
File diff suppressed because it is too large
Load Diff
Vendored
+162
-162
@@ -1,163 +1,163 @@
|
|||||||
Elementnummer;TeileArt;TeileId;NachbarIds;Bezeichnung;Planquadrat;rotation;Merkmale
|
Elementnummer;TeileArt;TeileId;NachbarIds;Bezeichnung;Planquadrat;rotation;Merkmale
|
||||||
0;"Omniflo Gerade";"shape_c28c3e87-a202-999b-8307-86423e59d723";;"OFGerade :1";"X:2987.01 Y:21597.21";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-157.5,"SivasNummer":"821106002"}
|
0;"Omniflo Gerade";"shape_9b26e364-d9f3-5f32-ee6c-0616b44e1798";;"OFGerade :1";"X:3962.26 Y:24338.11";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":0.0,"SivasNummer":"821106002"}
|
||||||
1;"Omniflo Weiche";"shape_ed65ab41-03ff-5643-5e6a-b65d4d741f66";;"OFWeiche :1";"X:3437.5 Y:20513.33";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
1;"Omniflo Weiche";"shape_49fb15fd-aacc-abe3-bb93-f1df4858fdd0";;"OFWeiche :1";"X:3928.57 Y:25518.11";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
||||||
2;"Omniflo Weiche";"shape_8a64f204-2809-7cdc-c381-f3774a1a2801";;"OFWeiche :5";"X:3640.11 Y:17135.33";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
2;"Omniflo Weiche";"shape_64347abe-fbf9-7873-2934-e14fc46d1a48";;"OFWeiche :5";"X:3988.09 Y:20504.27";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
||||||
3;"Omniflo Weiche";"shape_6ab32e55-7cfd-d321-35cb-e94716d19b24";;"OFWeiche :6";"X:3472.29 Y:17448.73";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-337.5,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
3;"Omniflo Weiche";"shape_318f47b2-7631-0ce8-13c2-316a7006c369";;"OFWeiche :6";"X:3820.28 Y:20817.67";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-337.5,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
||||||
4;"Omniflo Weiche";"shape_68202e3c-df01-0890-ddc8-a26e2039a735";;"OFWeiche :7";"X:3197.32 Y:17674.05";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-315.0,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
4;"Omniflo Weiche";"shape_6895c12f-32b6-317e-5e4c-8724b0b4b362";;"OFWeiche :7";"X:3545.3 Y:21043";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-315.0,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
||||||
5;"Omniflo Weiche";"shape_f84638af-d14a-8d9f-048b-4ba27581c686";;"OFWeiche :8";"X:2857.05 Y:17777";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-292.5,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
5;"Omniflo Weiche";"shape_28f608db-52db-7a27-daae-14692b7776b5";;"OFWeiche :8";"X:3205.03 Y:21145.95";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-292.5,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
||||||
6;"Omniflo Weiche";"shape_641956f7-eb1f-b8a9-2c29-4c755321c289";;"OFWeiche :9";"X:2503.28 Y:17741.89";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-270.0,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
6;"Omniflo Weiche";"shape_802dcf32-0209-913d-6633-45a0c7167cf2";;"OFWeiche :9";"X:2851.27 Y:21110.84";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-270.0,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
||||||
7;"Omniflo Weiche";"shape_24ff2071-a404-2ccf-350a-cbf7e82ddf38";;"OFWeiche :10";"X:2189.88 Y:17574.08";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-247.5,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
7;"Omniflo Weiche";"shape_fd30ae3c-7a2e-1305-7fec-ca78b36b0275";;"OFWeiche :10";"X:2537.87 Y:20943.03";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-247.5,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
||||||
8;"Omniflo Weiche";"shape_9e5458eb-22ac-aaaa-cead-b39a75afd5aa";;"OFWeiche :11";"X:1964.56 Y:17299.1";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-225.0,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
8;"Omniflo Weiche";"shape_3ce2b136-c43c-700b-a6e6-bef196cbe98b";;"OFWeiche :11";"X:2312.54 Y:20668.04";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-225.0,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
||||||
9;"Omniflo Weiche";"shape_66d309e1-b951-c72f-5f17-7fd7eac29c7f";;"OFWeiche :12";"X:1861.61 Y:16958.83";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-202.5,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
9;"Omniflo Weiche";"shape_323bc6de-6a93-979b-1e13-f729fb008136";;"OFWeiche :12";"X:2209.59 Y:20327.76";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-202.5,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
||||||
10;"Omniflo Weiche";"shape_321f24e1-b44a-b4ba-7b24-ee5e2fec7cac";;"OFWeiche :13";"X:1896.72 Y:16605.06";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-180.0,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
10;"Omniflo Weiche";"shape_d5333793-3140-9866-de6d-c53e3153a727";;"OFWeiche :13";"X:2244.7 Y:19974";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-180.0,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
||||||
11;"Omniflo Weiche";"shape_800bfe85-d8b8-f22b-7c84-5005548b013a";;"OFWeiche :14";"X:2064.54 Y:16291.66";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-157.5,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
11;"Omniflo Weiche";"shape_905bb376-c7f2-5635-2005-4b0049f6fb7c";;"OFWeiche :14";"X:2412.51 Y:19660.6";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-157.5,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
||||||
12;"Omniflo Weiche";"shape_7fd2a6f8-8cad-24ef-4e1f-900e920d4009";;"OFWeiche :15";"X:2339.52 Y:16066.33";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-135.0,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
12;"Omniflo Weiche";"shape_62644b1d-946d-6db8-ae47-9b9c86cddee9";;"OFWeiche :15";"X:2687.49 Y:19435.27";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-135.0,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
||||||
13;"Omniflo Weiche";"shape_6ab94c71-a18f-11d7-317e-aec53523f7ad";;"OFWeiche :16";"X:2679.78 Y:15963.38";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-112.5,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
13;"Omniflo Weiche";"shape_39c4b344-2124-657c-76f0-abc72a0b05d5";;"OFWeiche :16";"X:3027.76 Y:19332.32";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-112.5,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
||||||
14;"Omniflo Weiche";"shape_d9ea62df-a10b-7e40-df49-bd8948d96b09";;"OFWeiche :17";"X:3033.55 Y:15998.49";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-90.0,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
14;"Omniflo Weiche";"shape_1e047631-77f4-3b77-3580-fe218df549c7";;"OFWeiche :17";"X:3381.52 Y:19367.43";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-90.0,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
||||||
15;"Omniflo Weiche";"shape_d663149a-e3d0-972e-4ec6-2283b336c89b";;"OFWeiche :18";"X:3346.94 Y:16166.3";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-67.5,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
15;"Omniflo Weiche";"shape_cd5256ea-fd47-df0a-c071-5bea7ece9e42";;"OFWeiche :18";"X:3694.92 Y:19535.24";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-67.5,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
||||||
16;"Omniflo Weiche";"shape_0617228e-8d0c-9d0d-3e08-a8e7eeaf7b4b";;"OFWeiche :19";"X:3572.28 Y:16441.28";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-45.0,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
16;"Omniflo Weiche";"shape_30d81c27-ad8d-cdaf-a93a-03ce72089773";;"OFWeiche :19";"X:3920.24 Y:19810.22";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-45.0,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
||||||
17;"Omniflo Weiche";"shape_514f8c32-aa28-c580-51fc-74e610204553";;"OFWeiche :20";"X:3675.23 Y:16781.55";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-22.5,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
17;"Omniflo Weiche";"shape_879ddf67-143b-a25d-0d71-44f105ec918c";;"OFWeiche :20";"X:4023.19 Y:20150.49";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-22.5,"Antrieb Kurve":false,"SivasNummer":"834342011"}
|
||||||
18;"Omniflo Weiche";"shape_6aefdf65-10a6-01ad-a53c-46d0ad8a2c4b";;"OFWeiche :2";"X:4842.57 Y:20630.01";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
18;"Omniflo Weiche";"shape_b73972a6-d892-0833-40cc-86ba33983800";;"OFWeiche :3";"X:9386.3 Y:25634.03";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
||||||
19;"Omniflo Weiche";"shape_47adcba4-6c6a-36ba-1017-90230aba79d3";;"OFWeiche :21";"X:4743.48 Y:17368.23";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
19;"Omniflo Weiche";"shape_0269fea0-01a1-9fdc-9f3e-4174a29d61de";;"OFWeiche :37";"X:9623.05 Y:20582.39";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
||||||
20;"Omniflo Weiche";"shape_76485f6c-9477-b689-9e32-f0f13d027b37";;"OFWeiche :22";"X:4911.3 Y:17681.63";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-22.5,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
20;"Omniflo Weiche";"shape_2dc1496a-d8bf-92a6-b9c2-559b5cb2eab0";;"OFWeiche :38";"X:9455.23 Y:20895.79";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-337.5,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
||||||
21;"Omniflo Weiche";"shape_90232079-87f3-a60e-6600-f91137a6975a";;"OFWeiche :23";"X:5186.27 Y:17906.95";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-45.0,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
21;"Omniflo Weiche";"shape_693b4421-0efc-6e90-7dee-e8deebb11455";;"OFWeiche :39";"X:9180.25 Y:21121.13";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-315.0,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
||||||
22;"Omniflo Weiche";"shape_ab3559af-3ec7-f922-8c0f-146a26c99beb";;"OFWeiche :24";"X:5526.54 Y:18009.9";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-67.5,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
22;"Omniflo Weiche";"shape_c8392a6e-e378-a6f2-dcc4-35b0e3206e3e";;"OFWeiche :40";"X:8839.97 Y:21224.06";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-292.5,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
||||||
23;"Omniflo Weiche";"shape_db149b8f-ea68-27c3-8544-2f41512ba242";;"OFWeiche :25";"X:5880.31 Y:17974.8";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-90.0,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
23;"Omniflo Weiche";"shape_9bdfded6-4ad5-13c1-1fb6-71832b762d16";;"OFWeiche :41";"X:8486.21 Y:21188.95";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-270.0,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
||||||
24;"Omniflo Weiche";"shape_17a47f48-97fe-bbb3-43f8-a0da81b0eb33";;"OFWeiche :26";"X:6193.71 Y:17806.99";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-112.5,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
24;"Omniflo Weiche";"shape_ef1bf5c2-3f70-fe07-ad6d-1c381c52e0b6";;"OFWeiche :42";"X:8172.81 Y:21021.14";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-247.5,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
||||||
25;"Omniflo Weiche";"shape_6b47bb12-4a38-6b67-76c1-81ce8d91ff9c";;"OFWeiche :27";"X:6419.04 Y:17532.01";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-135.0,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
25;"Omniflo Weiche";"shape_6e64a28b-f8c6-2a4f-e28b-a0bfdc0c5af7";;"OFWeiche :43";"X:7947.48 Y:20746.16";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-225.0,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
||||||
26;"Omniflo Weiche";"shape_172842c7-8f23-d4fb-f6ff-e0cfb8723cd7";;"OFWeiche :28";"X:6521.99 Y:17191.74";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-157.5,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
26;"Omniflo Weiche";"shape_f051c29b-523f-c051-6a30-7c09feeab862";;"OFWeiche :44";"X:7844.53 Y:20405.89";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-202.5,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
||||||
27;"Omniflo Weiche";"shape_15bf22f8-8ebb-3421-f7a5-b29616eb8818";;"OFWeiche :29";"X:6486.88 Y:16837.97";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-180.0,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
27;"Omniflo Weiche";"shape_8451c719-af1a-7cfa-e424-a0c00c5f94ad";;"OFWeiche :45";"X:7879.64 Y:20052.13";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-180.0,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
||||||
28;"Omniflo Weiche";"shape_10e7f649-f966-2fb5-9b28-ce3ed35f5860";;"OFWeiche :30";"X:6319.07 Y:16524.57";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-202.5,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
28;"Omniflo Weiche";"shape_2acb8acb-d33c-457c-6027-b1cdb1fdf50b";;"OFWeiche :46";"X:8047.45 Y:19738.73";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-157.5,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
||||||
29;"Omniflo Weiche";"shape_ded388e2-f306-1e64-5ec9-812844f585e3";;"OFWeiche :31";"X:6044.08 Y:16299.24";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-225.0,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
29;"Omniflo Weiche";"shape_0a2d18ae-af55-5bdb-39fa-24d8977d20c2";;"OFWeiche :47";"X:8322.43 Y:19513.4";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-135.0,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
||||||
30;"Omniflo Weiche";"shape_0a6ba6f0-5b96-81d6-eba5-6e9a6d95131f";;"OFWeiche :32";"X:5703.82 Y:16196.29";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-247.5,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
30;"Omniflo Weiche";"shape_9ad86f6d-4041-8fac-847c-3a103e0dea05";;"OFWeiche :48";"X:8662.7 Y:19410.45";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-112.5,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
||||||
31;"Omniflo Weiche";"shape_a032f781-9a32-70a6-2d3d-042a6b2a4621";;"OFWeiche :33";"X:5350.06 Y:16231.4";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-270.0,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
31;"Omniflo Weiche";"shape_977e338e-2582-f208-94e1-b319e5f2401d";;"OFWeiche :49";"X:9016.46 Y:19445.56";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-90.0,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
||||||
32;"Omniflo Weiche";"shape_11221d63-9db5-ea80-db6d-e63e47eb9331";;"OFWeiche :34";"X:5036.66 Y:16399.21";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-292.5,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
32;"Omniflo Weiche";"shape_d59a1df2-ecf3-211b-d43b-68accbdaf162";;"OFWeiche :50";"X:9329.86 Y:19613.37";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-67.5,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
||||||
33;"Omniflo Weiche";"shape_536410df-9504-815f-2ca7-1aa3243fb019";;"OFWeiche :35";"X:4811.32 Y:16674.19";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-315.0,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
33;"Omniflo Weiche";"shape_c2c101a6-4706-61c5-889d-6f3474eac8f8";;"OFWeiche :51";"X:9555.19 Y:19888.35";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-45.0,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
||||||
34;"Omniflo Weiche";"shape_a1a55130-29a3-00b2-d4f9-53bf1fa4dffb";;"OFWeiche :36";"X:4708.37 Y:17014.46";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-337.5,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
34;"Omniflo Weiche";"shape_57de5bab-1811-7594-20ab-8fe95b8a6633";;"OFWeiche :52";"X:9658.14 Y:20228.62";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-22.5,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
||||||
35;"Omniflo Weiche";"shape_2b17c199-bc06-49c9-fbbd-5cf1d911213c";;"OFWeiche :4";"X:11001.35 Y:20013.22";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
35;"Omniflo Weiche";"shape_a16752d8-71cf-10d3-b9e3-00501f5b3521";;"OFWeiche :4";"X:11065.78 Y:25644.75";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
||||||
36;"Omniflo Weiche";"shape_37c38ff5-0008-28d6-ddaa-fb755559c355";;"OFWeiche :53";"X:10750.11 Y:16616.61";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
36;"Omniflo Weiche";"shape_099ac37a-41eb-f24e-ea33-ea1e37bc9d3f";;"OFWeiche :53";"X:10983.05 Y:20355.77";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
||||||
37;"Omniflo Weiche";"shape_faf356db-64e7-149d-2ad5-0d9a4657b293";;"OFWeiche :54";"X:10917.92 Y:16930.02";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-22.5,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
37;"Omniflo Weiche";"shape_ff3ccbec-db41-62c6-be11-ecd93202d54c";;"OFWeiche :54";"X:11150.87 Y:20669.17";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-22.5,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
||||||
38;"Omniflo Weiche";"shape_f734e32b-7940-dc13-07e9-4773a8faf92e";;"OFWeiche :55";"X:11192.9 Y:17155.34";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-45.0,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
38;"Omniflo Weiche";"shape_834f6365-cad2-d8c1-f6ea-8033ae65a49b";;"OFWeiche :55";"X:11425.85 Y:20894.5";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-45.0,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
||||||
39;"Omniflo Weiche";"shape_594e019f-1ef4-620d-23b4-9e0a727f1727";;"OFWeiche :56";"X:11533.16 Y:17258.29";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-67.5,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
39;"Omniflo Weiche";"shape_63066836-bb31-2a67-1c81-37c92095b7ae";;"OFWeiche :56";"X:11766.13 Y:20997.45";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-67.5,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
||||||
40;"Omniflo Weiche";"shape_af898037-336c-9986-1e58-58de76ac9d76";;"OFWeiche :57";"X:11886.93 Y:17223.19";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-90.0,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
40;"Omniflo Weiche";"shape_576b313c-3d93-965b-4ece-a845af325d7b";;"OFWeiche :57";"X:12119.89 Y:20962.34";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-90.0,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
||||||
41;"Omniflo Weiche";"shape_247bcf6a-42f9-3399-b905-d02c22b8dff3";;"OFWeiche :58";"X:12200.33 Y:17055.37";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-112.5,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
41;"Omniflo Weiche";"shape_7300ff5e-43a5-2cb3-3aa8-74c4b9fb3253";;"OFWeiche :58";"X:12433.29 Y:20794.53";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-112.5,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
||||||
42;"Omniflo Weiche";"shape_80bb2e1a-beac-bb76-8550-32400a0f8bde";;"OFWeiche :59";"X:12425.67 Y:16780.39";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-135.0,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
42;"Omniflo Weiche";"shape_493f4700-ec32-6dc2-da18-1d28dbaede7c";;"OFWeiche :59";"X:12658.62 Y:20519.54";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-135.0,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
||||||
43;"Omniflo Weiche";"shape_1a33b82d-385e-87ff-a8dc-aa4c497b680f";;"OFWeiche :60";"X:12528.62 Y:16440.13";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-157.5,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
43;"Omniflo Weiche";"shape_853a95e2-2d47-4678-904e-15acfdff35be";;"OFWeiche :60";"X:12761.57 Y:20179.28";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-157.5,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
||||||
44;"Omniflo Weiche";"shape_76bf365f-0837-14e1-ff51-bc9724f8ecb0";;"OFWeiche :61";"X:12493.5 Y:16086.36";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-180.0,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
44;"Omniflo Weiche";"shape_97c9b74c-e6a9-94bb-ab13-90e5b8fe240c";;"OFWeiche :61";"X:12726.46 Y:19825.51";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-180.0,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
||||||
45;"Omniflo Weiche";"shape_fc3e9554-56c0-e51e-3e0d-e9d994c15c72";;"OFWeiche :62";"X:12325.69 Y:15772.96";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-202.5,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
45;"Omniflo Weiche";"shape_deda337a-179c-b16c-a80b-3cfd5a53e8d4";;"OFWeiche :62";"X:12558.65 Y:19512.12";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-202.5,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
||||||
46;"Omniflo Weiche";"shape_63642dd0-a688-5709-2311-519f6e7f6ed1";;"OFWeiche :63";"X:12050.71 Y:15547.63";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-225.0,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
46;"Omniflo Weiche";"shape_bdfc688d-aea9-6b26-8065-109f450df824";;"OFWeiche :63";"X:12283.67 Y:19286.78";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-225.0,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
||||||
47;"Omniflo Weiche";"shape_e8be0ce0-321d-8733-ab85-2807eb2767d3";;"OFWeiche :64";"X:11710.44 Y:15444.68";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-247.5,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
47;"Omniflo Weiche";"shape_73e9d1d1-0ef4-ea4f-6fc9-2f4a7f8cdd69";;"OFWeiche :64";"X:11943.4 Y:19183.83";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-247.5,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
||||||
48;"Omniflo Weiche";"shape_cacd4b95-1823-2281-50be-63587b85426f";;"OFWeiche :65";"X:11356.68 Y:15479.79";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-270.0,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
48;"Omniflo Weiche";"shape_76928ec7-08b1-c086-c3a5-52a15ac2e4df";;"OFWeiche :65";"X:11589.64 Y:19218.95";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-270.0,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
||||||
49;"Omniflo Weiche";"shape_13d5f9cb-2405-02b7-ffe8-2ff787d855b0";;"OFWeiche :66";"X:11043.28 Y:15647.6";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-292.5,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
49;"Omniflo Weiche";"shape_7b218610-e98a-ef08-fb32-c817bf29988b";;"OFWeiche :66";"X:11276.24 Y:19386.76";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-292.5,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
||||||
50;"Omniflo Weiche";"shape_3a07e029-9233-277d-7a1c-2c06d2d8ab9c";;"OFWeiche :67";"X:10817.95 Y:15922.58";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-315.0,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
50;"Omniflo Weiche";"shape_5095147a-d039-c5a7-9fb5-15c60275e5b9";;"OFWeiche :67";"X:11050.91 Y:19661.74";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-315.0,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
||||||
51;"Omniflo Weiche";"shape_dcacbab1-2a2b-1c8c-2305-c439c5211f6c";;"OFWeiche :68";"X:10715 Y:16262.86";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-337.5,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
51;"Omniflo Weiche";"shape_6b3300bb-09d5-7c61-7934-7a60b32ab146";;"OFWeiche :68";"X:10947.96 Y:20002.01";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-337.5,"Antrieb Kurve":false,"SivasNummer":"834342002"}
|
||||||
52;"Omniflo Weiche";"shape_b5f9e1d6-ec82-58f7-df38-543c23300aa6";;"OFWeiche :3";"X:9733.32 Y:20197.59";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
52;"Omniflo Weiche";"shape_c2bea835-6174-d0c3-6246-0096706bb081";;"OFWeiche :2";"X:5669.64 Y:25566.62";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
||||||
53;"Omniflo Weiche";"shape_6bdc6141-69cc-29ca-233c-74dacbfafa6d";;"OFWeiche :37";"X:9397.83 Y:17436.71";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-315.0,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
53;"Omniflo Weiche";"shape_244e39c0-0f2e-c08b-968c-436612d7390c";;"OFWeiche :21";"X:5372.34 Y:20691.85";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
||||||
54;"Omniflo Weiche";"shape_3a03e7ce-dc23-8040-9233-8bbc9bfe2d4b";;"OFWeiche :38";"X:9057.56 Y:17539.66";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-292.5,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
54;"Omniflo Weiche";"shape_17d96b64-d9c7-14f1-86d8-f32ea52c72c3";;"OFWeiche :22";"X:5540.15 Y:21005.25";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-22.5,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
||||||
55;"Omniflo Weiche";"shape_9b299674-8a04-f186-4e7a-7374cc793877";;"OFWeiche :39";"X:9840.62 Y:16897.98";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
55;"Omniflo Weiche";"shape_db5e1581-1cb3-70ad-a648-2c5f02058c7b";;"OFWeiche :23";"X:5815.13 Y:21230.58";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-45.0,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
||||||
56;"Omniflo Weiche";"shape_6f6f6895-f27c-2a62-e395-9c78737d25a4";;"OFWeiche :40";"X:9672.8 Y:17211.39";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-337.5,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
56;"Omniflo Weiche";"shape_172f58d9-a614-6de7-e8e8-f0591d9e73f4";;"OFWeiche :24";"X:6155.4 Y:21333.53";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-67.5,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
||||||
57;"Omniflo Weiche";"shape_47dc4ae0-d662-247d-c3cf-100f6db40c6c";;"OFWeiche :41";"X:8165.06 Y:17061.76";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-225.0,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
57;"Omniflo Weiche";"shape_344aaffa-6909-2f8e-535f-0b895456eb8e";;"OFWeiche :25";"X:6509.16 Y:21298.42";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-90.0,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
||||||
58;"Omniflo Weiche";"shape_39206f42-bd37-22d8-4447-04e807e2f1f2";;"OFWeiche :42";"X:8062.12 Y:16721.5";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-202.5,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
58;"Omniflo Weiche";"shape_12484e71-d465-1909-0f20-a069ea8b7bf1";;"OFWeiche :26";"X:6822.57 Y:21130.61";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-112.5,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
||||||
59;"Omniflo Weiche";"shape_11572cf2-bdfa-cec6-5c56-9e8605d8af9c";;"OFWeiche :43";"X:8703.79 Y:17504.56";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-270.0,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
59;"Omniflo Weiche";"shape_5bc9cf29-7017-dae1-4aa1-6a315dfab1a7";;"OFWeiche :27";"X:7047.89 Y:20855.62";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-135.0,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
||||||
60;"Omniflo Weiche";"shape_359b95f3-7f89-b46f-fa71-787aa33f0e3a";;"OFWeiche :44";"X:8390.39 Y:17336.75";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-247.5,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
60;"Omniflo Weiche";"shape_1fef2a0b-0219-3152-c896-0ee89435d305";;"OFWeiche :28";"X:7150.85 Y:20515.36";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-157.5,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
||||||
61;"Omniflo Weiche";"shape_2240036f-3c1b-964c-1b40-22e3652547db";;"OFWeiche :45";"X:8540.03 Y:15829";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-135.0,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
61;"Omniflo Weiche";"shape_376ade13-eb6b-1a0a-100f-f377b9bf1287";;"OFWeiche :29";"X:7115.74 Y:20161.6";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-180.0,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
||||||
62;"Omniflo Weiche";"shape_3ea7a8a1-ba61-807d-3315-9f9641be145a";;"OFWeiche :46";"X:8880.3 Y:15726.05";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-112.5,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
62;"Omniflo Weiche";"shape_85c25caa-b5a5-7c1a-9e14-6199c3541d04";;"OFWeiche :30";"X:6947.93 Y:19848.2";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-202.5,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
||||||
63;"Omniflo Weiche";"shape_3501691e-1994-b951-ab1a-f3076dc78855";;"OFWeiche :47";"X:8097.23 Y:16367.73";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-180.0,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
63;"Omniflo Weiche";"shape_64c8ca46-4d4e-9cf8-df9c-3dea60be12c5";;"OFWeiche :31";"X:6672.95 Y:19622.86";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-225.0,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
||||||
64;"Omniflo Weiche";"shape_735e598d-5ead-894f-0347-c20c1cdf0fd3";;"OFWeiche :48";"X:8265.05 Y:16054.33";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-157.5,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
64;"Omniflo Weiche";"shape_58c38947-efe7-db1b-d1d9-2eda14480410";;"OFWeiche :32";"X:6332.68 Y:19519.92";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-247.5,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
||||||
65;"Omniflo Weiche";"shape_b547b91e-9eb3-0067-b874-ac0bed6373cd";;"OFWeiche :49";"X:9772.79 Y:16203.95";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-45.0,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
65;"Omniflo Weiche";"shape_b9a22166-28d2-0240-60e0-2133e22ed61f";;"OFWeiche :33";"X:5978.92 Y:19555.03";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-270.0,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
||||||
66;"Omniflo Weiche";"shape_8fe43748-94cb-8b2d-6fc7-19c1e850b324";;"OFWeiche :50";"X:9875.74 Y:16544.22";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-22.5,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
66;"Omniflo Weiche";"shape_ea4a1758-1579-cd29-f0ac-c529c7bc3c36";;"OFWeiche :34";"X:5665.52 Y:19722.84";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-292.5,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
||||||
67;"Omniflo Weiche";"shape_647a333a-4725-149d-1877-934ce43f35b3";;"OFWeiche :51";"X:9234.06 Y:15761.16";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-90.0,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
67;"Omniflo Weiche";"shape_ff8f5cf3-a77f-efc7-7c25-5ba17354864f";;"OFWeiche :35";"X:5440.19 Y:19997.82";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-315.0,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
||||||
68;"Omniflo Weiche";"shape_783f151b-e363-45ae-ee5d-85a7b77dae86";;"OFWeiche :52";"X:9547.46 Y:15928.97";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-67.5,"Antrieb Kurve":false,"SivasNummer":"834342012"}
|
68;"Omniflo Weiche";"shape_9fba3e21-9afa-3a31-4c72-f4ec3d83b74a";;"OFWeiche :36";"X:5337.24 Y:20338.1";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Einzelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-337.5,"Antrieb Kurve":false,"SivasNummer":"834342001"}
|
||||||
69;"Omniflo Gerade";"shape_e15a9ee3-d18a-82cb-1c7c-83cc7673151f";;"OFGerade :2";"X:3471.2 Y:21693.33";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-180.0,"SivasNummer":"821106002"}
|
69;"Omniflo Gerade";"shape_0390732f-452a-7fe8-2456-2a38898e458f";;"OFGerade :2";"X:3478.08 Y:26601.99";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-337.5,"SivasNummer":"821106002"}
|
||||||
70;"Omniflo Gerade";"shape_f0812e4f-c0db-4dc2-04f0-6763ce79043f";;"OFGerade :4";"X:5293.06 Y:21713.89";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-202.5,"SivasNummer":"821106002"}
|
70;"Omniflo Gerade";"shape_c9813720-d1ad-e7a0-2392-4d6c85120306";;"OFGerade :4";"X:5635.95 Y:24386.62";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":0.0,"SivasNummer":"821106002"}
|
||||||
71;"Omniflo Gerade";"shape_9febb504-a812-b945-c2f2-accdf67e38b6";;"OFGerade :3";"X:3471.2 Y:19333.33";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":0.0,"SivasNummer":"821106002"}
|
71;"Omniflo Gerade";"shape_8408812e-a914-b15a-ec28-516fa0f6d8da";;"OFGerade :5";"X:6120.13 Y:26650.5";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-22.5,"SivasNummer":"821106002"}
|
||||||
72;"Omniflo Gerade";"shape_6543d35f-9494-4a26-7cb4-00558d776cd0";;"OFGerade :6";"X:4808.87 Y:19450.01";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":0.0,"SivasNummer":"821106002"}
|
72;"Omniflo Gerade";"shape_d015912b-6243-fa63-1db0-a3a21a17dc67";;"OFGerade :3";"X:3962.26 Y:26698.11";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-180.0,"SivasNummer":"821106002"}
|
||||||
73;"Omniflo Gerade";"shape_85e377fa-67fc-1ebf-6407-62681289c348";;"OFGerade :7";"X:9282.84 Y:21281.47";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-157.5,"SivasNummer":"821106002"}
|
73;"Omniflo Gerade";"shape_768dca95-2c3b-88b6-d5ee-93cbe27a3254";;"OFGerade :6";"X:5635.95 Y:26746.62";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-180.0,"SivasNummer":"821106002"}
|
||||||
74;"Omniflo Gerade";"shape_4947a12e-d9b5-c6c5-b138-258cc3916e3f";;"OFGerade :9";"X:9767.02 Y:21377.59";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-180.0,"SivasNummer":"821106002"}
|
74;"Omniflo Gerade";"shape_0a652d48-0f3a-d4b2-a49f-4b410faacd59";;"OFGerade :7";"X:9420 Y:24454.03";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":0.0,"SivasNummer":"821106002"}
|
||||||
75;"Omniflo Gerade";"shape_a97214ae-a19e-16dc-d8fc-ea80ae19144d";;"OFGerade :5";"X:4808.87 Y:21810.01";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-180.0,"SivasNummer":"821106002"}
|
75;"Omniflo Gerade";"shape_e56e363d-d451-8e3e-fa25-9f32a06f9182";;"OFGerade :9";"X:9420 Y:26814.03";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-180.0,"SivasNummer":"821106002"}
|
||||||
76;"Omniflo Gerade";"shape_39ad72bc-c463-c6b4-0257-ed6c273439b1";;"OFGerade :11";"X:10967.66 Y:21193.22";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-180.0,"SivasNummer":"821106002"}
|
76;"Omniflo Gerade";"shape_207cd422-fbe4-1dc7-6592-40b3dff17700";;"OFGerade :8";"X:8935.81 Y:26717.91";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-337.5,"SivasNummer":"821106002"}
|
||||||
77;"Omniflo Gerade";"shape_a0957a75-33fa-039c-9cc2-84f52c6ed573";;"OFGerade :8";"X:9767.02 Y:19017.59";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":0.0,"SivasNummer":"821106002"}
|
77;"Omniflo Gerade";"shape_b0467877-85d8-37d8-be13-1c09708bdf49";;"OFGerade :10";"X:11032.08 Y:24464.75";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":0.0,"SivasNummer":"821106002"}
|
||||||
78;"Omniflo Gerade";"shape_dcc568a8-8282-fa20-1508-f802a848608b";;"OFGerade :10";"X:11451.84 Y:21097.1";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-202.5,"SivasNummer":"821106002"}
|
78;"Omniflo Gerade";"shape_db25308a-2ab1-a616-ffa6-5f7bfb14a7e8";;"OFGerade :12";"X:11032.09 Y:26824.75";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-180.0,"SivasNummer":"821106002"}
|
||||||
79;"Omniflo Weiche";"shape_2bb8e674-6c3a-e151-705d-3bf302336766";;"OFWeiche :69";"X:4062.5 Y:13013.33";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
79;"Omniflo Weiche";"shape_d978be2e-b4d1-b666-2a89-4f262878caad";;"OFWeiche :70";"X:8976.91 Y:14076.17";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
||||||
80;"Omniflo Weiche";"shape_041da0cf-8d6a-6135-6510-17600d97ba98";;"OFWeiche :71";"X:3259.37 Y:9633.58";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
80;"Omniflo Weiche";"shape_f3db1d4a-f915-f6d5-e23f-b26f3045a8a3";;"OFWeiche :87";"X:8936.89 Y:9956.45";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
||||||
81;"Omniflo Weiche";"shape_223d2db7-ee46-ada9-fac7-b71c26c51522";;"OFWeiche :72";"X:3427.47 Y:9948.38";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-22.5,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
81;"Omniflo Weiche";"shape_58a80dd5-4032-a696-66c1-c3c783fd4557";;"OFWeiche :88";"X:9104.99 Y:10283.23";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-22.5,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
||||||
82;"Omniflo Weiche";"shape_f181294b-a019-5568-8913-a2109d542904";;"OFWeiche :73";"X:3703.25 Y:10174.89";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-45.0,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
82;"Omniflo Weiche";"shape_ddaf90f0-cd0c-8b21-70ac-0b41f794022b";;"OFWeiche :89";"X:9385.34 Y:10520.78";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-45.0,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
||||||
83;"Omniflo Weiche";"shape_3ff6b943-0035-6acb-a172-65b1f737799a";;"OFWeiche :74";"X:4044.72 Y:10278.63";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-67.5,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
83;"Omniflo Weiche";"shape_110a18a6-6f7c-9ec9-62bd-e3953f5f6be5";;"OFWeiche :90";"X:9735.25 Y:10632.97";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-67.5,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
||||||
84;"Omniflo Weiche";"shape_3470fe79-dd44-a35d-56aa-81665a607de9";;"OFWeiche :75";"X:4399.88 Y:10243.79";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-90.0,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
84;"Omniflo Weiche";"shape_1d65180a-4876-c5a2-727d-0540eb277d37";;"OFWeiche :91";"X:10101.46 Y:10602.75";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-90.0,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
||||||
85;"Omniflo Weiche";"shape_cf530110-bef9-505e-5883-59e28cf4c6d3";;"OFWeiche :76";"X:4714.68 Y:10075.69";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-112.5,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
85;"Omniflo Weiche";"shape_41674a89-4242-b0f4-e151-e70ca3ddf437";;"OFWeiche :92";"X:10428.2 Y:10434.61";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-112.5,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
||||||
86;"Omniflo Weiche";"shape_b1d9d70a-7a39-470b-24ac-07964df31cbf";;"OFWeiche :77";"X:4941.19 Y:9799.87";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-135.0,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
86;"Omniflo Weiche";"shape_6ccaf0ce-c3a1-2960-a586-77b8e69a82ba";;"OFWeiche :93";"X:10665.76 Y:10154.29";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-135.0,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
||||||
87;"Omniflo Weiche";"shape_08895cb0-ce26-ec52-0985-648709fdc694";;"OFWeiche :78";"X:5044.92 Y:9458.43";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-157.5,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
87;"Omniflo Weiche";"shape_b5b3f052-60c7-941c-f222-64ded798378a";;"OFWeiche :94";"X:10777.94 Y:9804.37";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-157.5,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
||||||
88;"Omniflo Weiche";"shape_37a6a791-9a10-bd8a-8e40-a5f040b46833";;"OFWeiche :79";"X:5010.08 Y:9103.26";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-180.0,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
88;"Omniflo Weiche";"shape_9033812d-2cba-ca47-28b5-861bbd5892f1";;"OFWeiche :95";"X:10747.69 Y:9438.13";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-180.0,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
||||||
89;"Omniflo Weiche";"shape_db0aa45b-4b38-5d5d-252f-dade9af29e6d";;"OFWeiche :80";"X:4841.98 Y:8788.4";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-202.5,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
89;"Omniflo Weiche";"shape_e9045f58-16f8-02fc-2564-d709eb0115bd";;"OFWeiche :96";"X:10579.58 Y:9111.37";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-202.5,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
||||||
90;"Omniflo Weiche";"shape_72ddf224-2ed6-4f93-6f24-92b141b4c211";;"OFWeiche :81";"X:4566.2 Y:8561.92";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-225.0,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
90;"Omniflo Weiche";"shape_5899b317-e5fa-0b92-56f3-ad386c6ae3ba";;"OFWeiche :97";"X:10299.24 Y:8873.78";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-225.0,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
||||||
91;"Omniflo Weiche";"shape_5fdd1642-ab15-5331-ecd1-a75e5db56281";;"OFWeiche :82";"X:4224.75 Y:8458.2";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-247.5,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
91;"Omniflo Weiche";"shape_6de0d681-54f1-3d93-1f47-fc500ce615c5";;"OFWeiche :98";"X:9949.33 Y:8761.59";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-247.5,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
||||||
92;"Omniflo Weiche";"shape_c39d9426-56c4-7b65-2653-4769e023f0cc";;"OFWeiche :83";"X:3869.58 Y:8493";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-270.0,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
92;"Omniflo Weiche";"shape_e032685f-bed8-e7a6-2e71-f0543d16b681";;"OFWeiche :99";"X:9583.12 Y:8791.89";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-270.0,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
||||||
93;"Omniflo Weiche";"shape_11cc4e7f-f71c-a2a8-10a2-fe81289efa9e";;"OFWeiche :84";"X:3554.78 Y:8661.14";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-292.5,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
93;"Omniflo Weiche";"shape_2bb19ced-a1b9-566e-92e2-0313f86bc6b1";;"OFWeiche :100";"X:9256.38 Y:8960.03";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-292.5,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
||||||
94;"Omniflo Weiche";"shape_053f58a2-b45a-8dfd-e9f4-2e7e85c0d5d7";;"OFWeiche :85";"X:3328.27 Y:8936.97";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-315.0,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
94;"Omniflo Weiche";"shape_1c3b4a6a-43bc-e775-9137-0d15c8df7b88";;"OFWeiche :101";"X:9018.82 Y:9240.36";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-315.0,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
||||||
95;"Omniflo Weiche";"shape_bd2946c0-6ea0-fe80-a7e1-935b9903e6fe";;"OFWeiche :86";"X:3224.54 Y:9278.41";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-337.5,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
95;"Omniflo Weiche";"shape_e7622454-4ad8-2b60-89fa-1169d69ee9ff";;"OFWeiche :102";"X:8906.64 Y:9590.27";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-337.5,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
||||||
96;"Omniflo Gerade";"shape_b9ca0ac6-31bd-fd64-64c9-17565cd003db";;"OFGerade :12";"X:10967.66 Y:18833.22";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":0.0,"SivasNummer":"821106002"}
|
96;"Omniflo Weiche";"shape_92eff04c-78ae-b2c7-bf6a-aa49252bdf00";;"OFWeiche :69";"X:4285.69 Y:14089.53";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
||||||
97;"Omniflo Weiche";"shape_4d230566-6551-8300-484a-5d967872be13";;"OFWeiche :70";"X:6620.95 Y:12901.79";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
97;"Omniflo Weiche";"shape_116a62a7-dbe6-67f1-d822-3ed061d21b2b";;"OFWeiche :71";"X:4120.94 Y:10094.08";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
||||||
98;"Omniflo Weiche";"shape_174f1f2f-adbb-b033-97cd-9369cf3febb8";;"OFWeiche :87";"X:6559.22 Y:9659.4";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
98;"Omniflo Weiche";"shape_bb22417f-52fe-4335-c32b-755156444634";;"OFWeiche :72";"X:4289.04 Y:10420.84";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-22.5,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
||||||
99;"Omniflo Weiche";"shape_b3afef71-ff30-42ea-c61a-d9bd679979d6";;"OFWeiche :88";"X:6727.32 Y:9974.18";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-22.5,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
99;"Omniflo Weiche";"shape_28c9930d-9ad9-61a7-6053-af1cf8f7ea09";;"OFWeiche :73";"X:4569.38 Y:10658.43";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-45.0,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
||||||
100;"Omniflo Weiche";"shape_19c2db56-5250-5c3c-e7a6-dd1cce35ea5b";;"OFWeiche :89";"X:7003.09 Y:10200.69";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-45.0,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
100;"Omniflo Weiche";"shape_66cb58c6-7cd0-401f-238f-50649487858f";;"OFWeiche :74";"X:4919.29 Y:10770.62";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-67.5,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
||||||
101;"Omniflo Weiche";"shape_1af9ff99-b7eb-a0c0-a3e0-9936cdbb3be3";;"OFWeiche :90";"X:7344.55 Y:10304.42";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-67.5,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
101;"Omniflo Weiche";"shape_374f8fd7-4135-219a-c11e-f051048ac70b";;"OFWeiche :75";"X:5285.5 Y:10740.32";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-90.0,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
||||||
102;"Omniflo Weiche";"shape_1a295c40-7a81-8304-ccbd-3ece740aee78";;"OFWeiche :91";"X:7699.72 Y:10269.59";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-90.0,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
102;"Omniflo Weiche";"shape_d61ddd1c-bef7-f4f1-c34d-18b7b935d0ac";;"OFWeiche :76";"X:5612.25 Y:10572.18";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-112.5,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
||||||
103;"Omniflo Weiche";"shape_e4a46e39-577a-5845-b979-938320c1ffc2";;"OFWeiche :92";"X:8014.52 Y:10101.48";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-112.5,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
103;"Omniflo Weiche";"shape_aada6a91-14ec-6e46-2ae8-ada04c0090d9";;"OFWeiche :77";"X:5849.81 Y:10291.85";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-135.0,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
||||||
104;"Omniflo Weiche";"shape_ac35c116-8540-674a-cac9-267bbd770cc9";;"OFWeiche :93";"X:8241.03 Y:9825.67";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-135.0,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
104;"Omniflo Weiche";"shape_c18829f4-d44b-5c3e-a9a9-90bda78740e7";;"OFWeiche :78";"X:5961.99 Y:9941.94";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-157.5,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
||||||
105;"Omniflo Weiche";"shape_87099f46-591e-d319-520f-a0980f88f5cc";;"OFWeiche :94";"X:8344.76 Y:9484.22";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-157.5,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
105;"Omniflo Weiche";"shape_ee94d807-c63e-a6a4-3b0e-d90896c0ef77";;"OFWeiche :79";"X:5931.74 Y:9575.76";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-180.0,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
||||||
106;"Omniflo Weiche";"shape_c53d6df4-a77a-8459-83dd-25114f50775d";;"OFWeiche :95";"X:8309.93 Y:9129.06";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-180.0,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
106;"Omniflo Weiche";"shape_85887d52-5af0-1e70-101f-541ade7b31c4";;"OFWeiche :80";"X:5763.63 Y:9249";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-202.5,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
||||||
107;"Omniflo Weiche";"shape_d9fb25d0-79d4-0e2b-443f-394caf2770b2";;"OFWeiche :96";"X:8141.83 Y:8814.22";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-202.5,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
107;"Omniflo Weiche";"shape_9d834cc5-421e-8f21-6ac5-8f5d9167dab8";;"OFWeiche :81";"X:5483.29 Y:9011.4";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-225.0,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
||||||
108;"Omniflo Weiche";"shape_c3f2dbb3-37bc-b8c9-c8d0-dd7502710824";;"OFWeiche :97";"X:7866.05 Y:8587.73";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-225.0,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
108;"Omniflo Weiche";"shape_85b1c977-aa45-d562-7912-245ababf808c";;"OFWeiche :82";"X:5133.38 Y:8899.22";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-247.5,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
||||||
109;"Omniflo Weiche";"shape_0d28b368-c7a6-61b6-e1a7-46786b3953a1";;"OFWeiche :98";"X:7524.6 Y:8484.02";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-247.5,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
109;"Omniflo Weiche";"shape_aaf28fe8-497d-ca6c-0e7a-58c97bdc3ba2";;"OFWeiche :83";"X:4767.17 Y:8929.51";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-270.0,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
||||||
110;"Omniflo Weiche";"shape_676d9674-b761-f4cb-7fe1-37c2d92bda3b";;"OFWeiche :99";"X:7169.43 Y:8518.81";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-270.0,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
110;"Omniflo Weiche";"shape_b481d2fc-6d94-4bdd-3666-a292e864878c";;"OFWeiche :84";"X:4440.42 Y:9097.66";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-292.5,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
||||||
111;"Omniflo Weiche";"shape_1592f4d7-9ba5-800d-123b-f4942fdce17c";;"OFWeiche :100";"X:6854.63 Y:8686.95";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-292.5,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
111;"Omniflo Weiche";"shape_0c5ca6e2-6995-7730-4513-3bb2a673f590";;"OFWeiche :85";"X:4202.87 Y:9377.98";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-315.0,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
||||||
112;"Omniflo Weiche";"shape_4ec87ee5-a085-4f4a-a0bd-9d2d68d6ddd6";;"OFWeiche :101";"X:6628.12 Y:8962.78";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-315.0,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
112;"Omniflo Weiche";"shape_00a867fc-f5e3-528f-5b5e-8d84ae04462b";;"OFWeiche :86";"X:4090.69 Y:9727.89";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-337.5,"Antrieb Kurve":false,"SivasNummer":"834342100"}
|
||||||
113;"Omniflo Weiche";"shape_165b661e-abfc-ccc0-69c9-b47490175774";;"OFWeiche :102";"X:6524.39 Y:9304.23";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Doppelweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-337.5,"Antrieb Kurve":false,"SivasNummer":"834342101"}
|
113;"Omniflo Gerade";"shape_57344488-bf95-695f-cf55-007ed7116d54";;"OFGerade :11";"X:11516.27 Y:26728.63";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-22.5,"SivasNummer":"821106002"}
|
||||||
114;"Omniflo Gerade";"shape_a40d0370-30cc-d614-22cf-47eac751f50f";;"OFGerade :14";"X:3578.32 Y:14091.23";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-337.5,"SivasNummer":"821106002"}
|
114;"Omniflo Gerade";"shape_91aa3827-a26f-59d9-8f90-1391635d635a";;"OFGerade :15";"X:3801.51 Y:15179.38";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-157.5,"SivasNummer":"821106002"}
|
||||||
115;"Omniflo Gerade";"shape_fcda7b25-3893-fcf6-8a34-7df969801ef7";;"OFGerade :13";"X:4546.69 Y:14091.23";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-22.5,"SivasNummer":"821106002"}
|
115;"Omniflo Gerade";"shape_e5ca5ce3-ad67-940e-a3c9-5f9f06ef02a8";;"OFGerade :13";"X:4285.69 Y:12915.51";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":0.0,"SivasNummer":"821106002"}
|
||||||
116;"Omniflo Gerade";"shape_b5a80eb7-fd23-c393-5734-608fbcbe2cdf";;"OFGerade :15";"X:4062.5 Y:11839.3";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":0.0,"SivasNummer":"821106002"}
|
116;"Omniflo Gerade";"shape_7724af93-f739-9009-3de0-f493f705608e";;"OFGerade :14";"X:4769.88 Y:15179.38";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-22.5,"SivasNummer":"821106002"}
|
||||||
117;"Omniflo Gerade";"shape_b00aa523-ec5a-5d56-3687-423d792566ae";;"OFGerade :16";"X:7105.13 Y:13979.7";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-22.5,"SivasNummer":"821106002"}
|
117;"Omniflo Gerade";"shape_6561cab9-1005-a5b1-c409-8c5959eff47a";;"OFGerade :17";"X:8492.73 Y:15166.02";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-157.5,"SivasNummer":"821106002"}
|
||||||
118;"Omniflo Gerade";"shape_723b8795-a978-6e10-5bc1-8dcced33311f";;"OFGerade :18";"X:6620.95 Y:11727.77";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":0.0,"SivasNummer":"821106002"}
|
118;"Omniflo Gerade";"shape_49ece4f4-a0ab-b831-96ba-109c70a66bc2";;"OFGerade :18";"X:9461.1 Y:15166.02";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-22.5,"SivasNummer":"821106002"}
|
||||||
119;"Omniflo Gerade";"shape_ffa39de9-9974-68d7-2de8-dd93ac6f5a6e";;"OFGerade :17";"X:6136.76 Y:13979.7";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-337.5,"SivasNummer":"821106002"}
|
119;"Omniflo Gerade";"shape_ee2e6acc-6cd0-cdc2-5586-69d29e7d9647";;"OFGerade :16";"X:8976.91 Y:12902.14";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":0.0,"SivasNummer":"821106002"}
|
||||||
120;"Omniflo Weiche";"shape_4344e827-9d08-15f7-2c02-ca4dfd8038ac";;"OFWeiche :104";"X:7172.7 Y:5434.56";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
120;"Omniflo Weiche";"shape_781c209e-8b7e-e5ec-77dc-d84a5b60ad7b";;"OFWeiche :104";"X:9370.95 Y:5088.12";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
||||||
121;"Omniflo Weiche";"shape_4b863468-09aa-5f6f-1606-cd1f86bb83fd";;"OFWeiche :121";"X:8462.7 Y:1203.19";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
121;"Omniflo Weiche";"shape_913b1db5-dbeb-2ac3-630d-6682a1a76e51";;"OFWeiche :121";"X:9267.53 Y:1363.66";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
||||||
122;"Omniflo Weiche";"shape_810db42d-d195-4163-ec4e-d011a35d71bf";;"OFWeiche :122";"X:8292.31 Y:1529.44";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-337.5,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
122;"Omniflo Weiche";"shape_7295a06c-ecf3-1628-a0c1-63800467259f";;"OFWeiche :122";"X:9097.15 Y:1689.89";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-337.5,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
||||||
123;"Omniflo Weiche";"shape_71a110cc-efef-45e1-4c54-122d40278b60";;"OFWeiche :123";"X:8010.04 Y:1765.76";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-315.0,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
123;"Omniflo Weiche";"shape_820f03af-681c-fe0d-fa81-9b07d70868fe";;"OFWeiche :123";"X:8814.87 Y:1926.16";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-315.0,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
||||||
124;"Omniflo Weiche";"shape_33d4c2f8-cf49-8bb8-ae5a-9790b77261f0";;"OFWeiche :124";"X:7658.83 Y:1875.96";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-292.5,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
124;"Omniflo Weiche";"shape_23c956a1-b1fa-fb7c-56ee-2e06dad73c25";;"OFWeiche :124";"X:8463.66 Y:2036.36";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-292.5,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
||||||
125;"Omniflo Weiche";"shape_c46dd27d-3645-0f6c-604c-5c7d106498ce";;"OFWeiche :125";"X:7292.16 Y:1843.43";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-270.0,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
125;"Omniflo Weiche";"shape_18fa149d-4042-3f38-03f0-45c220474ef7";;"OFWeiche :125";"X:8097 Y:2003.82";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-270.0,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
||||||
126;"Omniflo Weiche";"shape_8ba2d344-68b1-3900-b7f1-c1be5652e801";;"OFWeiche :126";"X:6965.87 Y:1673.04";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-247.5,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
126;"Omniflo Weiche";"shape_8c598517-d272-d675-1b85-53feda99712e";;"OFWeiche :126";"X:7770.7 Y:1833.43";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-247.5,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
||||||
127;"Omniflo Weiche";"shape_62dbb0d4-3dcd-1bde-1a19-3f4e99a7a356";;"OFWeiche :127";"X:6729.61 Y:1390.73";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-225.0,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
127;"Omniflo Weiche";"shape_28f30b76-2f04-ef3c-a156-6c88dab9dcca";;"OFWeiche :127";"X:7534.44 Y:1551.12";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-225.0,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
||||||
128;"Omniflo Weiche";"shape_a4c7811f-4930-4867-57e3-82abcfc8541d";;"OFWeiche :128";"X:6619.35 Y:1039.49";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-202.5,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
128;"Omniflo Weiche";"shape_184058af-e1c1-ebfc-78ca-327525010958";;"OFWeiche :128";"X:7424.19 Y:1199.88";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-202.5,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
||||||
129;"Omniflo Weiche";"shape_8d38188c-9831-bee4-9487-d155c106d54a";;"OFWeiche :129";"X:6651.9 Y:672.83";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-180.0,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
129;"Omniflo Weiche";"shape_47c7907b-8226-8492-eb60-b52c3a7e2bfa";;"OFWeiche :129";"X:7456.74 Y:833.17";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-180.0,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
||||||
130;"Omniflo Weiche";"shape_0bd18242-96e1-723d-46cc-2c23a47b6140";;"OFWeiche :130";"X:6822.28 Y:346.47";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-157.5,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
130;"Omniflo Weiche";"shape_efa0072d-2799-a460-7116-71fcdb5b654b";;"OFWeiche :130";"X:7627.11 Y:506.94";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-157.5,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
||||||
131;"Omniflo Weiche";"shape_826ae9a2-0dfb-a646-fa74-a1933ebc99c0";;"OFWeiche :131";"X:7104.57 Y:110.19";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-135.0,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
131;"Omniflo Weiche";"shape_104be4d1-995a-b894-acc4-ebcbde86c53e";;"OFWeiche :131";"X:7909.4 Y:270.67";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-135.0,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
||||||
132;"Omniflo Weiche";"shape_56be85a5-dc95-6cd6-3753-42c70bad3008";;"OFWeiche :132";"X:7455.77 Y:0";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-112.5,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
132;"Omniflo Weiche";"shape_164b6d34-2c7d-7648-f051-09b61d1715b2";;"OFWeiche :132";"X:8260.61 Y:160.47";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-112.5,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
||||||
133;"Omniflo Weiche";"shape_be174689-5cc1-4dae-2799-bc31b8126476";;"OFWeiche :133";"X:7822.43 Y:32.54";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-90.0,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
133;"Omniflo Weiche";"shape_f3e05b51-9b4c-5abe-2042-8af24b658b44";;"OFWeiche :133";"X:8627.27 Y:193.01";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-90.0,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
||||||
134;"Omniflo Weiche";"shape_ca5cc998-c43e-8716-54f0-e955f3f4b7f5";;"OFWeiche :134";"X:8148.73 Y:202.93";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-67.5,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
134;"Omniflo Weiche";"shape_2850ef7e-1070-846e-0f94-5b0fd653ccbc";;"OFWeiche :134";"X:8953.56 Y:363.4";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-67.5,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
||||||
135;"Omniflo Weiche";"shape_eaebcfbb-d751-3c4c-b8fd-519fb211bd75";;"OFWeiche :135";"X:8384.99 Y:485.24";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-45.0,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
135;"Omniflo Weiche";"shape_9582eeae-0df5-55d3-2b62-f295002f7972";;"OFWeiche :135";"X:9189.82 Y:645.71";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-45.0,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
||||||
136;"Omniflo Weiche";"shape_7a84a28f-169d-ad90-3140-fd37cdd36243";;"OFWeiche :136";"X:8495.24 Y:836.48";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-22.5,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
136;"Omniflo Weiche";"shape_f0b0220c-62ca-9304-0494-56f3ea5ea72e";;"OFWeiche :136";"X:9300.07 Y:996.95";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-22.5,"Antrieb Kurve":false,"SivasNummer":"834342201"}
|
||||||
137;"Omniflo Gerade";"shape_4252db0f-3348-279d-aabb-93cde93c59df";;"OFGerade :19";"X:5266 Y:6640.47";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-202.5,"SivasNummer":"821106002"}
|
137;"Omniflo Weiche";"shape_b0427595-b41b-6d6e-4ef1-26b465fa4ba0";;"OFWeiche :103";"X:3949.86 Y:5269.36";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
||||||
138;"Omniflo Weiche";"shape_ce3c4c74-c20d-bca6-5a2f-1a7e7b1da764";;"OFWeiche :103";"X:4781.82 Y:5556.56";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
138;"Omniflo Weiche";"shape_53caa992-f6c0-d5cd-30af-53bf475dbc6a";;"OFWeiche :105";"X:4021.44 Y:1203.19";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
||||||
139;"Omniflo Weiche";"shape_5536580b-4002-75ac-4846-5fe15ea55d70";;"OFWeiche :105";"X:5122.18 Y:1531.93";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":0.0,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
139;"Omniflo Weiche";"shape_771a064f-06c0-af1a-abb5-ef0c38f77fb3";;"OFWeiche :106";"X:3851.06 Y:1529.55";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-337.5,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
||||||
140;"Omniflo Weiche";"shape_2cd6c02b-6826-8c7c-5234-ed652d2b26b0";;"OFWeiche :106";"X:4951.79 Y:1858.18";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-337.5,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
140;"Omniflo Weiche";"shape_4bc2a761-d244-6fe5-1729-a2ee58b483fe";;"OFWeiche :107";"X:3568.78 Y:1765.83";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-315.0,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
||||||
141;"Omniflo Weiche";"shape_369568c3-474e-5151-6a84-35fc8c70ff07";;"OFWeiche :107";"X:4669.51 Y:2094.37";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-315.0,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
141;"Omniflo Weiche";"shape_0cdabc89-149d-2c93-c379-dd694eee0502";;"OFWeiche :108";"X:3217.57 Y:1876.03";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-292.5,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
||||||
142;"Omniflo Weiche";"shape_75689a76-6a9d-1059-7f50-323600d5d7ff";;"OFWeiche :108";"X:4318.3 Y:2204.57";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-292.5,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
142;"Omniflo Weiche";"shape_c078c7e2-f18c-de88-e41e-a7ef73a6b82e";;"OFWeiche :109";"X:2850.91 Y:1843.48";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-270.0,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
||||||
143;"Omniflo Weiche";"shape_568d24dd-2b1f-9752-9f5f-f3b602fc420e";;"OFWeiche :109";"X:3951.64 Y:2172.04";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-270.0,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
143;"Omniflo Weiche";"shape_a33afa4c-a30f-a157-ffdd-26c9874efb24";;"OFWeiche :110";"X:2524.61 Y:1673.09";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-247.5,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
||||||
144;"Omniflo Weiche";"shape_494ac0b1-d31b-7d40-ae95-8cb58e714498";;"OFWeiche :110";"X:3625.34 Y:2001.65";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-247.5,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
144;"Omniflo Weiche";"shape_34fa2575-9379-c92f-a49f-f7d099c0bbff";;"OFWeiche :111";"X:2288.35 Y:1390.78";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-225.0,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
||||||
145;"Omniflo Weiche";"shape_79b821ff-018f-c963-e88b-f31e10919bef";;"OFWeiche :111";"X:3389.08 Y:1719.34";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-225.0,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
145;"Omniflo Weiche";"shape_fba8c563-2897-c288-1e77-8aa1129bf3fe";;"OFWeiche :112";"X:2178.1 Y:1039.55";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-202.5,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
||||||
146;"Omniflo Weiche";"shape_aab836b4-70dd-8130-d65b-d0396c75ecc6";;"OFWeiche :112";"X:3278.83 Y:1368.11";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-202.5,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
146;"Omniflo Weiche";"shape_92471692-978e-0736-563f-16c4c4b8f3b6";;"OFWeiche :113";"X:2210.64 Y:672.83";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-180.0,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
||||||
147;"Omniflo Weiche";"shape_ba2e453e-6419-a083-32bc-2b2693d97566";;"OFWeiche :113";"X:3311.38 Y:1001.45";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-180.0,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
147;"Omniflo Weiche";"shape_a6ecfb53-1532-d4c1-aab3-789c0c5ad2a9";;"OFWeiche :114";"X:2381.02 Y:346.47";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-157.5,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
||||||
148;"Omniflo Weiche";"shape_fea58350-d17e-5ecc-92e9-2ddcd2c5da90";;"OFWeiche :114";"X:3481.76 Y:675.08";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-157.5,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
148;"Omniflo Weiche";"shape_3c228aad-e823-a5d6-2709-5934a729e256";;"OFWeiche :115";"X:2663.31 Y:110.2";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-135.0,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
||||||
149;"Omniflo Weiche";"shape_4b33e5b8-893f-eede-5eb7-77e5af88d445";;"OFWeiche :115";"X:3764.04 Y:438.81";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-135.0,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
149;"Omniflo Weiche";"shape_be7c1147-1967-3765-a0a0-e5799ed2fe8a";;"OFWeiche :116";"X:3014.52 Y:0";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-112.5,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
||||||
150;"Omniflo Weiche";"shape_c5cbaa0a-a0bc-048c-9150-65b9384e3964";;"OFWeiche :116";"X:4115.25 Y:328.61";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-112.5,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
150;"Omniflo Weiche";"shape_70c5f2c2-4c19-4dac-168b-e3795c70b305";;"OFWeiche :117";"X:3381.18 Y:32.54";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-90.0,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
||||||
151;"Omniflo Weiche";"shape_ce25d10b-3650-e938-8165-4ba6dc2d42e0";;"OFWeiche :117";"X:4481.91 Y:361.15";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-90.0,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
151;"Omniflo Weiche";"shape_b68fb393-45de-f460-7698-a0684a64c1e1";;"OFWeiche :118";"X:3707.47 Y:202.93";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-67.5,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
||||||
152;"Omniflo Weiche";"shape_8baaf80d-5ead-d573-aa3a-928c7d161b8e";;"OFWeiche :118";"X:4808.21 Y:531.54";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-67.5,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
152;"Omniflo Weiche";"shape_1152d6c3-efcd-25ca-3958-290018a4f6ef";;"OFWeiche :119";"X:3943.73 Y:485.25";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-45.0,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
||||||
153;"Omniflo Weiche";"shape_168a80e6-b4d4-6639-eda0-4a9d71221712";;"OFWeiche :119";"X:5044.47 Y:813.86";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-45.0,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
153;"Omniflo Weiche";"shape_d6566d43-6b80-290e-b94c-35a85e1b27f5";;"OFWeiche :120";"X:4053.98 Y:836.48";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-22.5,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
||||||
154;"Omniflo Weiche";"shape_50b307ef-e4d2-2bf0-846c-b96fe7ca895e";;"OFWeiche :120";"X:5154.72 Y:1165.09";;{"Länge in Meter links":null,"Länge in Meter rechts":null,"Länge in Meter gerade":null,"Weichentyp":"Dreiwegeweiche","Richtung":"False","Weichenwinkel":22.5,"Höhe":"2000","Drehung":-22.5,"Antrieb Kurve":false,"SivasNummer":"834342200"}
|
154;"Omniflo Gerade";"shape_c01f26c6-2634-af0a-f6f3-9aeea765b99e";;"OFGerade :19";"X:3949.86 Y:6449.36";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":0.0,"SivasNummer":"821106002"}
|
||||||
155;"Omniflo Gerade";"shape_f67d332d-5006-6fcf-e44d-88aed25907da";;"OFGerade :21";"X:4297.63 Y:6640.47";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-337.5,"SivasNummer":"821106002"}
|
155;"Omniflo Gerade";"shape_303d7b75-2381-aa00-a3bf-e227214592d9";;"OFGerade :22";"X:4434.04 Y:6353.24";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-22.5,"SivasNummer":"821106002"}
|
||||||
156;"Omniflo Gerade";"shape_db8b6322-7432-f341-9c9f-209cd0a2dfc1";;"OFGerade :22";"X:4781.81 Y:4376.6";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":0.0,"SivasNummer":"821106002"}
|
156;"Omniflo Gerade";"shape_7b0313cb-77cb-f016-289f-c8b97c5d26a1";;"OFGerade :20";"X:3465.67 Y:6353.24";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-157.5,"SivasNummer":"821106002"}
|
||||||
157;"Omniflo Gerade";"shape_dddb805a-3853-efdd-a465-e01097ef0ffd";;"OFGerade :20";"X:4781.81 Y:6736.6";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-180.0,"SivasNummer":"821106002"}
|
157;"Omniflo Gerade";"shape_4d567ce6-ddc3-2f11-bda9-843f0b203c5b";;"OFGerade :21";"X:3949.86 Y:4089.36";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-180.0,"SivasNummer":"821106002"}
|
||||||
158;"Omniflo Gerade";"shape_1f22d496-db96-5462-ab9e-6005a04eca48";;"OFGerade :23";"X:7656.88 Y:6518.5";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-202.5,"SivasNummer":"821106002"}
|
158;"Omniflo Gerade";"shape_bb26f4ec-c56d-36ee-68a7-ad920bc03cc9";;"OFGerade :25";"X:9855.13 Y:6172";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-22.5,"SivasNummer":"821106002"}
|
||||||
159;"Omniflo Gerade";"shape_774b109d-cc64-45c6-023b-9ba6ae24a7dc";;"OFGerade :24";"X:7172.69 Y:6614.62";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-180.0,"SivasNummer":"821106002"}
|
159;"Omniflo Gerade";"shape_550bcbf3-e307-4ce1-4ba1-4fbf8174cb04";;"OFGerade :23";"X:9370.95 Y:6268.12";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":0.0,"SivasNummer":"821106002"}
|
||||||
160;"Omniflo Gerade";"shape_328e63f2-8cc3-c094-af79-3a2b6cf12ce4";;"OFGerade :25";"X:6688.51 Y:6518.5";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-337.5,"SivasNummer":"821106002"}
|
160;"Omniflo Gerade";"shape_dd0bb3b6-1aaf-7193-6749-82fd301a71d9";;"OFGerade :24";"X:8886.76 Y:6172";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-157.5,"SivasNummer":"821106002"}
|
||||||
161;"Omniflo Gerade";"shape_a48da57f-decc-9fa1-a787-c02ac0cdc194";;"OFGerade :26";"X:7172.69 Y:4254.62";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":0.0,"SivasNummer":"821106002"}
|
161;"Omniflo Gerade";"shape_854fa51f-c098-cebf-742f-5b09cf4d74a8";;"OFGerade :26";"X:9370.95 Y:3908.12";;{"Anzahl der Separatoren":"0","Länge in Meter":"2","Winkel":"0","Anzahl der Scanner":0,"Höhe oben":"2000","Höhe unten":"2000","Drehung":-180.0,"SivasNummer":"821106002"}
|
||||||
|
|||||||
|
Can't render this file because it contains an unexpected character in line 2 and column 105.
|
Vendored
+8931
-3185
File diff suppressed because it is too large
Load Diff
Vendored
+6569
-847
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user