Files
dxfmakros/lib/omniflo_utils.py
T

231 lines
7.7 KiB
Python

"""
Gemeinsame Hilfsfunktionen fuer DXF-Makros.
Enthaelt die Reihen-Gruppierung fuer Omniflo-Elemente und Layout-Funktionen
fuer die Uebersichts-DXF Erzeugung.
"""
import json
import os
import ezdxf
from ezdxf import bbox as ezdxf_bbox
from ezdxf.addons.importer import Importer
# ---------------------------------------------------------------------------
# Reihen-Gruppen: (Label, Quell-Key, Filter-Funktion)
# ---------------------------------------------------------------------------
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"),
]
# ---------------------------------------------------------------------------
# Schalter-Filter: (Label, JSON-Datei, Filter-Funktion)
# Gemeinsam genutzt von set_einfuegepkt.py und set_koords.py.
# ---------------------------------------------------------------------------
SWITCH_FILTERS = {
"boegen": (
"Boegen",
"omniflo_boegen.json",
lambda item: True,
),
"weichen45": (
"Weichen 45 Grad",
"omniflo_weichen.json",
lambda item: item["KurvenWinkel"] == 45
and item["WeichenTyp"] not in ("Dreifachweiche", "Deltaweiche"),
),
"weichen90": (
"Weichen 90 Grad",
"omniflo_weichen.json",
lambda item: item["KurvenWinkel"] == 90
and item["WeichenTyp"] not in ("Dreifachweiche", "Deltaweiche"),
),
"weichenkoerper": (
"Weichenkoerper",
"omniflo_weichen.json",
lambda item: item["KurvenWinkel"] == 22.5,
),
"weichen_parallel": (
"Weichen Parallel",
"omniflo_weichen.json",
lambda item: item["KurvenWinkel"] == 0 and item["WeichenTyp"] != "Sternweiche",
),
"sternweiche": (
"Sternweiche",
"omniflo_weichen.json",
lambda item: item["WeichenTyp"] == "Sternweiche",
),
"delta": (
"Deltaweichen",
"omniflo_weichen.json",
lambda item: item["WeichenTyp"] == "Deltaweiche",
),
"dreifachweiche": (
"Dreifachweichen",
"omniflo_weichen.json",
lambda item: item["WeichenTyp"] == "Dreifachweiche",
),
}
PADDING_X = 200
PADDING_Y = 400
TEXT_HEIGHT = 30
CROSS_SIZE = 40
TEXT_MARGIN = 20
ROW_LABEL_WIDTH = 600
def load_omniflo_data(data_dir):
"""Laedt Boegen- und Weichen-JSON und gibt ein Dict {boegen, weichen} zurueck."""
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)
return {"boegen": boegen_data, "weichen": weichen_data}
def is_bogen(sivasnr, sources):
"""Prueft ob eine Sivasnr ein Bogen ist."""
return any(str(b["Sivasnr"]) == str(sivasnr) for b in sources["boegen"])
def build_row_layout(data_dir, results_dir):
"""
Berechnet das Layout aller Omniflo-Elemente in Reihen.
Returns:
(sources, rows) wobei rows eine Liste von Dicts ist:
[{
'label': str,
'source_key': str,
'elements': [{'sivasnr', 'source', 'extmin', 'extmax',
'width', 'height', 'offset_x', 'offset_y'}],
'cursor_y': float,
'max_height': float,
}]
"""
sources = load_omniflo_data(data_dir)
omniflo_dir = os.path.join(data_dir, "omniflo")
rows = []
cursor_y = 0.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
row_elements = []
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 not os.path.exists(dxf_path):
continue
source_doc = ezdxf.readfile(dxf_path)
bb = ezdxf_bbox.extents(source_doc.modelspace())
if not bb.has_data:
continue
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],
})
if not row_elements:
continue
max_height = max(e['height'] for e in row_elements)
cursor_x = 0.0
for elem in row_elements:
elem['offset_x'] = cursor_x - elem['extmin'][0]
elem['offset_y'] = cursor_y - elem['extmin'][1]
cursor_x += elem['width'] + PADDING_X
rows.append({
'label': label,
'source_key': source_key,
'elements': row_elements,
'cursor_y': cursor_y,
'max_height': max_height,
})
cursor_y -= max_height + TEXT_HEIGHT + TEXT_MARGIN * 2 + PADDING_Y
return sources, rows
def import_element_as_block(source_doc, target_doc, block_name):
"""Importiert alle Modelspace-Entities eines Quell-Dokuments als Block."""
importer = Importer(source_doc, target_doc)
importer.import_tables()
blk = target_doc.blocks.new(name=block_name)
for entity in source_doc.modelspace():
importer.import_entity(entity, blk)
importer.finalize()
return block_name
def draw_cross(msp, x, y, size, color, layer):
"""Zeichnet ein Kreuz an (x, y)."""
msp.add_line((x - size, y), (x + size, y),
dxfattribs={'layer': layer, 'color': color})
msp.add_line((x, y - size), (x, y + size),
dxfattribs={'layer': layer, 'color': color})