This commit is contained in:
2025-07-31 08:53:34 +02:00
6 changed files with 628 additions and 155 deletions
+87 -32
View File
@@ -13,12 +13,21 @@ import configparser
import ezdxf
from pathlib import Path
import math
from utils import check_environment_var, setup_logger
# --------------------------------------------------------- CFG-Leser für shapes.cfg
def get_shape_cfg(teileart, cfg_path):
def get_shape_cfg(teileart, cfg_path, logger=None):
parser = configparser.ConfigParser()
with open(cfg_path, encoding='utf-8') as f:
parser.read_file(f)
try:
with open(cfg_path, encoding='utf-8') as f:
parser.read_file(f)
except Exception as e:
msg = f"Fehler beim Lesen der Config-Datei {cfg_path}: {e}"
if logger:
logger.error(msg)
else:
print(msg)
return []
section = teileart
if section not in parser:
return []
@@ -53,14 +62,6 @@ ATTR_TAG = "TeileId" # Attributtag im Block
RADIUS = 400 # Radius der Kreiselkreise (mm)
# --------------------------------------------------------- Hilfsfunktionen
def check_environment_var(env_str: str) -> Path:
"""Liefert Path aus Umgebungsvariable oder beendet mit Fehlermeldung."""
out_path = os.environ.get(env_str)
if out_path:
return Path(out_path)
print(f"Umgebungsvariable {env_str} ist nicht gesetzt oder leer.")
sys.exit(1)
def extract_coords(planquadrat: str) -> tuple[float, float]:
"""Extrahiert X/Y Koordinaten aus PlanquadratString."""
m = re.search(r"X:(\d+[\.,]?\d*)\s+Y:(\d+[\.,]?\d*)", planquadrat)
@@ -87,8 +88,9 @@ def import_block(block_name: str, from_doc, to_doc) -> None:
for ent in src:
tgt.add_entity(ent.copy())
def berechne_hoehe(csv_path):
y_werte = []
def berechne_hoehe(csv_path, logger=None):
y_werte = []
try:
with csv_path.open(newline="", encoding="utf-8") as fh:
reader = csv.DictReader(fh, delimiter=';')
for row in reader:
@@ -96,11 +98,23 @@ def berechne_hoehe(csv_path):
try:
_, y = extract_coords(planquadrat)
y_werte.append(y)
except Exception:
continue
if not y_werte:
raise ValueError("Keine Y-Koordinaten in der CSV gefunden!")
return max(y_werte)
except Exception as e:
if logger:
logger.warning(f"Fehler beim Extrahieren der Koordinate aus '{planquadrat}': {e}")
except Exception as e:
if logger:
logger.error(f"Fehler beim Lesen der CSV-Datei {csv_path}: {e}")
else:
print(f"Fehler beim Lesen der CSV-Datei {csv_path}: {e}")
return 0
if not y_werte:
msg = "Keine Y-Koordinaten in der CSV gefunden!"
if logger:
logger.error(msg)
else:
print(msg)
raise ValueError(msg)
return max(y_werte)
def transform_coords(x: float, y: float, height: float) -> tuple[float, float]:
"""Transformiert Bildschirmkoordinaten (0,0 oben links) ins DXF-KoSy (0,0 unten links)."""
@@ -329,20 +343,45 @@ def get_libfile_cfg(teileart, cfg_path):
return None
# --------------------------------------------------------- Hauptfunktion
def main(csv_path: Path, default_lib_path: Path, shapes_cfg_path: Path, output_path: Path, verbose=False):
def main(csv_path: Path, lib_path: Path, cfg_path: Path,
output_path: Path, verbose=False, logger=None):
# Bibliotheks-Cache
lib_docs = {}
# Verzeichnisse
data_dir = check_environment_var("PROJECT_DATA")
blocklib_dir = Path(data_dir) / "block_libaries"
# Bibliothek nur laden, wenn Datei existiert
lib_doc = None
if lib_path.exists():
try:
lib_doc = ezdxf.readfile(lib_path)
if verbose:
logger.info(f"[INFO] Bibliothek geladen: {lib_path}") if logger else print(f"[INFO] Bibliothek geladen: {lib_path}")
except Exception as e:
msg = f"Fehler beim Lesen der Bibliothek '{lib_path}': {e}"
if logger:
logger.error(msg)
else:
print(msg)
sys.exit(1)
else:
msg = f"[INFO] Keine Bibliothek gefunden unter {lib_path}."
if logger:
logger.warning(msg)
else:
print(msg)
sys.exit(1)
# Neue Zielzeichnung (DXF R2018)
# Neue Ziel­zeichnung (DXF R2018)
doc = ezdxf.new(dxfversion="R2018")
msp = doc.modelspace()
# Höhe bestimmen für Koordinaten-Transformation
height = berechne_hoehe(csv_path)
try:
height = berechne_hoehe(csv_path, logger=logger)
except Exception as e:
msg = f"Fehler bei der Höhenberechnung: {e}"
if logger:
logger.error(msg)
else:
print(msg)
sys.exit(1)
# Verarbeitung der Blöcke
with csv_path.open(newline="", encoding="utf-8") as fh:
@@ -357,7 +396,11 @@ def main(csv_path: Path, default_lib_path: Path, shapes_cfg_path: Path, output_p
x_screen, y_screen = extract_coords(planquadrat)
x, y = transform_coords(x_screen, y_screen, height)
except Exception as e:
print(f"[WARN] {teileid}: {e}")
msg = f"[WARN] {teileid}: {e}"
if logger:
logger.warning(msg)
else:
print(msg)
continue
# Bibliotheksdatei bestimmen
@@ -385,19 +428,26 @@ def main(csv_path: Path, default_lib_path: Path, shapes_cfg_path: Path, output_p
# Funktions-Dispatch: handle_<teileart> (mit _ statt Leerzeichen und Punkten, alles klein)
func_name = f'handle_{normalize_func_name(teileart)}'
handler = globals().get(func_name)
symbols = get_shape_cfg(teileart, shapes_cfg_path)
symbols = get_shape_cfg(teileart, shapes_cfg_path, logger=logger)
# Mapping für Omniflo-Typen
if func_name.startswith('handle_omniflo'):
handler = globals().get('handle_omniflo')
if handler:
handler(msp, teileid, merkmale, x, y, doc, lib_doc, verbose, symbols)
else:
print(f"[WARN] Keine Routine für TeileArt '{teileart}'. Überspringe '{teileid}'.")
continue
msg = f"[WARN] Keine Routine für TeileArt '{teileart}'. Überspringe '{teileid}'."
if logger:
logger.warning(msg)
else:
print(msg)
continue
# DXF speichern
doc.saveas(output_path)
print(f"[DONE] DXF gespeichert unter: {output_path}")
if logger:
logger.info(f"[DONE] DXF gespeichert unter: {output_path}")
else:
print(f"[DONE] DXF gespeichert unter: {output_path}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(
@@ -410,10 +460,14 @@ if __name__ == "__main__":
args = parser.parse_args()
# Verzeichnisse aus Umgebungs­variablen
log_dir = check_environment_var("PROJECT_LOG")
data_dir = check_environment_var("PROJECT_DATA")
work_dir = check_environment_var("PROJECT_WORK")
config_dir = check_environment_var("PROJECT_CFG")
logger = setup_logger(log_dir, name='plant2dxf')
logger.info("=== plant2dxf Verarbeitung gestartet ===")
# CSVPfad: nur Dateiname → im WORKOrdner suchen
if os.sep not in args.file and "/" not in args.file:
csv_path = work_dir / args.file
@@ -425,4 +479,5 @@ if __name__ == "__main__":
default_lib_path = Path(args.lib) if args.lib else data_dir / "blocks.dxf"
output_path = Path(args.output) if args.output else (work_dir / f"{csv_path.stem}.dxf")
main(csv_path, default_lib_path, cfg_path, output_path, verbose=args.verbose)
main(csv_path, default_lib_path, cfg_path, output_path, verbose=args.verbose, logger=logger)
logger.info("=== plant2dxf Verarbeitung abgeschlossen ===")