Merge branch 'main' of http://gitea.schoenenberger.de/mistangl/plant2dxf
This commit is contained in:
+87
-32
@@ -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 Zielzeichnung (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 Umgebungsvariablen
|
||||
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 ===")
|
||||
|
||||
# CSV‑Pfad: nur Dateiname → im WORK‑Ordner 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 ===")
|
||||
|
||||
Reference in New Issue
Block a user