knickpunktprüfung fehlende Knickupnkte auf Abschnitte auf dem BROBOR-Objekt umgestellt

This commit is contained in:
2026-07-10 07:33:31 +02:00
parent b9c03627ae
commit 978c259496
2 changed files with 397 additions and 94 deletions
+186 -18
View File
@@ -14,7 +14,7 @@ knickpunkt_pruefung:
- Kein PunktortTA-Layer → (None, 0, 0, 0)
- Identischer Punkt → grün gezählt
- Kein passender PunktortTA → rot gezählt
- PunktortTA nahe Umring auf Flurstücksgrenze → orange gezählt
- PunktortTA im 3cm-Puffer einer Verbindungslinie zwischen zwei gematchten PunktortTA → orange gezählt
- Abbruch via progress.is_canceled() → (None, 0, 0, 0)
"""
@@ -278,29 +278,197 @@ class TestKnickpunktPruefungKlassifizierung(unittest.TestCase):
self.assertEqual(kein_pta, 1)
# ---------------------------------------------------------------------------
# Tests: _baue_flst_vertex_set
# Tests: _fehlende_knickpunkte_via_verbindungslinien
# ---------------------------------------------------------------------------
class TestBaueFlstVertexSet(unittest.TestCase):
class TestFehlendKnickpunkteViaVerbindungslinien(unittest.TestCase):
"""Direkte Tests für :func:`_fehlende_knickpunkte_via_verbindungslinien`."""
def test_none_layer_gibt_leeres_set(self):
from sn_verfahrensgebiet.functions.knickpunkt_pruefung import _baue_flst_vertex_set
result = _baue_flst_vertex_set(None, MagicMock())
self.assertEqual(result, set())
def _fn(self, *args, **kwargs):
from sn_verfahrensgebiet.functions.knickpunkt_pruefung import (
_fehlende_knickpunkte_via_verbindungslinien,
)
return _fehlende_knickpunkte_via_verbindungslinien(*args, **kwargs)
def test_layer_ohne_schnitt_mit_puffer_ignoriert(self):
from sn_verfahrensgebiet.functions.knickpunkt_pruefung import _baue_flst_vertex_set
layer = _make_layer()
geom = MagicMock()
geom.isEmpty.return_value = False
geom.intersects.return_value = False # kein Schnitt
feat = MagicMock()
feat.geometry.return_value = geom
layer.getFeatures.return_value = [feat]
def test_leere_union_gibt_null_zurueck(self):
"""bror_union.isEmpty() == True → (0, [])."""
bror_union = MagicMock()
bror_union.isEmpty.return_value = True
with patch("qgis.core.QgsPointXY", create=True), \
patch("qgis.core.QgsProject", create=True):
count, feats = self._fn(
bror_union, MagicMock(), {}, set(), MagicMock(), "EPSG:25833"
)
self.assertEqual(count, 0)
self.assertEqual(feats, [])
def test_weniger_als_zwei_pta_auf_ring_kein_orange(self):
"""Nur 1 gematchter PunktortTA auf Ring → keine fehlenden Knickpunkte."""
bror_union = MagicMock()
bror_union.isEmpty.return_value = False
bror_union.isMultipart.return_value = False
bror_union.asPolygon.return_value = [
[(0.0, 0.0), (10.0, 0.0), (10.0, 10.0), (0.0, 0.0)]
]
def _mock_ptxy(x, y):
pt = MagicMock()
pt.x.return_value = x
pt.y.return_value = y
return pt
pta_geom = MagicMock()
pta_pt = MagicMock()
pta_pt.x.return_value = 0.0
pta_pt.y.return_value = 0.0
pta_geom.asPoint.return_value = pta_pt
geom_map = {1: pta_geom}
matched_pta_ids = {1} # nur 1 → < 2
with patch("qgis.core.QgsPointXY", create=True, side_effect=_mock_ptxy), \
patch("qgis.core.QgsProject", create=True):
count, feats = self._fn(
bror_union, MagicMock(), geom_map, matched_pta_ids,
MagicMock(), "EPSG:25833"
)
self.assertEqual(count, 0)
self.assertEqual(len(feats), 0)
@patch(f"{_MOD}.QgsGeometry")
@patch(f"{_MOD}.QgsVectorLayer")
def test_ungematchter_pta_im_puffer_wird_orange(
self, mock_vl_cls, mock_geom_cls
):
"""Nicht-gematchter PunktortTA innerhalb 3-cm-Puffer → orange gezählt."""
bror_union = MagicMock()
bror_union.isEmpty.return_value = False
bror_union.isMultipart.return_value = False
bror_union.asPolygon.return_value = [
[(0.0, 0.0), (10.0, 0.0), (10.0, 10.0), (0.0, 0.0)]
]
def _mock_ptxy(x, y):
pt = MagicMock()
pt.x.return_value = x
pt.y.return_value = y
return pt
# Zwei gematchte PunktortTA (fid 1 und 2)
pta_geom_1 = MagicMock()
pta_pt_1 = MagicMock()
pta_pt_1.x.return_value = 0.0
pta_pt_1.y.return_value = 0.0
pta_geom_1.asPoint.return_value = pta_pt_1
pta_geom_2 = MagicMock()
pta_pt_2 = MagicMock()
pta_pt_2.x.return_value = 10.0
pta_pt_2.y.return_value = 0.0
pta_geom_2.asPoint.return_value = pta_pt_2
# Nicht-gematchter PunktortTA (fid=3) liegt im Puffer
pta_geom_3 = MagicMock()
pta_geom_3.isEmpty.return_value = False
pta_geom_3.within.return_value = True
geom_map = {1: pta_geom_1, 2: pta_geom_2, 3: pta_geom_3}
matched_pta_ids = {1, 2}
# Spatial-Index liefert fid=3 als Kandidat
pta_index = MagicMock()
buffer_geom = MagicMock()
result = _baue_flst_vertex_set(layer, buffer_geom)
self.assertEqual(result, set())
buffer_geom.isEmpty.return_value = False
buffer_geom.boundingBox.return_value = MagicMock()
pta_index.intersects.return_value = [3]
line_geom = MagicMock()
line_geom.isEmpty.return_value = False
line_geom.buffer.return_value = buffer_geom
mock_geom_cls.fromPolylineXY.return_value = line_geom
pr_mock = MagicMock()
pr_mock.addFeatures.return_value = True
layer_mock = MagicMock()
layer_mock.dataProvider.return_value = pr_mock
mock_vl_cls.return_value = layer_mock
with patch("qgis.core.QgsPointXY", create=True, side_effect=_mock_ptxy), \
patch("qgis.core.QgsProject", create=True) as mock_proj:
mock_proj.instance.return_value = MagicMock()
count, feats = self._fn(
bror_union, pta_index, geom_map, matched_pta_ids,
MagicMock(), "EPSG:25833"
)
self.assertEqual(count, 1)
self.assertEqual(len(feats), 1)
@patch(f"{_MOD}.QgsGeometry")
@patch(f"{_MOD}.QgsVectorLayer")
def test_ungematchter_pta_ausserhalb_puffer_kein_orange(
self, mock_vl_cls, mock_geom_cls
):
"""Nicht-gematchter PunktortTA außerhalb Puffer → nicht orange gezählt."""
bror_union = MagicMock()
bror_union.isEmpty.return_value = False
bror_union.isMultipart.return_value = False
bror_union.asPolygon.return_value = [
[(0.0, 0.0), (10.0, 0.0), (10.0, 10.0), (0.0, 0.0)]
]
def _mock_ptxy(x, y):
pt = MagicMock()
pt.x.return_value = x
pt.y.return_value = y
return pt
pta_geom_1 = MagicMock()
pta_pt_1 = MagicMock()
pta_pt_1.x.return_value = 0.0
pta_pt_1.y.return_value = 0.0
pta_geom_1.asPoint.return_value = pta_pt_1
pta_geom_2 = MagicMock()
pta_pt_2 = MagicMock()
pta_pt_2.x.return_value = 10.0
pta_pt_2.y.return_value = 0.0
pta_geom_2.asPoint.return_value = pta_pt_2
# fid=3 liegt NICHT im Puffer
pta_geom_3 = MagicMock()
pta_geom_3.within.return_value = False
geom_map = {1: pta_geom_1, 2: pta_geom_2, 3: pta_geom_3}
matched_pta_ids = {1, 2}
pta_index = MagicMock()
buffer_geom = MagicMock()
buffer_geom.isEmpty.return_value = False
buffer_geom.boundingBox.return_value = MagicMock()
pta_index.intersects.return_value = [3]
line_geom = MagicMock()
line_geom.isEmpty.return_value = False
line_geom.buffer.return_value = buffer_geom
mock_geom_cls.fromPolylineXY.return_value = line_geom
pr_mock = MagicMock()
layer_mock = MagicMock()
layer_mock.dataProvider.return_value = pr_mock
mock_vl_cls.return_value = layer_mock
with patch("qgis.core.QgsPointXY", create=True, side_effect=_mock_ptxy), \
patch("qgis.core.QgsProject", create=True) as mock_proj:
mock_proj.instance.return_value = MagicMock()
count, feats = self._fn(
bror_union, pta_index, geom_map, matched_pta_ids,
MagicMock(), "EPSG:25833"
)
self.assertEqual(count, 0)
self.assertEqual(len(feats), 0)
if __name__ == "__main__":