From: Sarah Hoffmann Date: Wed, 29 Mar 2023 15:21:33 +0000 (+0200) Subject: python reverse: add support for point geometries in interpolations X-Git-Tag: v4.3.0~86^2~2 X-Git-Url: https://git.openstreetmap.org./nominatim.git/commitdiff_plain/26ee6b6dde8d27107f8d536778b42546c51419be python reverse: add support for point geometries in interpolations --- diff --git a/nominatim/api/reverse.py b/nominatim/api/reverse.py index f454a837..1c9cd4c1 100644 --- a/nominatim/api/reverse.py +++ b/nominatim/api/reverse.py @@ -66,6 +66,14 @@ def _interpolated_position(table: SaFromClause) -> SaLabel: else_=table.c.linegeo.ST_LineInterpolatePoint(rounded_pos)).label('centroid') +def _locate_interpolation(table: SaFromClause, wkt: WKTElement) -> SaLabel: + """ Given a position, locate the closest point on the line. + """ + return sa.case((table.c.linegeo.ST_GeometryType() == 'ST_LineString', + sa.func.ST_LineLocatePoint(table.c.linegeo, wkt)), + else_=0).label('position') + + def _is_address_point(table: SaFromClause) -> SaColumn: return sa.and_(table.c.rank_address == 30, sa.or_(table.c.housenumber != None, @@ -207,7 +215,7 @@ class ReverseGeocoder: sql = sa.select(t, t.c.linegeo.ST_Distance(wkt).label('distance'), - t.c.linegeo.ST_LineLocatePoint(wkt).label('position'))\ + _locate_interpolation(t, wkt))\ .where(t.c.linegeo.ST_DWithin(wkt, distance))\ .where(t.c.startnumber != None)\ .order_by('distance')\ @@ -239,7 +247,7 @@ class ReverseGeocoder: inner = sa.select(t, t.c.linegeo.ST_Distance(wkt).label('distance'), - sa.func.ST_LineLocatePoint(t.c.linegeo, wkt).label('position'))\ + _locate_interpolation(t, wkt))\ .where(t.c.linegeo.ST_DWithin(wkt, 0.001))\ .where(t.c.parent_place_id == parent_place_id)\ .order_by('distance')\ diff --git a/test/python/api/test_api_reverse.py b/test/python/api/test_api_reverse.py index e78dc071..d1d47f84 100644 --- a/test/python/api/test_api_reverse.py +++ b/test/python/api/test_api_reverse.py @@ -135,6 +135,23 @@ def test_reverse_housenumber_interpolation(apiobj): assert apiobj.api.reverse((10.0, 10.0)).place_id == 992 +def test_reverse_housenumber_point_interpolation(apiobj): + apiobj.add_placex(place_id=990, class_='highway', type='service', + rank_search=27, rank_address=27, + name = {'name': 'My Street'}, + centroid=(10.0, 10.0), + geometry='LINESTRING(9.995 10, 10.005 10)') + apiobj.add_osmline(place_id=992, + parent_place_id=990, + startnumber=42, endnumber=42, step=1, + centroid=(10.0, 10.00001), + geometry='POINT(10.0 10.00001)') + + res = apiobj.api.reverse((10.0, 10.0)) + assert res.place_id == 992 + assert res.housenumber == '42' + + def test_reverse_tiger_number(apiobj): apiobj.add_placex(place_id=990, class_='highway', type='service', rank_search=27, rank_address=27, @@ -152,6 +169,24 @@ def test_reverse_tiger_number(apiobj): assert apiobj.api.reverse((10.0, 10.00001)).place_id == 992 +def test_reverse_point_tiger(apiobj): + apiobj.add_placex(place_id=990, class_='highway', type='service', + rank_search=27, rank_address=27, + name = {'name': 'My Street'}, + centroid=(10.0, 10.0), + country_code='us', + geometry='LINESTRING(9.995 10, 10.005 10)') + apiobj.add_tiger(place_id=992, + parent_place_id=990, + startnumber=1, endnumber=1, step=1, + centroid=(10.0, 10.00001), + geometry='POINT(10.0 10.00001)') + + res = apiobj.api.reverse((10.0, 10.0)) + assert res.place_id == 992 + assert res.housenumber == '1' + + def test_reverse_low_zoom_address(apiobj): apiobj.add_placex(place_id=1001, class_='place', type='house', housenumber='1',