sepliste: Bauteil-IDs eintragen, AS/ES ueber dauerhaften Marker sichtbar machen

Stufe 1 (LISP-Export-Pfad): export_raw.json enthaelt jetzt fuer jeden
sepliste-Eintrag (AS/SEP/ES) einer VF_n/GF_n-Kette die ID des realen
Bauteils, das ihn vertritt.

- csv:sep-proxies-erzeugen (Separatoren) und die neuen AS/ES-Marker teilen
  sich csv:nested-welt-records/csv:block-einfuegen-welt zur Platzierung.
- csv:sepliste-paare ordnet sepliste-Eintraege ihrem Bauteil exklusiv nach
  Abstand zu (kuerzester zuerst, dann verbraucht) statt "jeder Eintrag
  nimmt sich das naechste" - ein einzelner fehlerhafter Koordinatenwert
  (bekannter Bug: gespiegeltes x bei lfdnr=2) verschiebt dadurch keine
  andere Zuordnung mehr.
- Neu: ZZ_ASES_MARKER - ein kleines Rechteck an jedem AS/ES-Kettenende,
  das nach dem Export STEHEN BLEIBT (anders als die temporaeren
  Separator-Kopien). Macht das sonst unsichtbare, in der Wrapper-
  Blockdefinition verpackte Kettenende in BricsCAD sichtbar/anklickbar
  und traegt seine ID unsichtbar am Attribut ID - dadurch behaelt ein
  AS/ES seine TeileId ueber Exportlaeufe hinweg. Wird bei jedem Export
  neu aufgebaut (Lage folgt der Kette), Wiederfund ueber ZUORDNUNG+TYP+
  LFDNR, verwaiste Marker werden entfernt.

In BricsCAD verifiziert (5 HundM05-Ketten, zwei Exportlaeufe: gleiche
Marker-IDs, korrekte sepliste-"id"-Felder). Dabei einen realen Bug
gefunden und behoben: die Blockdefinition des Markers uebernahm ueber
einen ungefilterten entnext-Walk versehentlich auch die Attribute des
zuletzt eingefuegten Blocks (VF_5 verlor dadurch alle Attribute inkl.
ID) - jetzt auf LWPOLYLINE/ATTDEF gefiltert.

9 neue zeichnungsfreie Unit-Tests (csv:sepliste-paare/*, csv:asmark-
finden/*, csv:proxy-typ/*), 4 neue de/en-Textschluessel (Paritaet
geprueft). bin\run_tests.bat --lisp: 257/257 bestanden.

Noch nicht enthalten (Stufe 2, Python): map_separator_kette_items nutzt
das neue "id"-Feld noch nicht, build_strecke_schleus_items synthetisiert
AS/ES-Zeilen weiterhin selbst statt die exportierten zu lesen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Samer Ayadi
2026-09-22 13:09:05 +02:00
co-authored by Claude Sonnet 5
parent 9671fe4e04
commit 618ff3d86c
15 changed files with 1205 additions and 216 deletions
+34 -1
View File
@@ -95,6 +95,19 @@ KREISEL_UMLAUF_TEILEARTEN = {
"Eingang", "Ausgang",
}
# Temporaerer Diagnose-Filter fuers Debuglog (siehe [Nachbarschaft] debug_log
# in cfg/export.cfg): markiert Zeilen zu diesen TeileIds im .dbg-Log
# besonders, um die fehlende Nachbarn-/TrackIds-Zuordnung einzelner
# Separatoren (0025/0029/0031/0035) nachzuvollziehen. Nach Abschluss der
# Diagnose wieder auf einen leeren Set zuruecksetzen oder entfernen.
DEBUG_HIGHLIGHT_TEILEIDS = {"0025", "0029", "0031", "0035"}
def dbg_highlight(teileid):
"""Suffix fuer eine Debuglog-Zeile, wenn teileid in
DEBUG_HIGHLIGHT_TEILEIDS steht - sonst leerer String."""
return " <<<< ZIEL-ID" if str(teileid) in DEBUG_HIGHLIGHT_TEILEIDS else ""
# Nur "ILS 2.0 Kreisel" (echte Kreisel-Bloecke mit AN8/Antrieb + SP8/Spann-
# station + ABSTAND-Attribut) werden links/rechts gesplittet - "ILS 2.0
# Eckrad" hat keine dieser zwei Stationen und bleibt eine einzelne BBox.
@@ -1480,15 +1493,32 @@ def compute_kreisel_umlauf(items, sep_kette, tolerance_mm, durchmesser_mm=800.0,
for item in items:
if item.get("teileart", "") not in KREISEL_UMLAUF_TEILEARTEN:
continue
teileid = item.get("teileid", "")
bbox = item.get("_bbox")
if not bbox:
if dbg:
dbg(f" Umlauf-Kandidat {teileid!r} ({item.get('teileart', '')!r}): "
f"KEINE Bounding-Box - kann keinem Kreisel zugeordnet werden"
f"{dbg_highlight(teileid)}")
continue
bounds = _bounds(bbox, half_tol)
matched_tid = None
for tid, kb in kreisel_bounds.items():
if _overlaps(bounds, kb):
punkte_je_kreisel[tid].append(
(item.get("teileid", ""), bbox.get("cx", 0.0), bbox.get("cy", 0.0)))
(teileid, bbox.get("cx", 0.0), bbox.get("cy", 0.0)))
matched_tid = tid
break
if dbg:
if matched_tid is not None:
dbg(f" Umlauf-Kandidat {teileid!r} ({item.get('teileart', '')!r}) "
f"bbox(cx={bbox.get('cx', 0):.0f},cy={bbox.get('cy', 0):.0f}) "
f"-> Kreisel {matched_tid}{dbg_highlight(teileid)}")
else:
dbg(f" Umlauf-Kandidat {teileid!r} ({item.get('teileart', '')!r}) "
f"bbox(cx={bbox.get('cx', 0):.0f},cy={bbox.get('cy', 0):.0f}) "
f"-> KEIN Kreisel in Reichweite (bounds={_fmt_bounds(bounds)})"
f"{dbg_highlight(teileid)}")
# AS/ES-Enden jeder Kette mit sepliste: naechstgelegener Kreisel (wie
# compute_strecke_kreisel_schleus._nearest), aber direkt aus sep_kette
@@ -1591,5 +1621,8 @@ def compute_kreisel_umlauf(items, sep_kette, tolerance_mm, durchmesser_mm=800.0,
if dbg:
dbg(f" Kreisel {tid} ({drehrichtung}): Umlauf "
f"{' -> '.join(p[0] for p in sortiert)}")
for punkt_key, vorgaenger, nachfolger in umlauf:
dbg(f" Punkt {punkt_key!r}: vorgaenger={vorgaenger!r} "
f"nachfolger={nachfolger!r}{dbg_highlight(punkt_key)}")
return result