Doku zum Programm zum setzen des Einfügepunktes
This commit is contained in:
+116
@@ -0,0 +1,116 @@
|
|||||||
|
# set_einfuegepunkt
|
||||||
|
|
||||||
|
Setzt den Einfuegepunkt (`$INSBASE`) von Omniflo DXF-Dateien anhand geometrischer Kriterien.
|
||||||
|
|
||||||
|
## Aufruf
|
||||||
|
|
||||||
|
```
|
||||||
|
bin\set_einfuegepunkt.bat [--schalter] [--number SIVASNR]
|
||||||
|
```
|
||||||
|
|
||||||
|
Das Batch-Skript ruft `setenv.bat` auf und startet `lib/set_einfuegepkt.py` mit den uebergebenen Argumenten.
|
||||||
|
|
||||||
|
## Datenquellen
|
||||||
|
|
||||||
|
| Pfad | Inhalt |
|
||||||
|
|---|---|
|
||||||
|
| `data/json/omniflo_boegen.json` | Liste aller Boegen mit Sivasnr, ProfilTyp, Radius, KurvenWinkel etc. |
|
||||||
|
| `data/json/omniflo_weichen.json` | Liste aller Weichen mit Sivasnr, ProfilTyp, WeichenTyp, KurvenWinkel etc. |
|
||||||
|
| `data/omniflo/*.dxf` | Die DXF-Quelldateien (je Sivasnr eine Datei) |
|
||||||
|
|
||||||
|
Die JSON-Dateien liefern die IDs (Sivasnr) und Metadaten zur Filterung. Die DXF-Dateien enthalten die Geometrie (Linien, Boegen), aus der der Einfuegepunkt berechnet wird.
|
||||||
|
|
||||||
|
## Ablauf
|
||||||
|
|
||||||
|
1. JSON-Datei einlesen und nach Schalter-Kriterien filtern
|
||||||
|
2. Fuer jede gefilterte Sivasnr die DXF-Datei aus `data/omniflo/` laden
|
||||||
|
3. Einfuegepunkt gemaess Typ-Kriterium geometrisch berechnen
|
||||||
|
4. `$INSBASE` im DXF-Header setzen und Datei nach `results/` speichern
|
||||||
|
|
||||||
|
## Schalter
|
||||||
|
|
||||||
|
### --boegen
|
||||||
|
|
||||||
|
Alle Eintraege aus `omniflo_boegen.json` (27 Items, KurvenWinkel 22.5/45/67.5/90/180).
|
||||||
|
|
||||||
|
**Kriterium:** Schnittpunkt der Tangenten am Anfangs- und Endpunkt der Bogenkurve. Bei 180-Grad-Boegen wird der Mittelpunkt zwischen Start und Ende verwendet.
|
||||||
|
|
||||||
|
### --weichen45
|
||||||
|
|
||||||
|
Einzel-, Doppel- und Dreiwegeweichen mit KurvenWinkel 45 (32 Items).
|
||||||
|
|
||||||
|
**Kriterium:** Schnittpunkt der laengsten vertikalen Linie mit der Tangente am oberen Bogenpunkt. Bei mehreren Boegen wird der mit dem hoechsten Y-Wert gewaehlt.
|
||||||
|
|
||||||
|
### --weichen90
|
||||||
|
|
||||||
|
Einzel-, Doppel- und Dreiwegeweichen mit KurvenWinkel 90 (24 Items).
|
||||||
|
|
||||||
|
**Kriterium:** Wie `--weichen45`.
|
||||||
|
|
||||||
|
### --weichenkoerper
|
||||||
|
|
||||||
|
Alle Weichen mit KurvenWinkel 22.5 (8 Items: Einzel-/Doppel-/Dreiwegeweiche).
|
||||||
|
|
||||||
|
**Kriterium:** Schnittpunkt der laengsten Diagonale mit der laengsten vertikalen Linie (Konvergenzpunkt aller Linien).
|
||||||
|
|
||||||
|
### --weichen-parallel
|
||||||
|
|
||||||
|
Einzel-, Doppel- und Dreiwegeweichen mit KurvenWinkel 0, ohne Sternweiche (8 Items).
|
||||||
|
|
||||||
|
**Kriterium:** Wie `--weichenkoerper`.
|
||||||
|
|
||||||
|
### --delta
|
||||||
|
|
||||||
|
Deltaweichen (1 Item).
|
||||||
|
|
||||||
|
**Kriterium:** Mittelpunkt der laengsten horizontalen Linie.
|
||||||
|
|
||||||
|
### --dreifachweiche
|
||||||
|
|
||||||
|
Dreifachweichen (6 Items).
|
||||||
|
|
||||||
|
**Kriterium:** Mittelpunkt der laengsten horizontalen Linie.
|
||||||
|
|
||||||
|
### --sternweiche
|
||||||
|
|
||||||
|
Sternweiche (1 Item).
|
||||||
|
|
||||||
|
**Kriterium:** Zentrum, berechnet als Mittelpunkt der laengsten horizontalen Linie (entspricht dem Schnittpunkt der horizontalen und vertikalen Mittelachse).
|
||||||
|
|
||||||
|
### --number SIVASNR
|
||||||
|
|
||||||
|
Optionaler Filter: nur die angegebene 9-stellige Sivasnr verarbeiten. Kombinierbar mit jedem Typ-Schalter.
|
||||||
|
|
||||||
|
### --show-omniflo
|
||||||
|
|
||||||
|
Erzeugt eine Uebersichts-DXF (`results/omniflo_uebersicht.dxf`) mit allen Omniflo-Elementen. Die Elemente werden in Reihen nach Typ gruppiert angezeigt. Jedes Element erhaelt:
|
||||||
|
- Den Dateinamen als Beschriftung oberhalb
|
||||||
|
- Ein rotes Kreuz am Einfuegepunkt
|
||||||
|
- Eine blaue Linie vom Einfuegepunkt zum tiefsten Punkt des Elements
|
||||||
|
|
||||||
|
## Abdeckung
|
||||||
|
|
||||||
|
Alle 107 Items (27 Boegen + 80 Weichen) sind exklusiv genau einem Schalter zugeordnet. Keine Ueberlappungen, keine Luecken.
|
||||||
|
|
||||||
|
## Uebersicht aller Schalter
|
||||||
|
|
||||||
|
| Schalter | Items | WeichenTyp | KurvenWinkel | Einfuegepunkt-Kriterium |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| `--boegen` | 27 | - | 22.5, 45, 67.5, 90, 180 | Tangentenschnittpunkt am Bogen (180: Mittelpunkt) |
|
||||||
|
| `--weichen45` | 32 | Einzel-, Doppel-, Dreiwegeweiche | 45 | Tangente oberer Bogenpunkt x laengste Vertikale |
|
||||||
|
| `--weichen90` | 24 | Einzel-, Doppel-, Dreiwegeweiche | 90 | Tangente oberer Bogenpunkt x laengste Vertikale |
|
||||||
|
| `--weichenkoerper` | 8 | Einzel-, Doppel-, Dreiwegeweiche | 22.5 | Laengste Diagonale x laengste Vertikale |
|
||||||
|
| `--weichen-parallel` | 8 | Einzel-, Doppel-, Dreiwegeweiche | 0 | Laengste Diagonale x laengste Vertikale |
|
||||||
|
| `--dreifachweiche` | 6 | Dreifachweiche | 90 | Mittelpunkt laengste Horizontale |
|
||||||
|
| `--delta` | 1 | Deltaweiche | 90 | Mittelpunkt laengste Horizontale |
|
||||||
|
| `--sternweiche` | 1 | Sternweiche | 0 | Zentrum (Mittelpunkt laengste Horizontale) |
|
||||||
|
| **Gesamt** | **107** | | | |
|
||||||
|
|
||||||
|
## Umgebungsvariablen
|
||||||
|
|
||||||
|
Werden durch `bin/setenv.bat` gesetzt:
|
||||||
|
|
||||||
|
| Variable | Verwendung |
|
||||||
|
|---|---|
|
||||||
|
| `DXFM_DATA` | Pfad zu `data/` (JSON + DXF Quelldateien) |
|
||||||
|
| `DXFM_RESULTS` | Pfad zu `results/` (Ausgabe) |
|
||||||
+429
-81
@@ -1,11 +1,26 @@
|
|||||||
"""
|
"""
|
||||||
Setzt den Einfuegepunkt ($INSBASE) von Omniflo DXF-Dateien.
|
Setzt den Einfuegepunkt ($INSBASE) von Omniflo DXF-Dateien.
|
||||||
|
|
||||||
Mit --boegen: Einfuegepunkt auf den Schnittpunkt der Tangenten
|
Kriterien je Typ:
|
||||||
am Anfangs- und Endpunkt der Bogenkurve.
|
|
||||||
|
|
||||||
Mit --weichen45 / --weichen90: Einfuegepunkt auf den Schnittpunkt
|
--boegen Schnittpunkt der Tangenten am Anfangs- und Endpunkt
|
||||||
der laengsten vertikalen Linie und des Endpunktes der Bogenkurve.
|
der Bogenkurve (bei 180-Grad: Mittelpunkt).
|
||||||
|
|
||||||
|
--weichen45 Schnittpunkt der laengsten vertikalen Linie mit einer
|
||||||
|
--weichen90 Horizontalen durch den Endpunkt der Bogenkurve.
|
||||||
|
|
||||||
|
--weichenkoerper Schnittpunkt der laengsten Diagonale mit der laengsten
|
||||||
|
vertikalen Linie (Konvergenzpunkt aller Linien).
|
||||||
|
|
||||||
|
--weichen-parallel Wie --weichenkoerper: Schnittpunkt der laengsten
|
||||||
|
Diagonale mit der laengsten vertikalen Linie.
|
||||||
|
|
||||||
|
--delta Mittelpunkt der laengsten horizontalen Linie.
|
||||||
|
--dreifachweiche Mittelpunkt der laengsten horizontalen Linie.
|
||||||
|
--sternweiche Zentrum: Mittelpunkt der laengsten horizontalen Linie.
|
||||||
|
|
||||||
|
--number SIVASNR Nur diese eine 9-stellige Sivasnr verarbeiten.
|
||||||
|
--show-omniflo Uebersichts-DXF mit allen Elementen erzeugen.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -15,8 +30,14 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
import ezdxf
|
import ezdxf
|
||||||
|
from ezdxf import bbox as ezdxf_bbox
|
||||||
|
from ezdxf.addons.importer import Importer
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Geometrie-Hilfsfunktionen
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def find_arc(doc):
|
def find_arc(doc):
|
||||||
"""Findet die erste ARC-Entity im Modelspace."""
|
"""Findet die erste ARC-Entity im Modelspace."""
|
||||||
msp = doc.modelspace()
|
msp = doc.modelspace()
|
||||||
@@ -35,23 +56,19 @@ def tangent_intersection(arc):
|
|||||||
a_start = math.radians(arc.dxf.start_angle)
|
a_start = math.radians(arc.dxf.start_angle)
|
||||||
a_end = math.radians(arc.dxf.end_angle)
|
a_end = math.radians(arc.dxf.end_angle)
|
||||||
|
|
||||||
# Start- und Endpunkt
|
|
||||||
p1x = cx + r * math.cos(a_start)
|
p1x = cx + r * math.cos(a_start)
|
||||||
p1y = cy + r * math.sin(a_start)
|
p1y = cy + r * math.sin(a_start)
|
||||||
p2x = cx + r * math.cos(a_end)
|
p2x = cx + r * math.cos(a_end)
|
||||||
p2y = cy + r * math.sin(a_end)
|
p2y = cy + r * math.sin(a_end)
|
||||||
|
|
||||||
# Tangentenrichtungen (senkrecht zum Radius)
|
|
||||||
d1x = -math.sin(a_start)
|
d1x = -math.sin(a_start)
|
||||||
d1y = math.cos(a_start)
|
d1y = math.cos(a_start)
|
||||||
d2x = -math.sin(a_end)
|
d2x = -math.sin(a_end)
|
||||||
d2y = math.cos(a_end)
|
d2y = math.cos(a_end)
|
||||||
|
|
||||||
# Determinante
|
|
||||||
det = d1x * (-d2y) - (-d2x) * d1y
|
det = d1x * (-d2y) - (-d2x) * d1y
|
||||||
|
|
||||||
if abs(det) < 1e-9:
|
if abs(det) < 1e-9:
|
||||||
# Tangenten parallel (z.B. 180-Grad-Bogen) -> Mittelpunkt
|
|
||||||
return (p1x + p2x) / 2, (p1y + p2y) / 2
|
return (p1x + p2x) / 2, (p1y + p2y) / 2
|
||||||
|
|
||||||
dx = p2x - p1x
|
dx = p2x - p1x
|
||||||
@@ -64,7 +81,7 @@ def tangent_intersection(arc):
|
|||||||
|
|
||||||
|
|
||||||
def find_longest_vertical_line(doc):
|
def find_longest_vertical_line(doc):
|
||||||
"""Findet die laengste vertikale Linie im Modelspace und gibt deren x-Koordinate zurueck."""
|
"""Findet die laengste vertikale Linie im Modelspace."""
|
||||||
msp = doc.modelspace()
|
msp = doc.modelspace()
|
||||||
longest = None
|
longest = None
|
||||||
longest_len = 0
|
longest_len = 0
|
||||||
@@ -83,6 +100,26 @@ def find_longest_vertical_line(doc):
|
|||||||
return longest
|
return longest
|
||||||
|
|
||||||
|
|
||||||
|
def find_longest_horizontal_line(doc):
|
||||||
|
"""Findet die laengste horizontale Linie im Modelspace."""
|
||||||
|
msp = doc.modelspace()
|
||||||
|
longest = None
|
||||||
|
longest_len = 0
|
||||||
|
for entity in msp:
|
||||||
|
if entity.dxftype() != "LINE":
|
||||||
|
continue
|
||||||
|
start = entity.dxf.start
|
||||||
|
end = entity.dxf.end
|
||||||
|
dy = abs(end[1] - start[1])
|
||||||
|
if dy > 0.01:
|
||||||
|
continue
|
||||||
|
length = abs(end[0] - start[0])
|
||||||
|
if length > longest_len:
|
||||||
|
longest_len = length
|
||||||
|
longest = entity
|
||||||
|
return longest
|
||||||
|
|
||||||
|
|
||||||
def arc_endpoint(arc):
|
def arc_endpoint(arc):
|
||||||
"""Gibt den Endpunkt (end_angle) des Bogens zurueck."""
|
"""Gibt den Endpunkt (end_angle) des Bogens zurueck."""
|
||||||
cx, cy, _ = arc.dxf.center
|
cx, cy, _ = arc.dxf.center
|
||||||
@@ -91,36 +128,179 @@ def arc_endpoint(arc):
|
|||||||
return cx + r * math.cos(a_end), cy + r * math.sin(a_end)
|
return cx + r * math.cos(a_end), cy + r * math.sin(a_end)
|
||||||
|
|
||||||
|
|
||||||
def weichen_insertion_point(doc):
|
# ---------------------------------------------------------------------------
|
||||||
"""Berechnet den Einfuegepunkt fuer eine Weiche:
|
# Einfuegepunkt-Berechnungen (je Typ)
|
||||||
Schnittpunkt der laengsten vertikalen Linie mit einer Horizontalen
|
# ---------------------------------------------------------------------------
|
||||||
durch den Endpunkt der Bogenkurve.
|
|
||||||
"""
|
def boegen_insertion_point(doc):
|
||||||
vline = find_longest_vertical_line(doc)
|
"""Tangentenschnittpunkt der Bogenkurve."""
|
||||||
if vline is None:
|
|
||||||
return None
|
|
||||||
arc = find_arc(doc)
|
arc = find_arc(doc)
|
||||||
if arc is None:
|
if arc is None:
|
||||||
return None
|
return None
|
||||||
|
return tangent_intersection(arc)
|
||||||
|
|
||||||
|
|
||||||
|
def weichen_insertion_point(doc):
|
||||||
|
"""Schnittpunkt der laengsten vertikalen Linie mit der Tangente am oberen Arc-Endpunkt."""
|
||||||
|
vline = find_longest_vertical_line(doc)
|
||||||
|
if vline is None:
|
||||||
|
return None
|
||||||
vx = vline.dxf.start[0]
|
vx = vline.dxf.start[0]
|
||||||
_, ey = arc_endpoint(arc)
|
|
||||||
return vx, ey
|
# Alle Arcs sammeln, oberen Punkt (max Y aus Start/Ende) waehlen
|
||||||
|
best_angle = None
|
||||||
|
best_y = -float('inf')
|
||||||
|
best_arc = None
|
||||||
|
for entity in doc.modelspace():
|
||||||
|
if entity.dxftype() != "ARC":
|
||||||
|
continue
|
||||||
|
cx, cy, _ = entity.dxf.center
|
||||||
|
r = entity.dxf.radius
|
||||||
|
for angle_deg in (entity.dxf.start_angle, entity.dxf.end_angle):
|
||||||
|
a = math.radians(angle_deg)
|
||||||
|
py = cy + r * math.sin(a)
|
||||||
|
if py > best_y:
|
||||||
|
best_y = py
|
||||||
|
best_angle = a
|
||||||
|
best_arc = entity
|
||||||
|
|
||||||
|
if best_arc is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
cx, cy, _ = best_arc.dxf.center
|
||||||
|
r = best_arc.dxf.radius
|
||||||
|
|
||||||
|
ex = cx + r * math.cos(best_angle)
|
||||||
|
ey = cy + r * math.sin(best_angle)
|
||||||
|
tdx = -math.sin(best_angle)
|
||||||
|
tdy = math.cos(best_angle)
|
||||||
|
|
||||||
|
if abs(tdx) < 1e-9:
|
||||||
|
return vx, ey
|
||||||
|
t = (vx - ex) / tdx
|
||||||
|
return vx, ey + t * tdy
|
||||||
|
|
||||||
|
|
||||||
def process_weichen(data_dir, json_path, results_dir, kurven_winkel):
|
def weichenkoerper_insertion_point(doc):
|
||||||
"""Verarbeitet Weichen-DXF-Dateien fuer den angegebenen KurvenWinkel."""
|
"""Schnittpunkt der laengsten Diagonale mit der vertikalen Linie."""
|
||||||
|
vline = find_longest_vertical_line(doc)
|
||||||
|
if vline is None:
|
||||||
|
return None
|
||||||
|
vx = vline.dxf.start[0]
|
||||||
|
|
||||||
|
best_point = None
|
||||||
|
best_len = 0
|
||||||
|
for entity in doc.modelspace():
|
||||||
|
if entity.dxftype() != "LINE":
|
||||||
|
continue
|
||||||
|
s = entity.dxf.start
|
||||||
|
e = entity.dxf.end
|
||||||
|
dx = abs(e[0] - s[0])
|
||||||
|
dy = abs(e[1] - s[1])
|
||||||
|
if dx < 0.01 or dy < 0.01:
|
||||||
|
continue
|
||||||
|
length = (dx ** 2 + dy ** 2) ** 0.5
|
||||||
|
if abs(s[0] - vx) < 0.01 and length > best_len:
|
||||||
|
best_point = (s[0], s[1])
|
||||||
|
best_len = length
|
||||||
|
if abs(e[0] - vx) < 0.01 and length > best_len:
|
||||||
|
best_point = (e[0], e[1])
|
||||||
|
best_len = length
|
||||||
|
return best_point
|
||||||
|
|
||||||
|
|
||||||
|
def horizontal_midpoint_insertion(doc):
|
||||||
|
"""Mittelpunkt der laengsten horizontalen Linie."""
|
||||||
|
hline = find_longest_horizontal_line(doc)
|
||||||
|
if hline is None:
|
||||||
|
return None
|
||||||
|
sx = hline.dxf.start[0]
|
||||||
|
ex = hline.dxf.end[0]
|
||||||
|
y = hline.dxf.start[1]
|
||||||
|
return (sx + ex) / 2, y
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Schalter-Definitionen: (Label, JSON-Datei, Filter, Einfuegepunkt-Funktion)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SWITCH_DEFS = {
|
||||||
|
"boegen": (
|
||||||
|
"Boegen",
|
||||||
|
"omniflo_boegen.json",
|
||||||
|
lambda item: True,
|
||||||
|
boegen_insertion_point,
|
||||||
|
),
|
||||||
|
"weichen45": (
|
||||||
|
"Weichen 45 Grad",
|
||||||
|
"omniflo_weichen.json",
|
||||||
|
lambda item: item["KurvenWinkel"] == 45
|
||||||
|
and item["WeichenTyp"] not in ("Dreifachweiche", "Deltaweiche"),
|
||||||
|
weichen_insertion_point,
|
||||||
|
),
|
||||||
|
"weichen90": (
|
||||||
|
"Weichen 90 Grad",
|
||||||
|
"omniflo_weichen.json",
|
||||||
|
lambda item: item["KurvenWinkel"] == 90
|
||||||
|
and item["WeichenTyp"] not in ("Dreifachweiche", "Deltaweiche"),
|
||||||
|
weichen_insertion_point,
|
||||||
|
),
|
||||||
|
"weichenkoerper": (
|
||||||
|
"Weichenkoerper",
|
||||||
|
"omniflo_weichen.json",
|
||||||
|
lambda item: item["KurvenWinkel"] == 22.5,
|
||||||
|
weichenkoerper_insertion_point,
|
||||||
|
),
|
||||||
|
"weichen_parallel": (
|
||||||
|
"Weichen Parallel",
|
||||||
|
"omniflo_weichen.json",
|
||||||
|
lambda item: item["KurvenWinkel"] == 0 and item["WeichenTyp"] != "Sternweiche",
|
||||||
|
weichenkoerper_insertion_point,
|
||||||
|
),
|
||||||
|
"sternweiche": (
|
||||||
|
"Sternweiche",
|
||||||
|
"omniflo_weichen.json",
|
||||||
|
lambda item: item["WeichenTyp"] == "Sternweiche",
|
||||||
|
horizontal_midpoint_insertion,
|
||||||
|
),
|
||||||
|
"delta": (
|
||||||
|
"Deltaweichen",
|
||||||
|
"omniflo_weichen.json",
|
||||||
|
lambda item: item["WeichenTyp"] == "Deltaweiche",
|
||||||
|
horizontal_midpoint_insertion,
|
||||||
|
),
|
||||||
|
"dreifachweiche": (
|
||||||
|
"Dreifachweichen",
|
||||||
|
"omniflo_weichen.json",
|
||||||
|
lambda item: item["WeichenTyp"] == "Dreifachweiche",
|
||||||
|
horizontal_midpoint_insertion,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def process_dxf(data_dir, label, json_file, filter_func, insertion_func,
|
||||||
|
results_dir, number=None):
|
||||||
|
"""Generische Verarbeitung: filtert IDs aus JSON, berechnet Einfuegepunkt, speichert."""
|
||||||
|
json_path = os.path.join(data_dir, "json", json_file)
|
||||||
|
if not os.path.exists(json_path):
|
||||||
|
print(f"FEHLER: {json_path} nicht gefunden.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
with open(json_path, "r", encoding="utf-8") as f:
|
with open(json_path, "r", encoding="utf-8") as f:
|
||||||
weichen = json.load(f)
|
items = json.load(f)
|
||||||
|
|
||||||
omniflo_dir = os.path.join(data_dir, "omniflo")
|
omniflo_dir = os.path.join(data_dir, "omniflo")
|
||||||
filtered = [w for w in weichen if w["KurvenWinkel"] == kurven_winkel]
|
filtered = [item for item in items if filter_func(item)]
|
||||||
|
if number:
|
||||||
|
filtered = [item for item in filtered if str(item["Sivasnr"]) == str(number)]
|
||||||
|
|
||||||
if not filtered:
|
if not filtered:
|
||||||
print(f"Keine Weichen mit KurvenWinkel={kurven_winkel} gefunden.")
|
print(f"Keine Elemente fuer '{label}' gefunden.")
|
||||||
return
|
return
|
||||||
|
|
||||||
for weiche in filtered:
|
print(f"=== {label} ===")
|
||||||
sivasnr = str(weiche["Sivasnr"])
|
for item in filtered:
|
||||||
|
sivasnr = str(item["Sivasnr"])
|
||||||
dxf_path = os.path.join(omniflo_dir, f"{sivasnr}.dxf")
|
dxf_path = os.path.join(omniflo_dir, f"{sivasnr}.dxf")
|
||||||
|
|
||||||
if not os.path.exists(dxf_path):
|
if not os.path.exists(dxf_path):
|
||||||
@@ -128,10 +308,10 @@ def process_weichen(data_dir, json_path, results_dir, kurven_winkel):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
doc = ezdxf.readfile(dxf_path)
|
doc = ezdxf.readfile(dxf_path)
|
||||||
result = weichen_insertion_point(doc)
|
result = insertion_func(doc)
|
||||||
|
|
||||||
if result is None:
|
if result is None:
|
||||||
print(f"WARNUNG: Kein ARC oder keine vertikale Linie in {sivasnr}.dxf, ueberspringe.")
|
print(f"WARNUNG: Kein Einfuegepunkt in {sivasnr}.dxf bestimmbar, ueberspringe.")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
ix, iy = result
|
ix, iy = result
|
||||||
@@ -143,72 +323,250 @@ def process_weichen(data_dir, json_path, results_dir, kurven_winkel):
|
|||||||
|
|
||||||
print(
|
print(
|
||||||
f"{sivasnr}: INSBASE ({old_base[0]:.2f}, {old_base[1]:.2f}) "
|
f"{sivasnr}: INSBASE ({old_base[0]:.2f}, {old_base[1]:.2f}) "
|
||||||
f"-> ({ix:.2f}, {iy:.2f}) [{weiche['ProfilTyp']}]"
|
f"-> ({ix:.2f}, {iy:.2f}) [{item['ProfilTyp']}]"
|
||||||
)
|
)
|
||||||
|
|
||||||
print(f"\nErgebnisse in: {results_dir}")
|
print(f"\nErgebnisse in: {results_dir}")
|
||||||
|
|
||||||
|
|
||||||
def process_boegen(data_dir, json_path, results_dir):
|
# ---------------------------------------------------------------------------
|
||||||
"""Verarbeitet alle Boegen-DXF-Dateien."""
|
# show-omniflo
|
||||||
with open(json_path, "r", encoding="utf-8") as f:
|
# ---------------------------------------------------------------------------
|
||||||
boegen = json.load(f)
|
|
||||||
|
|
||||||
|
def find_min_y_point(doc):
|
||||||
|
"""Findet den Punkt mit dem geringsten Y-Wert im Modelspace."""
|
||||||
|
min_y = float('inf')
|
||||||
|
min_point = None
|
||||||
|
for e in doc.modelspace():
|
||||||
|
points = []
|
||||||
|
if e.dxftype() == 'LINE':
|
||||||
|
points = [(e.dxf.start[0], e.dxf.start[1]),
|
||||||
|
(e.dxf.end[0], e.dxf.end[1])]
|
||||||
|
elif e.dxftype() == 'ARC':
|
||||||
|
cx, cy = e.dxf.center[0], e.dxf.center[1]
|
||||||
|
r = e.dxf.radius
|
||||||
|
a_s = math.radians(e.dxf.start_angle)
|
||||||
|
a_e = math.radians(e.dxf.end_angle)
|
||||||
|
points = [
|
||||||
|
(cx + r * math.cos(a_s), cy + r * math.sin(a_s)),
|
||||||
|
(cx + r * math.cos(a_e), cy + r * math.sin(a_e)),
|
||||||
|
]
|
||||||
|
for p in points:
|
||||||
|
if p[1] < min_y:
|
||||||
|
min_y = p[1]
|
||||||
|
min_point = p
|
||||||
|
return min_point
|
||||||
|
|
||||||
|
|
||||||
|
ROW_GROUPS = [
|
||||||
|
("Boegen 22.5", "boegen",
|
||||||
|
lambda b: b["KurvenWinkel"] == 22.5),
|
||||||
|
("Boegen 45", "boegen",
|
||||||
|
lambda b: b["KurvenWinkel"] == 45),
|
||||||
|
("Boegen 67.5", "boegen",
|
||||||
|
lambda b: b["KurvenWinkel"] == 67.5),
|
||||||
|
("Boegen 90", "boegen",
|
||||||
|
lambda b: b["KurvenWinkel"] == 90),
|
||||||
|
("Boegen 180", "boegen",
|
||||||
|
lambda b: b["KurvenWinkel"] == 180),
|
||||||
|
("Weichenkoerper Einzel", "weichen",
|
||||||
|
lambda w: w["WeichenTyp"] == "Einzelweiche" and w["KurvenWinkel"] == 22.5),
|
||||||
|
("Weichenkoerper Doppel", "weichen",
|
||||||
|
lambda w: w["WeichenTyp"] == "Doppelweiche" and w["KurvenWinkel"] == 22.5),
|
||||||
|
("Weichenkoerper Dreiwege", "weichen",
|
||||||
|
lambda w: w["WeichenTyp"] == "Dreiwegeweiche" and w["KurvenWinkel"] == 22.5),
|
||||||
|
("Einzelweiche 45", "weichen",
|
||||||
|
lambda w: w["WeichenTyp"] == "Einzelweiche" and w["KurvenWinkel"] == 45),
|
||||||
|
("Einzelweiche 90", "weichen",
|
||||||
|
lambda w: w["WeichenTyp"] == "Einzelweiche" and w["KurvenWinkel"] == 90),
|
||||||
|
("Einzelweiche Parallel", "weichen",
|
||||||
|
lambda w: w["WeichenTyp"] == "Einzelweiche" and w["KurvenWinkel"] == 0),
|
||||||
|
("Doppelweiche 45", "weichen",
|
||||||
|
lambda w: w["WeichenTyp"] == "Doppelweiche" and w["KurvenWinkel"] == 45),
|
||||||
|
("Doppelweiche 90", "weichen",
|
||||||
|
lambda w: w["WeichenTyp"] == "Doppelweiche" and w["KurvenWinkel"] == 90),
|
||||||
|
("Doppelweiche Parallel", "weichen",
|
||||||
|
lambda w: w["WeichenTyp"] == "Doppelweiche" and w["KurvenWinkel"] == 0),
|
||||||
|
("Dreiwegeweiche 45", "weichen",
|
||||||
|
lambda w: w["WeichenTyp"] == "Dreiwegeweiche" and w["KurvenWinkel"] == 45),
|
||||||
|
("Dreiwegeweiche 90", "weichen",
|
||||||
|
lambda w: w["WeichenTyp"] == "Dreiwegeweiche" and w["KurvenWinkel"] == 90),
|
||||||
|
("Dreiwegeweiche Parallel", "weichen",
|
||||||
|
lambda w: w["WeichenTyp"] == "Dreiwegeweiche" and w["KurvenWinkel"] == 0),
|
||||||
|
("Dreifachweiche", "weichen",
|
||||||
|
lambda w: w["WeichenTyp"] == "Dreifachweiche"),
|
||||||
|
("Deltaweiche", "weichen",
|
||||||
|
lambda w: w["WeichenTyp"] == "Deltaweiche"),
|
||||||
|
("Sternweiche", "weichen",
|
||||||
|
lambda w: w["WeichenTyp"] == "Sternweiche"),
|
||||||
|
]
|
||||||
|
|
||||||
|
PADDING_X = 200
|
||||||
|
PADDING_Y = 400
|
||||||
|
TEXT_HEIGHT = 30
|
||||||
|
CROSS_SIZE = 40
|
||||||
|
TEXT_MARGIN = 20
|
||||||
|
ROW_LABEL_WIDTH = 600
|
||||||
|
|
||||||
|
|
||||||
|
def show_omniflo(data_dir, results_dir):
|
||||||
|
"""Erzeugt eine Uebersichts-DXF mit allen Omniflo-Elementen in Reihen."""
|
||||||
|
boegen_path = os.path.join(data_dir, "json", "omniflo_boegen.json")
|
||||||
|
weichen_path = os.path.join(data_dir, "json", "omniflo_weichen.json")
|
||||||
|
|
||||||
|
with open(boegen_path, "r", encoding="utf-8") as f:
|
||||||
|
boegen_data = json.load(f)
|
||||||
|
with open(weichen_path, "r", encoding="utf-8") as f:
|
||||||
|
weichen_data = json.load(f)
|
||||||
|
|
||||||
|
sources = {"boegen": boegen_data, "weichen": weichen_data}
|
||||||
omniflo_dir = os.path.join(data_dir, "omniflo")
|
omniflo_dir = os.path.join(data_dir, "omniflo")
|
||||||
|
|
||||||
for bogen in boegen:
|
target = ezdxf.new(dxfversion='R2010')
|
||||||
sivasnr = str(bogen["Sivasnr"])
|
target_msp = target.modelspace()
|
||||||
dxf_path = os.path.join(omniflo_dir, f"{sivasnr}.dxf")
|
target.layers.add('ANNOTATION', color=7)
|
||||||
|
target.layers.add('INSPOINT', color=1)
|
||||||
|
target.layers.add('INSLINE', color=5)
|
||||||
|
target.layers.add('ROW_LABEL', color=3)
|
||||||
|
|
||||||
if not os.path.exists(dxf_path):
|
cursor_y = 0.0
|
||||||
print(f"WARNUNG: {dxf_path} nicht gefunden, ueberspringe.")
|
block_counter = 0
|
||||||
|
|
||||||
|
for label, source_key, filter_func in ROW_GROUPS:
|
||||||
|
items = [item for item in sources[source_key] if filter_func(item)]
|
||||||
|
if not items:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
doc = ezdxf.readfile(dxf_path)
|
row_elements = []
|
||||||
arc = find_arc(doc)
|
for item in items:
|
||||||
|
sivasnr = str(item["Sivasnr"])
|
||||||
|
dxf_path_result = os.path.join(results_dir, f"{sivasnr}.dxf")
|
||||||
|
dxf_path_orig = os.path.join(omniflo_dir, f"{sivasnr}.dxf")
|
||||||
|
dxf_path = dxf_path_result if os.path.exists(dxf_path_result) else dxf_path_orig
|
||||||
|
|
||||||
if arc is None:
|
if not os.path.exists(dxf_path):
|
||||||
print(f"WARNUNG: Kein ARC in {sivasnr}.dxf gefunden, ueberspringe.")
|
print(f" WARNUNG: {sivasnr}.dxf nicht gefunden, ueberspringe.")
|
||||||
|
continue
|
||||||
|
|
||||||
|
source_doc = ezdxf.readfile(dxf_path)
|
||||||
|
bb = ezdxf_bbox.extents(source_doc.modelspace())
|
||||||
|
if not bb.has_data:
|
||||||
|
continue
|
||||||
|
|
||||||
|
min_y_pt = find_min_y_point(source_doc)
|
||||||
|
insbase = source_doc.header.get("$INSBASE", (0, 0, 0))
|
||||||
|
|
||||||
|
row_elements.append({
|
||||||
|
'sivasnr': sivasnr,
|
||||||
|
'source': source_doc,
|
||||||
|
'extmin': bb.extmin,
|
||||||
|
'extmax': bb.extmax,
|
||||||
|
'width': bb.extmax[0] - bb.extmin[0],
|
||||||
|
'height': bb.extmax[1] - bb.extmin[1],
|
||||||
|
'insbase': insbase,
|
||||||
|
'min_y_point': min_y_pt,
|
||||||
|
})
|
||||||
|
|
||||||
|
if not row_elements:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
ix, iy = tangent_intersection(arc)
|
max_height = max(e['height'] for e in row_elements)
|
||||||
|
|
||||||
old_base = doc.header.get("$INSBASE", (0, 0, 0))
|
label_y = cursor_y + max_height / 2
|
||||||
doc.header["$INSBASE"] = (ix, iy, 0)
|
target_msp.add_mtext(
|
||||||
|
label,
|
||||||
|
dxfattribs={
|
||||||
|
'layer': 'ROW_LABEL',
|
||||||
|
'char_height': TEXT_HEIGHT * 1.2,
|
||||||
|
}
|
||||||
|
).set_location(insert=(-ROW_LABEL_WIDTH, label_y))
|
||||||
|
|
||||||
out_path = os.path.join(results_dir, f"{sivasnr}.dxf")
|
cursor_x = 0.0
|
||||||
doc.saveas(out_path)
|
for elem in row_elements:
|
||||||
|
block_name = f"BLK_{block_counter}"
|
||||||
|
block_counter += 1
|
||||||
|
|
||||||
print(
|
importer = Importer(elem['source'], target)
|
||||||
f"{sivasnr}: INSBASE ({old_base[0]:.2f}, {old_base[1]:.2f}) "
|
importer.import_tables()
|
||||||
f"-> ({ix:.2f}, {iy:.2f}) [{bogen['ProfilTyp']}]"
|
blk = target.blocks.new(name=block_name)
|
||||||
)
|
for entity in elem['source'].modelspace():
|
||||||
|
importer.import_entity(entity, blk)
|
||||||
|
importer.finalize()
|
||||||
|
|
||||||
print(f"\nErgebnisse in: {results_dir}")
|
offset_x = cursor_x - elem['extmin'][0]
|
||||||
|
offset_y = cursor_y - elem['extmin'][1]
|
||||||
|
target_msp.add_blockref(block_name, insert=(offset_x, offset_y))
|
||||||
|
|
||||||
|
ipx = elem['insbase'][0] + offset_x
|
||||||
|
ipy = elem['insbase'][1] + offset_y
|
||||||
|
|
||||||
|
target_msp.add_line(
|
||||||
|
(ipx - CROSS_SIZE, ipy),
|
||||||
|
(ipx + CROSS_SIZE, ipy),
|
||||||
|
dxfattribs={'layer': 'INSPOINT', 'color': 1}
|
||||||
|
)
|
||||||
|
target_msp.add_line(
|
||||||
|
(ipx, ipy - CROSS_SIZE),
|
||||||
|
(ipx, ipy + CROSS_SIZE),
|
||||||
|
dxfattribs={'layer': 'INSPOINT', 'color': 1}
|
||||||
|
)
|
||||||
|
|
||||||
|
if elem['min_y_point']:
|
||||||
|
low_x = elem['min_y_point'][0] + offset_x
|
||||||
|
low_y = elem['min_y_point'][1] + offset_y
|
||||||
|
target_msp.add_line(
|
||||||
|
(ipx, ipy),
|
||||||
|
(low_x, low_y),
|
||||||
|
dxfattribs={'layer': 'INSLINE', 'color': 5}
|
||||||
|
)
|
||||||
|
|
||||||
|
text_x = cursor_x
|
||||||
|
text_y = cursor_y + elem['height'] + TEXT_MARGIN
|
||||||
|
target_msp.add_mtext(
|
||||||
|
elem['sivasnr'],
|
||||||
|
dxfattribs={
|
||||||
|
'layer': 'ANNOTATION',
|
||||||
|
'char_height': TEXT_HEIGHT,
|
||||||
|
}
|
||||||
|
).set_location(insert=(text_x, text_y))
|
||||||
|
|
||||||
|
cursor_x += elem['width'] + PADDING_X
|
||||||
|
|
||||||
|
cursor_y -= max_height + TEXT_HEIGHT + TEXT_MARGIN * 2 + PADDING_Y
|
||||||
|
|
||||||
|
out_path = os.path.join(results_dir, "omniflo_uebersicht.dxf")
|
||||||
|
target.saveas(out_path)
|
||||||
|
print(f"Uebersicht gespeichert: {out_path}")
|
||||||
|
print(f" {block_counter} Elemente in {sum(1 for l, s, f in ROW_GROUPS if any(f(i) for i in sources[s]))} Reihen")
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# main
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="Setzt Einfuegepunkte fuer Omniflo DXF-Dateien"
|
description="Setzt Einfuegepunkte fuer Omniflo DXF-Dateien"
|
||||||
)
|
)
|
||||||
|
for key, (label, _, _, _) in SWITCH_DEFS.items():
|
||||||
|
arg_name = f"--{key.replace('_', '-')}"
|
||||||
|
parser.add_argument(arg_name, action="store_true", help=f"Einfuegepunkt fuer {label} setzen")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--boegen",
|
"--number", type=int,
|
||||||
action="store_true",
|
help="Nur diese 9-stellige Sivasnr verarbeiten",
|
||||||
help="Einfuegepunkt auf Tangentenschnittpunkt der Bogenkurve setzen",
|
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--weichen45",
|
"--show-omniflo", action="store_true",
|
||||||
action="store_true",
|
help="Uebersichts-DXF mit allen Omniflo-Elementen erzeugen",
|
||||||
help="Einfuegepunkt fuer 45-Grad-Weichen setzen",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--weichen90",
|
|
||||||
action="store_true",
|
|
||||||
help="Einfuegepunkt fuer 90-Grad-Weichen setzen",
|
|
||||||
)
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if not args.boegen and not args.weichen45 and not args.weichen90:
|
if args.number and len(str(args.number)) != 9:
|
||||||
|
print("FEHLER: --number muss eine 9-stellige Ganzzahl sein.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
active = [key for key in SWITCH_DEFS if getattr(args, key)]
|
||||||
|
if not active and not args.show_omniflo:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
@@ -222,24 +580,14 @@ def main():
|
|||||||
|
|
||||||
os.makedirs(results_dir, exist_ok=True)
|
os.makedirs(results_dir, exist_ok=True)
|
||||||
|
|
||||||
if args.boegen:
|
for key in active:
|
||||||
json_path = os.path.join(data_dir, "json", "omniflo_boegen.json")
|
label, json_file, filter_func, insertion_func = SWITCH_DEFS[key]
|
||||||
if not os.path.exists(json_path):
|
process_dxf(data_dir, label, json_file, filter_func, insertion_func,
|
||||||
print(f"FEHLER: {json_path} nicht gefunden.")
|
results_dir, args.number)
|
||||||
sys.exit(1)
|
|
||||||
process_boegen(data_dir, json_path, results_dir)
|
|
||||||
|
|
||||||
if args.weichen45 or args.weichen90:
|
if args.show_omniflo:
|
||||||
json_path = os.path.join(data_dir, "json", "omniflo_weichen.json")
|
print("=== Omniflo Uebersicht ===")
|
||||||
if not os.path.exists(json_path):
|
show_omniflo(data_dir, results_dir)
|
||||||
print(f"FEHLER: {json_path} nicht gefunden.")
|
|
||||||
sys.exit(1)
|
|
||||||
if args.weichen45:
|
|
||||||
print("=== Weichen 45 Grad ===")
|
|
||||||
process_weichen(data_dir, json_path, results_dir, 45)
|
|
||||||
if args.weichen90:
|
|
||||||
print("=== Weichen 90 Grad ===")
|
|
||||||
process_weichen(data_dir, json_path, results_dir, 90)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in New Issue
Block a user