Zeigen die Spec- bzw. Blockdefinitions-Struktur einer VF-/GF-Linienzugkette in der Konsole, um sichtbar zu machen, dass ein einzelner VF_n-Wrapper intern zwischen VF- und GF-Abschnitten wechseln kann (Grundlage fuer den noch ausstehenden Separator-TYP-Fix). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
158 lines
5.8 KiB
Python
158 lines
5.8 KiB
Python
"""
|
|
Diagnose: Inhalt jeder VF_n/GF_n-Linienzug-Kette aus Spec + sepliste
|
|
gegenueberstellen.
|
|
|
|
Zeigt fuer jede Kette (spec_id, z.B. VF_hundm05_LZ_01 = VF_1):
|
|
- die "glied"-Folge aus der Spec (Horizontal-VF/Linie-GF/... in
|
|
Baureihenfolge, siehe vf_spec.lsp/vsp-journal) - das ist die
|
|
DOMAENEN-Wahrheit ueber VF- vs. GF-Abschnitte,
|
|
- die tatsaechliche sepliste (AS/SEP/ES in Baureihenfolge) aus dem
|
|
zugehoerigen export_raw.json/export.csv-Eintrag des gleichnamigen
|
|
VF_n-Wrappers.
|
|
|
|
Zweck: sichtbar machen, wie viele Separatoren tatsaechlich je Glied-Uebergang
|
|
entstehen und ob ein einzelner VF_n-Wrapper (ein Blockname!) intern zwischen
|
|
VF- und GF-Abschnitten wechselt - der Blockname allein (VF_n/GF_n) sagt
|
|
darueber NICHTS aus, wie sich beim csv:wrapper-strecke-typ-Versuch gezeigt
|
|
hat (alle Separatoren eines VF_n-Wrappers bekamen "VF", obwohl mehrere davon
|
|
zwischen echten GF-Abschnitten liegen).
|
|
|
|
Aufruf:
|
|
python dump_vf_kette_inhalt.py <spec.json> [<export_raw.json>]
|
|
|
|
<spec.json> z.B. tests/testdata/hundm05.json (vf_spec_export.py-Format)
|
|
<export_raw.json> optional, z.B. results/export_raw.json - wenn angegeben,
|
|
wird die sepliste des gleichnamigen VF_n/GF_n-Wrappers
|
|
daneben gestellt (Zuordnung ueber Reihenfolge: die N-te
|
|
Kette der Spec-Datei = der N-te VF_n/GF_n-Wrapper in
|
|
export_raw.json, aufsteigend nach Blockname sortiert -
|
|
die einzige verlaessliche Zuordnung ohne eigene ID-Bruecke,
|
|
siehe Hinweis in der Ausgabe).
|
|
"""
|
|
import json
|
|
import re
|
|
import sys
|
|
|
|
|
|
def lade_json(pfad):
|
|
with open(pfad, encoding="utf-8") as f:
|
|
return json.load(f)
|
|
|
|
|
|
def ketten_aus_spec(spec_liste):
|
|
"""Gruppiert die flache Spec-Liste in Ketten (ein 'spec_id'-Kopf +
|
|
seine 'glied'/'sub'-Eintraege bis zum naechsten Kopf). Objekte ohne
|
|
'spec_id' UND ohne 'glied'/'sub' (z.B. von Hand ergaenzte Anlagenteile
|
|
mit 'function') werden uebersprungen - siehe vf_spec_export.py."""
|
|
ketten = []
|
|
aktuelle = None
|
|
for obj in spec_liste:
|
|
if "spec_id" in obj:
|
|
aktuelle = {"kopf": obj, "eintraege": []}
|
|
ketten.append(aktuelle)
|
|
elif aktuelle is not None and ("glied" in obj or "sub" in obj):
|
|
aktuelle["eintraege"].append(obj)
|
|
return ketten
|
|
|
|
|
|
def glied_typ(eintrag):
|
|
"""VF/GF-Familie eines 'glied'-Eintrags (siehe vfl-letzter-typ-familie,
|
|
vf_linienzug.lsp:5979). 'sub'-Eintraege gehoeren zum zuletzt genannten
|
|
'glied' und werden nicht separat eingeordnet."""
|
|
name = eintrag.get("glied", "")
|
|
if name.startswith("Linie-GF"):
|
|
return "GF"
|
|
if name.startswith(("Horizontal-VF", "Linie-VF")):
|
|
return "VF"
|
|
if name == "kettenende":
|
|
return "ES"
|
|
return name or "?"
|
|
|
|
|
|
def kette_zusammenfassung(kette):
|
|
kopf = kette["kopf"]
|
|
zeilen = []
|
|
zeilen.append(
|
|
f" Kopf: as_winkel={kopf.get('as_winkel')} as_seite={kopf.get('as_seite')} "
|
|
f"start_hoehe={kopf.get('start_hoehe')}"
|
|
)
|
|
for e in kette["eintraege"]:
|
|
if "glied" in e:
|
|
typ = glied_typ(e)
|
|
sep_vor = e.get("sep_vor", e.get("vf_sep_vor", ""))
|
|
sep_nach = e.get("sep_nach", e.get("vf_sep_nach", ""))
|
|
zeilen.append(
|
|
f" [{typ:2s}] glied={e['glied']:15s} nr={e.get('nr','')!s:3s} "
|
|
f"dl={e.get('dl','')!s:8s} sep_vor={sep_vor!s:2s} sep_nach={sep_nach!s:2s}"
|
|
)
|
|
elif e.get("sub") == "kettenende":
|
|
zeilen.append(
|
|
f" [ES] kettenende es_winkel={e.get('es_winkel')} "
|
|
f"es_seite={e.get('es_seite')} dl={e.get('dl')}"
|
|
)
|
|
else:
|
|
zeilen.append(f" sub={e.get('sub')}")
|
|
return "\n".join(zeilen)
|
|
|
|
|
|
def wrapper_aus_export_raw(export_raw):
|
|
wrapper = [
|
|
b for b in export_raw
|
|
if re.match(r"^(VF|GF)_\d+$", b.get("block_name", ""))
|
|
]
|
|
wrapper.sort(key=lambda b: (b["block_name"].split("_")[0],
|
|
int(b["block_name"].split("_")[1])))
|
|
return wrapper
|
|
|
|
|
|
def sepliste_zusammenfassung(wrapper_block):
|
|
sepliste = wrapper_block.get("sepliste", [])
|
|
if not sepliste:
|
|
return " (keine sepliste-XDATA am Wrapper - Altbestand oder Fehler)"
|
|
zeilen = []
|
|
for s in sepliste:
|
|
zeilen.append(
|
|
f" lfdnr={s['lfdnr']:2d} typ={s['typ']:3s} id={s.get('id','?'):6s} "
|
|
f"x={s['x']:10.2f} y={s['y']:10.2f}"
|
|
)
|
|
return "\n".join(zeilen)
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) not in (2, 3):
|
|
print(f"Aufruf: python {sys.argv[0]} <spec.json> [<export_raw.json>]")
|
|
sys.exit(1)
|
|
|
|
spec = lade_json(sys.argv[1])
|
|
ketten = ketten_aus_spec(spec)
|
|
|
|
export_raw = None
|
|
wrapper_liste = []
|
|
if len(sys.argv) == 3:
|
|
export_raw = lade_json(sys.argv[2])
|
|
wrapper_liste = wrapper_aus_export_raw(export_raw)
|
|
if len(wrapper_liste) != len(ketten):
|
|
print(
|
|
f"[WARNUNG] {len(ketten)} Ketten in der Spec, aber "
|
|
f"{len(wrapper_liste)} VF_n/GF_n-Wrapper in export_raw.json - "
|
|
f"Zuordnung nach Reihenfolge ist damit UNSICHER.\n"
|
|
)
|
|
|
|
for i, kette in enumerate(ketten):
|
|
kopf = kette["kopf"]
|
|
print(f"\n{'=' * 70}")
|
|
print(f"Kette {i + 1}: {kopf['spec_id']}"
|
|
+ (f" <-> {wrapper_liste[i]['block_name']} "
|
|
f"(handle={wrapper_liste[i].get('handle')})"
|
|
if i < len(wrapper_liste) else " <-> (kein Wrapper zugeordnet)"))
|
|
print(f"{'=' * 70}")
|
|
print("--- Spec (Domaenen-Wahrheit VF/GF) ---")
|
|
print(kette_zusammenfassung(kette))
|
|
if i < len(wrapper_liste):
|
|
print("--- sepliste (tatsaechlich exportierte Separator-Reihenfolge) ---")
|
|
print(sepliste_zusammenfassung(wrapper_liste[i]))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|