[MERGE] export Konflikt gelöst
This commit is contained in:
+49
-188
@@ -14,7 +14,8 @@ Neues CSV-Format:
|
||||
- IDs: kommaseparierte Liste der ID-Attribute aller Bloecke der Zeile
|
||||
(eigene Spalte, nicht mehr Teil des details-JSON).
|
||||
|
||||
- Omniflo Bogen/Weiche: gruppiert nach SivasNummer, Anzahl summiert
|
||||
- Omniflo (TEILEART "Omniflo ..."): je Nummer aus dem ARTINR-Attribut
|
||||
(kommagetrennt) eine Zeile, Anzahl summiert; TEF-Teile als "Omniflo TEF"
|
||||
- Omniflo Gerade: gruppiert nach ARTINR-Attribut, Laenge[mm] summiert
|
||||
- ILS 2.0 Kreisel: gruppiert nach Kreiselart+Abstand+Anzahl Separatoren/
|
||||
Scanner/Rampen, Anzahl summiert
|
||||
@@ -34,7 +35,8 @@ Aufruf:
|
||||
|
||||
Argumente:
|
||||
export_raw.json - JSON-Datei mit allen INSERT-Entities aus der Zeichnung
|
||||
data_dir - Pfad zum data/-Verzeichnis (mit json/ Unterordner)
|
||||
data_dir - Pfad zum data/-Verzeichnis (derzeit ungenutzt, bleibt
|
||||
fuer den Aufrufer export.lsp erhalten)
|
||||
output.csv - Ziel-CSV-Datei (reine Merkmalnummern, fuer den
|
||||
Sivas-Import)
|
||||
|
||||
@@ -71,47 +73,11 @@ def load_json(path):
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def build_lookup(boegen, weichen):
|
||||
"""Erzeugt ein Dict: SivasNr (als String) -> (typ, eintrag)"""
|
||||
lookup = {}
|
||||
for b in boegen:
|
||||
lookup[str(b["Sivasnr"])] = ("bogen", b)
|
||||
for w in weichen:
|
||||
lookup[str(w["Sivasnr"])] = ("weiche", w)
|
||||
return lookup
|
||||
|
||||
|
||||
def classify_weiche(eintrag):
|
||||
"""Bestimmt den Weichen-Subtyp fuer die ILS-Automation-Zaehlung."""
|
||||
wt = eintrag.get("WeichenTyp", "")
|
||||
profil = eintrag.get("ProfilTyp", "")
|
||||
if "WEICHENKOERPER" in profil.upper():
|
||||
return "weichenkoerper"
|
||||
if wt == "Einzelweiche":
|
||||
return "einzelweiche"
|
||||
if wt in ("Doppelweiche", "Dreiwegeweiche"):
|
||||
return "doppelweiche"
|
||||
if wt in ("Deltaweiche", "Dreifachweiche") or "DELTA" in profil.upper():
|
||||
return "deltaweiche"
|
||||
if wt == "Sternweiche" or "STAR" in profil.upper():
|
||||
return "sternweiche"
|
||||
return "einzelweiche"
|
||||
|
||||
|
||||
def get_id(block):
|
||||
"""Liest das eindeutige ID-Attribut eines Blocks (von ssg-id-check-all vergeben)."""
|
||||
return block.get("attribs", {}).get("ID", "")
|
||||
|
||||
|
||||
def format_sivasnr(sivasnr):
|
||||
"""
|
||||
Wandelt einen "+"-separierten Sivasnr-Wert (Rohformat aus den JSON-Katalogen,
|
||||
dort weiterhin benoetigt fuer Dateinamen-Referenzen) in eine reine
|
||||
kommaseparierte Liste fuer die Ausgabe (CSV/Block-Attribut) um.
|
||||
"""
|
||||
return ", ".join(p.strip() for p in str(sivasnr).split("+") if p.strip())
|
||||
|
||||
|
||||
# --- Sivas-Merkmalnummern: Anzeigetexte, die nicht 1:1 aus dem Attribut
|
||||
# uebernommen werden koennen (Attribute bleiben ASCII, siehe CLAUDE.md-
|
||||
# Konvention "Alle Texte in Dateien ohne Umlaute" - Sivas erwartet aber die
|
||||
@@ -218,42 +184,6 @@ def gefaellestrecke_signature(block):
|
||||
)
|
||||
|
||||
|
||||
def expand_tef_components(sivasnr_parts, sivasnr_tef):
|
||||
"""Ersetzt "0_BG*"-Platzhalter-Teile in sivasnr_parts durch die dahinter
|
||||
liegenden echten TEF-Sivasnummern (Katalogfeld SivasnrTEF).
|
||||
|
||||
"0_BG*"-Werte im Sivasnr-Rohwert (z.B. "834372404+0_BG071090") sind KEINE
|
||||
echten Sivasnummern, sondern reine Blocknamen-Platzhalter fuer eine TEF-
|
||||
Baugruppe aus mehreren realen Teilen - "0_BG071090" steht z.B. fuer die
|
||||
drei echten Teile "0_B10071"+"0_B10090"+"0_B10090" (siehe SivasnrTEF im
|
||||
Katalog, omniflo_weichen.json/omniflo_boegen.json). Ohne diese Aufloesung
|
||||
wuerde "0_BG071090" selbst als (nicht existente) Sivasnummer gezaehlt und
|
||||
die echten Teile (u.a. 0_B10071) fehlten in der Summierung.
|
||||
Reale TEF-Einzelteile, die bereits direkt im Sivasnr-Rohwert stehen
|
||||
(Praefix "0_B", aber nicht "0_BG", z.B. "821104026+0_B10071"), sind schon
|
||||
echte Sivasnummern und werden unveraendert uebernommen.
|
||||
Bei mehreren "0_BG*"-Platzhaltern im selben Rohwert (TEF beidseitig) wird
|
||||
SivasnrTEF zu gleichen Teilen aufgeteilt - der Katalog listet die Teile
|
||||
je Seite hintereinander in SivasnrTEF.
|
||||
"""
|
||||
bg_count = sum(1 for p in sivasnr_parts if p.startswith("0_BG"))
|
||||
if bg_count == 0:
|
||||
return list(sivasnr_parts)
|
||||
|
||||
tef_parts = [p.strip() for p in str(sivasnr_tef or "").split("+") if p.strip()]
|
||||
chunk_size = len(tef_parts) // bg_count if bg_count else 0
|
||||
|
||||
expanded = []
|
||||
tef_index = 0
|
||||
for part in sivasnr_parts:
|
||||
if part.startswith("0_BG"):
|
||||
expanded.extend(tef_parts[tef_index:tef_index + chunk_size])
|
||||
tef_index += chunk_size
|
||||
else:
|
||||
expanded.append(part)
|
||||
return expanded
|
||||
|
||||
|
||||
def parse_float_list(csv_str):
|
||||
"""Kommagetrennten Attribut-String (z.B. L_GF_m) in Liste von floats."""
|
||||
out = []
|
||||
@@ -443,17 +373,21 @@ ILS_SIVASNR = {
|
||||
}
|
||||
|
||||
|
||||
def process_blocks(blocks, lookup):
|
||||
def process_blocks(blocks):
|
||||
"""
|
||||
Verarbeitet alle Bloecke.
|
||||
|
||||
Omniflo-Elemente werden ueber das TEILEART-Attribut ("Omniflo ...")
|
||||
erkannt, ihre Sivas-Nummern kommen - wie beim Geruest - ausschliesslich
|
||||
aus dem ARTINR-Attribut (kommagetrennt, TEF-Teile dort bereits
|
||||
aufgeloest). Ein Katalog-Lookup ueber den Blocknamen findet nicht statt.
|
||||
|
||||
Rueckgabe:
|
||||
items - Liste der CSV-Zeilen als Dicts
|
||||
counters - Zaehler fuer ILS-Automation-Summierungszeile
|
||||
"""
|
||||
# Gruppen: sivasnr_str -> {anzahl, ids}
|
||||
bogen_groups = {} # sivasnr -> dict
|
||||
weiche_groups = {} # sivasnr -> dict
|
||||
# Omniflo: artinr -> {teileart, anzahl, ids}
|
||||
omniflo_groups = {}
|
||||
# Gerade: artinr_str -> {anzahl, laenge_mm_total, ids}
|
||||
gerade_groups = {}
|
||||
kreisel_list = [] # Liste von blocks
|
||||
@@ -467,14 +401,6 @@ def process_blocks(blocks, lookup):
|
||||
geruest_list = [] # Liste von GR_-Geruest-Baugruppenbloecken, je einer Zeile
|
||||
|
||||
counters = {
|
||||
"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,
|
||||
"anzahl_kreisel": 0,
|
||||
"anzahl_kreisel_pinband": 0,
|
||||
"sep_kreisel_pin": 0,
|
||||
@@ -544,76 +470,9 @@ def process_blocks(blocks, lookup):
|
||||
counters["anzahl_geruest"] += 1
|
||||
continue
|
||||
|
||||
# --- Omniflo Bogen oder Weiche (erkannt via Katalog) ---
|
||||
if bname in lookup:
|
||||
typ, eintrag = lookup[bname]
|
||||
sivasnr_raw = eintrag.get("Sivasnr", bname)
|
||||
sivasnr_parts = [p.strip() for p in str(sivasnr_raw).split("+")]
|
||||
has_tef = any(p.startswith("0_B") for p in sivasnr_parts)
|
||||
block_id = get_id(block)
|
||||
|
||||
if typ == "bogen":
|
||||
if has_tef and len(sivasnr_parts) > 1:
|
||||
# Multi-Komponenten: jede Komponente separat gruppieren
|
||||
# ("0_BG*"-Platzhalter werden ueber SivasnrTEF in ihre
|
||||
# echten Einzelteile aufgeloest, siehe expand_tef_components)
|
||||
expanded_parts = expand_tef_components(sivasnr_parts, eintrag.get("SivasnrTEF"))
|
||||
for i, comp_sivasnr in enumerate(expanded_parts):
|
||||
comp_id = f"{block_id}.t{i+1}"
|
||||
if comp_sivasnr not in bogen_groups:
|
||||
bogen_groups[comp_sivasnr] = {"anzahl": 0, "ids": []}
|
||||
bogen_groups[comp_sivasnr]["anzahl"] += 1
|
||||
bogen_groups[comp_sivasnr]["ids"].append(comp_id)
|
||||
else:
|
||||
# Normal: alle als eine Komponente
|
||||
sivasnr = format_sivasnr(sivasnr_raw)
|
||||
if sivasnr not in bogen_groups:
|
||||
bogen_groups[sivasnr] = {"anzahl": 0, "ids": []}
|
||||
bogen_groups[sivasnr]["anzahl"] += 1
|
||||
bogen_groups[sivasnr]["ids"].append(block_id)
|
||||
counters["anzahl_boegen"] += 1
|
||||
|
||||
elif typ == "weiche":
|
||||
subtyp = classify_weiche(eintrag)
|
||||
if has_tef and len(sivasnr_parts) > 1:
|
||||
# Multi-Komponenten: jede Komponente separat gruppieren
|
||||
# ("0_BG*"-Platzhalter werden ueber SivasnrTEF in ihre
|
||||
# echten Einzelteile aufgeloest, siehe expand_tef_components)
|
||||
expanded_parts = expand_tef_components(sivasnr_parts, eintrag.get("SivasnrTEF"))
|
||||
for i, comp_sivasnr in enumerate(expanded_parts):
|
||||
comp_id = f"{block_id}.t{i+1}"
|
||||
if comp_sivasnr.startswith("0_B"):
|
||||
# TEF-Komponente (Bogen) in bogen_groups
|
||||
if comp_sivasnr not in bogen_groups:
|
||||
bogen_groups[comp_sivasnr] = {"anzahl": 0, "ids": []}
|
||||
bogen_groups[comp_sivasnr]["anzahl"] += 1
|
||||
bogen_groups[comp_sivasnr]["ids"].append(comp_id)
|
||||
else:
|
||||
# Weichen-Komponente in weiche_groups
|
||||
if comp_sivasnr not in weiche_groups:
|
||||
weiche_groups[comp_sivasnr] = {"anzahl": 0, "ids": []}
|
||||
weiche_groups[comp_sivasnr]["anzahl"] += 1
|
||||
weiche_groups[comp_sivasnr]["ids"].append(comp_id)
|
||||
else:
|
||||
# Normal: alle als eine Komponente
|
||||
sivasnr = format_sivasnr(sivasnr_raw)
|
||||
if sivasnr not in weiche_groups:
|
||||
weiche_groups[sivasnr] = {"anzahl": 0, "ids": []}
|
||||
weiche_groups[sivasnr]["anzahl"] += 1
|
||||
weiche_groups[sivasnr]["ids"].append(block_id)
|
||||
if subtyp == "einzelweiche":
|
||||
counters["anzahl_einzelweichen"] += 1
|
||||
elif subtyp in ("doppelweiche", "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) ---
|
||||
# VOR dem allgemeinen Omniflo-Zweig: Geraden tragen ggf. ebenfalls
|
||||
# TEILEART "Omniflo ...", brauchen aber die Laengensumme.
|
||||
if matches_any(bname, BLOCKPATTERNS.get("pattern_gerade", [])):
|
||||
attribs = block.get("attribs", {})
|
||||
artinr = attribs.get("ARTINR", "")
|
||||
@@ -628,7 +487,33 @@ def process_blocks(blocks, lookup):
|
||||
gerade_groups[key]["anzahl"] += 1
|
||||
gerade_groups[key]["laenge_mm"] += laenge
|
||||
gerade_groups[key]["ids"].append(get_id(block))
|
||||
counters["gesamtlaenge_ap110"] += laenge
|
||||
continue
|
||||
|
||||
# --- Omniflo-Element (Bogen, Weiche, Ladeschleife, TEF, ...) ---
|
||||
# Erkennung ueber TEILEART, Sivas-Nummern aus ARTINR - wie beim
|
||||
# Geruest eine Zeile je Nummer, hier aber ueber ALLE Bloecke
|
||||
# gruppiert. Die DWGs fuehren TEF-Teile bereits aufgeloest im ARTINR
|
||||
# (z.B. "834372002, 0_B10090, 0_B10090"). TEF-Teile ("0_B*") laufen
|
||||
# unter "Omniflo TEF", damit dasselbe Teil aus Bogen und Weiche EINE
|
||||
# Zeile bleibt.
|
||||
attribs = block.get("attribs", {})
|
||||
teileart = attribs.get("TEILEART", "")
|
||||
if teileart.startswith("Omniflo"):
|
||||
artinr_list = [a.strip() for a in attribs.get("ARTINR", "").split(",") if a.strip()]
|
||||
block_id = get_id(block)
|
||||
if not artinr_list:
|
||||
print(f"[export_sivas] WARNUNG: Omniflo-Block {bname} (ID {block_id}) "
|
||||
f"ohne ARTINR - nicht exportiert.", file=sys.stderr)
|
||||
continue
|
||||
for i, artinr in enumerate(artinr_list):
|
||||
comp_id = f"{block_id}.t{i+1}" if len(artinr_list) > 1 else block_id
|
||||
if artinr not in omniflo_groups:
|
||||
omniflo_groups[artinr] = {
|
||||
"teileart": "Omniflo TEF" if artinr.startswith("0_B") else teileart,
|
||||
"anzahl": 0, "ids": [],
|
||||
}
|
||||
omniflo_groups[artinr]["anzahl"] += 1
|
||||
omniflo_groups[artinr]["ids"].append(comp_id)
|
||||
continue
|
||||
|
||||
# --- ILS Eckrad (vor Kreisel pruefen: pattern_kreisel schliesst
|
||||
@@ -695,27 +580,10 @@ def process_blocks(blocks, lookup):
|
||||
items = []
|
||||
nr = 1
|
||||
|
||||
for sivasnr, g in bogen_groups.items():
|
||||
teileart = "TEF Bogen" if str(sivasnr).startswith("0_B") else "Omniflo Bogen"
|
||||
for sivasnr, g in omniflo_groups.items():
|
||||
items.append({
|
||||
"nr": nr,
|
||||
"teileart": teileart,
|
||||
"sivasnr": sivasnr,
|
||||
"sivasnr_quoted": False,
|
||||
"bezeichnung": "",
|
||||
"dispgruppe": 10,
|
||||
"anzahl": g["anzahl"],
|
||||
"laenge_mm": "",
|
||||
"ids": g["ids"],
|
||||
"details": {},
|
||||
})
|
||||
nr += 1
|
||||
|
||||
for sivasnr, g in weiche_groups.items():
|
||||
teileart = "TEF Weiche" if str(sivasnr).startswith("0_B") else "Omniflo Weiche"
|
||||
items.append({
|
||||
"nr": nr,
|
||||
"teileart": teileart,
|
||||
"teileart": g["teileart"],
|
||||
"sivasnr": sivasnr,
|
||||
"sivasnr_quoted": False,
|
||||
"bezeichnung": "",
|
||||
@@ -842,7 +710,7 @@ def process_blocks(blocks, lookup):
|
||||
# ILS_SIVASNR - JEDE Artikelnummer bekommt ihre EIGENE Sivas-Zeile (Sivas
|
||||
# kennt nur eine Sivasnr je Zeile), gleiche Artikelnummern INNERHALB
|
||||
# derselben Baugruppe werden dabei zu einer Zeile mit anzahl>1
|
||||
# zusammengefasst (wie bogen_groups/weiche_groups oben). Die volle
|
||||
# zusammengefasst (wie omniflo_groups oben). Die volle
|
||||
# LAENGE der Baugruppe steht auf JEDER so entstandenen Zeile - Sivas hat
|
||||
# kein Konzept einer "gemeinsamen" Laenge ueber mehrere Zeilen hinweg.
|
||||
for block in geruest_list:
|
||||
@@ -1026,22 +894,15 @@ def main():
|
||||
sys.exit(1)
|
||||
|
||||
raw_json_path = sys.argv[1]
|
||||
data_dir = sys.argv[2]
|
||||
# sys.argv[2] (data_dir) wird derzeit nicht gebraucht - Omniflo-Nummern
|
||||
# kommen aus ARTINR, nicht mehr aus dem Katalog. Argument bleibt fuer
|
||||
# den Aufrufer (export.lsp) bestehen.
|
||||
output_csv = sys.argv[3]
|
||||
|
||||
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")
|
||||
print(f"[export_sivas] {len(blocks)} Bloecke geladen.")
|
||||
|
||||
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_sivas] {len(blocks)} Bloecke geladen, "
|
||||
f"{len(boegen)} Boegen, {len(weichen)} Weichen im Katalog.")
|
||||
|
||||
items, _ = process_blocks(blocks, lookup)
|
||||
items, _ = process_blocks(blocks)
|
||||
|
||||
header = "Nr;TeileArt;SivasNummer;Bezeichnung;Dispogruppe;Anzahl;Laenge[mm];IDs;details"
|
||||
with open(output_csv, "w", encoding="utf-8") as f:
|
||||
|
||||
Reference in New Issue
Block a user