X-Git-Url: https://git.openstreetmap.org./nominatim.git/blobdiff_plain/db3ced17bbfff00411f506d8c84419c875959d5e..11844313b4f420e13885714750d620ec41e75f36:/lib-php/ReverseGeocode.php diff --git a/lib-php/ReverseGeocode.php b/lib-php/ReverseGeocode.php index b420e5dd..d12e4da3 100644 --- a/lib-php/ReverseGeocode.php +++ b/lib-php/ReverseGeocode.php @@ -1,4 +1,12 @@ 4) { $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); if ($aPlace) { @@ -113,6 +122,7 @@ 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_search between 5 and ' .min(25, $iMaxRank); $sSQL .= ' AND class = \'place\' AND type != \'postcode\''; $sSQL .= ' AND name IS NOT NULL '; @@ -167,22 +177,28 @@ class ReverseGeocode { Debug::newFunction('lookupPolygon'); // polygon search begins at suburb-level - if ($iMaxRank > 25) $iMaxRank = 25; + if ($iMaxRank > 25) { + $iMaxRank = 25; + } // no polygon search over country-level - if ($iMaxRank < 5) $iMaxRank = 5; + if ($iMaxRank < 5) { + $iMaxRank = 5; + } // search for polygon $sSQL = 'SELECT place_id, parent_place_id, rank_address, rank_search FROM'; $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.'); @@ -190,12 +206,11 @@ class ReverseGeocode if ($aPoly) { // if a polygon is found, search for placenodes begins ... - $iParentPlaceID = $aPoly['parent_place_id']; $iRankAddress = $aPoly['rank_address']; $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'; @@ -205,6 +220,7 @@ class ReverseGeocode // 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 type != \'postcode\''; @@ -242,26 +258,24 @@ class ReverseGeocode public function lookupPoint($sPointSQL, $bDoInterpolation = true) { Debug::newFunction('lookupPoint'); - // 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. - $iMaxRank = $this->iMaxRank; - // Find the nearest point $fSearchDiam = 0.006; $oResult = null; $aPlace = null; // for POI or street level - if ($iMaxRank >= 26) { + if ($this->iMaxRank >= 26) { + // 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 chosen. $sSQL = 'select place_id,parent_place_id,rank_address,country_code,'; $sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance'; $sSQL .= ' FROM '; $sSQL .= ' placex'; $sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, '.$fSearchDiam.')'; $sSQL .= ' AND'; - $sSQL .= ' rank_address between 26 and '.$iMaxRank; + $sSQL .= ' rank_address between 26 and '.$this->iMaxRank; $sSQL .= ' and (name is not null or housenumber is not null'; $sSQL .= ' or rank_address between 26 and 27)'; $sSQL .= ' and (rank_address between 26 and 27'; @@ -280,34 +294,11 @@ class ReverseGeocode $iPlaceID = $aPlace['place_id']; $oResult = new Result($iPlaceID); $iRankAddress = $aPlace['rank_address']; - $iParentPlaceID = $aPlace['parent_place_id']; - } - - if ($bDoInterpolation && $iMaxRank >= 30) { - $fDistance = $fSearchDiam; - if ($aPlace) { - // 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 - // even when the street is closer. - $fDistance = $iRankAddress < 28 ? 0.001 : $aPlace['distance']; - } - - $aHouse = $this->lookupInterpolation($sPointSQL, $fDistance); - Debug::printVar('Interpolation result', $aPlace); - - if ($aHouse) { - $oResult = new Result($aHouse['place_id'], Result::TABLE_OSMLINE); - $oResult->iHouseNumber = closestHouseNumber($aHouse); - $aPlace = $aHouse; - $iRankAddress = 30; - } } if ($aPlace) { // if street and maxrank > streetlevel - if ($iRankAddress <= 27 && $iMaxRank > 27) { + if ($iRankAddress <= 27 && $this->iMaxRank > 27) { // find the closest object (up to a certain radius) of which the street is a parent of $sSQL = ' select place_id,'; $sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance'; @@ -328,7 +319,9 @@ class ReverseGeocode Debug::printVar('Closest POI result', $aStreet); if ($aStreet) { + $aPlace = $aStreet; $oResult = new Result($aStreet['place_id']); + $iRankAddress = 30; } } @@ -339,9 +332,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'; @@ -351,17 +344,50 @@ class ReverseGeocode Debug::printVar('Tiger house number result', $aPlaceTiger); 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; + } + } + } + + if ($bDoInterpolation && $this->iMaxRank >= 30) { + $fDistance = $fSearchDiam; + if ($aPlace) { + // 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 precedence + // even when the street is closer. + $fDistance = $iRankAddress < 28 ? 0.001 : $aPlace['distance']; + } + + $aHouse = $this->lookupInterpolation($sPointSQL, $fDistance); + Debug::printVar('Interpolation result', $aPlace); + + if ($aHouse) { + $oResult = new Result($aHouse['place_id'], Result::TABLE_OSMLINE); + $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; } - } else { + } + + if (!$aPlace) { // if no POI or street is found ... $oResult = $this->lookupLargeArea($sPointSQL, 25); } } else { // lower than street level ($iMaxRank < 26 ) - $oResult = $this->lookupLargeArea($sPointSQL, $iMaxRank); + $oResult = $this->lookupLargeArea($sPointSQL, $this->iMaxRank); } Debug::printVar('Final result', $oResult);