Files
dxfmakros/lib/export_sivas.py
T

394 lines
13 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
export_csv.py - Erzeugt CSV aus den von LISP gesammelten Block-Daten.
Aufruf:
python export_csv.py <export_raw.json> <data_dir> <output.csv>
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
"""
import json
import sys
import os
import uuid
def load_json(path):
with open(path, "r", encoding="utf-8") as f:
return json.load(f)
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)
for w in weichen:
key = str(w["Sivasnr"])
lookup[key] = ("weiche", w)
return lookup
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"
def build_bogen_merkmale(block, eintrag):
"""Merkmale-JSON fuer einen Omniflo Bogen."""
return {
"Länge in Meter": "0",
"Kurvenwinkel": eintrag.get("KurvenWinkel", 0),
"Radius": eintrag.get("Radius", 0),
"Höhe": "2000",
"Drehung": block.get("rotation", 0.0),
"SivasNummer": str(eintrag.get("Sivasnr", ""))
}
def build_weiche_merkmale(block, eintrag):
"""Merkmale-JSON fuer eine Omniflo Weiche."""
wt = eintrag.get("WeichenTyp", "Einzelweiche")
return {
"Länge in Meter links": None,
"Länge in Meter rechts": None,
"Länge in Meter gerade": None,
"Weichentyp": wt,
"Richtung": str(eintrag.get("KurvenRichtung", "")),
"Weichenwinkel": eintrag.get("KurvenWinkel", 0),
"Höhe": "2000",
"Drehung": block.get("rotation", 0.0),
"Antrieb Kurve": eintrag.get("SivasnrTEF") is not None,
"SivasNummer": str(eintrag.get("Sivasnr", ""))
}
def build_gerade_merkmale(block):
"""Merkmale-JSON fuer eine Omniflo Gerade (AP110)."""
return {
"Anzahl der Separatoren": "0",
"Länge in Meter": "2",
"Winkel": "0",
"Anzahl der Scanner": 0,
"Höhe oben": "2000",
"Höhe unten": "2000",
"Drehung": block.get("rotation", 0.0),
"SivasNummer": ""
}
def build_kreisel_merkmale(block):
"""Merkmale-JSON fuer einen ILS Kreisel."""
return {
"Abstand (Kreiselachse A - Kreiselachse) in Meter": "3",
"Anzahl der Separatoren": "2",
"Kreiselart": "Standard",
"Anzahl der Scanner": "0",
"Anzahl der Rampen": "0",
"Höhe in m": "2",
"Drehrichtung": "UZS",
"Drehung": block.get("rotation", 0.0)
}
# --- Bekannte Blocknamen fuer nicht-Omniflo Elemente ---
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,
}
elem_nr = 0
bogen_count = 0
weiche_count = {}
gerade_count = 0
kreisel_count = 0
for block in blocks:
bname = block.get("block_name", "")
# Koordinatensystem-Bloecke ueberspringen
if bname in SKIP_BLOCKS:
continue
# Omniflo Bogen oder Weiche?
if bname in lookup:
typ, eintrag = lookup[bname]
elem_nr += 1
shape_id = generate_shape_id()
if typ == "bogen":
bogen_count += 1
items.append({
"nr": elem_nr,
"teileart": "Omniflo Kurve",
"teileid": shape_id,
"bezeichnung": f"OFBogen :{bogen_count}",
"anzahl": 1,
"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,
"bezeichnung": f"OFWeiche :{weiche_count[wt]}",
"anzahl": 1,
"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)
if "AP110" in bname.upper() or "AP_110" in bname.upper():
elem_nr += 1
gerade_count += 1
items.append({
"nr": elem_nr,
"teileart": "Omniflo Gerade",
"teileid": generate_shape_id(),
"bezeichnung": f"OFGerade :{gerade_count}",
"anzahl": 1,
"merkmale": build_gerade_merkmale(block)
})
counters["gesamtlaenge_ap110"] += 2000.0
continue
# ILS Kreisel
if bname in KREISEL_BLOCKS:
elem_nr += 1
kreisel_count += 1
items.append({
"nr": elem_nr,
"teileart": "ILS 2.0 Kreisel",
"teileid": generate_shape_id(),
"bezeichnung": f"Kreisel :{kreisel_count}",
"anzahl": 1,
"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
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,
}
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,
)
def main():
if len(sys.argv) < 4:
print("Aufruf: python export_csv.py <export_raw.json> <data_dir> <output.csv>")
sys.exit(1)
raw_json_path = sys.argv[1]
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")
boegen = load_json(boegen_path) if os.path.exists(boegen_path) else []
weichen = load_json(weichen_path) if os.path.exists(weichen_path) else []
lookup = build_lookup(boegen, weichen)
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)
# 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"
with open(output_csv, "w", encoding="utf-8") as f:
f.write(header + "\n")
for item in items:
f.write(format_csv_line(item) + "\n")
print(f"[export_csv] CSV geschrieben: {output_csv} ({len(items)} Zeilen)")
if __name__ == "__main__":
main()