Bogen und Weiche nocheinmal dazu
This commit is contained in:
+5
-5
@@ -6,8 +6,8 @@ rot_symb1 = 0.0
|
|||||||
rot_symb2 = 0.0
|
rot_symb2 = 0.0
|
||||||
|
|
||||||
[ILS 2.0 Gefällestrecke]
|
[ILS 2.0 Gefällestrecke]
|
||||||
items = AE DS, EE DS
|
items = EE DS, AE DS
|
||||||
offset_symb1 = 0,0
|
offset_symb1 = 0,-330
|
||||||
offset_symb2 = 0,0
|
offset_symb2 = 0,1000
|
||||||
rot_symb1 = 90.0
|
rot_symb1 = 0.0
|
||||||
rot_symb2 = 90.0
|
rot_symb2 = 0.0
|
||||||
+1491
-1493
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,141 @@
|
|||||||
|
# Dokumentation: plant2dxf
|
||||||
|
|
||||||
|
## Übersicht
|
||||||
|
|
||||||
|
Das Skript `plant2dxf.py` dient dazu, aus einer RuleDesigner-CSV-Datei DXF-Elemente zu erzeugen. Es werden verschiedene Anlagenkomponenten anhand ihrer Typen (TeileArt) erkannt und als Blöcke in eine DXF-Zeichnung eingefügt. Je nach TeileArt werden die Elemente komplett neu erzeugt oder (teilweise) aus einer "Bibliotheks-dxf" kopiert. Die Konfiguration der Blöcke erfolgt über eine separate Konfigurationsdatei (`shapes.cfg`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Funktionsweise
|
||||||
|
|
||||||
|
1. **CSV-Einlesen:**
|
||||||
|
Das Skript liest eine CSV-Datei ein, in der für jede Anlagenkomponente u.a. Typ, ID, Planquadrat (Koordinaten) und optionale Merkmale angegeben sind.
|
||||||
|
|
||||||
|
2. **Konfiguration:**
|
||||||
|
Über die Datei `shapes.cfg` werden für jede TeileArt die zu verwendenden Blöcke, deren Offsets und Rotationen definiert.
|
||||||
|
|
||||||
|
3. **Blockplatzierung:**
|
||||||
|
Für jede Zeile der CSV wird anhand der TeileArt die passende Platzierungsroutine aufgerufen. Die Blöcke werden an die berechnete Position (transformiert ins DXF-Koordinatensystem) gesetzt. Je nach Teileart findet neben der Platzierung von Blöcken die Erzeugung zusätzlicher Elemente (z.B. Linien) statt.
|
||||||
|
|
||||||
|
4. **DXF-Ausgabe:**
|
||||||
|
Am Ende wird die generierte DXF-Datei unter dem Dateinamen der Eingabedatei gespeichert.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Aufruf
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python plant2dxf.py -f <input.csv> [-c <shapes.cfg>] [-l <bibliothek.dxf>] [-o <anlage.dxf>] [-v]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Argumente
|
||||||
|
|
||||||
|
- `-f, --file`
|
||||||
|
**(erforderlich)** Pfad zur Eingabe-CSV-Datei.
|
||||||
|
|
||||||
|
- `-c, --config`
|
||||||
|
Pfad zur Konfigurationsdatei mit Blockdefinitionen (Standard: `shapes.cfg` im PROJECT_CFG-Verzeichnis).
|
||||||
|
|
||||||
|
- `-l, --lib`
|
||||||
|
Pfad zur DXF-Bibliothek mit Blockdefinitionen (Standard: `blocks.dxf` im PROJECT_DATA-Verzeichnis).
|
||||||
|
|
||||||
|
- `-o, --output`
|
||||||
|
Pfad zur Ausgabedatei (Standard: `<inputname>.dxf` im PROJECT_WORK-Verzeichnis).
|
||||||
|
|
||||||
|
- `-v, --verbose`
|
||||||
|
Zeigt zusätzliche Ausgaben an.
|
||||||
|
|
||||||
|
### Umgebungsvariablen
|
||||||
|
|
||||||
|
- `PROJECT_DATA` – Verzeichnis für Bibliotheksdateien
|
||||||
|
- `PROJECT_WORK` – Arbeitsverzeichnis (z.B. für CSV und Ausgabedateien)
|
||||||
|
- `PROJECT_CFG` – Verzeichnis für Konfigurationsdateien
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Aufbau der CSV-Datei
|
||||||
|
|
||||||
|
Die CSV-Datei muss folgende Spalten enthalten:
|
||||||
|
|
||||||
|
- `TeileArt` – Typ der Komponente (z.B. "ILS 2.0 Kreisel")
|
||||||
|
- `TeileId` – Eindeutige ID der Komponente
|
||||||
|
- `Planquadrat` – Koordinaten im Format `X:<Wert> Y:<Wert>` (Beachte: Koordinaten hier sind "Bildschirmkoordinaten", d.h. 0/0 in der linken oberen Ecke. Transformation auf Normalkoordinaten findet im Skript statt.)
|
||||||
|
- `Merkmale` – (optional) JSON-String mit weiteren Eigenschaften
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
|
||||||
|
```csv
|
||||||
|
TeileArt;TeileId;Planquadrat;Merkmale
|
||||||
|
ILS 2.0 Kreisel;K1;X:1000 Y:2000;{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "20", "Drehung": "45"}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Aufbau der shapes.cfg
|
||||||
|
|
||||||
|
Die Datei `shapes.cfg` definiert für jede TeileArt die zu verwendenden Blöcke aus der Bibliotheks-dxf und deren Eigenschaften. Über die Offsets bzw. die Rotationen können die Blockursprünge auf die tatsächlichen Platzierungskoordinaten angepasst werden. Die Keys (Überschriften) **müssen** exakt den Bezeichner "TeileArt" der Eingabe-dxf entsprechen!
|
||||||
|
|
||||||
|
### Beispiel
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[ILS 2.0 Kreisel]
|
||||||
|
items = SP8, AN8
|
||||||
|
offset_symb1 = 0,0
|
||||||
|
offset_symb2 = 0,0
|
||||||
|
rot_symb1 = 0.0
|
||||||
|
rot_symb2 = 0.0
|
||||||
|
|
||||||
|
[ILS 2.0 Gefällestrecke]
|
||||||
|
items = EE DS, AE DS
|
||||||
|
offset_symb1 = 0,-330
|
||||||
|
offset_symb2 = 0,1000
|
||||||
|
rot_symb1 = 0.0
|
||||||
|
rot_symb2 = 0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Erklärung der Parameter
|
||||||
|
|
||||||
|
- **[TeileArt]**
|
||||||
|
Abschnittsname entspricht **exakt** dem Wert aus der CSV-Spalte `TeileArt`.
|
||||||
|
|
||||||
|
- **items**
|
||||||
|
Kommagetrennte Liste der Blocknamen, die für diese TeileArt verwendet werden.
|
||||||
|
|
||||||
|
- **offset_symbX**
|
||||||
|
Offset (in mm) für den X-ten Block relativ zur berechneten Position, Format: `x,y`.
|
||||||
|
|
||||||
|
- **rot_symbX**
|
||||||
|
Rotation (in Grad °) für den X-ten Block.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Erweiterbarkeit
|
||||||
|
|
||||||
|
- Neue TeileArten können durch Hinzufügen eines neuen Abschnitts in `shapes.cfg` und ggf. einer neuen Handler-Funktion im Skript (`handle_<teileart>`) ergänzt werden.
|
||||||
|
- Die Handler-Funktion muss nach dem Schema `handle_<teileart>` benannt werden (Sonderzeichen werden ersetzt, siehe Funktion `normalize_func_name`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Beispielablauf
|
||||||
|
|
||||||
|
1. **CSV und Konfiguration vorbereiten**
|
||||||
|
2. **Skript mit passenden Parametern aufrufen**
|
||||||
|
3. **DXF-Datei wird im Zielverzeichnis erzeugt**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
|
||||||
|
- Python 3.x
|
||||||
|
- [ezdxf](https://ezdxf.mozman.at/) (DXF-Bibliothek)
|
||||||
|
- Standardbibliotheken: os, sys, csv, json, re, argparse, configparser, math, pathlib
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Hinweise
|
||||||
|
|
||||||
|
- Die Blockbibliothek (`blocks.dxf`) ist optional, wird aber für komplexe Blöcke benötigt.
|
||||||
|
- Fehlerhafte oder fehlende Koordinaten/Merkmale werden übersprungen und als Warnung ausgegeben.
|
||||||
|
- Die Transformation der Koordinaten erfolgt so, dass (0,0) im DXF unten links ist.
|
||||||
|
|
||||||
|
---
|
||||||
+46
-2
@@ -1,8 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
placeblocks.py
|
placeblocks.py
|
||||||
Erzeugt DXF-Elemente aus einer RuleDesigner-CSV.
|
Erzeugt DXF-Elemente aus einer RuleDesigner-CSV.
|
||||||
Einfache Formen (z.B. "ILS 2.0 Kreisel") werden direkt konstruiert,
|
|
||||||
komplexe per Blockreferenz aus einer DXF-Bibliothek eingefügt.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@@ -145,6 +143,7 @@ def handle_ils_2_0_kreisel(msp, teileid, merkmale, x, y, doc, lib_doc, verbose,
|
|||||||
f"({pos[0]:.1f}, {pos[1]:.1f}), rot={rotation}")
|
f"({pos[0]:.1f}, {pos[1]:.1f}), rot={rotation}")
|
||||||
# Linien zeichnen
|
# Linien zeichnen
|
||||||
draw_kreisel_lines(msp, pos1, pos2)
|
draw_kreisel_lines(msp, pos1, pos2)
|
||||||
|
draw_kreisel_drehrichtung_markierung(msp, pos1, pos2, merkmale, lib_doc, doc, verbose)
|
||||||
|
|
||||||
def draw_kreisel_lines(msp, pos1, pos2):
|
def draw_kreisel_lines(msp, pos1, pos2):
|
||||||
"""Zeichnet tangentiale Linien zwischen zwei Kreiselblöcken, unabhängig vom Winkel."""
|
"""Zeichnet tangentiale Linien zwischen zwei Kreiselblöcken, unabhängig vom Winkel."""
|
||||||
@@ -169,6 +168,51 @@ def draw_kreisel_lines(msp, pos1, pos2):
|
|||||||
msp.add_line(p1a, p2a)
|
msp.add_line(p1a, p2a)
|
||||||
msp.add_line(p1b, p2b)
|
msp.add_line(p1b, p2b)
|
||||||
|
|
||||||
|
def draw_kreisel_drehrichtung_markierung(msp, pos1, pos2, merkmale, lib_doc, doc, verbose):
|
||||||
|
drehrichtung = merkmale.get("Drehrichtung", "").upper()
|
||||||
|
if drehrichtung not in ("UZS", "GUZS"):
|
||||||
|
return
|
||||||
|
x1, y1 = pos1
|
||||||
|
x2, y2 = pos2
|
||||||
|
dx = x2 - x1
|
||||||
|
dy = y2 - y1
|
||||||
|
length = math.hypot(dx, dy)
|
||||||
|
if length == 0:
|
||||||
|
return
|
||||||
|
# Normalenvektor (senkrecht, normiert, Länge = RADIUS)
|
||||||
|
nx = -dy / length * RADIUS
|
||||||
|
ny = dx / length * RADIUS
|
||||||
|
# Obere Linie
|
||||||
|
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)
|
||||||
|
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":
|
||||||
|
rotation += 180
|
||||||
|
import_block("S-LP", lib_doc, doc)
|
||||||
|
bref = msp.add_blockref("S-LP", (px, py), dxfattribs={"rotation": rotation})
|
||||||
|
if verbose:
|
||||||
|
print(f"[INFO] Drehrichtung '{drehrichtung}': S-LP 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
|
||||||
|
import_block("S-LP", lib_doc, doc)
|
||||||
|
bref = msp.add_blockref("S-LP", (px, py), dxfattribs={"rotation": rotation})
|
||||||
|
if verbose:
|
||||||
|
print(f"[INFO] Drehrichtung '{drehrichtung}': S-LP unten bei ({px:.1f}, {py:.1f}), rot={rotation:.1f}")
|
||||||
|
|
||||||
def handle_standard(msp, blocknames, teileid, x, y, lib_doc, doc, verbose):
|
def handle_standard(msp, blocknames, teileid, x, y, lib_doc, doc, verbose):
|
||||||
for blockname in blocknames:
|
for blockname in blocknames:
|
||||||
import_block(blockname, lib_doc, doc)
|
import_block(blockname, lib_doc, doc)
|
||||||
|
|||||||
Reference in New Issue
Block a user