Files
dxfmakros/tests/test_dxf_scan_gf.py
T

263 lines
11 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
test_dxf_scan_gf.py - Gefaellestrecken aus Staustrecken-Linien
(gf_eintraege_aus_linien in lib/dxf_scan_components.py). Laeuft ohne
BricsCAD und ohne DXF: die Linien und Ausschleuselemente sind die
gemessenen Werte aus Dematic_arvato_reduced.dxf, von Hand nachgestellt.
1. Fallende Linie mit AS am oberen Ende -> GF, AS wird verbraucht.
2. Der Nachbar-AS der Linie daneben (800 mm Raster, auf der anderen Seite
naeher dran) wird NICHT gegriffen - die Seite aus dem Blocknamen
entscheidet, nicht der kleinste Abstand.
3. Rueckwaerts gezeichnete GF (tiefes Ende zuerst) -> Start bleibt oben.
4. AS am UNTEREN Ende -> Steigfoerderer, keine GF, AS bleibt unverbraucht.
5. Waagrechte Linie -> keine GF.
6. Anschluss an die Kreisel: Start/Ende werden auf die Ketten geschoben,
deltaL reicht von Kette zu Kette; Hoehen kommen von den Kreiseln.
7. Separator auf der Achse wird verbraucht, einer daneben nicht.
8. hoehen_entfernen laesst nur Anwender-Hoehen stehen.
"""
import os
import sys
import pytest
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
"..", "lib"))
import dxf_scan_components as dsc # noqa: E402
AS_LINKS = "Ausschleuselement links 200000217 Draufsicht"
def _as(x, y, z=3191.63, block=AS_LINKS):
return {"familie": "schleuselement", "block": block,
"x": x, "y": y, "z": z, "rot": 270.0}
def _linie(a, b, layer="6-SP"):
return {"layer": layer, "a": list(a), "b": list(b)}
@pytest.fixture(autouse=True)
def _projekt(monkeypatch):
monkeypatch.setattr(dsc, "PROJEKT", "Test")
# Die beiden Kreisel am GF-Feld (Radmitten AN8 -> SP8, r = 400), wie
# baue_eintraege sie als kreisel_geo anlegt. Ketten: oben y = 12919.72,
# unten y = 24478.8.
def _kreisel_oben(z=2437.0):
return {"id": "K_oben", "a": (35460.37, 12519.72), "u": (-1.0, 0.0),
"laenge": 33044.28, "r": 400.0, "z_anwender": z}
def _kreisel_unten(z=1826.0):
return {"id": "K_unten", "a": (36261.24, 24878.8), "u": (-1.0, 0.0),
"laenge": 33470.18, "r": 400.0, "z_anwender": z}
def test_gf_mit_as_am_oberen_ende():
linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63))
as_eigen = _as(5367.10, 14505.61)
eintraege, belegt, hinweise = dsc.gf_eintraege_aus_linien([linie], [as_eigen])
assert len(eintraege) == 1
gf = eintraege[0]
assert gf["test_id"] == "GF_Test_01"
assert gf["modus"] == 1
# ohne Kreisel: Linienende bleibt stehen, Hoehe unbekannt -> Platzhalter
assert gf["start_mm"] == [5833.56, 13348.38, 0.0]
assert gf["deltaL_mm"] == pytest.approx(10654.16, abs=0.01)
assert gf["hz_grad"] == 90.0
assert gf["winkel_grad"] == 3.0
assert gf["hoehe_unbekannt"] is True
assert (gf["as_seite"], gf["as_winkel"]) == ("links", "90")
assert belegt == {id(as_eigen)}
assert len(hinweise) == 2 and all("kein Kreisel" in h for h in hinweise)
def test_anschluss_an_beide_kreisel_mit_hoehen():
linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63))
eintraege, _, hinweise = dsc.gf_eintraege_aus_linien(
[linie], [_as(5367.10, 14505.61)], [_kreisel_oben(), _kreisel_unten()])
gf = eintraege[0]
assert gf["start_mm"][1] == pytest.approx(12919.72, abs=0.01)
assert gf["start_mm"][2] == 2437.0
assert gf["hoehe_ende_mm"] == 1826.0
assert gf["hoehe_quelle"] == "Anwender"
assert "winkel_grad" not in gf # rechnet der LISP-Treiber
assert gf["deltaL_mm"] == pytest.approx(24478.8 - 12919.72, abs=0.05)
assert (gf["kreisel_start"], gf["kreisel_ende"]) == ("K_oben", "K_unten")
assert hinweise == []
def test_kreisel_ohne_hoehe_gibt_platzhalter():
linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63))
eintraege, _, _ = dsc.gf_eintraege_aus_linien(
[linie], [], [_kreisel_oben(z=None), _kreisel_unten()])
assert eintraege[0]["kreisel_start"] == "K_oben"
assert "hoehe_ende_mm" not in eintraege[0]
assert eintraege[0]["winkel_grad"] == 3.0
def test_separator_auf_achse_wird_verbraucht():
linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63))
sep_achse = {"familie": "sensor", "block": "S-SP", "x": 5834.0, "y": 23810.0}
sep_daneben = {"familie": "sensor", "block": "S-SP", "x": 6734.0, "y": 23810.0}
scanner = {"familie": "sensor", "block": "Scanner", "x": 5834.0, "y": 20000.0}
_, belegt, _ = dsc.gf_eintraege_aus_linien(
[linie], [], [_kreisel_oben(), _kreisel_unten()],
[sep_achse, sep_daneben, scanner])
assert belegt == {id(sep_achse)}
def test_hoehen_entfernen_laesst_anwender_hoehen_stehen():
eintraege = [
{"id": "K1", "x": 0, "y": 0, "z": 2437.0, "hoehe_quelle": "Anwender"},
{"block": "S-SP", "x": 0, "y": 0, "z": 2821.63, "comment": ""},
{"test_id": "G", "typ": "gerade", "startpunkt": [0, 0, 5.0],
"endpunkt": [1, 0, 5.0]},
]
assert dsc.hoehen_entfernen(eintraege) == 2
assert eintraege[0]["z"] == 2437.0
assert eintraege[1]["z"] == 0.0 and eintraege[1]["hoehe_unbekannt"] is True
assert eintraege[2]["startpunkt"][2] == 0.0 and eintraege[2]["endpunkt"][2] == 0.0
def test_nachbar_as_auf_falscher_seite_wird_nicht_gegriffen():
# Linie bei x=5834; ihr AS 467 mm links, der AS der Nachbarlinie
# (x=6734) 433 mm RECHTS - also naeher, aber auf der falschen Seite.
linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63))
as_eigen = _as(5367.10, 14505.61)
as_nachbar = _as(6267.10, 14505.61)
_, belegt, _ = dsc.gf_eintraege_aus_linien([linie], [as_nachbar, as_eigen])
assert belegt == {id(as_eigen)}
def test_rueckwaerts_gezeichnete_gf_startet_oben():
linie = _linie((5833.44, 24002.54, 2821.63), (5833.56, 13348.38, 3191.63))
eintraege, _, _ = dsc.gf_eintraege_aus_linien([linie], [_as(5367.10, 14505.61)])
assert eintraege[0]["start_mm"][:2] == [5833.56, 13348.38]
assert eintraege[0]["hz_grad"] == 90.0
def test_as_am_unteren_ende_ist_steigfoerderer():
# Gemessen: Linie x=2801 von 2822 hinauf auf 3192, AS am tiefen Ende.
linie = _linie((2801.42, 24043.0, 2821.63), (2801.42, 13389.0, 3191.63))
as_unten = _as(3267.48, 22892.92, z=2821.63)
eintraege, belegt, hinweise = dsc.gf_eintraege_aus_linien([linie], [as_unten])
assert eintraege == []
assert belegt == set()
assert len(hinweise) == 1 and "Steigfoerderer" in hinweise[0]
def test_waagrechte_linie_ist_keine_gf():
linie = _linie((36661.0, 10279.0, 2821.63), (36661.0, 24879.0, 2821.63))
eintraege, belegt, hinweise = dsc.gf_eintraege_aus_linien([linie], [])
assert eintraege == []
assert belegt == set()
assert any("waagrechte" in h for h in hinweise)
def test_ohne_as_defaults_und_hinweis():
linie = _linie((0.0, 0.0, 1000.0), (5000.0, 0.0, 800.0))
eintraege, _, hinweise = dsc.gf_eintraege_aus_linien([linie], [])
assert eintraege[0]["hz_grad"] == 0.0
assert eintraege[0]["as_seite"] == dsc.DEFAULT_SEITE
assert any("ohne Ausschleuselement" in h for h in hinweise)
# --- Showroom_ILS_3_0.dxf: flacher 2D-Plan, Werte dort gemessen -------------
def _station(x, y):
return {"x": x, "y": y}
def test_kreisel_paare_zwei_kreisel_auf_einer_achse():
# x=26998: AN8 y=3466 / SP8 y=12499 und AN8 y=13299 / SP8 y=16299. Die
# Luecke SP8(12499)-AN8(13299) = 800 ist das kuerzeste Paar - ohne
# Tausch-Nachbesserung kamen 800 + 12833 statt 9033 + 3000 heraus.
an = [_station(26998.0, 3466.4), _station(26998.0, 13298.9)]
sp = [_station(26998.0, 16298.9), _station(26998.0, 12498.9)]
paare, an_rest, sp_rest = dsc.kreisel_paare_bilden(an, sp)
assert an_rest == [] and sp_rest == []
abstaende = sorted(round(p[2], 1) for p in paare)
assert abstaende == [3000.0, 9032.5]
def test_zerstueckelte_linie_wird_vereint():
# GF bei x=34006 in vier Stuecken, das Separatorstueck 0,3 mm daneben
stuecke = [
_linie((34005.93, 13893.90, 0.0), (34005.93, 14193.90, 0.0)),
_linie((34005.93, 15043.90, 0.0), (34005.93, 15593.90, 0.0)),
_linie((34006.24, 14744.31, 0.0), (34006.24, 15044.31, 0.0)),
_linie((34005.93, 14193.90, 0.0), (34005.93, 14743.90, 0.0)),
]
vereint = dsc.linien_zusammenfassen(stuecke)
assert len(vereint) == 1
ys = sorted([vereint[0]["a"][1], vereint[0]["b"][1]])
assert ys == pytest.approx([13893.90, 15593.90], abs=0.01)
def test_parallele_nachbarlinie_wird_nicht_vereint():
linien = [_linie((0.0, 0.0, 0.0), (0.0, 1000.0, 0.0)),
_linie((800.0, 1000.0, 0.0), (800.0, 2000.0, 0.0))]
assert len(dsc.linien_zusammenfassen(linien)) == 2
def _kreisel_d():
# Schleife oben (Kette unten y=15898.9), Radmitten per --kreisel-achse
return {"id": "K_D", "a": (27797.93, 16298.9), "u": (1.0, 0.0),
"laenge": 8908.0, "r": 400.0, "z_anwender": None}
def _kreisel_e():
# Schleife Mitte (Kette oben y=13493.9)
return {"id": "K_E", "a": (28772.93, 13093.9), "u": (1.0, 0.0),
"laenge": 6533.0, "r": 400.0, "z_anwender": None}
def test_flacher_plan_richtung_und_seiten_aus_as_es():
# Waagrechte Linie; AE-D sitzt 305 mm VOR dem oberen Ende auf der
# Kreisel-Kette, 180 mm links der Fahrtrichtung (Fahrt -y, links = +x).
# EE-R am unteren Ende 212 mm rechts davon.
linie = _linie((30455.93, 13893.9, 0.0), (30455.93, 15593.9, 0.0))
ae = {"familie": "schleuselement", "block": "AE-D",
"x": 30636.27, "y": 15898.9, "z": 0.0, "rot": 270.0}
ee = {"familie": "schleuselement", "block": "EE-R",
"x": 30243.76, "y": 13493.9, "z": 0.0, "rot": 90.0}
eintraege, belegt, _ = dsc.gf_eintraege_aus_linien(
[linie], [ae], [_kreisel_d(), _kreisel_e()], es_liste=[ee], flach=True)
assert len(eintraege) == 1
gf = eintraege[0]
assert gf["hz_grad"] == 270.0
assert gf["start_mm"][:2] == [30455.93, 15898.9]
assert gf["deltaL_mm"] == pytest.approx(2405.0, abs=0.01)
assert (gf["as_seite"], gf["es_seite"]) == ("links", "rechts")
assert (gf["kreisel_start"], gf["kreisel_ende"]) == ("K_D", "K_E")
assert belegt == {id(ae), id(ee)}
def test_flacher_plan_ohne_flach_schalter_keine_gf():
linie = _linie((30455.93, 13893.9, 0.0), (30455.93, 15593.9, 0.0))
ae = {"familie": "schleuselement", "block": "AE-D",
"x": 30636.27, "y": 15898.9, "z": 0.0, "rot": 270.0}
eintraege, _, _ = dsc.gf_eintraege_aus_linien([linie], [ae])
assert eintraege == []
def test_flacher_plan_ohne_as_keine_gf():
# Staulinie am Kreisel B (x=36348) - kein AS an einem Ende
linie = _linie((36347.6, 11313.9, 0.0), (36347.6, 14913.9, 0.0))
eintraege, _, hinweise = dsc.gf_eintraege_aus_linien([linie], [], flach=True)
assert eintraege == []
assert any("waagrechte" in h for h in hinweise)
def test_kurznamen_ae_ee():
assert dsc.familie_von("AE-D") == "schleuselement"
assert dsc.familie_von("EE-R") == "schleuselement"
assert dsc.mappe_block("AE-D")[0].startswith("AS_Element_90_")
assert dsc.mappe_block("EE-R")[0].startswith("ES_Element_90_")