[FIX] Eindeutige IDs und korrekte ZUORDNUNG der verpackten Separatoren
Beim CSV-Export von Mubea trugen Gefaellestrecke/VF/Kreisel und die aus ihnen erzeugten Separator-Kopien dieselbe ID (26 Dubletten 0001-0026), und die ZUORDNUNG der Separatoren zeigte auf den falschen Carrier. ssg-id-check-all: neue Phase 0 ermittelt das globale Maximum der bereits vergebenen IDs, BEVOR die erste neue ID vergeben wird (ausgelagert nach ssg-id-max-in-ss, das auch ssg-id-max nutzt). Bisher wurde max-id erst waehrend Phase 1 mitgezogen (Start 0); da (ssget "X" ...) in BricsCAD die zuletzt erzeugten Entities zuerst liefert, standen die noch ID-losen Separator-Kopien ganz vorne und bekamen 0001, 0002, ... - genau die IDs der weiter hinten liegenden Wrapper-Bloecke. Phase 2 konnte das nicht heilen, weil frisch vergebene IDs nicht in id-map landen. ssg-collect-nested-inserts: fuehrt Position, Z-Drehung und Skalierung jetzt ueber alle Verschachtelungsebenen mit (Records statt nackter Entity-Namen). Vorher gab die Rekursion Entities tieferer Ebenen mit ihrer ROH-Position aus der Zwischen-Blockdefinition zurueck - zwei Separatoren an derselben lokalen Stelle in zwei verschieden platzierten Zwischenbloecken landeten dadurch auf exakt derselben Weltposition. csv:sep-proxies-erzeugen: die Kopie steht jetzt exakt auf Position/Drehung/ Skalierung ihres verpackten Vorbilds; der kosmetische Versatz von 500 mm ist weg (er kippte Separatoren am Kettenende in die Boundingbox des Nachbar- Carriers). Der vla-InsertBlock-Aufruf ist gekapselt, damit ein Sonderfall nur diese eine Kopie ausfallen laesst statt den ganzen Export abzubrechen. csv:sep-proxies-zuordnung-setzen (neu, laeuft NACH ssg-id-check-all, da ein frisch gebauter Wrapper vorher keine ID hat): fuer einen VERPACKTEN Separator ist der Carrier bekannt - es ist der Wrapper, in dem er steckt. ZUORDNUNG wird daher auf die Wrapper-ID gesetzt (Separator in VF 0010 -> ZUORDNUNG 0010) und ueber *cs-sep-fix-by-handle* festgenagelt: cs-zuordnung-lauf uebernimmt sie unveraendert statt sie geometrisch neu zu raten, und csv:block-to-json reicht sie als "zuordnung_fix" an export_csv.py durch. Ohne das ueberschrieb compute_sensor_zuordnung (Prioritaet GF > Foerderer > Kreiselhaelfte) den bekannten Wert - in der Mubea-Zeichnung landeten 26 in VF/GF verpackte Separatoren so bei einer Kreiselhaelfte. export_csv.py: respektiert "zuordnung_fix" und ersetzt eine vorhandene ZUORDNUNG nicht mehr durch "nicht zugeordnet" - nur ein echter Treffer ueberschreibt, wie im Docstring von compute_sensor_zuordnung beschrieben. tests/test_export_ids.py (neu): prueft je tests/output/*_export.csv, dass jede TeileId hoechstens einmal vorkommt und jede Sensor-Zuordnung auf eine existierende TeileId zeigt. Gegen die fehlerhafte Mubea-CSV schlaegt der Test mit allen 26 Dubletten an. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+27
-4
@@ -282,10 +282,15 @@ def build_sensor_merkmale(block):
|
||||
Scanner-Block (siehe pattern_separator/pattern_scanner in cfg/export.cfg).
|
||||
ZUORDNUNG/ARTINR/LAYER (+ neuerdings ID) sind die ATTDEFs (siehe
|
||||
ils-insert-sensor/mubea:build-separator-one, ssg-id-collect-blocks in
|
||||
ssg_id.lsp)."""
|
||||
ssg_id.lsp).
|
||||
|
||||
"zuordnung_fix" (csv:block-to-json) hat Vorrang vor dem ZUORDNUNG-Attribut:
|
||||
es steht an den temporaeren Kopien der in VF_n/GF_n/KREISEL_n VERPACKTEN
|
||||
Separator_SP-Symbole und traegt die ID des Wrapper-Blocks, in dem das
|
||||
Symbol steckt - eine bekannte, keine geratene Zuordnung."""
|
||||
attribs = block.get("attribs", {})
|
||||
return {
|
||||
"Zuordnung": attribs.get("ZUORDNUNG", ""),
|
||||
"Zuordnung": block.get("zuordnung_fix") or attribs.get("ZUORDNUNG", ""),
|
||||
"ARTINR": attribs.get("ARTINR", ""),
|
||||
"Höhe": get_hoehe(block),
|
||||
"Drehung": get_drehung(block),
|
||||
@@ -757,6 +762,10 @@ def process_blocks(blocks, lookup, dbg=None):
|
||||
"bezeichnung": f"Separator :{separator_count}",
|
||||
"planquadrat": planquadrat_column(block, planquadrat_cfg),
|
||||
"merkmale": build_sensor_merkmale(block),
|
||||
# Privates Feld (nicht in der CSV): markiert eine BEKANNTE
|
||||
# Zuordnung, die compute_sensor_zuordnung unten nicht
|
||||
# ueberschreiben darf - siehe build_sensor_merkmale.
|
||||
"_zuordnung_fix": bool(block.get("zuordnung_fix")),
|
||||
**bbox_columns(block),
|
||||
})
|
||||
continue
|
||||
@@ -819,8 +828,22 @@ def process_blocks(blocks, lookup, dbg=None):
|
||||
sensor_zuordnung = compute_sensor_zuordnung(
|
||||
items, NEIGHBOR_TOLERANCE_MM, kreisel_durchmesser_mm=KREISEL_DURCHMESSER_MM, dbg=dbg)
|
||||
for item, zuordnung in zip(items, sensor_zuordnung):
|
||||
if item.get("teileart", "") in SENSOR_TEILEARTEN and zuordnung:
|
||||
item["merkmale"]["Zuordnung"] = zuordnung
|
||||
if item.get("teileart", "") not in SENSOR_TEILEARTEN or not zuordnung:
|
||||
continue
|
||||
# Bekannte Zuordnung (verpackter Separator, Carrier = Wrapper-Block,
|
||||
# siehe "_zuordnung_fix"/build_sensor_merkmale) nicht ueberschreiben:
|
||||
# die BBox-Suche hier priorisiert GF > Foerderer > Kreiselhaelfte und
|
||||
# wuerde einen in einem VF-Block verpackten Separator an eine
|
||||
# Gefaellestrecke haengen, in deren Box er zufaellig hineinragt.
|
||||
if item.get("_zuordnung_fix"):
|
||||
continue
|
||||
# Kein Treffer ("nicht zugeordnet") ersetzt einen vorhandenen
|
||||
# ZUORDNUNG-Attributwert nicht - sonst geht die in der Zeichnung
|
||||
# gesetzte Zuordnung verloren (siehe Docstring von
|
||||
# compute_sensor_zuordnung: ersetzen nur bei echtem Treffer).
|
||||
if zuordnung == "nicht zugeordnet" and item["merkmale"].get("Zuordnung"):
|
||||
continue
|
||||
item["merkmale"]["Zuordnung"] = zuordnung
|
||||
|
||||
# NACH der Separator-Zuordnung: zu jedem Scanner den raeumlich naechst-
|
||||
# gelegenen Separator suchen (eigene, unabhaengige Suche - siehe
|
||||
|
||||
Reference in New Issue
Block a user