tro_annotate: Lagebezug ueber die TeileId, Ablaufbeschreibung CSV/DXF -> SCL
dxf_registration.derive_from_ids: Zeichnungen aus dxfmakros tragen an jedem Layout-Block das Attribut ID = TeileId des CSV. tro_annotate paart CSV- Separatoren mit den Separator-Bloecken gleicher ID (sonst Scanner) und nimmt den Median-Versatz - eindeutig statt Abstimmung, bei jedem Lauf neu, gilt auch fuer eine verschobene Kopie der Zeichnung. Vorrang vor abgelegtem und abgestimmtem Bezug; --offset bleibt. Parameter id_spread_mm, id_min_share in cfg/parameter.ini [dxf_registration]. Dematic: gemeinsame Zeichnung 0/0, Mechanik-Zeichnung dematic.dxf +466,1/-163549,3 mm. Die Abstimmung rastete vorher auf den Scanner-Bloecken ein (Einfuegepunkt 360 mm neben der CSV-Position) und lag 360 mm daneben. Gesperrte Ausgabedatei (in BricsCAD geoeffnet) gibt eine Meldung statt Traceback. Neu: doc/Workflow_CSV_DXF_to_SCL.md - der ganze Ablauf vom CSV-Export und der Zeichnung bis zur SCL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Tests fuer den Lagebezug ueber die TeileId (dxf_registration.derive_from_ids).
|
||||
|
||||
Nachbau der Dematic-Befunde: dieselbe Anlage einmal als gemeinsame Zeichnung
|
||||
(Versatz 0) und einmal als verschobene Mechanik-Zeichnung (~163 m in y). Die
|
||||
Separator-Bloecke sitzen je nach Drehung +-60 mm neben der CSV-Position, die
|
||||
Scanner-Bloecke 360 mm - die automatische Abstimmung rastete dort auf den
|
||||
Scannern ein und lag 360 mm daneben.
|
||||
"""
|
||||
|
||||
import ezdxf
|
||||
import pytest
|
||||
|
||||
import tro_annotate
|
||||
from dxf_registration import MIN_INLIERS, derive_from_ids
|
||||
|
||||
SHIFT = (-466.1, 163549.3) # DXF = CSV + SHIFT (Dematic Mechanik)
|
||||
|
||||
|
||||
def _csv(n=11):
|
||||
seps = {f"{38 + i:04d}": ("Separator", 3000.0 + i * 800.0, 12120.0) for i in range(n)}
|
||||
scans = {f"{60 + i:04d}": ("Scanner", 3000.0 + i * 900.0, 25000.0) for i in range(7)}
|
||||
return {**seps, **scans}
|
||||
|
||||
|
||||
def _dxf(csv_points, shift=SHIFT):
|
||||
out = {}
|
||||
for i, (tid, (rolle, x, y)) in enumerate(csv_points.items()):
|
||||
if rolle == "Separator":
|
||||
bias = (-60.0 if i % 3 else 60.0, 0.0)
|
||||
else:
|
||||
bias = (0.0, -360.0)
|
||||
out[tid] = (rolle, x + shift[0] + bias[0], y + shift[1] + bias[1])
|
||||
return out
|
||||
|
||||
|
||||
def test_verschobene_zeichnung_ueber_die_separatoren():
|
||||
csv_points = _csv()
|
||||
t = derive_from_ids(csv_points, _dxf(csv_points), "x.csv", "mech.dxf")
|
||||
assert t is not None and t.source == "ids"
|
||||
# DXF -> CSV: Gegenrichtung des Verschubs, Separator-Bias hoechstens 60 mm
|
||||
assert abs(t.dx - (-SHIFT[0])) <= 60.0 + 1e-6
|
||||
assert t.dy == pytest.approx(-SHIFT[1])
|
||||
assert "Separator" in t.anchor
|
||||
|
||||
|
||||
def test_gemeinsame_zeichnung_versatz_null():
|
||||
csv_points = _csv()
|
||||
t = derive_from_ids(csv_points, _dxf(csv_points, shift=(0.0, 0.0)))
|
||||
assert abs(t.dx) <= 60.0 + 1e-6 and t.dy == pytest.approx(0.0)
|
||||
|
||||
|
||||
def test_ohne_genug_separatoren_die_scanner():
|
||||
csv_points = _csv(n=MIN_INLIERS - 1)
|
||||
t = derive_from_ids(csv_points, _dxf(csv_points))
|
||||
assert t is not None and "Scanner" in t.anchor
|
||||
assert t.dy == pytest.approx(-SHIFT[1] + 360.0) # Scanner-Bias bleibt drin
|
||||
|
||||
|
||||
def test_ohne_ids_kein_ergebnis():
|
||||
assert derive_from_ids(_csv(), {}) is None
|
||||
|
||||
|
||||
def test_uneinheitlicher_versatz_wird_nicht_genommen():
|
||||
csv_points = _csv()
|
||||
dxf = _dxf(csv_points)
|
||||
# die Haelfte der Separatoren weit daneben (falsche IDs) -> keine Rolle passt
|
||||
for tid in list(dxf)[:6]:
|
||||
rolle, x, y = dxf[tid]
|
||||
dxf[tid] = (rolle, x + 5000.0, y)
|
||||
for tid in [k for k, v in dxf.items() if v[0] == "Scanner"]:
|
||||
del dxf[tid]
|
||||
assert derive_from_ids(csv_points, dxf) is None
|
||||
|
||||
|
||||
def test_ids_aus_der_zeichnung():
|
||||
doc = ezdxf.new()
|
||||
blk = doc.blocks.new("Separator_SP_3D")
|
||||
blk.add_attdef("ID", (0, 0))
|
||||
andere = doc.blocks.new("KREISEL_1_STANDARD_3619")
|
||||
andere.add_attdef("ID", (0, 0))
|
||||
msp = doc.modelspace()
|
||||
msp.add_blockref("Separator_SP_3D", (10, 20)).add_auto_attribs({"ID": "0038"})
|
||||
msp.add_blockref("Separator_SP_3D", (30, 40)).add_auto_attribs({"ID": "0039"})
|
||||
msp.add_blockref("Separator_SP_3D", (50, 60)).add_auto_attribs({"ID": "0039"})
|
||||
msp.add_blockref("Separator_SP_3D", (70, 80)).add_auto_attribs({"ID": ""})
|
||||
msp.add_blockref("KREISEL_1_STANDARD_3619", (0, 0)).add_auto_attribs({"ID": "0001"})
|
||||
# nur eindeutige Ziffern-IDs von Anker-Bloecken
|
||||
assert tro_annotate.id_points_dxf(msp) == {"0038": ("Separator", 10.0, 20.0)}
|
||||
Reference in New Issue
Block a user