feat: GR_-Geruest-Baugruppen in EXPORTCSV/EXPORTSIVAS aufnehmen
GR_-Bloecke werden jetzt wie BTMT eigenstaendig gesammelt (LISP: neues pattern_geruest in cfg/export.cfg, csv:collect-export-blocks, ssg-id-collect-blocks + ID-ATTDEF in *geruest-attrib-defs*) und in beiden Python-Exporten als eigene TeileArt-Zeile ausgegeben: ARTINR/BEZEICHNUNG/ TEILEART/LAENGE in festen Spalten, restliche Attribute (FARBE/LAYER) im Merkmale-/details-JSON. Dabei zwei Bugs behoben, die beim ersten echten GR_-Export sichtbar wurden: - csv:json-escape nutzte vl-string-subst (ersetzt nur das erste Vorkommen) statt des global ersetzenden ssg-str-replace-all - bei Attributwerten mit mehreren Anfuehrungszeichen blieb ein Zeichen unescaped und brach die JSON-Struktur beim Python-Parsen. - Gradzeichen (°) in data/json/geruest.json durch "Grad" ersetzt, um das Encoding-Risiko (cp1252 vs. UTF-8 beim LISP-Export) zu vermeiden.
This commit is contained in:
@@ -263,6 +263,23 @@ def build_btmt_merkmale(block):
|
||||
}
|
||||
|
||||
|
||||
def build_geruest_merkmale(block):
|
||||
"""Merkmale-Dict fuer einen GR_-Geruest-Baugruppenblock (siehe
|
||||
pattern_geruest in cfg/export.cfg, GeruestInsert.lsp *geruest-attrib-defs*).
|
||||
|
||||
ARTINR/LAENGE/BEZEICHNUNG wandern in feste CSV-Spalten (teileid/
|
||||
bezeichnung ueben in process_blocks unten), TEILEART/FARBE/LAYER bleiben
|
||||
als Rest-Attribute in der Merkmale-JSON-Spalte - so wie bei Separator/
|
||||
Scanner/BTMT bereits ueblich."""
|
||||
attribs = block.get("attribs", {})
|
||||
return {
|
||||
"TeileArt": attribs.get("TEILEART", ""),
|
||||
"Farbe": attribs.get("FARBE", ""),
|
||||
"Laenge": attribs.get("LAENGE", ""),
|
||||
"Layer": attribs.get("LAYER", ""),
|
||||
}
|
||||
|
||||
|
||||
def format_sensor_id(prefix, n):
|
||||
"""Fallback-TeileId fuer Separator/Scanner-Zeilen im CSV-Export, falls das
|
||||
Block-Attribut "ID" (noch) leer ist.
|
||||
@@ -869,6 +886,7 @@ def process_blocks(blocks, lookup, dbg=None):
|
||||
scanner_count = 0
|
||||
btmt_beladung_count = 0
|
||||
btmt_entladung_count = 0
|
||||
geruest_count = 0
|
||||
|
||||
# Zaehlung fuer die Omniflo-Sum-Zeile (nur Bogen/Weiche/Gerade)
|
||||
cnt_wk = cnt_einzel = cnt_delta = cnt_doppel = cnt_stern = 0
|
||||
@@ -1141,6 +1159,30 @@ def process_blocks(blocks, lookup, dbg=None):
|
||||
})
|
||||
continue
|
||||
|
||||
# Geruest-Baugruppe (GR_<id>_<timestamp>) - eigene TeileArt-Zeile,
|
||||
# analog zu BTMT: kein ANZAHL_*-Attribut an einem Carrier zaehlt sie
|
||||
# mit. TeileId ist das echte ID-Attribut (ssg-id-check-all fuellt es
|
||||
# vor jedem Export, siehe *geruest-attrib-defs*); ARTINR (Sivas-IDs,
|
||||
# ggf. mehrere kommagetrennt) landet als eigene Spalte in den
|
||||
# Merkmalen statt in "teileart" - anders als bei Kreisel/BTMT ist
|
||||
# "TEILEART" hier ein FREIES Attribut (Rohrabhaenger/Saeule/...), keine
|
||||
# feste Konstante.
|
||||
if matches_any(bname, BLOCKPATTERNS.get("pattern_geruest", [])):
|
||||
elem_nr += 1
|
||||
geruest_count += 1
|
||||
attribs = block.get("attribs", {})
|
||||
bezeichnung = attribs.get("BEZEICHNUNG", "").strip()
|
||||
items.append({
|
||||
"nr": elem_nr,
|
||||
"teileart": "Geruest",
|
||||
"teileid": attribs.get("ID") or format_sensor_id("GR", geruest_count),
|
||||
"bezeichnung": bezeichnung if bezeichnung else f"Geruest :{geruest_count}",
|
||||
"planquadrat": planquadrat_column(block, planquadrat_cfg),
|
||||
"merkmale": {"ARTINR": attribs.get("ARTINR", ""), **build_geruest_merkmale(block)},
|
||||
**bbox_columns(block),
|
||||
})
|
||||
continue
|
||||
|
||||
if has_omniflo:
|
||||
elem_nr += 1
|
||||
items.append({
|
||||
|
||||
@@ -288,6 +288,19 @@ def build_eckrad_details(block):
|
||||
}
|
||||
|
||||
|
||||
def build_geruest_details(block):
|
||||
"""Merkmale-Dict fuer eine GR_-Geruest-Baugruppe (siehe pattern_geruest in
|
||||
cfg/export.cfg, GeruestInsert.lsp *geruest-attrib-defs*). ARTINR/
|
||||
BEZEICHNUNG/TEILEART/LAENGE wandern in feste Sivas-Spalten (sivasnr/
|
||||
bezeichnung/teileart/laenge_mm), FARBE/LAYER bleiben als Rest-Attribute
|
||||
hier."""
|
||||
attribs = block.get("attribs", {})
|
||||
return {
|
||||
"Farbe": attribs.get("FARBE", ""),
|
||||
"Layer": attribs.get("LAYER", ""),
|
||||
}
|
||||
|
||||
|
||||
# --- Bekannte Bloecke ignorieren ---
|
||||
SKIP_BLOCKS = set(BLOCKPATTERNS.get("pattern_ks_subblocks", ["K1", "K2", "K3", "K4", "KS_EIN", "KS_AUS"]))
|
||||
|
||||
@@ -339,6 +352,7 @@ def process_blocks(blocks, lookup):
|
||||
btmt_beladung_bezeichnungen = []
|
||||
btmt_entladung_ids = [] # IDs aller SC_Entladung*-Bloecke (eine gruppierte Zeile)
|
||||
btmt_entladung_bezeichnungen = []
|
||||
geruest_list = [] # Liste von GR_-Geruest-Baugruppenbloecken, je einer Zeile
|
||||
|
||||
counters = {
|
||||
"anzahl_boegen": 0,
|
||||
@@ -369,6 +383,7 @@ def process_blocks(blocks, lookup):
|
||||
"anzahl_scanner": 0,
|
||||
"anzahl_btbeladung": 0,
|
||||
"anzahl_abwurfstationen": 0,
|
||||
"anzahl_geruest": 0,
|
||||
}
|
||||
|
||||
for block in blocks:
|
||||
@@ -398,6 +413,18 @@ def process_blocks(blocks, lookup):
|
||||
counters["anzahl_abwurfstationen"] += 1
|
||||
continue
|
||||
|
||||
# --- Geruest-Baugruppe ---
|
||||
# Anders als BTMT/Separator je Block eine EIGENE Zeile statt gruppiert:
|
||||
# ARTINR (Sivas-IDs) und Laenge/Farbe koennen von Block zu Block
|
||||
# unterschiedlich sein (freie Basis-Variante+Anbauteile-Auswahl je
|
||||
# GERUEST_*-Aufruf), eine Gruppierung wuerde das verschleiern - wie
|
||||
# bei VF_N/Kreisel oben, die aus demselben Grund ebenfalls einzeln
|
||||
# bleiben.
|
||||
if matches_any(bname, BLOCKPATTERNS.get("pattern_geruest", [])):
|
||||
geruest_list.append(block)
|
||||
counters["anzahl_geruest"] += 1
|
||||
continue
|
||||
|
||||
# --- Omniflo Bogen oder Weiche (erkannt via Katalog) ---
|
||||
if bname in lookup:
|
||||
typ, eintrag = lookup[bname]
|
||||
@@ -702,6 +729,28 @@ def process_blocks(blocks, lookup):
|
||||
})
|
||||
nr += 1
|
||||
|
||||
# Geruest-Baugruppen (GR_<id>_<timestamp>) - je Block eine eigene Zeile
|
||||
# (siehe Kommentar bei geruest_list oben). Sivasnr kommt direkt aus dem
|
||||
# ARTINR-Attribut - kann bereits mehrere, kommagetrennte Sivas-IDs
|
||||
# enthalten (Baugruppe aus mehreren Einzelteilen, siehe ssg-join in
|
||||
# GeruestInsert.lsp), anders als bei den uebrigen Teilearten also KEIN
|
||||
# fester Eintrag aus ILS_SIVASNR.
|
||||
for block in geruest_list:
|
||||
attribs = block.get("attribs", {})
|
||||
items.append({
|
||||
"nr": nr,
|
||||
"teileart": attribs.get("TEILEART", "Geruest"),
|
||||
"sivasnr": attribs.get("ARTINR", ""),
|
||||
"sivasnr_quoted": True,
|
||||
"bezeichnung": attribs.get("BEZEICHNUNG", ""),
|
||||
"dispgruppe": 20,
|
||||
"anzahl": 1,
|
||||
"laenge_mm": attribs.get("LAENGE", ""),
|
||||
"ids": [get_id(block)],
|
||||
"details": build_geruest_details(block),
|
||||
})
|
||||
nr += 1
|
||||
|
||||
# VarioFoerderer-Compound-Bloecke (VF_N) - je Block eine eigene Zeile mit
|
||||
# vollstaendigen Gefaelle-/Angetrieben-Teilgruppen (immer TYP "Streckengruppe").
|
||||
for block in vario_list:
|
||||
|
||||
Reference in New Issue
Block a user