<?php
+ function failInternalError($sError, $sSQL = false, $vDumpVar = false)
+ {
+ header('HTTP/1.0 500 Internal Server Error');
+ header('Content-type: text/html; charset=utf-8');
+ echo "<html><body><h1>Internal Server Error</h1>";
+ echo '<p>Nominatim has encountered an internal error while processing your request. This is most likely because of a bug in the software.</p>';
+ echo "<p><b>Details:</b> ".$sError,"</p>";
+ echo '<p>Feel free to report the bug in the <a href="http://trac.openstreetmap.org">OSM bug database</a>. Please include the error message above an the URL you used.</p>';
+ if (CONST_Debug)
+ {
+ echo "<hr><h2>Debugging Information</h2><br>";
+ if ($sSQL) {
+ echo "<h3>SQL query</h3><code>".$sSQL."</code>";
+ }
+ if ($vDumpVar) {
+ echo "<h3>Result</h3> <code>";
+ var_dump($vDumpVar);
+ echo "</code>";
+ }
+ }
+ echo "\n</body></html>\n";
+ exit;
+
+ }
+
function fail($sError, $sUserError = false)
{
if (!$sUserError) $sUserError = $sError;
- log('ERROR:'.$sError);
+ error_log('ERROR: '.$sError);
echo $sUserError."\n";
exit;
}
return sizeof($aMatches[0]);
}
+ function getTotalMemoryMB()
+ {
+ $sCPU = file_get_contents('/proc/meminfo');
+ preg_match('#MemTotal: +([0-9]+) kB#', $sCPU, $aMatches);
+ return (int)($aMatches[1]/1024);
+ }
+
+ function getCacheMemoryMB()
+ {
+ $sCPU = file_get_contents('/proc/meminfo');
+ preg_match('#Cached: +([0-9]+) kB#', $sCPU, $aMatches);
+ return (int)($aMatches[1]/1024);
+ }
+
function bySearchRank($a, $b)
{
if ($a['iSearchRank'] == $b['iSearchRank']) return 0;
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['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);
}
exit;
}
-
if (sizeof($aNearPostcodes))
{
return array(array('lat' => $aNearPostcodes[0]['lat'], 'lon' => $aNearPostcodes[0]['lon'], 'radius' => 0.005));
}
- $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.'\'';
- $aNearPostcodes = $oDB->getAll($sSQL);
- if (PEAR::IsError($aNearPostcodes))
- {
- var_dump($sSQL, $aNearPostcodes);
- exit;
- }
-
- if (!sizeof($aNearPostcodes))
- {
- return false;
- }
-
- $fTotalLat = 0;
- $fTotalLon = 0;
- $fTotalFac = 0;
- foreach($aNearPostcodes as $aPostcode)
- {
- $iDiff = gbPostcodeAlphaDifference($sPostcodeEnd, $aPostcode['substring'])*2 + 1;
- if ($iDiff == 0)
- $fFac = 1;
- else
- $fFac = 1/($iDiff*$iDiff);
-
- $fTotalFac += $fFac;
- $fTotalLat += $aPostcode['lat'] * $fFac;
- $fTotalLon += $aPostcode['lon'] * $fFac;
- }
- if ($fTotalFac)
- {
- $fLat = $fTotalLat / $fTotalFac;
- $fLon = $fTotalLon / $fTotalFac;
- $fRadius = min(0.1 / $fTotalFac, 0.02);
- 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));
- $iZoom = max(13,min(18,$iZoom));
- */
}
function usPostcodeCalculate($sPostcode, &$oDB)
function getClassTypes()
{
return array(
- 'boundary:adminitrative:2' => array('label'=>'Country','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
- 'boundary:adminitrative:4' => array('label'=>'State','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
- 'boundary:adminitrative:5' => array('label'=>'State District','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
- 'boundary:adminitrative:6' => array('label'=>'County','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
- 'boundary:adminitrative:8' => array('label'=>'City','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
- 'boundary:adminitrative:9' => array('label'=>'City District','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
- 'boundary:adminitrative:10' => array('label'=>'Suburb','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
- 'boundary:adminitrative: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,),
+ '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,),
- 'place:region' => array('label'=>'State','frequency'=>0,'icon'=>'poi_boundary_administrative','defzoom'=>8, 'defdiameter' => 5.12,),
- 'place:island' => array('label'=>'Island','frequency'=>288,'icon'=>'','defzoom'=>11, 'defdiameter' => 0.64,),
+ '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:adminitrative' => array('label'=>'Administrative','frequency'=>413,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
+ '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: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,),
+ '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,),
'place:hamlet' => array('label'=>'Hamlet','frequency'=>7075,'icon'=>'poi_place_village','defzoom'=>15, 'defdiameter' => 0.04,),
'place:airport' => array('label'=>'Airport','frequency'=>36,'icon'=>'transport_airport2', 'defdiameter' => 0.03,),
'railway:station' => array('label'=>'Station','frequency'=>3431,'icon'=>'transport_train_station2', 'defdiameter' => 0.01,),
- 'amenity:place_of_worship' => array('label'=>'Place Of Worship','frequency'=>9049,'icon'=>'place_of_worship3',),
+ 'amenity:place_of_worship' => array('label'=>'Place Of Worship','frequency'=>9049,'icon'=>'place_of_worship_unknown3',),
'amenity:pub' => array('label'=>'Pub','frequency'=>18969,'icon'=>'food_pub',),
'amenity:bar' => array('label'=>'Bar','frequency'=>164,'icon'=>'food_bar',),
'amenity:university' => array('label'=>'University','frequency'=>607,'icon'=>'education_university',),
'tourism:motel' => array('label'=>'Motel','frequency'=>43,'icon'=>'',),
'amenity:cinema' => array('label'=>'Cinema','frequency'=>277,'icon'=>'tourist_cinema',),
'tourism:information' => array('label'=>'Information','frequency'=>224,'icon'=>'amenity_information',),
- 'tourism:artwork' => array('label'=>'Artwork','frequency'=>171,'icon'=>'art_gallery2',),
+ 'tourism:artwork' => array('label'=>'Artwork','frequency'=>171,'icon'=>'tourist_art_gallery2',),
'historic:archaeological_site' => array('label'=>'Archaeological Site','frequency'=>407,'icon'=>'tourist_archaeological2',),
'amenity:doctors' => array('label'=>'Doctors','frequency'=>581,'icon'=>'health_doctors',),
'leisure:sports_centre' => array('label'=>'Sports Centre','frequency'=>767,'icon'=>'sport_leisure_centre',),
'amenity:shop' => array('label'=>'Shop','frequency'=>61,'icon'=>'',),
'place:house' => array('label'=>'House','frequency'=>2086,'icon'=>'','defzoom'=>18,),
+ 'place:house_name' => array('label'=>'House','frequency'=>2086,'icon'=>'','defzoom'=>18,),
+ 'place:house_number' => array('label'=>'House Number','frequency'=>2086,'icon'=>'','defzoom'=>18,),
+ 'place:country_code' => array('label'=>'Country Code','frequency'=>2086,'icon'=>'','defzoom'=>18,),
//
'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',),
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)))).'"';
}
}
function _debugDumpGroupedSearches($aData, $aTokens)
{
$aWordsIDs = array();
- foreach($aTokens as $sToken => $aWords)
+ if ($aTokens)
{
- foreach($aWords as $aToken)
+ foreach($aTokens as $sToken => $aWords)
{
- $aWordsIDs[$aToken['word_id']] = $sToken.'('.$aToken['word_id'].')';
+ if ($aWords)
+ {
+ foreach($aWords as $aToken)
+ {
+ $aWordsIDs[$aToken['word_id']] = $sToken.'('.$aToken['word_id'].')';
+ }
+ }
}
}
echo "<table border=\"1\">";
function getAddressDetails(&$oDB, $sLanguagePrefArraySQL, $iPlaceID, $sCountryCode = false, $bRaw = false)
{
- $aHouseNumber = $oDB->getRow('select housenumber, get_name_by_language(name,ARRAY[\'addr:housename\']) as housename,rank_search from placex where place_id = '.$iPlaceID);
+ $sSQL = "select *,get_name_by_language(name,$sLanguagePrefArraySQL) as localname from get_addressdata($iPlaceID)";
+ IF (!$bRaw) $sSQL .= " WHERE isaddress OR type = 'country_code'";
+ $sSQL .= " order by rank_address desc,isaddress desc";
+ $aAddressLines = $oDB->getAll($sSQL);
+ if (PEAR::IsError($aAddressLines))
+ {
+ var_dump($aAddressLines);
+ exit;
+ }
+ if ($bRaw) return $aAddressLines;
+//echo "<pre>";
+//var_dump($aAddressLines);
+ $aAddress = array();
+ $aClassType = getClassTypes();
+ foreach($aAddressLines as $aLine)
+ {
+ $aTypeLabel = false;
+ if (isset($aClassType[$aLine['class'].':'.$aLine['type'].':'.$aLine['admin_level']])) $aTypeLabel = $aClassType[$aLine['class'].':'.$aLine['type'].':'.$aLine['admin_level']];
+ elseif (isset($aClassType[$aLine['class'].':'.$aLine['type']])) $aTypeLabel = $aClassType[$aLine['class'].':'.$aLine['type']];
+ else $aTypeLabel = array('simplelabel'=>$aLine['class']);
+ if ($aTypeLabel && ($aLine['localname'] || $aLine['housenumber']))
+ {
+ $sTypeLabel = strtolower(isset($aTypeLabel['simplelabel'])?$aTypeLabel['simplelabel']:$aTypeLabel['label']);
+ $sTypeLabel = str_replace(' ','_',$sTypeLabel);
+ if (!isset($aAddress[$sTypeLabel]) && $aLine['localname']) $aAddress[$sTypeLabel] = $aLine['localname']?$aLine['localname']:$aLine['housenumber'];
+ }
+ }
+//var_dump($aAddress);
+//exit;
+ return $aAddress;
+
+ $aHouseNumber = $oDB->getRow('select housenumber, get_name_by_language(name,ARRAY[\'addr:housename\']) as housename,rank_search,postcode from placex where place_id = '.$iPlaceID);
$sHouseNumber = $aHouseNumber['housenumber'];
$sHouseName = $aHouseNumber['housename'];
+ $sPostcode = $aHouseNumber['postcode'];
$iRank = $aHouseNumber['rank_search'];
// Address
$sSQL .= " length(name::text) as namelength ";
$sSQL .= " from place_addressline join placex on (address_place_id = placex.place_id)";
$sSQL .= " where place_addressline.place_id = $iPlaceID and (rank_address > 0 OR address_place_id = $iPlaceID)";
- $sSQL .= " order by cached_rank_address desc,isaddress desc,fromarea desc,distance asc,rank_search desc,namelength
-desc";
+ if (!$bRaw) $sSQL .= " and isaddress";
+ $sSQL .= " order by cached_rank_address desc,isaddress desc,fromarea desc,distance asc,rank_search desc,namelength desc";
//var_dump($sSQL);
$aAddressLines = $oDB->getAll($sSQL);
if (PEAR::IsError($aAddressLines))
if ($aTypeLabel && ($aLine['localname'] || $aLine['housenumber']))
{
$sTypeLabel = strtolower(isset($aTypeLabel['simplelabel'])?$aTypeLabel['simplelabel']:$aTypeLabel['label']);
+ $sTypeLabel = str_replace(' ','_',$sTypeLabel);
if (!isset($aAddress[$sTypeLabel]) && $aLine['localname']) $aAddress[$sTypeLabel] = $aLine['localname']?$aLine['localname']:$aLine['housenumber'];
}
$iMinRank = $aLine['rank_address'];
}
}
+
+ if ($sPostcode)
+ {
+ $aAddress['postcode'] = $sPostcode;
+ }
+
if ($iMinRank > 4 && $sCountryCode)
{
$sSQL = "select get_name_by_language(country_name.name,$sLanguagePrefArraySQL) as name";
$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;
+ }