27ae3df056
Kreisel-Kreisel-Weichen fehlten bisher im Kreisel-Umlauf (compute_kreisel_umlauf), wodurch angrenzende Separatoren auf falsche/fehlende Nachbarn zeigten. Die kreisel_bounds-Matching-Box ignorierte ausserdem die tatsaechliche Kreiseldrehung (faelschlich als achsparallel angenommen), was bei gedrehten langen Kreiseln (Mubea Kreisel 0002) zu falschen Nachbarschaften fuehrte. Die sepliste-XDATA (AS/SEP/ES-Reihenfolge je VF_n/GF_n) wurde nie ans Python-Item durchgereicht - die gesamte Ketten-Nachbarschaftserkennung lief dadurch ins Leere. Nach dem Beheben entstand eine Doppelzaehlung: die in einer Kette verpackten Separatoren existieren bereits als echte Proxy-INSERTs (csv:sep-proxies-erzeugen); build_separator_kette_items erzeugte zusaetzlich eigene Zeilen aus der sepliste. Umgebaut zu map_separator_kette_items: ordnet die sepliste-Reihenfolge den vorhandenen Proxy-Items zu (Match ueber Wrapper-ID + INSERT-Punkt) statt neue Zeilen zu erzeugen - keine Doppelzaehlung mehr, Nachbarn korrekt gesetzt. Ausserdem: vla-getboundingbox scheiterte in einem realen Export bei ALLEN Bloecken (fehlende bbox ueberall), der Fehler wurde bisher still verschluckt. REGENALL vor der Export-Schleife behebt das; eine neue Diagnose (exp-bbox-fail) meldet kuenftige Ausfaelle statt sie zu verschlucken. Freie/eingebettete Separatoren ohne bbox bekommen zusaetzlich einen Fallback aus einer konfigurierbaren Symbol-Groesse (cfg/export.cfg [Boundingbox] separator_box_*). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
97 lines
4.1 KiB
Python
97 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
test_export_separator_bbox.py - Feste Separator-Symbol-Bounding-Box.
|
|
Laeuft komplett ohne BricsCAD (reine Python-Logik).
|
|
|
|
Regressionstest fuer einen realen Mubea-Befund: die meisten Separatoren
|
|
blieben ohne "Nachbarn", weil in ihrem export_raw.json KEINE Bounding-Box
|
|
stand. Zwei Ursachen:
|
|
|
|
1. In eine VF_n/GF_n-Kette EINGEBETTETE Separatoren sind seit der Umstellung
|
|
auf die "sepliste"-XDATA kein reales INSERT mehr - vla-getboundingbox kann
|
|
fuer sie keine Box liefern.
|
|
2. Frei platzierte Separator_SP-INSERTs, deren vla-getboundingbox beim Export
|
|
scheiterte (z.B. eingefrorener Layer).
|
|
|
|
Beide bekommen jetzt eine feste Symbol-Box aus cfg [Boundingbox]
|
|
separator_box_* (siehe export_neighbors.separator_bbox / load_separator_box_mm),
|
|
damit sie ein "_bbox" haben und an der Nachbarschafts-/Umlauf-/Zuordnungs-
|
|
erkennung teilnehmen.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "lib"))
|
|
|
|
from export_neighbors import ( # noqa: E402
|
|
separator_bbox,
|
|
load_separator_box_mm,
|
|
SEPARATOR_BOX_LAENGE_MM,
|
|
SEPARATOR_BOX_BREITE_MM,
|
|
SEPARATOR_BOX_HOEHE_MM,
|
|
)
|
|
from export_csv import ( # noqa: E402
|
|
bbox_columns,
|
|
_fallback_separator_bbox,
|
|
)
|
|
|
|
|
|
class TestSeparatorBboxGeometrie:
|
|
|
|
def test_unrotiert(self):
|
|
box = (210.0, 150.0, 14.0)
|
|
bb = separator_bbox(1000.0, 2000.0, 0.0, separator_box_mm=box)
|
|
assert bb["cx"] == 1000.0 and bb["cy"] == 2000.0
|
|
assert abs(bb["dx"] - 210.0) < 1e-6, "Laenge liegt bei Drehung 0 entlang X"
|
|
assert abs(bb["dy"] - 150.0) < 1e-6, "Breite liegt bei Drehung 0 entlang Y"
|
|
assert abs(bb["dz"] - 14.0) < 1e-6
|
|
|
|
def test_um_90_grad_gedreht_vertauscht_dx_dy(self):
|
|
box = (210.0, 150.0, 14.0)
|
|
bb = separator_bbox(0.0, 0.0, 90.0, separator_box_mm=box)
|
|
assert abs(bb["dx"] - 150.0) < 1e-6, "bei 90 Grad liegt die Breite entlang X"
|
|
assert abs(bb["dy"] - 210.0) < 1e-6, "bei 90 Grad liegt die Laenge entlang Y"
|
|
|
|
def test_default_masse_aus_cfg(self):
|
|
# load_separator_box_mm liest cfg/export.cfg; die Werte muessen positiv
|
|
# und plausibel sein (Symbol ~210 x 150 x 14).
|
|
laenge, breite, hoehe = load_separator_box_mm()
|
|
assert laenge > 0 and breite > 0 and hoehe > 0
|
|
# Fallback-Konstanten muessen mit dem gemessenen Symbol uebereinstimmen
|
|
assert (SEPARATOR_BOX_LAENGE_MM, SEPARATOR_BOX_BREITE_MM, SEPARATOR_BOX_HOEHE_MM) == (210.0, 150.0, 14.0)
|
|
|
|
|
|
class TestFallbackSeparatorBbox:
|
|
|
|
def test_fehlende_bbox_wird_ergaenzt(self):
|
|
"""Ein Separator-INSERT ohne bbox (vla-getboundingbox scheiterte)
|
|
bekommt aus Position/Drehung + fester Box eine _bbox."""
|
|
block = {"block_name": "Separator_SP_3D", "x": 5000.0, "y": -3000.0,
|
|
"z": 100.0, "rotation": 90.0, "attribs": {"ID": "0050"}}
|
|
cols = bbox_columns(block)
|
|
assert cols["_bbox"] is None, "Vorbedingung: Block hat keine bbox"
|
|
|
|
cols = _fallback_separator_bbox(cols, block, separator_box_mm=(210.0, 150.0, 14.0))
|
|
assert cols["_bbox"] is not None, "Fallback hat keine _bbox gesetzt"
|
|
assert cols["_bbox"]["cx"] == 5000.0 and cols["_bbox"]["cy"] == -3000.0
|
|
# 90 Grad -> dx=Breite, dy=Laenge
|
|
assert abs(cols["_bbox"]["dx"] - 150.0) < 1e-6
|
|
assert abs(cols["_bbox"]["dy"] - 210.0) < 1e-6
|
|
assert cols["boundingbox"] != "", "Boundingbox-Spalte muss nun gefuellt sein"
|
|
|
|
def test_vorhandene_bbox_bleibt_unveraendert(self):
|
|
"""Hat der Block bereits eine echte bbox (vla-getboundingbox erfolgreich),
|
|
darf der Fallback sie NICHT ueberschreiben."""
|
|
block = {"block_name": "Separator_SP_3D", "x": 5000.0, "y": -3000.0,
|
|
"rotation": 90.0,
|
|
"bbox": {"cx": 5001.0, "cy": -3002.0, "cz": 7.0,
|
|
"dx": 209.9, "dy": 150.0, "dz": 3.0}}
|
|
cols = bbox_columns(block)
|
|
assert cols["_bbox"] is not None
|
|
original = dict(cols["_bbox"])
|
|
|
|
cols2 = _fallback_separator_bbox(cols, block)
|
|
assert cols2["_bbox"] == original, "echte bbox wurde vom Fallback ueberschrieben"
|