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 --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
|
||||
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 (
|
||||
goto %~1_local
|
||||
SET PYTHON_EXE=python
|
||||
)
|
||||
|
||||
:activate_interpreter_local
|
||||
IF NOT EXIST %PROJECT%\.venv CALL %PROJECT_BIN%\install_py.bat
|
||||
CALL %PROJECT%\.venv\Scripts\activate.bat
|
||||
goto :eof
|
||||
REM venv sicherstellen
|
||||
IF NOT EXIST "%PROJECT%\.venv" (
|
||||
"%PYTHON_EXE%" -m venv "%PROJECT%\.venv"
|
||||
)
|
||||
|
||||
:deactivate_interpreter_local
|
||||
deactivate
|
||||
goto :eof
|
||||
REM venv aktivieren
|
||||
CALL "%PROJECT%\.venv\Scripts\activate.bat"
|
||||
|
||||
:activate_interpreter_network
|
||||
SET OLD_PATH=%PATH%
|
||||
SET PATH=%NETWORK_INTERPRETER_PATH%;%PATH%
|
||||
CALL %PROJECT%\.venv\Scripts\activate.bat
|
||||
goto :eof
|
||||
REM Interpreter festnageln
|
||||
SET VIRTUAL_ENV_PYTHON=%PYTHON_EXE%
|
||||
GOTO :eof
|
||||
|
||||
:deactivate_interpreter_network
|
||||
SET PATH=%OLD_PATH%
|
||||
SET OLD_PATH=
|
||||
SET NETWORK_INTERPRETER_PATH=
|
||||
CALL %PROJECT%\.venv\Scripts\deactivate.bat
|
||||
goto :eof
|
||||
|
||||
:deactivate
|
||||
CALL "%PROJECT%\.venv\Scripts\deactivate.bat"
|
||||
SET VIRTUAL_ENV_PYTHON=
|
||||
GOTO :eof
|
||||
echo off
|
||||
|
||||
+17
-3
@@ -1,4 +1,18 @@
|
||||
@echo off
|
||||
CALL manage_interpreter.bat activate_interpreter
|
||||
python %PROJECT_LIB%\plant2dxf.py %*
|
||||
CALL manage_interpreter.bat deactivate_interpreter
|
||||
CALL manage_interpreter.bat activate
|
||||
if errorlevel 1 (
|
||||
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
|
||||
|
||||
set PATH=%PROJECT_BIN%;%PATH%
|
||||
REM set NETWORK_PYTHON=TO_BE_SET
|
||||
|
||||
|
||||
popd
|
||||
|
||||
@@ -25,16 +25,19 @@ esoffset = 479.95
|
||||
Umlenkstation = 500.0, 0.0, 0.0
|
||||
Motorstation = 500.0, 0.0, 0.0
|
||||
vario_abstand = 66.5
|
||||
|
||||
[Ils 2.0 core winkel]
|
||||
winkel_boegen = 3
|
||||
winkel_motor = 3.0
|
||||
winkel_umlenk = 3.0
|
||||
winkel_as = 3.0
|
||||
winkel_es = 3.0
|
||||
|
||||
[Omniflo]
|
||||
OFgeradesivas = 821106002
|
||||
Tefgeradesivas = 0_B10030
|
||||
OFfoerderer = 2
|
||||
|
||||
[Scanner_Stoper_namen]
|
||||
Omniflo_stopper = 827062022
|
||||
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:
|
||||
|
||||
- `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
|
||||
- `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_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)
|
||||
|
||||
@@ -33,7 +33,7 @@ Die Höhenvergleiche zur Bestimmung der Verbindungsart zwischen Gefällestrecken
|
||||
**Betroffene Dateien:**
|
||||
- `lib/as_es_methoden.py`: AS/ES-Element-Berechnungen
|
||||
- `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
|
||||
|
||||
## Übersicht
|
||||
@@ -505,7 +505,7 @@ msp.add_blockref(blockname, (x, y, z), dxfattribs={"rotation": rotation, "layer"
|
||||
|
||||
```python
|
||||
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"})
|
||||
```
|
||||
|
||||
@@ -536,13 +536,13 @@ if blockname not in doc.blocks:
|
||||
**Beispiel:**
|
||||
|
||||
```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:
|
||||
block = doc.blocks.new(name=blockname, base_point=(0, 0, 0))
|
||||
# Füge Komponenten zum Block hinzu
|
||||
block.add_blockref("Vario_Motorstation_500mm", (0, 0, 0))
|
||||
line = Line.new(dxfattribs={"start": start, "end": ende})
|
||||
line.translate(-x, -y, -hoehe_gefaehlle)
|
||||
line.translate(-x, -y, -hoehe_gefaelle)
|
||||
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:**
|
||||
|
||||
- Wenn `upper_hoehe_gefaehlle > lower_hoehe_gefaehlle`:
|
||||
- Wenn `vario_hoehe_0` oder `vario_hoehe_1 == upper_hoehe_gefaehlle` → `hat_motor_0 = True`
|
||||
- Wenn `upper_hoehe_gefaelle > lower_hoehe_gefaelle`:
|
||||
- Wenn `vario_hoehe_0` oder `vario_hoehe_1 == upper_hoehe_gefaelle` → `hat_motor_0 = True`
|
||||
- Sonst → `hat_umlenk_0 = True`
|
||||
- Wenn `upper_hoehe_gefaehlle < lower_hoehe_gefaehlle`:
|
||||
- Wenn `vario_hoehe_0` oder `vario_hoehe_1 == lower_hoehe_gefaehlle` → `hat_motor_0 = True`
|
||||
- Wenn `upper_hoehe_gefaelle < lower_hoehe_gefaelle`:
|
||||
- Wenn `vario_hoehe_0` oder `vario_hoehe_1 == lower_hoehe_gefaelle` → `hat_motor_0 = True`
|
||||
- Sonst → `hat_umlenk_0 = True`
|
||||
|
||||
**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:
|
||||
|
||||
```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
|
||||
@@ -825,19 +825,19 @@ dy = halbe_laenge * math.cos(0) # dy = halbe_laenge (da cos(0) = 1)
|
||||
**Rechts-Version:**
|
||||
|
||||
```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:**
|
||||
|
||||
```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:**
|
||||
|
||||
- `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
|
||||
- `hoehe_vario`: Mittlere Höhe ((h0 + h1) / 2)
|
||||
- `motor_vorhanden`: True/False
|
||||
@@ -874,7 +874,7 @@ Vario_Foerderer_{winkel}_{voerder_richtung}_{laenge}_{hoehe_vario}_links_{motor_
|
||||
foerderer, doc, lib_doc, config,
|
||||
block, block_name_links,
|
||||
start, ende,
|
||||
voerder_richtung,
|
||||
foerder_richtung,
|
||||
winkel_VP_offset_vorne, # None, da keine Verbindung
|
||||
winkel_VP_offset_hinten # None, da keine Verbindung
|
||||
)
|
||||
|
||||
@@ -1,29 +1,71 @@
|
||||
# -*- 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
|
||||
|
||||
|
||||
class Angetriebene_Kurve(BaseModel):
|
||||
"""Modell für eine angetriebene Kurve."""
|
||||
|
||||
teileid: str
|
||||
x: float
|
||||
y:float
|
||||
drehung: float = Field(default=0.0,description="Rotation der Kurve")
|
||||
hoehe0: float = Field(default=0.0,description="Hoehe Anfang der Kurve")
|
||||
hoehe1: float = Field(default=0.0,description="Hoehe Ende der Kurve")
|
||||
y: float
|
||||
drehung: float = Field(default=0.0, description="Rotation der Kurve")
|
||||
hoehe0: float = Field(default=0.0, description="Hoehe Anfang der Kurve")
|
||||
hoehe1: float = Field(default=0.0, description="Hoehe Ende 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")
|
||||
|
||||
|
||||
@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
|
||||
def antrieb(self):
|
||||
if self.antriebNebenStrecke == "Aussen":
|
||||
self.antriebNebenStrecke = "außen"
|
||||
elif self.antriebNebenStrecke == "Innen":
|
||||
self.antriebNebenStrecke = "innen"
|
||||
def antrieb(self) -> str:
|
||||
"""Antrieb-Seite (read-only, normalisiert beim Erstellen)."""
|
||||
return self.antriebNebenStrecke
|
||||
|
||||
@property
|
||||
def hight_zwischen(self):
|
||||
return ((self.hoehe0 + self.hoehe1) /2)
|
||||
"""Mittlere Höhe zwischen hoehe0 und hoehe1."""
|
||||
return (self.hoehe0 + self.hoehe1) / 2
|
||||
|
||||
@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
|
||||
hoehe1 = float(merkmale.get("Höhe Ende")) * 1000
|
||||
winkel = int(merkmale.get("Kurvenwinkel"))
|
||||
@@ -31,18 +73,17 @@ class Angetriebene_Kurve(BaseModel):
|
||||
antriebNebenstrecke = merkmale.get("AntriebNebenStrecke")
|
||||
try:
|
||||
drehung = float(merkmale.get("Drehung"))
|
||||
except Exception as e:
|
||||
except (TypeError, ValueError):
|
||||
drehung = 0.0
|
||||
|
||||
return cls(
|
||||
teileid = teileid,
|
||||
x = x,
|
||||
y = y,
|
||||
drehung = drehung,
|
||||
hoehe0 = hoehe0,
|
||||
hoehe1 = hoehe1,
|
||||
kurvenrichtung = kurvenrichtung,
|
||||
antriebNebenStrecke = antriebNebenstrecke,
|
||||
winkel = winkel
|
||||
|
||||
)
|
||||
return cls(
|
||||
teileid=teileid,
|
||||
x=x,
|
||||
y=y,
|
||||
drehung=drehung,
|
||||
hoehe0=hoehe0,
|
||||
hoehe1=hoehe1,
|
||||
kurvenrichtung=kurvenrichtung,
|
||||
antriebNebenStrecke=antriebNebenstrecke,
|
||||
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()
|
||||
+10
-11
@@ -1,14 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class Bt_element(BaseModel):
|
||||
"""Das sind beide BTMT Elemente"""
|
||||
|
||||
teileid: str
|
||||
drehung: Optional [float] = Field(default=0.0,description="Rotation des Elements")
|
||||
hoehe: Optional [float] = Field(default=0.0,description="Hoehe des Elements")
|
||||
drehung: Optional[float] = Field(default=0.0, description="Rotation des Elements")
|
||||
hoehe: Optional[float] = Field(default=0.0, description="Hoehe des Elements")
|
||||
|
||||
@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:
|
||||
hoehe = float(merkmale.get("Höhe in Meter"))
|
||||
except Exception as e:
|
||||
@@ -17,11 +22,5 @@ class Bt_element(BaseModel):
|
||||
drehung = float(merkmale.get("Drehung"))
|
||||
except Exception as e:
|
||||
drehung = 0.0
|
||||
|
||||
return cls(
|
||||
teileid = teileid,
|
||||
x = x,
|
||||
y = y,
|
||||
hoehe = hoehe,
|
||||
drehung = drehung
|
||||
)
|
||||
|
||||
return cls(teileid=teileid, x=x, y=y, hoehe=hoehe, drehung=drehung)
|
||||
|
||||
+139
-39
@@ -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
|
||||
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):
|
||||
"""Modell für Eckrad-Komponenten."""
|
||||
|
||||
teileid: str
|
||||
drehung: Optional [float] = Field(default=0.0,description="Rotation des Elements")
|
||||
hoehe: Optional [float] = Field(default=0.0,description="Hoehe des Elements")
|
||||
drehrichtung: Optional [str] =Field(default=None,description="Richtung des Eckrads")
|
||||
drehung: Optional[float] = Field(default=0.0, description="Rotation des Elements")
|
||||
hoehe: Optional[float] = Field(default=0.0, description="Hoehe des Elements")
|
||||
drehrichtung: Optional[str] = Field(
|
||||
default=None, description="Richtung des Eckrads"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_merkmale(cls, teileid: str, x: float, y: float, merkmale: dict) -> 'Eckrad':
|
||||
try:
|
||||
hoehe = float(merkmale.get("Höhe in Meter")) * 1000
|
||||
except Exception as e:
|
||||
hoehe = 0.0
|
||||
try:
|
||||
drehung = float(merkmale.get("Drehung"))
|
||||
except Exception as e:
|
||||
drehung = 0.0
|
||||
try:
|
||||
drehrichtung = merkmale.get("Drehrichtung")
|
||||
except Exception as e:
|
||||
drehrichtung = None
|
||||
def from_merkmale(
|
||||
cls, teileid: str, x: float, y: float, merkmale: dict
|
||||
) -> "Eckrad":
|
||||
"""
|
||||
Erstellt Eckrad aus einem Merkmale-Dictionary.
|
||||
|
||||
Args:
|
||||
teileid: Teile-Identifikator
|
||||
x, y: Koordinaten (werden vom Modell nicht gespeichert)
|
||||
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")
|
||||
|
||||
return cls(
|
||||
teileid = teileid,
|
||||
x = x,
|
||||
y = y,
|
||||
hoehe = hoehe,
|
||||
drehrichtung = drehrichtung
|
||||
teileid=teileid,
|
||||
hoehe=hoehe,
|
||||
drehung=drehung,
|
||||
drehrichtung=drehrichtung,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def erstellung_eckrad_richtung(merkmale, doc, lib_doc):
|
||||
block_methoden.import_block("AN8",lib_doc,doc)
|
||||
block_methoden.import_block("Richtungspfeil",lib_doc,doc)
|
||||
eckrad_rechts = "eckrad_UZS"
|
||||
eckrad_links = "eckrad_GUZS"
|
||||
"""
|
||||
Erstellt Eckrad-Blöcke mit Richtungspfeilen (UZS und 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
|
||||
# Erstellung der Richtungung Blöcke der Eckrads
|
||||
if eckrad_rechts not in doc.blocks:
|
||||
block_rechts = doc.blocks.new(name= eckrad_rechts,base_point=(0,0,0))
|
||||
block_links = doc.blocks.new(name= eckrad_links,base_point=(0,0,0))
|
||||
block_rechts.add_blockref("AN8",(0,0,0))
|
||||
block_links.add_blockref("AN8",(0,0,0))
|
||||
block_rechts.add_blockref("Richtungspfeil",(0+200,0+ RADIUS,0))
|
||||
block_rechts.add_blockref("Richtungspfeil",(0-200,0- RADIUS,0),dxfattribs={"rotation": 180})
|
||||
block_links.add_blockref("Richtungspfeil",(0+200,0- RADIUS,0))
|
||||
block_links.add_blockref("Richtungspfeil",(0-200,0+ RADIUS,0),dxfattribs={"rotation": 180})
|
||||
return eckrad_rechts,eckrad_links,hight
|
||||
|
||||
# Blöcke nur erstellen wenn noch nicht vorhanden
|
||||
if BLOCK_ECKRAD_UZS not in doc.blocks:
|
||||
block_rechts = doc.blocks.new(name=BLOCK_ECKRAD_UZS, base_point=(0, 0, 0))
|
||||
block_links = doc.blocks.new(name=BLOCK_ECKRAD_GUZS, base_point=(0, 0, 0))
|
||||
|
||||
# Grundform für beide
|
||||
block_rechts.add_blockref(BLOCK_AN8, (0, 0, 0))
|
||||
block_links.add_blockref(BLOCK_AN8, (0, 0, 0))
|
||||
|
||||
# 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()
|
||||
+193
-102
@@ -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
|
||||
import math
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from typing import Optional
|
||||
import plant2dxf
|
||||
import block_methoden
|
||||
|
||||
from lib import block_methoden
|
||||
|
||||
|
||||
ATTR_TAG = "TeileId" # Attributtag im Block
|
||||
RADIUS = 400 # Radius der Kreiselkreise (mm)
|
||||
# ============================================================================
|
||||
# KONSTANTEN
|
||||
# ============================================================================
|
||||
|
||||
ATTR_TAG = "TeileId" # Attributtag im Block
|
||||
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):
|
||||
"""Pydantic-Modell für Kreisel-Komponenten."""
|
||||
|
||||
teileid: str
|
||||
x: float = Field(description="X-Koordinate des Kreisel-Zentrums")
|
||||
y: float = Field(description="Y-Koordinate des Kreisel-Zentrums")
|
||||
hoehe: float = Field(description="Höhe in mm")
|
||||
drehung: float = Field(default=0.0, description="Drehung/Winkel in Grad")
|
||||
drehrichtung: Optional[str] = Field(default=None, description="Drehrichtung: UZS oder GUZS")
|
||||
abstand: float = Field(default=20000.0, description="Abstand zwischen Kreiselachsen in mm")
|
||||
kreiselart: Optional[str] = Field(default=None, description="Kreiselart, z.B. 'Pin'")
|
||||
drehrichtung: Optional[str] = Field(
|
||||
default=None, description="Drehrichtung: UZS oder GUZS"
|
||||
)
|
||||
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_separatoren: float = Field(default=0.0, description="Anzahl der Separatoren")
|
||||
|
||||
@field_validator('abstand')
|
||||
|
||||
@field_validator("abstand")
|
||||
@classmethod
|
||||
def validate_abstand(cls, v):
|
||||
"""Konvertiert Abstand von Meter zu mm, falls nötig."""
|
||||
@@ -34,8 +92,8 @@ class Kreisel(BaseModel):
|
||||
except ValueError:
|
||||
v = 10000.0 # Fallback 10 m
|
||||
return v
|
||||
|
||||
@field_validator('hoehe')
|
||||
|
||||
@field_validator("hoehe")
|
||||
@classmethod
|
||||
def validate_hoehe(cls, v):
|
||||
"""Konvertiert Höhe von Meter zu mm, falls nötig."""
|
||||
@@ -46,12 +104,12 @@ class Kreisel(BaseModel):
|
||||
except ValueError:
|
||||
v = 0.0
|
||||
return v
|
||||
|
||||
|
||||
@property
|
||||
def halbabstand(self) -> float:
|
||||
"""Halbabstand zwischen den beiden Blöcken."""
|
||||
return self.abstand / 2
|
||||
|
||||
|
||||
@property
|
||||
def winkel_rad(self) -> float:
|
||||
"""Winkel in Radianten für Berechnungen."""
|
||||
@@ -59,62 +117,65 @@ class Kreisel(BaseModel):
|
||||
return math.radians(self.drehung)
|
||||
else:
|
||||
return math.radians(self.drehung - 180)
|
||||
|
||||
|
||||
@property
|
||||
def richtung_rad(self) -> float:
|
||||
"""Richtung in Radianten (für am_kreisel_direct_verbunden)."""
|
||||
# Wird aus drehung abgeleitet oder separat gesetzt
|
||||
return math.radians(self.drehung)
|
||||
|
||||
|
||||
@property
|
||||
def pos1(self) -> tuple[float, float, float]:
|
||||
"""Position des ersten Blocks (x, y, z)."""
|
||||
dx = self.halbabstand * math.cos(self.winkel_rad)
|
||||
dy = self.halbabstand * math.sin(self.winkel_rad)
|
||||
return (self.x - dx, self.y - dy, self.hoehe)
|
||||
|
||||
|
||||
@property
|
||||
def pos2(self) -> tuple[float, float, float]:
|
||||
"""Position des zweiten Blocks (x, y, z)."""
|
||||
dx = self.halbabstand * math.cos(self.winkel_rad)
|
||||
dy = self.halbabstand * math.sin(self.winkel_rad)
|
||||
return (self.x + dx, self.y + dy, self.hoehe)
|
||||
|
||||
|
||||
@property
|
||||
def z(self) -> float:
|
||||
"""Z-Koordinate (gleich der Höhe)."""
|
||||
return self.hoehe
|
||||
|
||||
|
||||
@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."""
|
||||
hoehe_m = merkmale.get("Höhe in m", "0").replace(",", ".")
|
||||
try:
|
||||
hoehe = float(hoehe_m) * 1000
|
||||
except (ValueError, TypeError):
|
||||
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:
|
||||
abstand = float(abstand_m) * 1000
|
||||
except (ValueError, TypeError):
|
||||
abstand = 10000.0
|
||||
|
||||
|
||||
try:
|
||||
drehung = float(merkmale.get("Drehung", "0"))
|
||||
except (ValueError, TypeError):
|
||||
drehung = 0.0
|
||||
|
||||
|
||||
try:
|
||||
anzahl_scanner = float(merkmale.get("Anzahl der Scanner", "0"))
|
||||
except (ValueError, TypeError):
|
||||
anzahl_scanner = 0.0
|
||||
|
||||
|
||||
try:
|
||||
anzahl_separatoren = float(merkmale.get("Anzahl der Separatoren", "0"))
|
||||
except (ValueError, TypeError):
|
||||
anzahl_separatoren = 0.0
|
||||
|
||||
|
||||
return cls(
|
||||
teileid=teileid,
|
||||
x=x,
|
||||
@@ -125,14 +186,25 @@ class Kreisel(BaseModel):
|
||||
abstand=abstand,
|
||||
kreiselart=merkmale.get("Kreiselart"),
|
||||
anzahl_scanner=anzahl_scanner,
|
||||
anzahl_separatoren=anzahl_separatoren
|
||||
anzahl_separatoren=anzahl_separatoren,
|
||||
)
|
||||
|
||||
|
||||
@staticmethod
|
||||
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
|
||||
x1, y1, z1 = pos1
|
||||
x2, y2, z1 = pos2
|
||||
x2, y2, _ = pos2 # z identisch für beide Blöcke
|
||||
# Verbindungsvektor
|
||||
dx = x2 - x1
|
||||
dy = y2 - y1
|
||||
@@ -141,62 +213,57 @@ class Kreisel(BaseModel):
|
||||
if length == 0:
|
||||
return # keine Linie bei identischen Punkten
|
||||
# Normalenvektor (senkrecht, normiert, Länge = RADIUS)
|
||||
|
||||
nx = -dy / length * RADIUS
|
||||
ny = dx / length * RADIUS
|
||||
# Tangentialpunkte
|
||||
p1a = (x1 + nx, y1 + ny,z1)
|
||||
p1b = (x1 - nx, y1 - ny,z1)
|
||||
p2a = (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)
|
||||
p1a = (x1 + nx, y1 + ny, z1)
|
||||
p1b = (x1 - nx, y1 - ny, z1)
|
||||
p2a = (x2 + nx, y2 + ny, z1)
|
||||
p2b = (x2 - nx, y2 - ny, z1)
|
||||
|
||||
# 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(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()
|
||||
if drehrichtung not in ("UZS", "GUZS"):
|
||||
return
|
||||
x1, y1,z1= pos1
|
||||
x2, y2,z2 = pos2
|
||||
x1, y1, z1 = pos1
|
||||
x2, y2, _ = pos2
|
||||
dx = x2 - x1
|
||||
dy = y2 - y1
|
||||
length = math.hypot(dx, dy)
|
||||
@@ -205,35 +272,59 @@ class Kreisel(BaseModel):
|
||||
# Normalenvektor (senkrecht, normiert, Länge = RADIUS)
|
||||
nx = -dy / length * RADIUS
|
||||
ny = dx / length * RADIUS
|
||||
# Obere Linie
|
||||
# Obere und untere Tangentiallinien
|
||||
p1_oben = (x1 + nx, y1 + ny)
|
||||
p2_oben = (x2 + nx, y2 + ny)
|
||||
# Untere Linie
|
||||
p1_unten = (x1 - nx, y1 - 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):
|
||||
t = i / 4 # 1/4, 2/4, 3/4
|
||||
px = p1_oben[0] + t * (p2_oben[0] - p1_oben[0])
|
||||
py = p1_oben[1] + t * (p2_oben[1] - p1_oben[1])
|
||||
rotation = math.degrees(math.atan2(p2_oben[1] - p1_oben[1], p2_oben[0] - p1_oben[0]))
|
||||
if drehrichtung == "GUZS":
|
||||
px = p1[0] + t * (p2[0] - p1[0])
|
||||
py = p1[1] + t * (p2[1] - p1[1])
|
||||
rotation = math.degrees(math.atan2(p2[1] - p1[1], p2[0] - p1[0]))
|
||||
# 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
|
||||
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})
|
||||
msp.add_blockref(
|
||||
"Richtungspfeil",
|
||||
(px, py, z),
|
||||
dxfattribs={"rotation": rotation, "layer": blockref_layer},
|
||||
)
|
||||
if verbose:
|
||||
print(f"[INFO] Drehrichtung '{drehrichtung}': Richtungspfeil oben bei ({px:.1f}, {py:.1f}), rot={rotation:.1f}")
|
||||
# S-LP auf unterer Linie (Drehrichtung invertiert)
|
||||
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}")
|
||||
print(
|
||||
f"[INFO] Drehrichtung '{drehrichtung}': Richtungspfeil {label} 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()
|
||||
+156
-76
@@ -1,94 +1,172 @@
|
||||
# -*- 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
|
||||
import math
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from pydantic import BaseModel, Field
|
||||
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):
|
||||
teileid:str
|
||||
x:float
|
||||
y:float
|
||||
sivasnummer:str
|
||||
laenge: Optional [float]
|
||||
"""Modell für Omniflo-Kettenförderer."""
|
||||
|
||||
teileid: str
|
||||
x: float
|
||||
y: float
|
||||
sivasnummer: str
|
||||
laenge: Optional[float]
|
||||
drehung: float
|
||||
hoehe : Optional[float]
|
||||
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")
|
||||
anzahl_scanner: Optional [int] = Field(default=0, description="Anzahl der Scanner")
|
||||
anzahl_stopper: Optional [int] = Field(default=0, description="Anzahl der Separatoren")
|
||||
hoehe: Optional[float]
|
||||
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")
|
||||
anzahl_scanner: Optional[int] = Field(default=0, description="Anzahl der Scanner")
|
||||
anzahl_stopper: Optional[int] = Field(
|
||||
default=0, description="Anzahl der Separatoren"
|
||||
)
|
||||
|
||||
@property
|
||||
def hight_zwischen(self):
|
||||
return ((self.h0 + self.h1) /2)
|
||||
"""Mittlere Höhe zwischen h0 und h1."""
|
||||
return (self.h0 + self.h1) / 2
|
||||
|
||||
@classmethod
|
||||
def from_merkmale(cls, teileid,x,y, merkmale):
|
||||
sivasnummer = merkmale.get("SivasNummer")
|
||||
try:
|
||||
laenge = float(merkmale.get("Länge in Meter", "0").replace(",", ".")) * 1000 # Meter → mm
|
||||
except Exception:
|
||||
laenge = 0
|
||||
try:
|
||||
winkel = float(merkmale.get("Drehung"))
|
||||
except Exception:
|
||||
winkel = 0.0
|
||||
try:
|
||||
hoehe = float(merkmale.get("Höhe"))
|
||||
except Exception:
|
||||
hoehe = 0.0
|
||||
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
|
||||
def from_merkmale(cls, teileid, x, y, merkmale):
|
||||
"""
|
||||
Erstellt Omniflo aus einem Merkmale-Dictionary.
|
||||
|
||||
Verwendet _safe_float/_safe_int für robuste Konvertierung
|
||||
statt 8x wiederholtem try/except-Muster.
|
||||
|
||||
Args:
|
||||
teileid: Teile-Identifikator
|
||||
x, y: Koordinaten in mm
|
||||
merkmale: Dictionary mit Eigenschaftswerten
|
||||
|
||||
Returns:
|
||||
Omniflo-Instanz
|
||||
"""
|
||||
return cls(
|
||||
teileid= teileid,
|
||||
teileid=teileid,
|
||||
x=x,
|
||||
y=y,
|
||||
sivasnummer = sivasnummer,
|
||||
laenge = laenge,
|
||||
drehung = winkel,
|
||||
hoehe = hoehe,
|
||||
h0 = h0,
|
||||
h1 = h1,
|
||||
anzahl_scanner = anzahl_scanner,
|
||||
anzahl_stopper = anzahl_separatoren
|
||||
sivasnummer=merkmale.get("SivasNummer"),
|
||||
laenge=_safe_float(merkmale.get("Länge in Meter"), 0.0) * 1000, # Meter → mm
|
||||
drehung=_safe_float(merkmale.get("Drehung"), 0.0),
|
||||
hoehe=_safe_float(merkmale.get("Höhe"), 0.0),
|
||||
h0=_safe_float(merkmale.get("Höhe unten"), 0.0),
|
||||
h1=_safe_float(merkmale.get("Höhe oben"), 0.0),
|
||||
anzahl_scanner=_safe_int(merkmale.get("Anzahl der Scanner"), 0),
|
||||
anzahl_stopper=_safe_int(merkmale.get("Anzahl der Separatoren"), 0),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
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)
|
||||
halbe_laenge = omniflo_objekt.laenge / 2
|
||||
x = omniflo_objekt.x
|
||||
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)
|
||||
dy = halbe_laenge * math.cos(winkel_rad)
|
||||
start = (x + dx, y + dy, omniflo_objekt.h1 )
|
||||
ende = (x - dx, y - dy, omniflo_objekt.h0)
|
||||
start = (x + dx, y + dy, omniflo_objekt.h1)
|
||||
ende = (x - dx, y - dy, omniflo_objekt.h0)
|
||||
if "A-2" not in doc.layers:
|
||||
doc.layers.add(name="A-2", color=2)
|
||||
if "F-1" not in doc.layers:
|
||||
doc.layers.add(name="F-1", color =1)
|
||||
linie=msp.add_line(start, ende)
|
||||
doc.layers.add(name="F-1", color=1)
|
||||
linie = msp.add_line(start, ende)
|
||||
if omniflo_objekt.sivasnummer == tefsivas:
|
||||
linie.dxf.layer = "F-1"
|
||||
else:
|
||||
linie.dxf.layer = "A-2"
|
||||
|
||||
@staticmethod
|
||||
def omniflo_foerdererstellung(msp, doc, lib_doc, omniflo_objekt):
|
||||
""""Erstellung des Kettenförderers aktuell nur grundriss"""
|
||||
block_methoden.import_block("bogen1",lib_doc,doc)
|
||||
block_methoden.import_block("bogen2",lib_doc,doc)
|
||||
"""
|
||||
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("bogen2", lib_doc, doc)
|
||||
x = omniflo_objekt.x
|
||||
y = omniflo_objekt.y
|
||||
rotation = omniflo_objekt.drehung
|
||||
@@ -96,21 +174,23 @@ class Omniflo(BaseModel):
|
||||
h0 = omniflo_objekt.h0
|
||||
h1 = omniflo_objekt.h1
|
||||
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)
|
||||
halbe_laenge = laenge / 2
|
||||
# Man muss bei sin -1 machen wegen des links koordinaten system
|
||||
dx = halbe_laenge * math.sin(rotation * -1)
|
||||
dy = halbe_laenge * math.cos(rotation)
|
||||
start = (x + dx, y + dy, h1 )
|
||||
ende = (x - dx, y - dy, h0)
|
||||
# BUG FIX: war `math.sin(rotation * -1)` — rotation ist in Grad!
|
||||
# Muss winkel_rad (Radianten) verwenden wie in Omniflo_geraden_erstellung
|
||||
dx = halbe_laenge * math.sin(winkel_rad * -1)
|
||||
dy = halbe_laenge * math.cos(winkel_rad)
|
||||
start = (x + dx, y + dy, h1)
|
||||
ende = (x - dx, y - dy, h0)
|
||||
if blockname not in doc.blocks:
|
||||
block = doc.blocks.new(blockname, base_point=(0,0,0))
|
||||
block.add_blockref("bogen1",start)
|
||||
block.add_blockref("bogen2",ende)
|
||||
line = Line.new(dxfattribs={"start": start,"end":ende})
|
||||
block = doc.blocks.new(blockname, base_point=(0, 0, 0))
|
||||
block.add_blockref("bogen1", start)
|
||||
block.add_blockref("bogen2", ende)
|
||||
line = Line.new(dxfattribs={"start": start, "end": ende})
|
||||
copy = line.copy()
|
||||
copy.translate(-x,-y,-h_zwischen)
|
||||
copy.translate(-x, -y, -h_zwischen)
|
||||
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()
|
||||
+1160
-704
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 sys
|
||||
import csv
|
||||
@@ -5,8 +6,8 @@ import json
|
||||
import re
|
||||
import configparser
|
||||
from pathlib import Path
|
||||
from utils import check_environment_var, setup_logger
|
||||
from Elemente import Kreisel, VarioFoerderer,Gefaehllestrecke,Angetriebene_Kurve,Bt_element,Omniflo, Eckrad
|
||||
from lib.utils import check_environment_var, setup_logger
|
||||
from lib.Elemente import Kreisel, VarioFoerderer,Gefaellestrecke,Angetriebene_Kurve,Bt_element,Omniflo, Eckrad
|
||||
# --------------------------------------------------------- CFG-Leser für shapes.cfg
|
||||
def get_shape_cfg(teileart, cfg_path, logger=None):
|
||||
parser = configparser.ConfigParser()
|
||||
@@ -218,4 +219,4 @@ def normalize_func_name(name):
|
||||
.replace('.', '_')
|
||||
.replace('-', '_')
|
||||
.lower()
|
||||
)
|
||||
)
|
||||
|
||||
+718
-309
File diff suppressed because it is too large
Load Diff
+94
-50
@@ -1,24 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import math
|
||||
import plant2dxf
|
||||
from lib import plant2dxf
|
||||
from ezdxf import units
|
||||
from ezdxf.entities import Line
|
||||
from ezdxf.addons import importer
|
||||
from ezdxf.math import Matrix44, X_AXIS,Y_AXIS,Z_AXIS
|
||||
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
|
||||
"""
|
||||
dreh_block_name = block_name +f"_{math.degrees(winkel)}"
|
||||
layer, color = get_insert_color_layer(lib_doc,block_name)
|
||||
if (dreh_block_name in to_doc.blocks):
|
||||
return dreh_block_name
|
||||
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))
|
||||
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":
|
||||
from ezdxf.math import Matrix44, X_AXIS, Y_AXIS, Z_AXIS
|
||||
|
||||
|
||||
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"""
|
||||
dreh_block_name = block_name + f"_{math.degrees(winkel)}"
|
||||
layer, color = get_insert_color_layer(lib_doc, block_name)
|
||||
if dreh_block_name in to_doc.blocks:
|
||||
return dreh_block_name
|
||||
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))
|
||||
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)
|
||||
else:
|
||||
else:
|
||||
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:
|
||||
copy = e.copy()
|
||||
copy.transform(rotation_matrix)
|
||||
@@ -26,14 +37,14 @@ def dreh_block(block_name: str, to_doc,lib_doc, winkel) :
|
||||
return dreh_block_name
|
||||
|
||||
|
||||
def import_block(block_name: str, from_doc, to_doc, winkel = None) -> None:
|
||||
def import_block(block_name: str, from_doc, to_doc, winkel=None) -> None:
|
||||
"""Importiert Blockdefinition block_name von from_doc nach to_doc.
|
||||
|
||||
- Kopiert alle Entities des Blocks
|
||||
- Stellt sicher, dass benutzte Layer im Ziel existieren (mit Eigenschaften)
|
||||
- Übernimmt Basispunkt und Block-Layer, falls vorhanden
|
||||
"""
|
||||
msp2 = from_doc.modelspace()
|
||||
|
||||
src = from_doc.blocks[block_name]
|
||||
att_def = {}
|
||||
if block_name == "Pinbereich":
|
||||
@@ -41,16 +52,16 @@ def import_block(block_name: str, from_doc, to_doc, winkel = None) -> None:
|
||||
|
||||
# Alle Linientypen importieren
|
||||
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
|
||||
for ent in src:
|
||||
copy = ent.copy()
|
||||
|
||||
if ent.dxftype() == "ATTDEF":
|
||||
att_def[ent.dxf.tag] =ent.dxf.text
|
||||
att_def[ent.dxf.tag] = ent.dxf.text
|
||||
if ent.dxftype() == "INSERT":
|
||||
|
||||
import_block(ent.dxf.name,from_doc, to_doc,None)
|
||||
import_block(ent.dxf.name, from_doc, to_doc, None)
|
||||
|
||||
if att_def != {}:
|
||||
return att_def
|
||||
@@ -87,21 +98,22 @@ def import_block(block_name: str, from_doc, to_doc, winkel = None) -> None:
|
||||
except Exception:
|
||||
pass
|
||||
# kopiert die elemente von dem element aus dem block und speichert diese in den block für dass Modelspace auf und # speichern der attdef elemente in eine Liste falks diese verhanden sind und gibt diese zurück
|
||||
|
||||
|
||||
for ent in src:
|
||||
copy = ent.copy()
|
||||
|
||||
if ent.dxftype() == "ATTDEF":
|
||||
att_def[ent.dxf.tag] =ent.dxf.text
|
||||
att_def[ent.dxf.tag] = ent.dxf.text
|
||||
if ent.dxftype() == "INSERT":
|
||||
import_block(ent.dxf.name,from_doc, to_doc,None)
|
||||
import_block(ent.dxf.name, from_doc, to_doc, None)
|
||||
tgt.add_entity(copy)
|
||||
|
||||
|
||||
if att_def != {}:
|
||||
return att_def
|
||||
|
||||
|
||||
|
||||
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()
|
||||
color = 0
|
||||
layer = 0
|
||||
@@ -110,34 +122,66 @@ def get_insert_color_layer(lib_doc, blockname):
|
||||
color = insert.dxf.color
|
||||
layer = insert.dxf.layer
|
||||
return layer, color
|
||||
def rotatate_and_left_motor_umlenk(doc, lib_doc,config):
|
||||
motor_rotation = float(config.get("Ils 2.0 core winkel","winkel_motor"))
|
||||
umlenk_rotation = float(config.get("Ils 2.0 core winkel","winkel_umlenk"))
|
||||
block_Vario_Umlenkstation_500mm ="Vario_Umlenkstation_500mm"
|
||||
|
||||
|
||||
def rotatate_and_left_motor_umlenk(doc, lib_doc, config):
|
||||
motor_rotation = float(config.get("Ils 2.0 core winkel", "winkel_motor"))
|
||||
umlenk_rotation = float(config.get("Ils 2.0 core winkel", "winkel_umlenk"))
|
||||
block_Vario_Umlenkstation_500mm = "Vario_Umlenkstation_500mm"
|
||||
block_Vario_Motorstation_500mm = "Vario_Motorstation_500mm"
|
||||
blockname_motor_links = block_Vario_Motorstation_500mm +"_links"
|
||||
blockname_motor_links = block_Vario_Motorstation_500mm + "_links"
|
||||
blockname_umlenk_links = block_Vario_Umlenkstation_500mm + "_links"
|
||||
import_block(block_Vario_Umlenkstation_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)
|
||||
import_block(block_Vario_Umlenkstation_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,
|
||||
)
|
||||
|
||||
block_Vario_Umlenkstation_500mm =dreh_block(block_Vario_Umlenkstation_500mm,doc,lib_doc,math.radians(umlenk_rotation))
|
||||
block_Vario_Motorstation_500mm =dreh_block(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
|
||||
block_Vario_Umlenkstation_500mm = dreh_block(
|
||||
block_Vario_Umlenkstation_500mm, doc, lib_doc, math.radians(umlenk_rotation)
|
||||
)
|
||||
block_Vario_Motorstation_500mm = dreh_block(
|
||||
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
|
||||
blockname2 = block_2_name_zwischen
|
||||
if block_2_left_name not in doc.blocks:
|
||||
matrix = Matrix44.scale(1,-1,1)
|
||||
block1_zwischen = doc.blocks.new(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_1_left_name = doc.blocks.new(name=block_1_left_name,base_point=(0,0,0))
|
||||
block1_zwischen.add_blockref(blockname1,(0,0,0))
|
||||
block2_zwischen.add_blockref(blockname2,(0,0,0))
|
||||
matrix = Matrix44.scale(1, -1, 1)
|
||||
block1_zwischen = doc.blocks.new(
|
||||
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_1_left_name = doc.blocks.new(name=block_1_left_name, base_point=(0, 0, 0))
|
||||
block1_zwischen.add_blockref(blockname1, (0, 0, 0))
|
||||
block2_zwischen.add_blockref(blockname2, (0, 0, 0))
|
||||
for e in block2_zwischen:
|
||||
copy = e.copy()
|
||||
copy.transform(matrix)
|
||||
@@ -148,11 +192,11 @@ def turn_two_blocks_left(doc, block_1_name_zwischen, block_2_name_zwischen, bloc
|
||||
copy.transform(matrix)
|
||||
block_1_left_name.add_entity(copy)
|
||||
|
||||
|
||||
def add_attributes_to_block(block, attributes):
|
||||
|
||||
"""
|
||||
Fügt einem bestehenden ezdxf-Block Attribut-Definitionen hinzu.
|
||||
|
||||
|
||||
Parameter:
|
||||
block – ein ezdxf.blocks.BlockLayout Objekt
|
||||
attributes – Liste von Tupeln [(tag, value), ...]
|
||||
@@ -160,8 +204,8 @@ def add_attributes_to_block(block, attributes):
|
||||
for tag, value in attributes.items():
|
||||
tag = tag
|
||||
value = value
|
||||
a =block.add_attrib(
|
||||
a = block.add_attrib(
|
||||
tag=tag,
|
||||
text=value,
|
||||
)
|
||||
a.is_invisible = True
|
||||
a.is_invisible = True
|
||||
|
||||
+262
-187
@@ -1,30 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import ezdxf
|
||||
from ezdxf.math import Matrix44, Vec3, BoundingBox, Vec2
|
||||
import math
|
||||
import argparse
|
||||
import sys
|
||||
import shutil
|
||||
import configparser
|
||||
from utils import check_environment_var, setup_logger
|
||||
from pathlib import Path
|
||||
import logging
|
||||
|
||||
|
||||
def create_block_library(input_dir, output_file, config, logger=None):
|
||||
"""
|
||||
Erstellt eine DXF-Block-Bibliothek aus einzelnen DXF-Dateien.
|
||||
|
||||
|
||||
Diese Funktion liest alle DXF-Dateien aus einem Verzeichnis und erstellt
|
||||
daraus eine Bibliothek mit Blöcken. Die Blöcke werden in einem Raster
|
||||
angeordnet und mit Beschriftungen versehen. Fehlerhafte Dateien werden
|
||||
protokolliert.
|
||||
|
||||
|
||||
Args:
|
||||
input_dir (str): Verzeichnis mit den zu verarbeitenden DXF-Dateien
|
||||
output_file (str): Pfad zur zu erstellenden Bibliotheks-DXF-Datei
|
||||
config: ConfigParser-Objekt mit den Konfigurationswerten
|
||||
logger: Optionaler Logger für Logging-Ausgaben
|
||||
|
||||
|
||||
Note:
|
||||
- Unterstützte Entity-Typen: LINE, LWPOLYLINE, POLYLINE, SPLINE, CIRCLE, ARC, INSERT, TEXT, MTEXT, REGION, …
|
||||
- Blöcke werden zentriert und in einem 20x20 Raster angeordnet
|
||||
@@ -37,12 +38,12 @@ def create_block_library(input_dir, output_file, config, logger=None):
|
||||
x_offset = 0
|
||||
y_offset = 0
|
||||
blocks_in_row = 0
|
||||
|
||||
|
||||
error_files = []
|
||||
processed_files = []
|
||||
max_blockspacing_x = 0
|
||||
max_blockspacing_y = 0
|
||||
|
||||
|
||||
for filename in os.listdir(input_dir):
|
||||
|
||||
if not filename.lower().endswith(".dxf"):
|
||||
@@ -79,22 +80,21 @@ def create_block_library(input_dir, output_file, config, logger=None):
|
||||
"REGION",
|
||||
}
|
||||
filtered_entities = []
|
||||
att_def= {}
|
||||
att_def = {}
|
||||
for insert in src_msp.query("INSERT"):
|
||||
for attrib in insert.attribs:
|
||||
att_def[attrib.dxf.tag] = attrib.dxf.text
|
||||
|
||||
|
||||
for e in entities:
|
||||
if e.dxftype() in allowed_types:
|
||||
if e.dxftype() in allowed_types:
|
||||
filtered_entities.append(e)
|
||||
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
|
||||
|
||||
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Fehler beim Lesen von {filename}: {e}"
|
||||
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
|
||||
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:
|
||||
if layer_name and layer_name not in doc.layers:
|
||||
try:
|
||||
@@ -122,8 +124,10 @@ def create_block_library(input_dir, output_file, config, logger=None):
|
||||
doc.layers.add(name=layer_name)
|
||||
except Exception:
|
||||
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:
|
||||
error_msg = f"Keine gültige Geometrie in {filename}"
|
||||
if logger:
|
||||
@@ -136,7 +140,7 @@ def create_block_library(input_dir, output_file, config, logger=None):
|
||||
if name in doc.blocks:
|
||||
doc.blocks.delete_block(name)
|
||||
|
||||
blk = doc.blocks.new(name=name, base_point=(0,0))
|
||||
blk = doc.blocks.new(name=name, base_point=(0, 0))
|
||||
|
||||
for e in entities:
|
||||
cp = copy_entity(logger, error_files, filename, e, center)
|
||||
@@ -146,11 +150,10 @@ def create_block_library(input_dir, output_file, config, logger=None):
|
||||
# Platzierung in Reihen und Spalten
|
||||
# Attribut-Definition (ATTDEF) hinzufügen
|
||||
|
||||
|
||||
# Blockreferenz-Layer bestimmen
|
||||
# Blockreferenz-Layer bestimmen
|
||||
blockref_layer = None
|
||||
try:
|
||||
#Konfiguration erlaubt expliziten Layernamen
|
||||
# Konfiguration erlaubt expliziten Layernamen
|
||||
cfg_layer = None
|
||||
try:
|
||||
cfg_layer = config.get("dxf2lib", "blockref_layer")
|
||||
@@ -186,42 +189,59 @@ def create_block_library(input_dir, output_file, config, logger=None):
|
||||
blockref_layer = None
|
||||
section = "dxf2lib"
|
||||
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"])
|
||||
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"])
|
||||
extra_block_space_x = get_cfg_value(
|
||||
section, "extra_block_space_x", DEFAULTS["extra_block_space_x"]
|
||||
)
|
||||
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]
|
||||
|
||||
|
||||
block_spacing_y = ausdehung_y + 400
|
||||
block_spacing_x = ausdehnung_x + extra_block_space_x
|
||||
max_blockspacing_x = max(max_blockspacing_x, block_spacing_x)
|
||||
max_blockspacing_y = max(max_blockspacing_y, block_spacing_y)
|
||||
x_offset += max_blockspacing_x
|
||||
max_blockspacing_x = max(max_blockspacing_x, block_spacing_x)
|
||||
max_blockspacing_y = max(max_blockspacing_y, block_spacing_y)
|
||||
x_offset += max_blockspacing_x
|
||||
# Blockreferenz mit optionalem Layer einfügen (Entity-Layer bleiben erhalten)
|
||||
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:
|
||||
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
|
||||
if name == "a" or name == "b":
|
||||
for tag, value in att_def.items():
|
||||
|
||||
tag = tag
|
||||
value = value
|
||||
a =test.add_attrib(
|
||||
a = test.add_attrib(
|
||||
tag=tag,
|
||||
text=value,
|
||||
)
|
||||
a.is_invisible = True
|
||||
# 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)
|
||||
blocks_in_row += 1
|
||||
# Abstand zwischen Blöcken in einer Reihe
|
||||
# Abstand zwischen Blöcken in einer Reihe
|
||||
if blocks_in_row == blocks_per_row:
|
||||
|
||||
|
||||
blocks_in_row = 0
|
||||
x_offset = 0
|
||||
y_offset -= max_blockspacing_y # Neue Zeile, nach unten versetzt
|
||||
@@ -232,9 +252,11 @@ def create_block_library(input_dir, output_file, config, logger=None):
|
||||
logger.info(f"Bibliotheks-DXF gespeichert: {output_file}")
|
||||
logger.info(f"Verarbeitete Dateien: {len(processed_files)}")
|
||||
logger.info(f"Fehlerhafte Dateien: {len(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:
|
||||
logger.error(f"{filename}: {error_msg}")
|
||||
else:
|
||||
@@ -243,9 +265,11 @@ def create_block_library(input_dir, output_file, config, logger=None):
|
||||
print(f"Bibliotheks-DXF gespeichert: {output_file}")
|
||||
print(f"Verarbeitete Dateien: {len(processed_files)}")
|
||||
print(f"Fehlerhafte Dateien: {len(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
|
||||
if not output_dir.exists():
|
||||
@@ -267,24 +291,26 @@ def copy_entity(logger, error_files, filename, e, center):
|
||||
return cp
|
||||
|
||||
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:
|
||||
logger.error(error_msg)
|
||||
else:
|
||||
print(error_msg)
|
||||
error_files.append((filename, error_msg))
|
||||
return None
|
||||
|
||||
|
||||
|
||||
# Standardwerte (falls nicht in der Config)
|
||||
DEFAULTS = {
|
||||
"text_height": 20, # Schriftgröße des Texts (in DXF-Einheiten)
|
||||
"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_text_space_y" : 50 # Abstand der Überschrift über dem Symbol
|
||||
|
||||
"text_height": 20, # Schriftgröße des Texts (in DXF-Einheiten)
|
||||
"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_text_space_y": 50, # Abstand der Überschrift über dem Symbol
|
||||
}
|
||||
|
||||
|
||||
def get_cfg_value(section, key, fallback):
|
||||
try:
|
||||
return int(config.get(section, key))
|
||||
@@ -292,9 +318,9 @@ def get_cfg_value(section, key, 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
|
||||
INSERTs werden als Referenzen beibehalten (nicht explodiert)
|
||||
@@ -303,57 +329,57 @@ def convert_dxf_to_block_with_inserts(input_filename, output_filename, block_nam
|
||||
# Eingabe-DXF laden
|
||||
input_doc = ezdxf.readfile(input_filename)
|
||||
print(f"Lade DXF-Datei: {input_filename}")
|
||||
|
||||
|
||||
# Neue Ausgabe-DXF erstellen
|
||||
output_doc = ezdxf.new('R2010')
|
||||
output_doc.header['$INSUNITS'] = 4 # Millimeter
|
||||
|
||||
output_doc = ezdxf.new("R2010")
|
||||
output_doc.header["$INSUNITS"] = 4 # Millimeter
|
||||
|
||||
# Zuerst alle Block-Definitionen kopieren
|
||||
copied_blocks = copy_block_definitions(input_doc, output_doc)
|
||||
print(f"Block-Definitionen kopiert: {len(copied_blocks)}")
|
||||
|
||||
|
||||
# Neuen Hauptblock erstellen
|
||||
new_block = output_doc.blocks.new(name=block_name)
|
||||
print(f"Erstelle neuen Block: {block_name}")
|
||||
|
||||
|
||||
# Alle Entities aus dem Modelspace kopieren
|
||||
msp = input_doc.modelspace()
|
||||
entity_count = 0
|
||||
insert_count = 0
|
||||
|
||||
|
||||
for entity in msp:
|
||||
if entity.dxftype() == 'INSERT':
|
||||
if entity.dxftype() == "INSERT":
|
||||
# INSERT direkt kopieren (nicht explodieren)
|
||||
copy_entity_to_block(entity, new_block)
|
||||
insert_count += 1
|
||||
else:
|
||||
# Normale Entity kopieren
|
||||
copy_entity_to_block(entity, new_block)
|
||||
|
||||
|
||||
entity_count += 1
|
||||
|
||||
|
||||
# Bounding Box berechnen
|
||||
bbox = calculate_block_bounding_box(new_block, output_doc)
|
||||
|
||||
|
||||
# Block im Modelspace der neuen Datei platzieren
|
||||
output_msp = output_doc.modelspace()
|
||||
output_msp.add_blockref(block_name, insert=(0, 0))
|
||||
|
||||
|
||||
# Bounding Box als Hilfslinien hinzufügen (optional)
|
||||
if bbox.has_data:
|
||||
add_bounding_box_to_modelspace(output_msp, bbox)
|
||||
|
||||
|
||||
# Speichern
|
||||
output_doc.saveas(output_filename)
|
||||
|
||||
|
||||
print(f"Konvertierung abgeschlossen:")
|
||||
print(f" - {entity_count} Entities übertragen")
|
||||
print(f" - {insert_count} INSERTs als Referenzen beibehalten")
|
||||
print(f" - Bounding Box: {format_bounding_box(bbox)}")
|
||||
print(f" - Ausgabe: {output_filename}")
|
||||
|
||||
|
||||
return bbox
|
||||
|
||||
|
||||
except FileNotFoundError:
|
||||
print(f"Fehler: Datei {input_filename} nicht gefunden")
|
||||
return None
|
||||
@@ -370,48 +396,53 @@ def copy_block_definitions(source_doc, target_doc):
|
||||
Kopiert alle Block-Definitionen vom Quell- zum Ziel-Dokument
|
||||
"""
|
||||
copied_blocks = []
|
||||
|
||||
|
||||
for block_name in source_doc.blocks:
|
||||
# Standard-Blöcke (MODEL_SPACE, PAPER_SPACE) überspringen
|
||||
if block_name.startswith('*'):
|
||||
if block_name.startswith("*"):
|
||||
continue
|
||||
|
||||
|
||||
source_block = source_doc.blocks[block_name]
|
||||
|
||||
|
||||
# Prüfen ob Block bereits existiert
|
||||
if block_name in target_doc.blocks:
|
||||
print(f"Warnung: Block '{block_name}' existiert bereits, wird übersprungen")
|
||||
continue
|
||||
|
||||
|
||||
# Neuen Block in Ziel-Dokument erstellen
|
||||
target_block = target_doc.blocks.new(name=block_name)
|
||||
|
||||
|
||||
# Alle Entities des Quell-Blocks kopieren
|
||||
for entity in source_block:
|
||||
copy_entity_to_block(entity, target_block)
|
||||
|
||||
|
||||
copied_blocks.append(block_name)
|
||||
|
||||
|
||||
return copied_blocks
|
||||
|
||||
|
||||
def calculate_block_bounding_box(block, doc, src_doc, filename,config):
|
||||
def calculate_block_bounding_box(block, doc, src_doc, filename, config):
|
||||
"""
|
||||
Berechnet die Bounding Box eines Blocks inklusive aller INSERTs
|
||||
"""
|
||||
|
||||
|
||||
bbox = BoundingBox()
|
||||
|
||||
|
||||
for entity in block:
|
||||
entity_bbox = get_entity_bounding_box(entity, doc,src_doc,filename,config)
|
||||
entity_bbox = get_entity_bounding_box(entity, doc, src_doc, filename, config)
|
||||
if entity_bbox and entity_bbox.has_data:
|
||||
bbox.extend(entity_bbox)
|
||||
|
||||
|
||||
return bbox, (bbox.extmax.x - bbox.extmin.x, bbox.extmax.y - bbox.extmin.y), bbox.center
|
||||
|
||||
return (
|
||||
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
|
||||
auswertbare Geometrie zu zerlegen und darauf eine Bounding Box zu
|
||||
@@ -432,15 +463,15 @@ def _bbox_from_virtual_entities(entity, doc, src_doc, filename, config, transfor
|
||||
return v_bbox
|
||||
|
||||
|
||||
def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=None):
|
||||
def get_entity_bounding_box(e, doc, src_doc, filename, config, transform_matrix=None):
|
||||
"""
|
||||
Berechnet die Bounding Box einer einzelnen Entity
|
||||
Berücksichtigt INSERTs mit ihren Block-Inhalten
|
||||
"""
|
||||
|
||||
bbox = BoundingBox()
|
||||
bbox = BoundingBox()
|
||||
try:
|
||||
if e.dxftype() == 'LINE':
|
||||
if e.dxftype() == "LINE":
|
||||
start = Vec3(e.dxf.start)
|
||||
end = Vec3(e.dxf.end)
|
||||
if transform_matrix:
|
||||
@@ -448,8 +479,8 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
|
||||
end = transform_matrix.transform(end)
|
||||
bbox.extend([start])
|
||||
bbox.extend([end])
|
||||
|
||||
elif e.dxftype() == 'CIRCLE':
|
||||
|
||||
elif e.dxftype() == "CIRCLE":
|
||||
# Kreis durch Punktabtastung (robust bei Transformationen)
|
||||
center = Vec3(e.dxf.center)
|
||||
radius = float(e.dxf.radius)
|
||||
@@ -464,8 +495,8 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
|
||||
points.append(p)
|
||||
if points:
|
||||
bbox.extend(points)
|
||||
|
||||
elif e.dxftype() == 'ARC':
|
||||
|
||||
elif e.dxftype() == "ARC":
|
||||
# Bogen durch Punktabtastung zwischen Start- und Endwinkel
|
||||
center = Vec3(e.dxf.center)
|
||||
radius = float(e.dxf.radius)
|
||||
@@ -495,16 +526,16 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
|
||||
points.append(p)
|
||||
if points:
|
||||
bbox.extend(points)
|
||||
|
||||
elif e.dxftype() == 'LWPOLYLINE':
|
||||
|
||||
elif e.dxftype() == "LWPOLYLINE":
|
||||
# Nutze virtuelle Entities (Linien/Bögen), inkl. Bulge-Unterstützung
|
||||
ve_bbox = _bbox_from_virtual_entities(
|
||||
e, doc, src_doc, filename, config, transform_matrix
|
||||
)
|
||||
if ve_bbox.has_data:
|
||||
bbox.extend(ve_bbox)
|
||||
|
||||
elif e.dxftype() == 'POLYLINE':
|
||||
|
||||
elif e.dxftype() == "POLYLINE":
|
||||
# 2D/3D Polylines ebenfalls über virtuelle Entities
|
||||
ve_bbox = _bbox_from_virtual_entities(
|
||||
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:
|
||||
bbox.extend(ve_bbox)
|
||||
|
||||
elif e.dxftype() == '3DFACE':
|
||||
elif e.dxftype() == "3DFACE":
|
||||
# 3DFace: direkte Eckpunkte verwenden
|
||||
pts = []
|
||||
try:
|
||||
@@ -527,15 +558,15 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
|
||||
if pts:
|
||||
bbox.extend(pts)
|
||||
|
||||
elif e.dxftype() in {'MESH', 'POLYFACE', 'POLYFACEMESH'}:
|
||||
elif e.dxftype() in {"MESH", "POLYFACE", "POLYFACEMESH"}:
|
||||
# Mesh/Polyface über virtuelle Geometrie auswerten
|
||||
ve_bbox = _bbox_from_virtual_entities(
|
||||
e, doc, src_doc, filename, config, transform_matrix
|
||||
)
|
||||
if ve_bbox.has_data:
|
||||
bbox.extend(ve_bbox)
|
||||
|
||||
elif e.dxftype() == 'SPLINE':
|
||||
|
||||
elif e.dxftype() == "SPLINE":
|
||||
# Approximation der Spline-Kurve
|
||||
try:
|
||||
pts = list(e.approximate(60))
|
||||
@@ -556,19 +587,21 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
|
||||
sampled.append(v)
|
||||
if sampled:
|
||||
bbox.extend(sampled)
|
||||
|
||||
elif e.dxftype() == 'ATTDEF':
|
||||
|
||||
|
||||
elif e.dxftype() == "ATTDEF":
|
||||
|
||||
insert_point = Vec3(e.dxf.insert)
|
||||
if transform_matrix:
|
||||
insert_point = transform_matrix.transform(insert_point)
|
||||
elif e.dxftype() == 'TEXT':
|
||||
elif e.dxftype() == "TEXT":
|
||||
insert_point = Vec3(e.dxf.insert)
|
||||
height = float(getattr(e.dxf, "height", 1.0))
|
||||
width_factor = float(getattr(e.dxf, "width", 1.0))
|
||||
rotation = math.radians(getattr(e.dxf, "rotation", 0.0))
|
||||
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 = [
|
||||
insert_point,
|
||||
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)
|
||||
bbox.extend([pt])
|
||||
|
||||
elif e.dxftype() == 'MTEXT':
|
||||
elif e.dxftype() == "MTEXT":
|
||||
insert_point = Vec3(e.dxf.insert)
|
||||
char_height = float(getattr(e.dxf, "char_height", 1.0))
|
||||
width = float(getattr(e.dxf, "width", 0.0))
|
||||
@@ -610,86 +643,99 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
|
||||
pt = transform_matrix.transform(pt)
|
||||
bbox.extend([pt])
|
||||
|
||||
elif e.dxftype() == 'REGION':
|
||||
elif e.dxftype() == "REGION":
|
||||
# Region: Begrenzungsgeometrie über virtual_entities()
|
||||
ve_bbox = _bbox_from_virtual_entities(
|
||||
e, doc, src_doc, filename, config, transform_matrix
|
||||
)
|
||||
if ve_bbox.has_data:
|
||||
bbox.extend(ve_bbox)
|
||||
|
||||
elif e.dxftype().endswith('SURFACE'):
|
||||
|
||||
elif e.dxftype().endswith("SURFACE"):
|
||||
# Viele Surface-Typen liefern ihre Proxy-Geometrie über virtual_entities()
|
||||
ve_bbox = _bbox_from_virtual_entities(
|
||||
e, doc, src_doc, filename, config, transform_matrix
|
||||
)
|
||||
if ve_bbox.has_data:
|
||||
bbox.extend(ve_bbox)
|
||||
|
||||
elif e.dxftype() == 'INSERT':
|
||||
|
||||
elif e.dxftype() == "INSERT":
|
||||
# INSERT: Block-Inhalt mit Transformation berücksichtigen
|
||||
insert_bbox = calculate_insert_bounding_box(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"):
|
||||
insert_bbox = calculate_insert_bounding_box(
|
||||
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)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
print(f"Fehler bei Bounding Box Berechnung für {e.dxftype()}: {e}")
|
||||
|
||||
|
||||
|
||||
return bbox
|
||||
|
||||
def extract_scaling(matrix):
|
||||
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)
|
||||
return sx, sy,
|
||||
|
||||
def calculate_insert_bounding_box(insert_entity, doc,src_doc,filename,config,parent_transform=None):
|
||||
def extract_scaling(matrix):
|
||||
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)
|
||||
return (
|
||||
sx,
|
||||
sy,
|
||||
)
|
||||
|
||||
|
||||
def calculate_insert_bounding_box(
|
||||
insert_entity, doc, src_doc, filename, config, parent_transform=None
|
||||
):
|
||||
"""
|
||||
Berechnet die Bounding Box eines INSERTs inklusive Block-Inhalt
|
||||
"""
|
||||
|
||||
|
||||
try:
|
||||
# Block-Definition finden
|
||||
# Block-Definition finden
|
||||
block_name = insert_entity.dxf.name
|
||||
src_blk = src_doc.blocks[block_name]
|
||||
|
||||
|
||||
if block_name in doc.blocks:
|
||||
dst_blk = doc.blocks[block_name]
|
||||
|
||||
new_insert = False
|
||||
|
||||
|
||||
else:
|
||||
dst_blk = doc.blocks.new(name=block_name)
|
||||
new_insert = True
|
||||
if block_name not in src_doc.blocks:
|
||||
print(f"Warnung: Block '{block_name}' ")
|
||||
return BoundingBox()
|
||||
|
||||
|
||||
block_def = src_blk
|
||||
|
||||
|
||||
# Transformation der INSERT-Entity berechnen
|
||||
insert_transform = get_insert_transform_matrix(insert_entity)
|
||||
|
||||
|
||||
# Mit übergeordneter Transformation kombinieren
|
||||
if parent_transform:
|
||||
combined_transform = parent_transform * insert_transform
|
||||
else:
|
||||
combined_transform = insert_transform
|
||||
|
||||
|
||||
# Bounding Box aller Entities im Block berechnen
|
||||
block_bbox = BoundingBox()
|
||||
|
||||
|
||||
for block_entity in block_def:
|
||||
|
||||
entity_bbox= get_entity_bounding_box(block_entity, doc,src_doc,filename, config,combined_transform)
|
||||
if entity_bbox and entity_bbox.has_data:
|
||||
if new_insert:
|
||||
dst_blk.add_entity(block_entity.copy())
|
||||
block_bbox.extend(entity_bbox)
|
||||
|
||||
entity_bbox = get_entity_bounding_box(
|
||||
block_entity, doc, src_doc, filename, config, combined_transform
|
||||
)
|
||||
if entity_bbox and entity_bbox.has_data:
|
||||
if new_insert:
|
||||
dst_blk.add_entity(block_entity.copy())
|
||||
block_bbox.extend(entity_bbox)
|
||||
|
||||
return block_bbox
|
||||
|
||||
|
||||
except Exception as e:
|
||||
print(f"Fehler bei INSERT Bounding Box: {e},{filename}")
|
||||
return BoundingBox()
|
||||
@@ -701,22 +747,22 @@ def get_insert_transform_matrix(insert_entity):
|
||||
"""
|
||||
# Position
|
||||
insert_point = Vec3(insert_entity.dxf.insert)
|
||||
|
||||
|
||||
# Skalierung
|
||||
xscale = getattr(insert_entity.dxf, 'xscale', 1.0)
|
||||
yscale = getattr(insert_entity.dxf, 'yscale', 1.0)
|
||||
zscale = getattr(insert_entity.dxf, 'zscale', 1.0)
|
||||
|
||||
xscale = getattr(insert_entity.dxf, "xscale", 1.0)
|
||||
yscale = getattr(insert_entity.dxf, "yscale", 1.0)
|
||||
zscale = getattr(insert_entity.dxf, "zscale", 1.0)
|
||||
|
||||
# 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
|
||||
matrix = Matrix44.chain(
|
||||
Matrix44.scale(xscale, yscale, zscale),
|
||||
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
|
||||
|
||||
|
||||
@@ -728,7 +774,7 @@ def copy_entity_to_block(entity, target_block):
|
||||
# Entity kopieren und zum Block hinzufügen
|
||||
entity_copy = entity.copy()
|
||||
target_block.add_entity(entity_copy)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
print(f"Fehler beim Kopieren von {entity.dxftype()}: {e}")
|
||||
|
||||
@@ -741,13 +787,13 @@ def add_bounding_box_to_modelspace(msp, bbox, centered=False):
|
||||
"""
|
||||
if not bbox.has_data:
|
||||
return
|
||||
|
||||
|
||||
# Bounding Box Rechteck zeichnen
|
||||
min_pt = bbox.extmin
|
||||
max_pt = bbox.extmax
|
||||
width = max_pt.x - min_pt.x
|
||||
height = max_pt.y - min_pt.y
|
||||
|
||||
|
||||
if centered:
|
||||
# Rechteck um (0,0) zentriert
|
||||
left = -width / 2.0
|
||||
@@ -759,11 +805,14 @@ def add_bounding_box_to_modelspace(msp, bbox, centered=False):
|
||||
(right, bottom),
|
||||
(right, top),
|
||||
(left, top),
|
||||
(left, bottom)
|
||||
(left, bottom),
|
||||
]
|
||||
# Roter Punkt in der Mitte
|
||||
msp.add_circle(center=(0.0, 0.0), radius=max(0.5, min(width, height) * 0.01),
|
||||
dxfattribs={"layer": "BOUNDING_BOX", "color": 1})
|
||||
msp.add_circle(
|
||||
center=(0.0, 0.0),
|
||||
radius=max(0.5, min(width, height) * 0.01),
|
||||
dxfattribs={"layer": "BOUNDING_BOX", "color": 1},
|
||||
)
|
||||
else:
|
||||
# Ursprüngliche, nicht-zentrierte Bounding Box
|
||||
bbox_points = [
|
||||
@@ -771,21 +820,31 @@ def add_bounding_box_to_modelspace(msp, bbox, centered=False):
|
||||
(max_pt.x, min_pt.y),
|
||||
(max_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.dxf.layer = "BOUNDING_BOX"
|
||||
bbox_poly.dxf.color = 1 # Rot
|
||||
|
||||
|
||||
# Text mit Abmessungen
|
||||
text_pos = Vec3(bbox_points[0][0], (bbox_points[2][1] if centered else max_pt.y) + 5, 0)
|
||||
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)
|
||||
msp.add_text(f"Höhe: {height:.2f} mm", height=3,
|
||||
dxfattribs={'insert': text_pos2, 'layer': "BOUNDING_BOX", 'color': 1})
|
||||
text_pos = Vec3(
|
||||
bbox_points[0][0], (bbox_points[2][1] if centered else max_pt.y) + 5, 0
|
||||
)
|
||||
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
|
||||
)
|
||||
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):
|
||||
@@ -794,16 +853,18 @@ def format_bounding_box(bbox):
|
||||
"""
|
||||
if not bbox.has_data:
|
||||
return "Keine gültigen Geometriedaten gefunden"
|
||||
|
||||
|
||||
min_pt = bbox.extmin
|
||||
max_pt = bbox.extmax
|
||||
width = max_pt.x - min_pt.x
|
||||
height = max_pt.y - min_pt.y
|
||||
depth = max_pt.z - min_pt.z
|
||||
|
||||
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"Größe: {width:.2f} × {height:.2f} × {depth:.2f} mm")
|
||||
|
||||
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"Größe: {width:.2f} × {height:.2f} × {depth:.2f} mm"
|
||||
)
|
||||
|
||||
|
||||
def analyze_source_dxf_with_blocks(filename):
|
||||
@@ -813,76 +874,88 @@ def analyze_source_dxf_with_blocks(filename):
|
||||
try:
|
||||
doc = ezdxf.readfile(filename)
|
||||
msp = doc.modelspace()
|
||||
|
||||
|
||||
entity_types = {}
|
||||
layer_count = {}
|
||||
insert_blocks = {}
|
||||
block_definitions = {}
|
||||
|
||||
|
||||
# Modelspace analysieren
|
||||
for entity in msp:
|
||||
entity_type = entity.dxftype()
|
||||
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
|
||||
|
||||
if entity_type == 'INSERT':
|
||||
|
||||
if entity_type == "INSERT":
|
||||
block_name = entity.dxf.name
|
||||
insert_blocks[block_name] = insert_blocks.get(block_name, 0) + 1
|
||||
|
||||
|
||||
# Block-Definitionen analysieren
|
||||
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]
|
||||
entity_count = len(list(block_def))
|
||||
block_definitions[block_name] = entity_count
|
||||
|
||||
|
||||
print(f"\nAnalyse von {filename}:")
|
||||
print("=" * 50)
|
||||
print("Entity-Typen im Modelspace:")
|
||||
for etype, count in sorted(entity_types.items()):
|
||||
print(f" {etype}: {count}")
|
||||
|
||||
|
||||
print(f"\nLayer ({len(layer_count)}):")
|
||||
for layer, count in sorted(layer_count.items()):
|
||||
print(f" {layer}: {count} entities")
|
||||
|
||||
|
||||
if insert_blocks:
|
||||
print(f"\nINSERT-Verwendungen ({sum(insert_blocks.values())} total):")
|
||||
for block, count in sorted(insert_blocks.items()):
|
||||
print(f" {block}: {count}× verwendet")
|
||||
|
||||
|
||||
if block_definitions:
|
||||
print(f"\nBlock-Definitionen ({len(block_definitions)}):")
|
||||
for block, count in sorted(block_definitions.items()):
|
||||
print(f" {block}: {count} entities")
|
||||
|
||||
|
||||
return entity_types, layer_count, insert_blocks, block_definitions
|
||||
|
||||
|
||||
except Exception as e:
|
||||
print(f"Fehler bei der Analyse: {e}")
|
||||
return {}, {}, {}, {}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Argumentparser für Kommandozeilenoptionen
|
||||
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('-n', '--name', required=False, type=str, help='Name der zu erzeugenden Bibliothek (optional, wird sonst abgefragt)', default="test")
|
||||
|
||||
parser.add_argument(
|
||||
"-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"):
|
||||
parser.print_help()
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
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:
|
||||
print("Fehler: Kein Name angegeben. Beende.")
|
||||
sys.exit(1)
|
||||
|
||||
# Verzeichnisse über Umgebungsvariablen oder Fallback
|
||||
# Verzeichnisse über Umgebungsvariablen oder Fallback
|
||||
if args.input:
|
||||
INPUT_DIR = Path(args.input)
|
||||
print(f"Verwende Input-Verzeichnis: {INPUT_DIR} \n")
|
||||
@@ -890,7 +963,9 @@ if __name__ == "__main__":
|
||||
INPUT_DIR = check_environment_var("PROJECT_DATA") / "omniflo"
|
||||
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
|
||||
log_dir = check_environment_var("PROJECT_LOG")
|
||||
@@ -899,9 +974,9 @@ if __name__ == "__main__":
|
||||
print(f"Log-Verzeichnis erstellt: {log_dir}")
|
||||
|
||||
# Logger Setup
|
||||
log_file = Path(os.environ['PROJECT_LOG']) / 'dxf2lib.log'
|
||||
file_handler = logging.FileHandler(str(log_file), 'a', 'utf-8')
|
||||
logger = setup_logger(log_dir, name='dxf2lib')
|
||||
log_file = Path(os.environ["PROJECT_LOG"]) / "dxf2lib.log"
|
||||
file_handler = logging.FileHandler(str(log_file), "a", "utf-8")
|
||||
logger = setup_logger(log_dir, name="dxf2lib")
|
||||
logger.info("=== DXF2LIB Verarbeitung gestartet ===")
|
||||
logger.info(f"Input-Verzeichnis: {INPUT_DIR}")
|
||||
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
|
||||
from pathlib import Path
|
||||
|
||||
@@ -7,7 +8,7 @@ def inspect_blocks(dxf_path):
|
||||
print(f"Datei: {dxf_path}")
|
||||
print("Gefundene Blöcke und Attribute:\n")
|
||||
for block in doc.blocks:
|
||||
if block.name.startswith('*'): # Überspringe anonyme/Standardblöcke
|
||||
if block.name.startswith("*"): # Überspringe anonyme/Standardblöcke
|
||||
continue
|
||||
print(f"Block: {block.name}")
|
||||
attribs = [e for e in block if e.dxftype() == "ATTDEF"]
|
||||
@@ -22,4 +23,4 @@ def inspect_blocks(dxf_path):
|
||||
|
||||
if __name__ == "__main__":
|
||||
dxf_file = "data/blocks.dxf"
|
||||
inspect_blocks(dxf_file)
|
||||
inspect_blocks(dxf_file)
|
||||
|
||||
+1172
-437
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
|
||||
svg.path==7.0
|
||||
pydantic>=2.0.0
|
||||
+218
-72
@@ -1,9 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
import difflib
|
||||
from utils import check_environment_var, setup_logger
|
||||
import plant2dxf
|
||||
|
||||
|
||||
class TestDXFGeometry(unittest.TestCase):
|
||||
testordner_path = Path(check_environment_var("PROJECT_TEST"))
|
||||
lib_path = Path(check_environment_var("PROJECT_DATA"))
|
||||
@@ -12,8 +14,26 @@ class TestDXFGeometry(unittest.TestCase):
|
||||
default_lib_path = lib_path / "blocks.dxf"
|
||||
cfg_path = config_dir / "shapes.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):
|
||||
"""
|
||||
@@ -39,125 +59,251 @@ class TestDXFGeometry(unittest.TestCase):
|
||||
geom1 = self.extract_geometry_lines(file1)
|
||||
geom2 = self.extract_geometry_lines(file2)
|
||||
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}")
|
||||
|
||||
def test_omniflobogen_dxf_file(self):
|
||||
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_jason = self.work_dir / f"{omniflo_bogen}.jason"
|
||||
omniflo_bogen_output = self.work_dir / 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)
|
||||
omniflo_bogen_json = self.work_dir / f"{omniflo_bogen}.json"
|
||||
omniflo_bogen_output = self.work_dir / 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_json,
|
||||
)
|
||||
self.assert_dxf_geometry_equal(omniflo_bogen_output, omniflo_bogen_reference)
|
||||
|
||||
|
||||
def test_weiche_90_dxf_file(self):
|
||||
weiche_90= "weiche_90"
|
||||
weiche_90_csv = self.testordner_path / f"{weiche_90}.csv"
|
||||
weiche_90 = "weiche_90"
|
||||
weiche_90_csv = self.testordner_path / f"{weiche_90}.csv"
|
||||
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_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)
|
||||
|
||||
def test_weiche_45_simple_dxf_file(self):
|
||||
weiche_45_simple= "weiche_45_simple"
|
||||
weiche_45_simple_csv = self.testordner_path / f"{weiche_45_simple}.csv"
|
||||
weiche_45_simple = "weiche_45_simple"
|
||||
weiche_45_simple_csv = self.testordner_path / f"{weiche_45_simple}.csv"
|
||||
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_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)
|
||||
self.assert_dxf_geometry_equal(weiche_45_simple_output, weiche_45_simple_reference)
|
||||
plant2dxf.main(
|
||||
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):
|
||||
weiche_45_doppel= "weiche_45_doppel"
|
||||
weiche_45_doppel_csv = self.testordner_path / f"{weiche_45_doppel}.csv"
|
||||
weiche_45_doppel = "weiche_45_doppel"
|
||||
weiche_45_doppel_csv = self.testordner_path / f"{weiche_45_doppel}.csv"
|
||||
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_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)
|
||||
self.assert_dxf_geometry_equal(weiche_45_doppel_output, weiche_45_doppel_reference)
|
||||
plant2dxf.main(
|
||||
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):
|
||||
weiche_45_dreiwege= "weiche_45_dreiwege"
|
||||
weiche_45_dreiwege_csv = self.testordner_path / f"{weiche_45_dreiwege}.csv"
|
||||
weiche_45_dreiwege = "weiche_45_dreiwege"
|
||||
weiche_45_dreiwege_csv = self.testordner_path / f"{weiche_45_dreiwege}.csv"
|
||||
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_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)
|
||||
self.assert_dxf_geometry_equal(weiche_45_dreiwege_output, weiche_45_dreiwege_reference)
|
||||
plant2dxf.main(
|
||||
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):
|
||||
weichenkoerper= "weichenkoerper"
|
||||
weichenkoerper_csv = self.testordner_path / f"{weichenkoerper}.csv"
|
||||
weichenkoerper = "weichenkoerper"
|
||||
weichenkoerper_csv = self.testordner_path / f"{weichenkoerper}.csv"
|
||||
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_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)
|
||||
|
||||
def test_weichenkombination_dxf_file(self):
|
||||
weichenkombination= "weichenkombination"
|
||||
weichenkombination_csv = self.testordner_path / f"{weichenkombination}.csv"
|
||||
weichenkombination = "weichenkombination"
|
||||
weichenkombination_csv = self.testordner_path / f"{weichenkombination}.csv"
|
||||
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_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)
|
||||
self.assert_dxf_geometry_equal(weichenkombination_output, weichenkombination_reference)
|
||||
|
||||
plant2dxf.main(
|
||||
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):
|
||||
gefaelle= "gefaelle"
|
||||
gefaelle_csv = self.testordner_path / f"{gefaelle}.csv"
|
||||
gefaelle = "gefaelle"
|
||||
gefaelle_csv = self.testordner_path / f"{gefaelle}.csv"
|
||||
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_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)
|
||||
self.assert_dxf_geometry_equal(weichenkombination_output, weichenkombination_reference)
|
||||
plant2dxf.main(
|
||||
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):
|
||||
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_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_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_jason)
|
||||
self.assert_dxf_geometry_equal(gefaelle_ausnahme_gleiche_orientierung_output, gefaelle_ausnahme_gleiche_orientierung_reference)
|
||||
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_dxf = (
|
||||
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):
|
||||
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_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_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_jason)
|
||||
self.assert_dxf_geometry_equal(gefaelle_ausnahme_unterschiedlich_orientierung_output, gefaelle_ausnahme_unterschiedlich_orientierung_reference)
|
||||
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_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):
|
||||
gefaelle_einzeln_verbunden= "gefaelle_einzeln_verbunden"
|
||||
gefaelle_einzeln_verbunden_csv = self.testordner_path / f"{gefaelle_einzeln_verbunden}.csv"
|
||||
gefaelle_einzeln_verbunden = "gefaelle_einzeln_verbunden"
|
||||
gefaelle_einzeln_verbunden_csv = (
|
||||
self.testordner_path / f"{gefaelle_einzeln_verbunden}.csv"
|
||||
)
|
||||
gefaelle_einzeln_verbunden_dxf = f"{gefaelle_einzeln_verbunden}.dxf"
|
||||
gefaelle_einzeln_verbunden_jason = self.work_dir /f"{gefaelle_einzeln_verbunden}.jason"
|
||||
gefaelle_einzeln_verbunden_output = 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_jason)
|
||||
self.assert_dxf_geometry_equal(gefaelle_einzeln_verbunden_output, gefaelle_einzeln_verbunden_reference)
|
||||
|
||||
|
||||
|
||||
gefaelle_einzeln_verbunden_json = (
|
||||
self.work_dir / f"{gefaelle_einzeln_verbunden}.json"
|
||||
)
|
||||
gefaelle_einzeln_verbunden_output = (
|
||||
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__":
|
||||
unittest.main()
|
||||
|
||||
|
||||
|
||||
+7
-5
@@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
@@ -14,11 +15,11 @@ def check_environment_var(env_str: str) -> Path:
|
||||
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.
|
||||
Die Logdatei erhält einen Zeitstempel im Namen und ist UTF-8 kodiert.
|
||||
|
||||
|
||||
Args:
|
||||
log_dir (Path): Verzeichnis für die Log-Dateien
|
||||
name (str): Name des Loggers (z.B. 'plant2dxf', 'dxf2lib')
|
||||
@@ -26,6 +27,7 @@ def setup_logger(log_dir: Path, name: str = 'app') -> logging.Logger:
|
||||
logging.Logger: Konfigurierter Logger
|
||||
"""
|
||||
from datetime import datetime
|
||||
|
||||
logger = logging.getLogger(name)
|
||||
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
|
||||
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)
|
||||
|
||||
# Handler für die Konsole
|
||||
@@ -46,11 +48,11 @@ def setup_logger(log_dir: Path, name: str = 'app') -> logging.Logger:
|
||||
console_handler.setLevel(logging.INFO)
|
||||
|
||||
# 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)
|
||||
console_handler.setFormatter(formatter)
|
||||
|
||||
# Handler dem Logger hinzufügen
|
||||
logger.addHandler(file_handler)
|
||||
logger.addHandler(console_handler)
|
||||
return logger
|
||||
return logger
|
||||
|
||||
@@ -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
+12414
-6692
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
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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"}
|
||||
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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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 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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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 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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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 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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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 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_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_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_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_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_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_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_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