diff --git a/CHANGES.rst b/CHANGES.rst index ec764a1d..50f290a2 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -8,6 +8,7 @@ Changelog of threedi-modelchecker - Remove checks for model_settings.epsg_code (317 and 318) - Remove usage of epsg 4326 in the tests because this CRS is no longer valid - Remove no longer needed transformations +- Change ConnectionNodeCheck (201) to require minimum distance of 10cm 2.15.0 (2025-01-08) diff --git a/threedi_modelchecker/checks/other.py b/threedi_modelchecker/checks/other.py index 0e04bbfa..49eab224 100644 --- a/threedi_modelchecker/checks/other.py +++ b/threedi_modelchecker/checks/other.py @@ -320,30 +320,26 @@ def get_invalid(self, session: Session) -> List[NamedTuple]: distance between all connection nodes. """ query = text( - f"""SELECT * - FROM connection_node AS cn1, connection_node AS cn2 - WHERE - distance(cn1.geom, cn2.geom) < :min_distance - AND cn1.ROWID != cn2.ROWID - AND cn2.ROWID IN ( - SELECT ROWID - FROM SpatialIndex - WHERE ( - f_table_name = "connection_node" - AND search_frame = Buffer(cn1.geom, {self.minimum_distance / 2}))); + f""" + SELECT * + FROM connection_node AS cn1, connection_node AS cn2 + WHERE ST_Distance(cn1.geom, cn2.geom) < {self.minimum_distance} + AND cn1.ROWID != cn2.ROWID + AND cn2.ROWID IN ( + SELECT ROWID + FROM SpatialIndex + WHERE ( + f_table_name = "connection_node" + AND search_frame = Buffer(cn1.geom, {self.minimum_distance / 2}))) """ ) - results = ( - session.connection() - .execute(query, {"min_distance": self.minimum_distance}) - .fetchall() - ) - + results = session.connection().execute(query).fetchall() return results def description(self) -> str: + return ( - f"The connection_node is within {self.minimum_distance} degrees of " + f"The connection_node is within {self.minimum_distance * 100 } cm of " f"another connection_node." ) diff --git a/threedi_modelchecker/config.py b/threedi_modelchecker/config.py index 3053ef21..2931a072 100644 --- a/threedi_modelchecker/config.py +++ b/threedi_modelchecker/config.py @@ -1062,7 +1062,7 @@ def is_none_or_empty(col): ## 020x: Spatial checks -CHECKS += [ConnectionNodesDistance(error_code=201, minimum_distance=0.001)] +CHECKS += [ConnectionNodesDistance(error_code=201, minimum_distance=0.1)] CHECKS += [ QueryCheck( error_code=202, diff --git a/threedi_modelchecker/tests/test_checks_other.py b/threedi_modelchecker/tests/test_checks_other.py index 37b222be..263764d4 100644 --- a/threedi_modelchecker/tests/test_checks_other.py +++ b/threedi_modelchecker/tests/test_checks_other.py @@ -1,8 +1,7 @@ from unittest import mock import pytest -from sqlalchemy import func, select, text -from sqlalchemy.orm import aliased, Query +from sqlalchemy import select, text from threedi_schema import constants, models, ThreediDatabase from threedi_schema.beta_features import BETA_COLUMNS, BETA_VALUES @@ -224,31 +223,18 @@ def test_channel_manhole_level_check( assert len(errors) == errors_number -def test_node_distance(session): - con1_too_close = factories.ConnectionNodeFactory( - geom=f"SRID={SRID};POINT(142740 473443)", - ) - con2_too_close = factories.ConnectionNodeFactory( - geom=f"SRID={SRID};POINT(142743 473443)", - ) - # Good distance - factories.ConnectionNodeFactory( - geom=f"SRID={SRID};POINT(142755 473443)", - ) - # sanity check to see the distances between the nodes - node_a = aliased(models.ConnectionNode) - node_b = aliased(models.ConnectionNode) - distances_query = Query(func.ST_Distance(node_a.geom, node_b.geom)).filter( - node_a.id != node_b.id - ) - # Shows the distances between all 3 nodes: node 1 and 2 are too close - distances_query.with_session(session).all() - check = ConnectionNodesDistance(minimum_distance=10) +@pytest.mark.parametrize("other_x, valid", [(142740.05, False), (142740.15, True)]) +def test_node_distance_alt(session, other_x, valid): + factories.ConnectionNodeFactory(id=0, geom=f"SRID={SRID};POINT(142740 473443)") + factories.ConnectionNodeFactory(id=1, geom=f"SRID={SRID};POINT({other_x} 473443)") + # Note that the test uses plain sqlite, so this needs to be committed + session.commit() + check = ConnectionNodesDistance(minimum_distance=0.1) invalid = check.get_invalid(session) - assert len(invalid) == 2 - invalid_ids = [i.id for i in invalid] - assert con1_too_close.id in invalid_ids - assert con2_too_close.id in invalid_ids + assert (len(invalid) == 0) == valid + # Remove connection nodes + session.query(models.ConnectionNode).delete() + session.commit() class TestCrossSectionSameConfiguration: