From: Sarah Hoffmann Date: Wed, 16 Mar 2022 10:19:09 +0000 (+0100) Subject: correctly handle single-point interpolations in reverse X-Git-Tag: v4.1.0~71^2 X-Git-Url: https://git.openstreetmap.org./nominatim.git/commitdiff_plain/ef98a85b05f02068ada85dd50b15f2e960ca35bc correctly handle single-point interpolations in reverse Lookup in location_property_osmline needs to be special cased for startnumber = endnumber. Also adds tests for the case. Fixes #2680. --- diff --git a/lib-php/ReverseGeocode.php b/lib-php/ReverseGeocode.php index 646c592b..35103aeb 100644 --- a/lib-php/ReverseGeocode.php +++ b/lib-php/ReverseGeocode.php @@ -64,7 +64,9 @@ class ReverseGeocode { Debug::newFunction('lookupInterpolation'); $sSQL = 'SELECT place_id, parent_place_id, 30 as rank_search,'; - $sSQL .= ' (endnumber - startnumber) * ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fhnr,'; + $sSQL .= ' (CASE WHEN endnumber != startnumber'; + $sSQL .= ' THEN (endnumber - startnumber) * ST_LineLocatePoint(linegeo,'.$sPointSQL.')'; + $sSQL .= ' ELSE startnumber END) as fhnr,'; $sSQL .= ' startnumber, endnumber, step,'; $sSQL .= ' ST_Distance(linegeo,'.$sPointSQL.') as distance'; $sSQL .= ' FROM location_property_osmline'; diff --git a/test/bdd/db/query/interpolation.feature b/test/bdd/db/query/interpolation.feature new file mode 100644 index 00000000..602ac434 --- /dev/null +++ b/test/bdd/db/query/interpolation.feature @@ -0,0 +1,58 @@ +@DB +Feature: Query of address interpolations + Tests that interpolated addresses can be queried correctly + + Background: + Given the grid + | 1 | | 2 | | 3 | + | 10 | | 12 | | 13 | + | 7 | | 8 | | 9 | + + Scenario: Find interpolations with single number + Given the places + | osm | class | type | name | geometry | + | W10 | highway | primary | Nickway | 10,12,13 | + And the places + | osm | class | type | addr+interpolation | geometry | + | W1 | place | houses | odd | 1,3 | + And the places + | osm | class | type | housenr | geometry | + | N1 | place | house | 1 | 1 | + | N3 | place | house | 5 | 3 | + And the ways + | id | nodes | + | 1 | 1,3 | + When importing + When sending jsonv2 reverse point 2 + Then results contain + | ID | display_name | + | 0 | 3, Nickway | + When sending search query "Nickway 3" + Then results contain + | osm | display_name | + | W1 | 3, Nickway | + + + Scenario: Find interpolations with multiple numbers + Given the places + | osm | class | type | name | geometry | + | W10 | highway | primary | Nickway | 10,12,13 | + And the places + | osm | class | type | addr+interpolation | geometry | + | W1 | place | houses | even | 1,3 | + And the places + | osm | class | type | housenr | geometry | + | N1 | place | house | 2 | 1 | + | N3 | place | house | 16 | 3 | + And the ways + | id | nodes | + | 1 | 1,3 | + When importing + When sending jsonv2 reverse point 2 + Then results contain + | ID | display_name | centroid | + | 0 | 10, Nickway | 2 | + When sending search query "Nickway 10" + Then results contain + | osm | display_name | centroid | + | W1 | 10, Nickway | 2 | diff --git a/test/bdd/steps/http_responses.py b/test/bdd/steps/http_responses.py index fa6ab7fb..fa841d25 100644 --- a/test/bdd/steps/http_responses.py +++ b/test/bdd/steps/http_responses.py @@ -62,6 +62,8 @@ class GenericResponse: if errorcode == 200 and fmt != 'debug': getattr(self, '_parse_' + fmt)() + else: + print("Bad response: ", page) def _parse_json(self): m = re.fullmatch(r'([\w$][^(]*)\((.*)\)', self.page) @@ -128,7 +130,7 @@ class GenericResponse: "\nBad value for row {} field '{}' in address. Expected: {}, got: {}.\nFull address: {}"""\ .format(idx, field, value, address[field], json.dumps(address, indent=4)) - def match_row(self, row): + def match_row(self, row, context=None): """ Match the result fields against the given behave table row. """ if 'ID' in row.headings: @@ -151,7 +153,12 @@ class GenericResponse: assert self.result[i]['osm_type'] in (OSM_TYPE[value[0]], value[0]), \ BadRowValueAssert(self, i, 'osm_type', value) elif name == 'centroid': - lon, lat = value.split(' ') + if ' ' in value: + lon, lat = value.split(' ') + elif context is not None: + lon, lat = context.osm.grid_node(int(value)) + else: + raise RuntimeError("Context needed when using grid coordinates") self.assert_field(i, 'lat', float(lat)) self.assert_field(i, 'lon', float(lon)) else: diff --git a/test/bdd/steps/steps_api_queries.py b/test/bdd/steps/steps_api_queries.py index 0fda8f08..22517338 100644 --- a/test/bdd/steps/steps_api_queries.py +++ b/test/bdd/steps/steps_api_queries.py @@ -153,6 +153,20 @@ def website_reverse_request(context, fmt, lat, lon): context.response = ReverseResponse(outp, fmt or 'xml', status) +@when(u'sending (?P\S+ )?reverse point (?P.+)') +def website_reverse_request(context, fmt, nodeid): + params = {} + if fmt and fmt.strip() == 'debug': + params['debug'] = '1' + params['lon'], params['lat'] = (f'{c:f}' for c in context.osm.grid_node(int(nodeid))) + + + outp, status = send_api_query('reverse', params, fmt, context) + + context.response = ReverseResponse(outp, fmt or 'xml', status) + + + @when(u'sending (?P\S+ )?details query for (?P.*)') def website_details_request(context, fmt, query): params = {} @@ -238,7 +252,7 @@ def step_impl(context): context.execute_steps("then at least 1 result is returned") for line in context.table: - context.response.match_row(line) + context.response.match_row(line, context=context) @then(u'result (?P\d+ )?has (?Pnot )?attributes (?P.*)') def validate_attributes(context, lid, neg, attrs):