X-Git-Url: https://git.openstreetmap.org./nominatim.git/blobdiff_plain/8e439d3dd9b74752594f5ff9e32f4e70b00d35ff..b8a73192128b162ea32bf2f622875a543a39d955:/lib-php/ReverseGeocode.php?ds=inline diff --git a/lib-php/ReverseGeocode.php b/lib-php/ReverseGeocode.php index a670c623..fddad60d 100644 --- a/lib-php/ReverseGeocode.php +++ b/lib-php/ReverseGeocode.php @@ -1,4 +1,12 @@ 12, 10 => 17, // City 11 => 17, - 12 => 18, // Town / Village - 13 => 18, - 14 => 22, // Suburb - 15 => 22, + 12 => 18, // Town + 13 => 19, // Village + 14 => 22, // Neighbourhood + 15 => 25, // Locality 16 => 26, // major street 17 => 27, // minor street 18 => 30, // or >, Building @@ -56,12 +64,15 @@ class ReverseGeocode { Debug::newFunction('lookupInterpolation'); $sSQL = 'SELECT place_id, parent_place_id, 30 as rank_search,'; - $sSQL .= ' ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fraction,'; - $sSQL .= ' startnumber, endnumber, interpolationtype,'; + $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'; $sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', linegeo, '.$fSearchDiam.')'; - $sSQL .= ' and indexed_status = 0 and startnumber is not NULL '; + $sSQL .= ' and indexed_status = 0 and startnumber is not NULL '; + $sSQL .= ' and parent_place_id != 0'; $sSQL .= ' ORDER BY distance ASC limit 1'; Debug::printSQL($sSQL); @@ -111,12 +122,13 @@ class ReverseGeocode $sSQL .= ' FROM placex'; $sSQL .= ' WHERE osm_type = \'N\''; $sSQL .= ' AND country_code = \''.$sCountryCode.'\''; - $sSQL .= ' AND rank_search < 26 '; // needed to select right index + $sSQL .= ' AND rank_address between 4 and 25'; // needed to select right index $sSQL .= ' AND rank_search between 5 and ' .min(25, $iMaxRank); - $sSQL .= ' AND class = \'place\' AND type != \'postcode\''; + $sSQL .= ' AND type != \'postcode\''; $sSQL .= ' AND name IS NOT NULL '; $sSQL .= ' and indexed_status = 0 and linked_place_id is null'; - $sSQL .= ' AND ST_DWithin('.$sPointSQL.', geometry, 1.8)) p '; + $sSQL .= ' AND ST_Buffer(geometry, reverse_place_diameter(rank_search)) && '.$sPointSQL; + $sSQL .= ') as a '; $sSQL .= 'WHERE distance <= reverse_place_diameter(rank_search)'; $sSQL .= ' ORDER BY rank_search DESC, distance ASC'; $sSQL .= ' LIMIT 1'; @@ -178,14 +190,16 @@ class ReverseGeocode $sSQL .= '(select place_id, parent_place_id, rank_address, rank_search, country_code, geometry'; $sSQL .= ' FROM placex'; $sSQL .= ' WHERE ST_GeometryType(geometry) in (\'ST_Polygon\', \'ST_MultiPolygon\')'; - $sSQL .= ' AND rank_address Between 5 AND ' .$iMaxRank; + // Ensure that query planner doesn't use the index on rank_search. + $sSQL .= ' AND coalesce(rank_search, 0) between 5 and ' .$iMaxRank; + $sSQL .= ' AND rank_address between 4 and 25'; // needed for index selection $sSQL .= ' AND geometry && '.$sPointSQL; $sSQL .= ' AND type != \'postcode\' '; $sSQL .= ' AND name is not null'; $sSQL .= ' AND indexed_status = 0 and linked_place_id is null'; - $sSQL .= ' ORDER BY rank_address DESC LIMIT 50 ) as a'; - $sSQL .= ' WHERE ST_CONTAINS(geometry, '.$sPointSQL.' )'; - $sSQL .= ' ORDER BY rank_address DESC LIMIT 1'; + $sSQL .= ' ORDER BY rank_search DESC LIMIT 50 ) as a'; + $sSQL .= ' WHERE ST_Contains(geometry, '.$sPointSQL.' )'; + $sSQL .= ' ORDER BY rank_search DESC LIMIT 1'; Debug::printSQL($sSQL); $aPoly = $this->oDB->getRow($sSQL, null, 'Could not determine polygon containing the point.'); @@ -197,29 +211,24 @@ class ReverseGeocode $iRankSearch = $aPoly['rank_search']; $iPlaceID = $aPoly['place_id']; - if ($iRankAddress != $iMaxRank) { + if ($iRankSearch != $iMaxRank) { $sSQL = 'SELECT place_id FROM '; $sSQL .= '(SELECT place_id, rank_search, country_code, geometry,'; $sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance'; $sSQL .= ' FROM placex'; $sSQL .= ' WHERE osm_type = \'N\''; - // using rank_search because of a better differentiation - // for place nodes at rank_address 16 $sSQL .= ' AND rank_search > '.$iRankSearch; $sSQL .= ' AND rank_search <= '.$iMaxRank; - $sSQL .= ' AND rank_search < 26 '; // needed to select right index - $sSQL .= ' AND rank_address > 0'; - $sSQL .= ' AND class = \'place\''; + $sSQL .= ' AND rank_address between 4 and 25'; // needed to select right index $sSQL .= ' AND type != \'postcode\''; $sSQL .= ' AND name IS NOT NULL '; $sSQL .= ' AND indexed_status = 0 AND linked_place_id is null'; - $sSQL .= ' AND ST_DWithin('.$sPointSQL.', geometry, reverse_place_diameter('.$iRankSearch.'::smallint))'; - $sSQL .= ' ORDER BY distance ASC,'; - $sSQL .= ' rank_address DESC'; - $sSQL .= ' limit 500) as a'; - $sSQL .= ' WHERE ST_CONTAINS((SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.'), geometry )'; + $sSQL .= ' AND ST_Buffer(geometry, reverse_place_diameter(rank_search)) && '.$sPointSQL; + $sSQL .= ' ORDER BY rank_search DESC, distance ASC'; + $sSQL .= ' limit 100) as a'; + $sSQL .= ' WHERE ST_Contains((SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.'), geometry )'; $sSQL .= ' AND distance <= reverse_place_diameter(rank_search)'; - $sSQL .= ' ORDER BY distance ASC, rank_search DESC'; + $sSQL .= ' ORDER BY rank_search DESC, distance ASC'; $sSQL .= ' LIMIT 1'; Debug::printSQL($sSQL); @@ -255,7 +264,7 @@ class ReverseGeocode // starts if the search is on POI or street level, // searches for the nearest POI or street, // if a street is found and a POI is searched for, - // the nearest POI which the found street is a parent of is choosen. + // the nearest POI which the found street is a parent of is chosen. $sSQL = 'select place_id,parent_place_id,rank_address,country_code,'; $sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance'; $sSQL .= ' FROM '; @@ -319,9 +328,9 @@ class ReverseGeocode && $this->iMaxRank >= 28 ) { $sSQL = 'SELECT place_id,parent_place_id,30 as rank_search,'; - $sSQL .= 'ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fraction,'; - $sSQL .= 'ST_distance('.$sPointSQL.', linegeo) as distance,'; - $sSQL .= 'startnumber,endnumber,interpolationtype'; + $sSQL .= ' (endnumber - startnumber) * ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fhnr,'; + $sSQL .= ' startnumber, endnumber, step,'; + $sSQL .= ' ST_Distance('.$sPointSQL.', linegeo) as distance'; $sSQL .= ' FROM location_property_tiger WHERE parent_place_id = '.$oResult->iId; $sSQL .= ' AND ST_DWithin('.$sPointSQL.', linegeo, 0.001)'; $sSQL .= ' ORDER BY distance ASC limit 1'; @@ -333,7 +342,11 @@ class ReverseGeocode if ($aPlaceTiger) { $aPlace = $aPlaceTiger; $oResult = new Result($aPlaceTiger['place_id'], Result::TABLE_TIGER); - $oResult->iHouseNumber = closestHouseNumber($aPlaceTiger); + $iRndNum = max(0, round($aPlaceTiger['fhnr'] / $aPlaceTiger['step']) * $aPlaceTiger['step']); + $oResult->iHouseNumber = $aPlaceTiger['startnumber'] + $iRndNum; + if ($oResult->iHouseNumber > $aPlaceTiger['endnumber']) { + $oResult->iHouseNumber = $aPlaceTiger['endnumber']; + } $iRankAddress = 30; } } @@ -345,7 +358,7 @@ class ReverseGeocode // We can't reliably go from the closest street to an // interpolation line because the closest interpolation // may have a different street segments as a parent. - // Therefore allow an interpolation line to take precendence + // Therefore allow an interpolation line to take precedence // even when the street is closer. $fDistance = $iRankAddress < 28 ? 0.001 : $aPlace['distance']; } @@ -355,7 +368,11 @@ class ReverseGeocode if ($aHouse) { $oResult = new Result($aHouse['place_id'], Result::TABLE_OSMLINE); - $oResult->iHouseNumber = closestHouseNumber($aHouse); + $iRndNum = max(0, round($aHouse['fhnr'] / $aHouse['step']) * $aHouse['step']); + $oResult->iHouseNumber = $aHouse['startnumber'] + $iRndNum; + if ($oResult->iHouseNumber > $aHouse['endnumber']) { + $oResult->iHouseNumber = $aHouse['endnumber']; + } $aPlace = $aHouse; } }