From 75bd20a46ba89af041106445b2081d865ddf751f Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Wed, 13 May 2026 23:37:48 +0200 Subject: [PATCH] =?UTF-8?q?PYthon=20Programm=20f=C3=BCr=20einfachen=20St?= =?UTF-8?q?=C3=BCcklistenexport?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/export_csv.py | 270 ++++++++++++---------------------------------- 1 file changed, 68 insertions(+), 202 deletions(-) diff --git a/lib/export_csv.py b/lib/export_csv.py index b1e7a3f..1feab4d 100644 --- a/lib/export_csv.py +++ b/lib/export_csv.py @@ -1,15 +1,13 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ -export_csv.py - Erzeugt CSV aus den von LISP gesammelten Block-Daten. +export_csv.py - Erzeugt eine einfache Item-Liste als CSV (ohne Summierung). Aufruf: python export_csv.py -Argumente: - export_raw.json - JSON-Datei mit allen INSERT-Entities aus der Zeichnung - data_dir - Pfad zum data/-Verzeichnis (mit json/ Unterordner) - output.csv - Ziel-CSV-Datei +CSV-Format: + Elementnummer;TeileArt;TeileId;NachbarIds;Bezeichnung;Planquadrat;rotation;Merkmale """ import json @@ -18,6 +16,10 @@ import os import uuid +# --------------------------------------------------------------------------- +# Gemeinsame Hilfsfunktionen (auch in export_sivas.py verwendet) +# --------------------------------------------------------------------------- + def load_json(path): with open(path, "r", encoding="utf-8") as f: return json.load(f) @@ -27,11 +29,9 @@ def build_lookup(boegen, weichen): """Erzeugt ein Dict: SivasNr (als String) -> (typ, eintrag)""" lookup = {} for b in boegen: - key = str(b["Sivasnr"]) - lookup[key] = ("bogen", b) + lookup[str(b["Sivasnr"])] = ("bogen", b) for w in weichen: - key = str(w["Sivasnr"]) - lookup[key] = ("weiche", w) + lookup[str(w["Sivasnr"])] = ("weiche", w) return lookup @@ -39,29 +39,11 @@ def generate_shape_id(): return "shape_" + str(uuid.uuid4()) -def classify_weiche(eintrag): - """Bestimmt den Weichen-Subtyp fuer die Omniflo Sum Zaehlung.""" - wt = eintrag.get("WeichenTyp", "") - profil = eintrag.get("ProfilTyp", "") - if "WEICHENKOERPER" in profil.upper(): - return "weichenkoerper" - if wt == "Einzelweiche": - return "einzelweiche" - if wt == "Doppelweiche": - return "doppelweiche" - if wt == "Dreiwegeweiche": - return "dreiwegeweiche" - if wt == "Deltaweiche" or "DELTA" in profil.upper(): - return "deltaweiche" - if wt == "Dreifachweiche": - return "deltaweiche" - if wt == "Sternweiche" or "STAR" in profil.upper(): - return "sternweiche" - return "einzelweiche" - +# --------------------------------------------------------------------------- +# Merkmale-Builder +# --------------------------------------------------------------------------- def build_bogen_merkmale(block, eintrag): - """Merkmale-JSON fuer einen Omniflo Bogen.""" return { "Länge in Meter": "0", "Kurvenwinkel": eintrag.get("KurvenWinkel", 0), @@ -73,7 +55,6 @@ def build_bogen_merkmale(block, eintrag): def build_weiche_merkmale(block, eintrag): - """Merkmale-JSON fuer eine Omniflo Weiche.""" wt = eintrag.get("WeichenTyp", "Einzelweiche") return { "Länge in Meter links": None, @@ -90,7 +71,6 @@ def build_weiche_merkmale(block, eintrag): def build_gerade_merkmale(block): - """Merkmale-JSON fuer eine Omniflo Gerade (AP110).""" return { "Anzahl der Separatoren": "0", "Länge in Meter": "2", @@ -104,7 +84,6 @@ def build_gerade_merkmale(block): def build_kreisel_merkmale(block): - """Merkmale-JSON fuer einen ILS Kreisel.""" return { "Abstand (Kreiselachse A - Kreiselachse) in Meter": "3", "Anzahl der Separatoren": "2", @@ -117,60 +96,31 @@ def build_kreisel_merkmale(block): } -# --- Bekannte Blocknamen fuer nicht-Omniflo Elemente --- +# --------------------------------------------------------------------------- +# Bekannte Blocknamen +# --------------------------------------------------------------------------- + KREISEL_BLOCKS = {"AN8", "SP8"} - -VARIO_BLOCKS = { - "AUS_Element_links", "EIN_Element_links", - "Staustrecke_SP_1000_mm", "Staustrecke_Separator_SP_300_mm", - "Vario_Spannstation_SP_500mm", "Vario_Motorstation_SP_500mm", -} - -# Koordinatensystem-Bloecke (ignorieren) SKIP_BLOCKS = {"K1", "K2", "K3", "K4", "KS_EIN", "KS_AUS"} -def process_blocks(blocks, lookup): - """ - Verarbeitet alle Bloecke und erzeugt: - - items: Liste der CSV-Einzelzeilen - - counters: Zaehler fuer Summierungszeilen - """ - items = [] - counters = { - # Omniflo Sum - "anzahl_boegen": 0, - "anzahl_weichenkoerper": 0, - "anzahl_einzelweichen": 0, - "anzahl_deltaweichen": 0, - "anzahl_doppel_dreiwegeweichen": 0, - "anzahl_sternweichen": 0, - "gesamtlaenge_ap110": 0.0, - "gesamtlaenge_ap60": 0.0, - # ILS Automation - "anzahl_kreisel": 0, - "anzahl_kreisel_pinband": 0, - "sep_kreisel_pin": 0, - "sep_kreisel_ohne_pin": 0, - "anzahl_verbindungskreisel": 0, - "laengen_kreisel": 0.0, - "anzahl_weichen_ils": 0, - "anzahl_eckraeder": 0, - "anzahl_gefaellestrecken": 0, - "anzahl_variofoerderer": 0, - "anzahl_streckengruppen": 0, - "laengen_gefaellestrecken": 0.0, - "anzahl_motoren_vario": 0, - "laengen_variofoerderer": 0.0, - "anzahl_etf": 0, - "laengen_etf": 0.0, - "anzahl_separatoren": 0, - "anzahl_scanner": 0, - "anzahl_btbeladung": 0, - "anzahl_abwurfstationen": 0, - } +# --------------------------------------------------------------------------- +# Planquadrat aus Block-Koordinaten +# --------------------------------------------------------------------------- - elem_nr = 0 +def format_planquadrat(block): + x = block.get("x", 0.0) + y = block.get("y", 0.0) + return f"X:{x:.2f} Y:{y:.2f}" + + +# --------------------------------------------------------------------------- +# Bloecke verarbeiten (einfache Liste, keine Summierung) +# --------------------------------------------------------------------------- + +def process_blocks(blocks, lookup): + items = [] + elem_nr = -1 bogen_count = 0 weiche_count = {} gerade_count = 0 @@ -179,11 +129,10 @@ def process_blocks(blocks, lookup): for block in blocks: bname = block.get("block_name", "") - # Koordinatensystem-Bloecke ueberspringen if bname in SKIP_BLOCKS: continue - # Omniflo Bogen oder Weiche? + # Omniflo Bogen oder Weiche if bname in lookup: typ, eintrag = lookup[bname] elem_nr += 1 @@ -195,37 +144,26 @@ def process_blocks(blocks, lookup): "nr": elem_nr, "teileart": "Omniflo Kurve", "teileid": shape_id, + "nachbarids": "", "bezeichnung": f"OFBogen :{bogen_count}", - "anzahl": 1, - "merkmale": build_bogen_merkmale(block, eintrag) + "planquadrat": format_planquadrat(block), + "rotation": block.get("rotation", 0.0), + "merkmale": build_bogen_merkmale(block, eintrag), }) - counters["anzahl_boegen"] += 1 elif typ == "weiche": - subtyp = classify_weiche(eintrag) wt = eintrag.get("WeichenTyp", "Einzelweiche") weiche_count[wt] = weiche_count.get(wt, 0) + 1 - items.append({ "nr": elem_nr, "teileart": "Omniflo Weiche", "teileid": shape_id, + "nachbarids": "", "bezeichnung": f"OFWeiche :{weiche_count[wt]}", - "anzahl": 1, - "merkmale": build_weiche_merkmale(block, eintrag) + "planquadrat": format_planquadrat(block), + "rotation": block.get("rotation", 0.0), + "merkmale": build_weiche_merkmale(block, eintrag), }) - - if subtyp == "einzelweiche": - counters["anzahl_einzelweichen"] += 1 - elif subtyp == "doppelweiche" or subtyp == "dreiwegeweiche": - counters["anzahl_doppel_dreiwegeweichen"] += 1 - elif subtyp == "deltaweiche": - counters["anzahl_deltaweichen"] += 1 - elif subtyp == "sternweiche": - counters["anzahl_sternweichen"] += 1 - elif subtyp == "weichenkoerper": - counters["anzahl_weichenkoerper"] += 1 - continue # Omniflo Gerade (AP110) @@ -236,11 +174,12 @@ def process_blocks(blocks, lookup): "nr": elem_nr, "teileart": "Omniflo Gerade", "teileid": generate_shape_id(), + "nachbarids": "", "bezeichnung": f"OFGerade :{gerade_count}", - "anzahl": 1, - "merkmale": build_gerade_merkmale(block) + "planquadrat": format_planquadrat(block), + "rotation": block.get("rotation", 0.0), + "merkmale": build_gerade_merkmale(block), }) - counters["gesamtlaenge_ap110"] += 2000.0 continue # ILS Kreisel @@ -251,100 +190,39 @@ def process_blocks(blocks, lookup): "nr": elem_nr, "teileart": "ILS 2.0 Kreisel", "teileid": generate_shape_id(), + "nachbarids": "", "bezeichnung": f"Kreisel :{kreisel_count}", - "anzahl": 1, - "merkmale": build_kreisel_merkmale(block) + "planquadrat": format_planquadrat(block), + "rotation": block.get("rotation", 0.0), + "merkmale": build_kreisel_merkmale(block), }) - counters["anzahl_kreisel"] += 1 - counters["sep_kreisel_ohne_pin"] += 2 - counters["laengen_kreisel"] += 3.0 - counters["anzahl_separatoren"] += 2 - if counters["anzahl_streckengruppen"] == 0: - counters["anzahl_streckengruppen"] = 1 continue - # VarioFoerderer-Bloecke - is_vario = False - for vb in VARIO_BLOCKS: - if vb in bname: - is_vario = True - break - if is_vario: - counters["anzahl_variofoerderer"] += 1 - continue - - return items, counters + return items -def build_ils_automation_row(elem_nr, counters): - """Erzeugt die ILS 2.0 Automation Summierungszeile.""" - merkmale = { - "Anzahl Kreisel": counters["anzahl_kreisel"], - "Anzahl Kreisel mit Pinband": counters["anzahl_kreisel_pinband"], - "Anzahl aller Separatoren in Kreisel mit PIN": counters["sep_kreisel_pin"], - "Anzahl aller Separatoren in Kreisel ohne PIN": counters["sep_kreisel_ohne_pin"], - "Anzahl Verbindungskreisel": counters["anzahl_verbindungskreisel"], - "Längen aller Kreisel": counters["laengen_kreisel"], - "Anzahl der Weichen": counters["anzahl_weichen_ils"], - "Anzahl der Eckräder": counters["anzahl_eckraeder"], - "Anzahl der einzelnen Gefällestrecken": counters["anzahl_gefaellestrecken"], - "Anzahl der einzelnen Varioförderer": counters["anzahl_variofoerderer"], - "Anzahl der Streckengruppen": counters["anzahl_streckengruppen"], - "Längen aller Gefällestrecken": counters["laengen_gefaellestrecken"], - "Anzahl der Motoren Varioförderer": counters["anzahl_motoren_vario"], - "Längen aller Varioförderer": counters["laengen_variofoerderer"], - "Anzahl ETFs": counters["anzahl_etf"], - "Längen aller ETFs": counters["laengen_etf"], - "Anzahl aller Separatoren": counters["anzahl_separatoren"], - "Anzahl aller Scanner": counters["anzahl_scanner"], - "Anzahl aller BTBeladung": counters["anzahl_btbeladung"], - "Anzahl aller Abwurfstationen": counters["anzahl_abwurfstationen"], - } - return { - "nr": elem_nr, - "teileart": "ILS 2.0 Automation", - "teileid": "autogenerated_ils_automation_json", - "bezeichnung": "Automation ILS structgen", - "anzahl": 1, - "merkmale": merkmale, - } - - -def build_omniflo_sum_row(elem_nr, counters): - """Erzeugt die Omniflo Sum Summierungszeile.""" - merkmale = { - "Anzahl Bögen": counters["anzahl_boegen"], - "Anzahl Weichengrundkörper": counters["anzahl_weichenkoerper"], - "Anzahl Einwegweichen": counters["anzahl_einzelweichen"], - "Anzahl Deltaweichen": counters["anzahl_deltaweichen"], - "Anzahl Doppelweichen und Dreiwegeweichen": counters["anzahl_doppel_dreiwegeweichen"], - "Anzahl Sternweichen": counters["anzahl_sternweichen"], - "Gesamtlänge AP110": counters["gesamtlaenge_ap110"], - "Gesamtlänge AP60": counters["gesamtlaenge_ap60"], - } - return { - "nr": elem_nr, - "teileart": "Omniflo Sum", - "teileid": "autogenerated_of_json", - "bezeichnung": "Omniflo sum", - "anzahl": 1, - "merkmale": merkmale, - } - +# --------------------------------------------------------------------------- +# CSV-Formatierung +# --------------------------------------------------------------------------- def format_csv_line(item): - """Formatiert eine CSV-Zeile im geforderten Format.""" merkmale_json = json.dumps(item["merkmale"], ensure_ascii=False) - return '{nr};"{teileart}";"{teileid}";"{bezeichnung}";{anzahl};{merkmale}'.format( - nr=item["nr"], - teileart=item["teileart"], - teileid=item["teileid"], - bezeichnung=item["bezeichnung"], - anzahl=item["anzahl"], - merkmale=merkmale_json, + return ( + f'{item["nr"]}' + f';"{item["teileart"]}"' + f';"{item["teileid"]}"' + f';{item["nachbarids"]}' + f';"{item["bezeichnung"]}"' + f';"{item["planquadrat"]}"' + f';' + f';{merkmale_json}' ) +# --------------------------------------------------------------------------- +# Main +# --------------------------------------------------------------------------- + def main(): if len(sys.argv) < 4: print("Aufruf: python export_csv.py ") @@ -354,7 +232,6 @@ def main(): data_dir = sys.argv[2] output_csv = sys.argv[3] - # Daten laden blocks = load_json(raw_json_path) boegen_path = os.path.join(data_dir, "json", "omniflo_boegen.json") weichen_path = os.path.join(data_dir, "json", "omniflo_weichen.json") @@ -367,20 +244,9 @@ def main(): print(f"[export_csv] {len(blocks)} Bloecke geladen, " f"{len(boegen)} Boegen, {len(weichen)} Weichen im Katalog.") - # Bloecke verarbeiten - items, counters = process_blocks(blocks, lookup) + items = process_blocks(blocks, lookup) - # Summierungszeilen anhaengen - next_nr = (items[-1]["nr"] + 1) if items else 1 - - ils_row = build_ils_automation_row(next_nr, counters) - items.append(ils_row) - - of_row = build_omniflo_sum_row(next_nr + 1, counters) - items.append(of_row) - - # CSV schreiben - header = "Elementnummer;TeileArt;TeileId;Bezeichnung;Anzahl;Merkmale" + header = "Elementnummer;TeileArt;TeileId;NachbarIds;Bezeichnung;Planquadrat;rotation;Merkmale" with open(output_csv, "w", encoding="utf-8") as f: f.write(header + "\n") for item in items: