X-Git-Url: https://git.openstreetmap.org./nominatim.git/blobdiff_plain/10620c71bb7999ed89ca45e545d9ce611a5e1476..a038582e34d73ac2575572c9dec0e890557fb0f5:/lib/lib.php diff --git a/lib/lib.php b/lib/lib.php index 9ee93105..a7c805f7 100644 --- a/lib/lib.php +++ b/lib/lib.php @@ -3,7 +3,7 @@ function fail($sError, $sUserError = false) { if (!$sUserError) $sUserError = $sError; - log('ERROR:'.$sError); + error_log('ERROR: '.$sError); echo $sUserError."\n"; exit; } @@ -40,14 +40,18 @@ function byImportance($a, $b) { +/* + if ($a['importance'] != $b['importance']) + return ($a['importance'] > $b['importance']?-1:1); if ($a['aPointPolygon']['numfeatures'] != $b['aPointPolygon']['numfeatures']) return ($a['aPointPolygon']['numfeatures'] > $b['aPointPolygon']['numfeatures']?-1:1); if ($a['aPointPolygon']['area'] != $b['aPointPolygon']['area']) return ($a['aPointPolygon']['area'] > $b['aPointPolygon']['area']?-1:1); - if ($a['levenshtein'] != $b['levenshtein']) - return ($a['levenshtein'] < $b['levenshtein']?-1:1); - if ($a['importance'] != $b['importance']) - return ($a['importance'] < $b['importance']?-1:1); +// if ($a['levenshtein'] != $b['levenshtein']) +// return ($a['levenshtein'] < $b['levenshtein']?-1:1); + if ($a['rank_search'] != $b['rank_search']) + return ($a['rank_search'] < $b['rank_search']?-1:1); +*/ return ($a['foundorder'] < $b['foundorder']?-1:1); } @@ -175,6 +179,10 @@ return array(array('lat' => $aNearPostcodes[0]['lat'], 'lon' => $aNearPostcodes[0]['lon'], 'radius' => 0.005)); } + return false; + + /* partial search disabled because it sequentially scans placex + $sSQL = 'select substring(upper(postcode) from \'^[A-Z][A-Z]?[0-9][0-9A-Z]? [0-9]([A-Z][A-Z])$\'),ST_X(ST_Centroid(geometry)) as lon,ST_Y(ST_Centroid(geometry)) as lat from placex where country_code::text = \'gb\'::text AND substring(postcode from \'^([A-Z][A-Z]?[0-9][0-9A-Z]? [0-9])[A-Z][A-Z]$\') = \''.$sPostcodeSector.'\' and class=\'place\' and type=\'postcode\' '; $sSQL .= ' union '; $sSQL .= 'select substring(upper(postcode) from \'^[A-Z][A-Z]?[0-9][0-9A-Z]? [0-9]([A-Z][A-Z])$\'),ST_X(ST_Centroid(geometry)) as lon,ST_Y(ST_Centroid(geometry)) as lat from gb_postcode where substring(postcode from \'^([A-Z][A-Z]?[0-9][0-9A-Z]? [0-9])[A-Z][A-Z]$\') = \''.$sPostcodeSector.'\''; @@ -213,7 +221,7 @@ return array(array('lat' => $fLat, 'lon' => $fLon, 'radius' => $fRadius)); } return false; - + */ /* $fTotalFac is a suprisingly good indicator of accuracy $iZoom = 18 + round(log($fTotalFac,32)); @@ -284,19 +292,19 @@ { return array( 'boundary:administrative:2' => array('label'=>'Country','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,), + 'place:country' => array('label'=>'Country','frequency'=>0,'icon'=>'poi_boundary_administrative','defzoom'=>6, 'defdiameter' => 15,), 'boundary:administrative:4' => array('label'=>'State','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,), + 'place:state' => array('label'=>'State','frequency'=>0,'icon'=>'poi_boundary_administrative','defzoom'=>8, 'defdiameter' => 5.12,), 'boundary:administrative:5' => array('label'=>'State District','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,), 'boundary:administrative:6' => array('label'=>'County','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,), + 'place:county' => array('label'=>'County','frequency'=>108,'icon'=>'poi_boundary_administrative','defzoom'=>10, 'defdiameter' => 1.28,), 'boundary:administrative:8' => array('label'=>'City','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,), + 'place:city' => array('label'=>'City','frequency'=>66,'icon'=>'poi_place_city','defzoom'=>12, 'defdiameter' => 0.32,), 'boundary:administrative:9' => array('label'=>'City District','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,), 'boundary:administrative:10' => array('label'=>'Suburb','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,), 'boundary:administrative:11' => array('label'=>'Neighbourhood','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,), - 'place:city' => array('label'=>'City','frequency'=>66,'icon'=>'poi_place_city','defzoom'=>12, 'defdiameter' => 0.32,), - 'place:country' => array('label'=>'Country','frequency'=>0,'icon'=>'poi_boundary_administrative','defzoom'=>6, 'defdiameter' => 15,), - 'place:state' => array('label'=>'State','frequency'=>0,'icon'=>'poi_boundary_administrative','defzoom'=>8, 'defdiameter' => 5.12,), - 'place:region' => array('label'=>'State','frequency'=>0,'icon'=>'poi_boundary_administrative','defzoom'=>8, 'defdiameter' => 5.12,), + 'place:region' => array('label'=>'Region','frequency'=>0,'icon'=>'poi_boundary_administrative','defzoom'=>8, 'defdiameter' => 5.12,), 'place:island' => array('label'=>'Island','frequency'=>288,'icon'=>'','defzoom'=>11, 'defdiameter' => 0.64,), - 'place:county' => array('label'=>'County','frequency'=>108,'icon'=>'poi_boundary_administrative','defzoom'=>10, 'defdiameter' => 1.28,), 'boundary:administrative' => array('label'=>'Administrative','frequency'=>413,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,), 'place:town' => array('label'=>'Town','frequency'=>1497,'icon'=>'poi_place_town','defzoom'=>14, 'defdiameter' => 0.08,), 'place:village' => array('label'=>'Village','frequency'=>11230,'icon'=>'poi_place_village','defzoom'=>15, 'defdiameter' => 0.04,), @@ -564,6 +572,7 @@ 'amenity:shopping' => array('label'=>'Shopping','frequency'=>21,'icon'=>'',), 'natural:scrub' => array('label'=>'Scrub','frequency'=>20,'icon'=>'',), 'natural:fen' => array('label'=>'Fen','frequency'=>20,'icon'=>'',), + 'building:yes' => array('label'=>'Building','frequency'=>200,'icon'=>'',), 'amenity:parking' => array('label'=>'Parking','frequency'=>3157,'icon'=>'',), 'highway:bus_stop' => array('label'=>'Bus Stop','frequency'=>35777,'icon'=>'transport_bus_stop2',), @@ -627,7 +636,7 @@ else { if (is_bool($xVal)) return $xVal?'true':'false'; - if (is_numeric($xVal)) return $xVal; +// if (is_numeric($xVal)) return $xVal; return '"'.str_replace('>','\\>',str_replace(array("\n","\r"),'\\n',str_replace(array("\n\r","\r\n"),'\\n',str_replace('"','\\"',$xVal)))).'"'; } } @@ -811,3 +820,102 @@ $aSimilar = $oDB->getAll($sSQL); return $aSimilar; } + + function geocodeReverse($fLat, $fLon, $iZoom=18) + { + $oDB =& getDB(); + + $sPointSQL = "ST_SetSRID(ST_Point($fLon,$fLat),4326)"; + + // Zoom to rank, this could probably be calculated but a lookup gives fine control + $aZoomRank = array( + 0 => 2, // Continent / Sea + 1 => 2, + 2 => 2, + 3 => 4, // Country + 4 => 4, + 5 => 8, // State + 6 => 10, // Region + 7 => 10, + 8 => 12, // County + 9 => 12, + 10 => 17, // City + 11 => 17, + 12 => 18, // Town / Village + 13 => 18, + 14 => 22, // Suburb + 15 => 22, + 16 => 26, // Street, TODO: major street? + 17 => 26, + 18 => 30, // or >, Building + 19 => 30, // or >, Building + ); + $iMaxRank = isset($aZoomRank[$iZoom])?$aZoomRank[$iZoom]:28; + + // Find the nearest point + $fSearchDiam = 0.0001; + $iPlaceID = null; + $aArea = false; + $fMaxAreaDistance = 1; + while(!$iPlaceID && $fSearchDiam < $fMaxAreaDistance) + { + $fSearchDiam = $fSearchDiam * 2; + + // If we have to expand the search area by a large amount then we need a larger feature + // then there is a limit to how small the feature should be + if ($fSearchDiam > 2 && $iMaxRank > 4) $iMaxRank = 4; + if ($fSearchDiam > 1 && $iMaxRank > 9) $iMaxRank = 8; + if ($fSearchDiam > 0.8 && $iMaxRank > 10) $iMaxRank = 10; + if ($fSearchDiam > 0.6 && $iMaxRank > 12) $iMaxRank = 12; + if ($fSearchDiam > 0.2 && $iMaxRank > 17) $iMaxRank = 17; + if ($fSearchDiam > 0.1 && $iMaxRank > 18) $iMaxRank = 18; + if ($fSearchDiam > 0.008 && $iMaxRank > 22) $iMaxRank = 22; + if ($fSearchDiam > 0.001 && $iMaxRank > 26) $iMaxRank = 26; + + $sSQL = 'select place_id,parent_place_id from placex'; + $sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, '.$fSearchDiam.')'; + $sSQL .= ' and rank_search != 28 and rank_search >= '.$iMaxRank; + $sSQL .= ' and (name is not null or housenumber is not null)'; + $sSQL .= ' and class not in (\'waterway\')'; + $sSQL .= ' and (ST_GeometryType(geometry) not in (\'ST_Polygon\',\'ST_MultiPolygon\') '; + $sSQL .= ' OR ST_DWithin('.$sPointSQL.', ST_Centroid(geometry), '.$fSearchDiam.'))'; + $sSQL .= ' ORDER BY ST_distance('.$sPointSQL.', geometry) ASC limit 1'; +//var_dump($sSQL); + $aPlace = $oDB->getRow($sSQL); + $iPlaceID = $aPlace['place_id']; + if (PEAR::IsError($iPlaceID)) + { + var_Dump($sSQL, $iPlaceID); + exit; + } + } + + // The point we found might be too small - use the address to find what it is a child of + if ($iPlaceID) + { + $sSQL = "select address_place_id from place_addressline where cached_rank_address <= $iMaxRank and place_id = $iPlaceID order by cached_rank_address desc,isaddress desc,distance desc limit 1"; + $iPlaceID = $oDB->getOne($sSQL); + if (PEAR::IsError($iPlaceID)) + { + var_Dump($sSQL, $iPlaceID); + exit; + } + + if ($iPlaceID && $aPlace['place_id'] && $iMaxRank < 28) + { + $sSQL = "select address_place_id from place_addressline where cached_rank_address <= $iMaxRank and place_id = ".$aPlace['place_id']." order by cached_rank_address desc,isaddress desc,distance desc"; + $iPlaceID = $oDB->getOne($sSQL); + if (PEAR::IsError($iPlaceID)) + { + var_Dump($sSQL, $iPlaceID); + exit; + } + } + if (!$iPlaceID) + { + $iPlaceID = $aPlace['place_id']; + } + } + + return $iPlaceID; + }