Files
dxfmakros/tests/test_export_separator_bbox.py
T
m.stangl 27ae3df056 CSV-Export: Nachbarschaft/bbox fuer Kreisel-Kreisel-Weichen, sepliste-Ketten und Separatoren repariert
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>
2026-09-10 09:41:02 +02:00

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"