- * reverse geocoding looking includes looking up Tiger data
+2.5
+ * reverse geocoding includes looking up housenumbers from Tiger data
+ * added parameter to return simplified geometries
+ * new lookup call for getting address information for OSM objects
+ * new namedetails and extratags parameters that expose the name and extratags
+ fields of the placex table
+ * mobile website
+ * reverse web view
2.4
1. Start the virtual machine
- vagrant up
+ vagrant up ubuntu
2. Log into the virtual machine
- vagrant ssh
+ vagrant ssh ubuntu
3. Import a small country (Monaco)
To repeat an import you'd need to delete the database first
- dropdb --username postgres -if-exists nominatim
+ dropdb -if-exists nominatim
Also this document skips the optional Wikipedia data import which affects ranking
of search results. See [Nominatim installation](http://wiki.openstreetmap.org/wiki/Nominatim/Installation) for details.
-##### Why Ubuntu, can I test CentOS/CoreOS/FreeBSD?
+##### Why Ubuntu and CentOS, can I test CentOS/CoreOS/FreeBSD?
-In general Nominatim will run in all these environment. The installation steps
+There is a Vagrant script for CentOS available. Simply start your box
+with `vagrant up centos` and then log in with `vagrant ssh centos`.
+In general Nominatim will also run in the other environments. The installation steps
are slightly different, e.g. the name of the package manager, Apache2 package
name, location of files. We chose Ubuntu because that is closest to the
nominatim.openstreetmap.org production environment.
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
-
- # Ubuntu LTS 14.04
- config.vm.box = "ubuntu/trusty64"
-
# Apache webserver
config.vm.network "forwarded_port", guest: 8089, host: 8089
-
# If true, then any SSH connections made will enable agent forwarding.
config.ssh.forward_agent = true
config.vm.synced_folder ".", "/home/vagrant/Nominatim"
-
-
- # provision using a simple shell script
- config.vm.provision :shell, :path => "vagrant-provision.sh"
-
+ config.vm.define "ubuntu" do |sub|
+ sub.vm.box = "ubuntu/trusty64"
+ sub.vm.provision :shell, :path => "vagrant/ubuntu-trusty-provision.sh"
+ end
+ config.vm.define "centos" do |sub|
+ sub.vm.box = "bento/centos-7.2"
+ sub.vm.provision :shell, :path => "vagrant/centos-7-provision.sh"
+ end
# configure shared package cache if possible
- if Vagrant.has_plugin?("vagrant-cachier")
- config.cache.enable :apt
- config.cache.scope = :box
- end
+ #if Vagrant.has_plugin?("vagrant-cachier")
+ # config.cache.enable :apt
+ # config.cache.scope = :box
+ #end
config.vm.provider "virtualbox" do |vb|
<?php
+ require_once(CONST_BasePath.'/lib/PlaceLookup.php');
+
class Geocode
{
protected $oDB;
function getGroupedSearches($aSearches, $aPhraseTypes, $aPhrases, $aValidTokens, $aWordFrequencyScores, $bStructuredPhrases)
{
/*
- Calculate all searches using aValidTokens i.e.
- 'Wodsworth Road, Sheffield' =>
+ Calculate all searches using aValidTokens i.e.
+ 'Wodsworth Road, Sheffield' =>
- Phrase Wordset
- 0 0 (wodsworth road)
- 0 1 (wodsworth)(road)
- 1 0 (sheffield)
+ Phrase Wordset
+ 0 0 (wodsworth road)
+ 0 1 (wodsworth)(road)
+ 1 0 (sheffield)
- Score how good the search is so they can be ordered
+ Score how good the search is so they can be ordered
*/
foreach($aPhrases as $iPhrase => $sPhrase)
{
/* Perform the actual query lookup.
Returns an ordered list of results, each with the following fields:
- osm_type: type of corresponding OSM object
+ osm_type: type of corresponding OSM object
N - node
W - way
R - relation
P - postcode (internally computed)
- osm_id: id of corresponding OSM object
- class: general object class (corresponds to tag key of primary OSM tag)
- type: subclass of object (corresponds to tag value of primary OSM tag)
- admin_level: see http://wiki.openstreetmap.org/wiki/Admin_level
- rank_search: rank in search hierarchy
+ osm_id: id of corresponding OSM object
+ class: general object class (corresponds to tag key of primary OSM tag)
+ type: subclass of object (corresponds to tag value of primary OSM tag)
+ admin_level: see http://wiki.openstreetmap.org/wiki/Admin_level
+ rank_search: rank in search hierarchy
(see also http://wiki.openstreetmap.org/wiki/Nominatim/Development_overview#Country_to_street_level)
- rank_address: rank in address hierarchy (determines orer in address)
- place_id: internal key (may differ between different instances)
- country_code: ISO country code
- langaddress: localized full address
- placename: localized name of object
- ref: content of ref tag (if available)
- lon: longitude
- lat: latitude
- importance: importance of place based on Wikipedia link count
- addressimportance: cumulated importance of address elements
- extra_place: type of place (for admin boundaries, if there is a place tag)
- aBoundingBox: bounding Box
- label: short description of the object class/type (English only)
- name: full name (currently the same as langaddress)
- foundorder: secondary ordering for places with same importance
+ rank_address: rank in address hierarchy (determines orer in address)
+ place_id: internal key (may differ between different instances)
+ country_code: ISO country code
+ langaddress: localized full address
+ placename: localized name of object
+ ref: content of ref tag (if available)
+ lon: longitude
+ lat: latitude
+ importance: importance of place based on Wikipedia link count
+ addressimportance: cumulated importance of address elements
+ extra_place: type of place (for admin boundaries, if there is a place tag)
+ aBoundingBox: bounding Box
+ label: short description of the object class/type (English only)
+ name: full name (currently the same as langaddress)
+ foundorder: secondary ordering for places with same importance
*/
function lookup()
{
{
// Start with a blank search
$aSearches = array(
- array('iSearchRank' => 0, 'iNamePhrase' => -1, 'sCountryCode' => false, 'aName'=>array(), 'aAddress'=>array(), 'aFullNameAddress'=>array(),
- 'aNameNonSearch'=>array(), 'aAddressNonSearch'=>array(),
- 'sOperator'=>'', 'aFeatureName' => array(), 'sClass'=>'', 'sType'=>'', 'sHouseNumber'=>'', 'fLat'=>'', 'fLon'=>'', 'fRadius'=>'')
+ array('iSearchRank' => 0,
+ 'iNamePhrase' => -1,
+ 'sCountryCode' => false,
+ 'aName' => array(),
+ 'aAddress' => array(),
+ 'aFullNameAddress' => array(),
+ 'aNameNonSearch' => array(),
+ 'aAddressNonSearch' => array(),
+ 'sOperator' => '',
+ 'aFeatureName' => array(),
+ 'sClass' => '',
+ 'sType' => '',
+ 'sHouseNumber' => '',
+ 'fLat' => '',
+ 'fLon' => '',
+ 'fRadius' => ''
+ )
);
// Do we have a radius search?
{
$sSQL = "select place_id from placex where calculated_country_code='".$aSearch['sCountryCode']."' and rank_search = 4";
if ($sCountryCodesSQL) $sSQL .= " and calculated_country_code in ($sCountryCodesSQL)";
- if ($bBoundingBoxSearch)
- $sSQL .= " and _st_intersects($this->sViewboxSmallSQL, geometry)";
+ if ($bBoundingBoxSearch)
+ $sSQL .= " and _st_intersects($this->sViewboxSmallSQL, geometry)";
$sSQL .= " order by st_area(geometry) desc limit 1";
if (CONST_Debug) var_dump($sSQL);
$aPlaceIDs = $this->oDB->getCol($sSQL);
if (!preg_match('/\pL/', $sWord)) unset($aRecheckWords[$i]);
}
- if (CONST_Debug) { echo '<i>Recheck words:<\i>'; var_dump($aRecheckWords); }
+ if (CONST_Debug) { echo '<i>Recheck words:<\i>'; var_dump($aRecheckWords); }
foreach($aSearchResults as $iResNum => $aResult)
{
// Default
- $fDiameter = 0.0001;
-
- if (isset($aClassType[$aResult['class'].':'.$aResult['type'].':'.$aResult['admin_level']]['defdiameter'])
- && $aClassType[$aResult['class'].':'.$aResult['type'].':'.$aResult['admin_level']]['defdiameter'])
- {
- $fDiameter = $aClassType[$aResult['class'].':'.$aResult['type'].':'.$aResult['admin_level']]['defdiameter'];
- }
- elseif (isset($aClassType[$aResult['class'].':'.$aResult['type']]['defdiameter'])
- && $aClassType[$aResult['class'].':'.$aResult['type']]['defdiameter'])
- {
- $fDiameter = $aClassType[$aResult['class'].':'.$aResult['type']]['defdiameter'];
- }
- $fRadius = $fDiameter / 2;
-
- if (CONST_Search_AreaPolygons)
- {
- // Get the bounding box and outline polygon
- $sSQL = "select place_id,0 as numfeatures,st_area(geometry) as area,";
- $sSQL .= "ST_Y(centroid) as centrelat,ST_X(centroid) as centrelon,";
- $sSQL .= "ST_YMin(geometry) as minlat,ST_YMax(geometry) as maxlat,";
- $sSQL .= "ST_XMin(geometry) as minlon,ST_XMax(geometry) as maxlon";
- if ($this->bIncludePolygonAsGeoJSON) $sSQL .= ",ST_AsGeoJSON(geometry) as asgeojson";
- if ($this->bIncludePolygonAsKML) $sSQL .= ",ST_AsKML(geometry) as askml";
- if ($this->bIncludePolygonAsSVG) $sSQL .= ",ST_AsSVG(geometry) as assvg";
- if ($this->bIncludePolygonAsText || $this->bIncludePolygonAsPoints) $sSQL .= ",ST_AsText(geometry) as astext";
- $sFrom = " from placex where place_id = ".$aResult['place_id'];
- if ($this->fPolygonSimplificationThreshold > 0)
- {
- $sSQL .= " from (select place_id,centroid,ST_SimplifyPreserveTopology(geometry,".$this->fPolygonSimplificationThreshold.") as geometry".$sFrom.") as plx";
- }
- else
- {
- $sSQL .= $sFrom;
- }
+ $fDiameter = getResultDiameter($aResult);
- $aPointPolygon = $this->oDB->getRow($sSQL);
- if (PEAR::IsError($aPointPolygon))
- {
- failInternalError("Could not get outline.", $sSQL, $aPointPolygon);
- }
+ $oPlaceLookup = new PlaceLookup($this->oDB);
+ $oPlaceLookup->setIncludePolygonAsPoints($this->bIncludePolygonAsPoints);
+ $oPlaceLookup->setIncludePolygonAsText($this->bIncludePolygonAsText);
+ $oPlaceLookup->setIncludePolygonAsGeoJSON($this->bIncludePolygonAsGeoJSON);
+ $oPlaceLookup->setIncludePolygonAsKML($this->bIncludePolygonAsKML);
+ $oPlaceLookup->setIncludePolygonAsSVG($this->bIncludePolygonAsSVG);
+ $oPlaceLookup->setPolygonSimplificationThreshold($this->fPolygonSimplificationThreshold);
- if ($aPointPolygon['place_id'])
- {
- if ($this->bIncludePolygonAsGeoJSON) $aResult['asgeojson'] = $aPointPolygon['asgeojson'];
- if ($this->bIncludePolygonAsKML) $aResult['askml'] = $aPointPolygon['askml'];
- if ($this->bIncludePolygonAsSVG) $aResult['assvg'] = $aPointPolygon['assvg'];
- if ($this->bIncludePolygonAsText) $aResult['astext'] = $aPointPolygon['astext'];
-
- if ($aPointPolygon['centrelon'] !== null && $aPointPolygon['centrelat'] !== null )
- {
- $aResult['lat'] = $aPointPolygon['centrelat'];
- $aResult['lon'] = $aPointPolygon['centrelon'];
- }
-
- if ($this->bIncludePolygonAsPoints)
- {
- // Translate geometry string to point array
- if (preg_match('#POLYGON\\(\\(([- 0-9.,]+)#',$aPointPolygon['astext'],$aMatch))
- {
- preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/',$aMatch[1],$aPolyPoints,PREG_SET_ORDER);
- }
- /*
- elseif (preg_match('#MULTIPOLYGON\\(\\(\\(([- 0-9.,]+)#',$aPointPolygon['astext'],$aMatch))
- {
- preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/',$aMatch[1],$aPolyPoints,PREG_SET_ORDER);
- }
- */
- elseif (preg_match('#POINT\\((-?[0-9.]+) (-?[0-9.]+)\\)#',$aPointPolygon['astext'],$aMatch))
- {
- $iSteps = max(8, min(100, ($fRadius * 40000)^2));
- $fStepSize = (2*pi())/$iSteps;
- $aPolyPoints = array();
- for($f = 0; $f < 2*pi(); $f += $fStepSize)
- {
- $aPolyPoints[] = array('',$aMatch[1]+($fRadius*sin($f)),$aMatch[2]+($fRadius*cos($f)));
- }
- }
- }
-
- // Output data suitable for display (points and a bounding box)
- if ($this->bIncludePolygonAsPoints && isset($aPolyPoints))
- {
- $aResult['aPolyPoints'] = array();
- foreach($aPolyPoints as $aPoint)
- {
- $aResult['aPolyPoints'][] = array($aPoint[1], $aPoint[2]);
- }
- }
-
- if (abs($aPointPolygon['minlat'] - $aPointPolygon['maxlat']) < 0.0000001)
- {
- $aPointPolygon['minlat'] = $aPointPolygon['minlat'] - $fRadius;
- $aPointPolygon['maxlat'] = $aPointPolygon['maxlat'] + $fRadius;
- }
- if (abs($aPointPolygon['minlon'] - $aPointPolygon['maxlon']) < 0.0000001)
- {
- $aPointPolygon['minlon'] = $aPointPolygon['minlon'] - $fRadius;
- $aPointPolygon['maxlon'] = $aPointPolygon['maxlon'] + $fRadius;
- }
- $aResult['aBoundingBox'] = array((string)$aPointPolygon['minlat'],(string)$aPointPolygon['maxlat'],(string)$aPointPolygon['minlon'],(string)$aPointPolygon['maxlon']);
- }
- }
+ $aOutlineResult = $oPlaceLookup->getOutlines($aResult['place_id'], $aResult['lon'], $aResult['lat'], $fDiameter/2);
+ $aResult = array_merge($aResult, $aOutlineResult);
if ($aResult['extra_place'] == 'city')
{
$aResult['rank_search'] = 16;
}
- if (!isset($aResult['aBoundingBox']))
- {
- $iSteps = max(8,min(100,$fRadius * 3.14 * 100000));
- $fStepSize = (2*pi())/$iSteps;
- $aPointPolygon['minlat'] = $aResult['lat'] - $fRadius;
- $aPointPolygon['maxlat'] = $aResult['lat'] + $fRadius;
- $aPointPolygon['minlon'] = $aResult['lon'] - $fRadius;
- $aPointPolygon['maxlon'] = $aResult['lon'] + $fRadius;
-
- // Output data suitable for display (points and a bounding box)
- if ($this->bIncludePolygonAsPoints)
- {
- $aPolyPoints = array();
- for($f = 0; $f < 2*pi(); $f += $fStepSize)
- {
- $aPolyPoints[] = array('',$aResult['lon']+($fRadius*sin($f)),$aResult['lat']+($fRadius*cos($f)));
- }
- $aResult['aPolyPoints'] = array();
- foreach($aPolyPoints as $aPoint)
- {
- $aResult['aPolyPoints'][] = array($aPoint[1], $aPoint[2]);
- }
- }
- $aResult['aBoundingBox'] = array((string)$aPointPolygon['minlat'],(string)$aPointPolygon['maxlat'],(string)$aPointPolygon['minlon'],(string)$aPointPolygon['maxlon']);
- }
-
// Is there an icon set for this type of result?
if (isset($aClassType[$aResult['class'].':'.$aResult['type']]['icon'])
&& $aClassType[$aResult['class'].':'.$aResult['type']]['icon'])
protected $bNameDetails = false;
+ protected $bIncludePolygonAsPoints = false;
+ protected $bIncludePolygonAsText = false;
+ protected $bIncludePolygonAsGeoJSON = false;
+ protected $bIncludePolygonAsKML = false;
+ protected $bIncludePolygonAsSVG = false;
+ protected $fPolygonSimplificationThreshold = 0.0;
+
+
function PlaceLookup(&$oDB)
{
$this->oDB =& $oDB;
}
}
+
+ function setIncludePolygonAsPoints($b = true)
+ {
+ $this->bIncludePolygonAsPoints = $b;
+ }
+
+ function getIncludePolygonAsPoints()
+ {
+ return $this->bIncludePolygonAsPoints;
+ }
+
+ function setIncludePolygonAsText($b = true)
+ {
+ $this->bIncludePolygonAsText = $b;
+ }
+
+ function getIncludePolygonAsText()
+ {
+ return $this->bIncludePolygonAsText;
+ }
+
+ function setIncludePolygonAsGeoJSON($b = true)
+ {
+ $this->bIncludePolygonAsGeoJSON = $b;
+ }
+
+ function setIncludePolygonAsKML($b = true)
+ {
+ $this->bIncludePolygonAsKML = $b;
+ }
+
+ function setIncludePolygonAsSVG($b = true)
+ {
+ $this->bIncludePolygonAsSVG = $b;
+ }
+
+ function setPolygonSimplificationThreshold($f)
+ {
+ $this->fPolygonSimplificationThreshold = $f;
+ }
+
+
function setPlaceID($iPlaceID)
{
$this->iPlaceID = $iPlaceID;
return $aAddress;
}
+
+
+ // returns an array which will contain the keys
+ // aBoundingBox
+ // and may also contain one or more of the keys
+ // asgeojson
+ // askml
+ // assvg
+ // astext
+ // lat
+ // lon
+ function getOutlines($iPlaceID, $fLon=null, $fLat=null, $fRadius=null)
+ {
+
+ $aOutlineResult = array();
+ if (!$iPlaceID) return $aOutlineResult;
+
+ if (CONST_Search_AreaPolygons)
+ {
+ // Get the bounding box and outline polygon
+ $sSQL = "select place_id,0 as numfeatures,st_area(geometry) as area,";
+ $sSQL .= "ST_Y(centroid) as centrelat,ST_X(centroid) as centrelon,";
+ $sSQL .= "ST_YMin(geometry) as minlat,ST_YMax(geometry) as maxlat,";
+ $sSQL .= "ST_XMin(geometry) as minlon,ST_XMax(geometry) as maxlon";
+ if ($this->bIncludePolygonAsGeoJSON) $sSQL .= ",ST_AsGeoJSON(geometry) as asgeojson";
+ if ($this->bIncludePolygonAsKML) $sSQL .= ",ST_AsKML(geometry) as askml";
+ if ($this->bIncludePolygonAsSVG) $sSQL .= ",ST_AsSVG(geometry) as assvg";
+ if ($this->bIncludePolygonAsText || $this->bIncludePolygonAsPoints) $sSQL .= ",ST_AsText(geometry) as astext";
+ $sFrom = " from placex where place_id = ".$iPlaceID;
+ if ($this->fPolygonSimplificationThreshold > 0)
+ {
+ $sSQL .= " from (select place_id,centroid,ST_SimplifyPreserveTopology(geometry,".$this->fPolygonSimplificationThreshold.") as geometry".$sFrom.") as plx";
+ }
+ else
+ {
+ $sSQL .= $sFrom;
+ }
+
+ $aPointPolygon = $this->oDB->getRow($sSQL);
+ if (PEAR::IsError($aPointPolygon))
+ {
+ echo var_dump($aPointPolygon);
+ failInternalError("Could not get outline.", $sSQL, $aPointPolygon);
+ }
+
+ if ($aPointPolygon['place_id'])
+ {
+ if ($aPointPolygon['centrelon'] !== null && $aPointPolygon['centrelat'] !== null )
+ {
+ $aOutlineResult['lat'] = $aPointPolygon['centrelat'];
+ $aOutlineResult['lon'] = $aPointPolygon['centrelon'];
+ }
+
+ if ($this->bIncludePolygonAsGeoJSON) $aOutlineResult['asgeojson'] = $aPointPolygon['asgeojson'];
+ if ($this->bIncludePolygonAsKML) $aOutlineResult['askml'] = $aPointPolygon['askml'];
+ if ($this->bIncludePolygonAsSVG) $aOutlineResult['assvg'] = $aPointPolygon['assvg'];
+ if ($this->bIncludePolygonAsText) $aOutlineResult['astext'] = $aPointPolygon['astext'];
+ if ($this->bIncludePolygonAsPoints) $aOutlineResult['aPolyPoints'] = geometryText2Points($aPointPolygon['astext'], $fRadius);
+
+
+ if (abs($aPointPolygon['minlat'] - $aPointPolygon['maxlat']) < 0.0000001)
+ {
+ $aPointPolygon['minlat'] = $aPointPolygon['minlat'] - $fRadius;
+ $aPointPolygon['maxlat'] = $aPointPolygon['maxlat'] + $fRadius;
+ }
+ if (abs($aPointPolygon['minlon'] - $aPointPolygon['maxlon']) < 0.0000001)
+ {
+ $aPointPolygon['minlon'] = $aPointPolygon['minlon'] - $fRadius;
+ $aPointPolygon['maxlon'] = $aPointPolygon['maxlon'] + $fRadius;
+ }
+
+ $aOutlineResult['aBoundingBox'] = array(
+ (string)$aPointPolygon['minlat'],
+ (string)$aPointPolygon['maxlat'],
+ (string)$aPointPolygon['minlon'],
+ (string)$aPointPolygon['maxlon']
+ );
+ }
+ } // CONST_Search_AreaPolygons
+
+ // as a fallback we generate a bounding box without knowing the size of the geometry
+ if ( (!isset($aOutlineResult['aBoundingBox'])) && isset($fLon) )
+ {
+
+ if ($this->bIncludePolygonAsPoints)
+ {
+ $sGeometryText = 'POINT('.$fLon.','.$fLat.')';
+ $aOutlineResult['aPolyPoints'] = geometryText2Points($sGeometryText, $fRadius);
+ }
+
+ $aBounds = array();
+ $aBounds['minlat'] = $fLat - $fRadius;
+ $aBounds['maxlat'] = $fLat + $fRadius;
+ $aBounds['minlon'] = $fLon - $fRadius;
+ $aBounds['maxlon'] = $fLon + $fRadius;
+
+ $aOutlineResult['aBoundingBox'] = array(
+ (string)$aBounds['minlat'],
+ (string)$aBounds['maxlat'],
+ (string)$aBounds['minlon'],
+ (string)$aBounds['maxlon']
+ );
+ }
+ return $aOutlineResult;
+ }
}
?>
protected $aLangPrefOrder = array();
+ protected $bIncludePolygonAsPoints = false;
+ protected $bIncludePolygonAsText = false;
+ protected $bIncludePolygonAsGeoJSON = false;
+ protected $bIncludePolygonAsKML = false;
+ protected $bIncludePolygonAsSVG = false;
+ protected $fPolygonSimplificationThreshold = 0.0;
+
+
function ReverseGeocode(&$oDB)
{
$this->oDB =& $oDB;
$this->iMaxRank = (isset($iZoom) && isset($aZoomRank[$iZoom]))?$aZoomRank[$iZoom]:28;
}
+ function setIncludePolygonAsPoints($b = true)
+ {
+ $this->bIncludePolygonAsPoints = $b;
+ }
+
+ function getIncludePolygonAsPoints()
+ {
+ return $this->bIncludePolygonAsPoints;
+ }
+
+ function setIncludePolygonAsText($b = true)
+ {
+ $this->bIncludePolygonAsText = $b;
+ }
+
+ function getIncludePolygonAsText()
+ {
+ return $this->bIncludePolygonAsText;
+ }
+
+ function setIncludePolygonAsGeoJSON($b = true)
+ {
+ $this->bIncludePolygonAsGeoJSON = $b;
+ }
+
+ function setIncludePolygonAsKML($b = true)
+ {
+ $this->bIncludePolygonAsKML = $b;
+ }
+
+ function setIncludePolygonAsSVG($b = true)
+ {
+ $this->bIncludePolygonAsSVG = $b;
+ }
+
+ function setPolygonSimplificationThreshold($f)
+ {
+ $this->fPolygonSimplificationThreshold = $f;
+ }
+
+ // returns { place_id =>, type => '(osm|tiger)' }
+ // fails if no place was found
function lookup()
{
$sPointSQL = 'ST_SetSRID(ST_Point('.$this->fLon.','.$this->fLat.'),4326)';
if ($fSearchDiam > 0.008 && $iMaxRank > 22) $iMaxRank = 22;
if ($fSearchDiam > 0.001 && $iMaxRank > 26) $iMaxRank = 26;
- $sSQL = 'select place_id,parent_place_id,rank_search,calculated_country_code from placex';
+ $sSQL = 'select place_id,parent_place_id,rank_search,calculated_country_code';
+ $sSQL .= ' 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)';
{
$iPlaceID = $iParentPlaceID;
}
- $sSQL = "select address_place_id from place_addressline where place_id = $iPlaceID order by abs(cached_rank_address - $iMaxRank) asc,cached_rank_address desc,isaddress desc,distance desc limit 1";
+ $sSQL = 'select address_place_id';
+ $sSQL .= ' FROM place_addressline';
+ $sSQL .= " WHERE place_id = $iPlaceID";
+ $sSQL .= " ORDER BY abs(cached_rank_address - $iMaxRank) asc,cached_rank_address desc,isaddress desc,distance desc";
+ $sSQL .= ' LIMIT 1';
$iPlaceID = $this->oDB->getOne($sSQL);
if (PEAR::IsError($iPlaceID))
{
}
return array('place_id' => $iPlaceID,
- 'type' => $bPlaceIsTiger ? 'tiger' : 'osm');
+ 'type' => $bPlaceIsTiger ? 'tiger' : 'osm');
}
+
}
?>
}
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') exit;
- header('Content-type: text/html; charset=utf-8');
+ header('Content-type: text/html; charset=utf-8');
if (!CONST_ConnectionBucket_MemcacheServerAddress) return null;
if (!isset($m))
{
- $m = new Memcached();
- $m->addServer(CONST_ConnectionBucket_MemcacheServerAddress, CONST_ConnectionBucket_MemcacheServerPort);
+ $m = new Memcached();
+ $m->addServer(CONST_ConnectionBucket_MemcacheServerAddress, CONST_ConnectionBucket_MemcacheServerPort);
}
return $m;
}
function doBucket($asKey, $iRequestCost, $iLeakPerSecond, $iThreshold)
{
- $m = getBucketMemcache();
+ $m = getBucketMemcache();
if (!$m) return 0;
$iMaxVal = 0;
- $t = time();
+ $t = time();
foreach($asKey as $sKey)
{
- $aCurrentBlock = $m->get($sKey);
- if (!$aCurrentBlock)
+ $aCurrentBlock = $m->get($sKey);
+ if (!$aCurrentBlock)
{
- $aCurrentBlock = array($iRequestCost, $t, false);
- }
+ $aCurrentBlock = array($iRequestCost, $t, false);
+ }
else
{
// add RequestCost
// remove leak * the time since the last request
- $aCurrentBlock[0] += $iRequestCost - ($t - $aCurrentBlock[1])*$iLeakPerSecond;
- $aCurrentBlock[1] = $t;
+ $aCurrentBlock[0] += $iRequestCost - ($t - $aCurrentBlock[1])*$iLeakPerSecond;
+ $aCurrentBlock[1] = $t;
}
- if ($aCurrentBlock[0] <= 0)
+ if ($aCurrentBlock[0] <= 0)
{
- $m->delete($sKey);
- }
+ $m->delete($sKey);
+ }
else
{
// If we have hit the threshold stop and record this to the block list
}
}
// Only keep in memcache until the time it would have expired (to avoid clutering memcache)
- $m->set($sKey, $aCurrentBlock, $t + 1 + $aCurrentBlock[0]/$iLeakPerSecond);
+ $m->set($sKey, $aCurrentBlock, $t + 1 + $aCurrentBlock[0]/$iLeakPerSecond);
}
// Bucket result in the largest bucket we find
}
return $iMaxVal;
- }
+ }
function isBucketSleeping($asKey)
{
- $m = getBucketMemcache();
+ $m = getBucketMemcache();
if (!$m) return false;
foreach($asKey as $sKey)
{
- $aCurrentBlock = $m->get($sKey);
+ $aCurrentBlock = $m->get($sKey);
if ($aCurrentBlock[2]) return true;
}
return false;
function setBucketSleeping($asKey, $bVal)
{
- $m = getBucketMemcache();
+ $m = getBucketMemcache();
if (!$m) return false;
$iMaxVal = 0;
- $t = time();
+ $t = time();
foreach($asKey as $sKey)
{
- $aCurrentBlock = $m->get($sKey);
+ $aCurrentBlock = $m->get($sKey);
$aCurrentBlock[2] = $bVal;
$m->set($sKey, $aCurrentBlock, $t + 1 + $aCurrentBlock[0]/CONST_ConnectionBucket_LeakRate);
}
function getBucketBlocks()
{
- $m = getBucketMemcache();
+ $m = getBucketMemcache();
if (!$m) return null;
- $t = time();
+ $t = time();
$aBlockedList = $m->get('blockedList', null, $hCasToken);
if (!$aBlockedList) $aBlockedList = array();
foreach($aBlockedList as $sKey => $aDetails)
function clearBucketBlocks()
{
- $m = getBucketMemcache();
+ $m = getBucketMemcache();
if (!$m) return false;
$m->delete('blockedList');
return true;
function bySearchRank($a, $b)
{
if ($a['iSearchRank'] == $b['iSearchRank'])
- return strlen($a['sOperator']) + strlen($a['sHouseNumber']) - strlen($b['sOperator']) - strlen($b['sHouseNumber']);
+ return strlen($a['sOperator']) + strlen($a['sHouseNumber']) - strlen($b['sOperator']) - strlen($b['sHouseNumber']);
return ($a['iSearchRank'] < $b['iSearchRank']?-1:1);
}
return $aOrders;
}
+ function getResultDiameter($aResult)
+ {
+ $aClassType = getClassTypes();
+
+ $fDiameter = 0.0001;
+
+ if (isset($aResult['class'])
+ && isset($aResult['type'])
+ && isset($aResult['admin_level'])
+ && isset($aClassType[$aResult['class'].':'.$aResult['type'].':'.$aResult['admin_level']]['defdiameter'])
+ && $aClassType[$aResult['class'].':'.$aResult['type'].':'.$aResult['admin_level']]['defdiameter'])
+ {
+ $fDiameter = $aClassType[$aResult['class'].':'.$aResult['type'].':'.$aResult['admin_level']]['defdiameter'];
+ }
+ elseif (isset($aResult['class'])
+ && isset($aResult['type'])
+ && isset($aClassType[$aResult['class'].':'.$aResult['type']]['defdiameter'])
+ && $aClassType[$aResult['class'].':'.$aResult['type']]['defdiameter'])
+ {
+ $fDiameter = $aClassType[$aResult['class'].':'.$aResult['type']]['defdiameter'];
+ }
+
+ return $fDiameter;
+ }
+
function javascript_renderData($xVal, $iOptions = 0)
{
return array('lat' => $fQueryLat, 'lon' => $fQueryLon, 'query' => $sQuery);
}
+
+
+ function geometryText2Points($geometry_as_text, $fRadius)
+ {
+ $aPolyPoints = NULL;
+ if (preg_match('#POLYGON\\(\\(([- 0-9.,]+)#', $geometry_as_text, $aMatch))
+ {
+ preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/', $aMatch[1], $aPolyPoints, PREG_SET_ORDER);
+ }
+ elseif (preg_match('#LINESTRING\\(([- 0-9.,]+)#', $geometry_as_text, $aMatch))
+ {
+ preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/', $aMatch[1], $aPolyPoints, PREG_SET_ORDER);
+ }
+/* elseif (preg_match('#MULTIPOLYGON\\(\\(\\(([- 0-9.,]+)#', $geometry_as_text, $aMatch))
+ {
+ preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/', $aMatch[1], $aPolyPoints, PREG_SET_ORDER);
+ }*/
+ elseif (preg_match('#POINT\\((-?[0-9.]+) (-?[0-9.]+)\\)#', $geometry_as_text, $aMatch))
+ {
+ $aPolyPoints = createPointsAroundCenter($aMatch[1], $aMatch[2], $fRadius);
+ }
+
+ if (isset($aPolyPoints))
+ {
+ $aResultPoints = array();
+ foreach($aPolyPoints as $aPoint)
+ {
+ $aResultPoints[] = array($aPoint[1], $aPoint[2]);
+ }
+ return $aResultPoints;
+ }
+
+ return;
+ }
+
+ function createPointsAroundCenter($fLon, $fLat, $fRadius)
+ {
+ $iSteps = max(8, min(100, ($fRadius * 40000)^2));
+ $fStepSize = (2*pi())/$iSteps;
+ $aPolyPoints = array();
+ for($f = 0; $f < 2*pi(); $f += $fStepSize)
+ {
+ $aPolyPoints[] = array('', $fLon+($fRadius*sin($f)), $fLat+($fRadius*cos($f)) );
+ }
+ return $aPolyPoints;
+ }
<?php
- header("content-type: text/html; charset=UTF-8");
+ header("content-type: text/html; charset=UTF-8");
?>
<?php include(CONST_BasePath.'/lib/template/includes/html-header.php'); ?>
- <link href="css/common.css" rel="stylesheet" type="text/css" />
- <link href="css/search.css" rel="stylesheet" type="text/css" />
+ <link href="css/common.css" rel="stylesheet" type="text/css" />
+ <link href="css/search.css" rel="stylesheet" type="text/css" />
</head>
<body id="reverse-page">
- <?php include(CONST_BasePath.'/lib/template/includes/html-top-navigation.php'); ?>
-
- <form class="form-inline" role="search" accept-charset="UTF-8" action="<?php echo CONST_Website_BaseURL; ?>reverse.php">
- <div class="form-group">
- <input name="format" type="hidden" value="html">
- <input name="lat" type="text" class="form-control input-sm" placeholder="latitude" value="<?php echo htmlspecialchars($_GET['lat']); ?>" >
- <input name="lon" type="text" class="form-control input-sm" placeholder="longitude" value="<?php echo htmlspecialchars($_GET['lon']); ?>" >
- max zoom
-
- <select name="zoom" class="form-control input-sm" value="<?php echo htmlspecialchars($_GET['zoom']); ?>">
- <option value="" <?php echo $_GET['zoom']==''?'selected':'' ?> >--</option>
- <?php
-
- $aZoomLevels = array(
- 0 => "Continent / Sea",
- 1 => "",
- 2 => "",
- 3 => "Country",
- 4 => "",
- 5 => "State",
- 6 => "Region",
- 7 => "",
- 8 => "County",
- 9 => "",
- 10 => "City",
- 11 => "",
- 12 => "Town / Village",
- 13 => "",
- 14 => "Suburb",
- 15 => "",
- 16 => "Street",
- 17 => "",
- 18 => "Building",
- 19 => "",
- 20 => "",
- 21 => "",
- );
-
- foreach($aZoomLevels as $iZoomLevel => $sLabel)
- {
- $bSel = isset($_GET['zoom']) && ($_GET['zoom'] == (string)$iZoomLevel);
- echo '<option value="'.$iZoomLevel.'"'.($bSel?'selected':'').'>'.$iZoomLevel.' '.$sLabel.'</option>'."\n";
- }
- ?>
- </select>
- </div>
- <div class="form-group search-button-group">
- <button type="submit" class="btn btn-primary btn-sm">Search</button>
- </div>
- <div class="search-type-link">
- <a href="<?php echo CONST_Website_BaseURL; ?>search.php">forward search</a>
- </div>
- </form>
-
-
- <div id="content">
+ <?php include(CONST_BasePath.'/lib/template/includes/html-top-navigation.php'); ?>
+
+ <form class="form-inline" role="search" accept-charset="UTF-8" action="<?php echo CONST_Website_BaseURL; ?>reverse.php">
+ <div class="form-group">
+ <input name="format" type="hidden" value="html">
+ <input name="lat" type="text" class="form-control input-sm" placeholder="latitude" value="<?php echo htmlspecialchars($_GET['lat']); ?>" >
+ <input name="lon" type="text" class="form-control input-sm" placeholder="longitude" value="<?php echo htmlspecialchars($_GET['lon']); ?>" >
+ max zoom
+
+ <select name="zoom" class="form-control input-sm" value="<?php echo htmlspecialchars($_GET['zoom']); ?>">
+ <option value="" <?php echo $_GET['zoom']==''?'selected':'' ?> >--</option>
+ <?php
+
+ $aZoomLevels = array(
+ 0 => "Continent / Sea",
+ 1 => "",
+ 2 => "",
+ 3 => "Country",
+ 4 => "",
+ 5 => "State",
+ 6 => "Region",
+ 7 => "",
+ 8 => "County",
+ 9 => "",
+ 10 => "City",
+ 11 => "",
+ 12 => "Town / Village",
+ 13 => "",
+ 14 => "Suburb",
+ 15 => "",
+ 16 => "Street",
+ 17 => "",
+ 18 => "Building",
+ 19 => "",
+ 20 => "",
+ 21 => "",
+ );
+
+ foreach($aZoomLevels as $iZoomLevel => $sLabel)
+ {
+ $bSel = isset($_GET['zoom']) && ($_GET['zoom'] == (string)$iZoomLevel);
+ echo '<option value="'.$iZoomLevel.'"'.($bSel?'selected':'').'>'.$iZoomLevel.' '.$sLabel.'</option>'."\n";
+ }
+ ?>
+ </select>
+ </div>
+ <div class="form-group search-button-group">
+ <button type="submit" class="btn btn-primary btn-sm">Search</button>
+ </div>
+ <div class="search-type-link">
+ <a href="<?php echo CONST_Website_BaseURL; ?>search.php">forward search</a>
+ </div>
+ </form>
+
+
+ <div id="content">
<?php if ($aPlace) { ?>
- <div id="searchresults" class="sidebar">
- <?php
- $aResult = $aPlace;
-
- echo '<div class="result" data-position="0">';
-
- echo (isset($aResult['icon'])?'<img alt="icon" src="'.$aResult['icon'].'"/>':'');
- echo ' <span class="name">'.htmlspecialchars($aResult['langaddress']).'</span>';
- if (isset($aResult['label']))
- echo ' <span class="type">('.$aResult['label'].')</span>';
- else if ($aResult['type'] == 'yes')
- echo ' <span class="type">('.ucwords(str_replace('_',' ',$aResult['class'])).')</span>';
- else
- echo ' <span class="type">('.ucwords(str_replace('_',' ',$aResult['type'])).')</span>';
- echo '<p>'.$aResult['lat'].','.$aResult['lon'].'</p>';
- echo ' <a class="btn btn-default btn-xs details" href="details.php?place_id='.$aResult['place_id'].'">details</a>';
- echo '</div>';
- ?>
- </div>
+ <div id="searchresults" class="sidebar">
+ <?php
+ $aResult = $aPlace;
+
+ echo '<div class="result" data-position="0">';
+
+ echo (isset($aResult['icon'])?'<img alt="icon" src="'.$aResult['icon'].'"/>':'');
+ echo ' <span class="name">'.htmlspecialchars($aResult['langaddress']).'</span>';
+ if (isset($aResult['label']))
+ echo ' <span class="type">('.$aResult['label'].')</span>';
+ else if ($aResult['type'] == 'yes')
+ echo ' <span class="type">('.ucwords(str_replace('_',' ',$aResult['class'])).')</span>';
+ else
+ echo ' <span class="type">('.ucwords(str_replace('_',' ',$aResult['type'])).')</span>';
+ echo '<p>'.$aResult['lat'].','.$aResult['lon'].'</p>';
+ echo ' <a class="btn btn-default btn-xs details" href="details.php?place_id='.$aResult['place_id'].'">details</a>';
+ echo '</div>';
+ ?>
+ </div>
<?php } else { ?>
- <div id="intro" class="sidebar">
- Search for coordinates or click anywhere on the map.
- </div>
+ <div id="intro" class="sidebar">
+ Search for coordinates or click anywhere on the map.
+ </div>
<?php } ?>
- <div id="map-wrapper">
- <div id="map-position"></div>
- <div id="map"></div>
- </div>
+ <div id="map-wrapper">
+ <div id="map-position"></div>
+ <div id="map"></div>
+ </div>
- </div> <!-- /content -->
+ </div> <!-- /content -->
- <script type="text/javascript">
- <?php
+ <script type="text/javascript">
+ <?php
- $aNominatimMapInit = [
- 'zoom' => isset($_GET['zoom']) ? htmlspecialchars($_GET['zoom']) : CONST_Default_Zoom,
- 'lat' => isset($_GET['lat'] ) ? htmlspecialchars($_GET['lat'] ) : CONST_Default_Lat,
- 'lon' => isset($_GET['lon'] ) ? htmlspecialchars($_GET['lon'] ) : CONST_Default_Lon,
- 'tile_url' => $sTileURL,
- 'tile_attribution' => $sTileAttribution
- ];
- echo 'var nominatim_map_init = ' . json_encode($aNominatimMapInit, JSON_PRETTY_PRINT) . ';';
+ $aNominatimMapInit = [
+ 'zoom' => isset($_GET['zoom']) ? htmlspecialchars($_GET['zoom']) : CONST_Default_Zoom,
+ 'lat' => isset($_GET['lat'] ) ? htmlspecialchars($_GET['lat'] ) : CONST_Default_Lat,
+ 'lon' => isset($_GET['lon'] ) ? htmlspecialchars($_GET['lon'] ) : CONST_Default_Lon,
+ 'tile_url' => $sTileURL,
+ 'tile_attribution' => $sTileAttribution
+ ];
+ echo 'var nominatim_map_init = ' . json_encode($aNominatimMapInit, JSON_PRETTY_PRINT) . ';';
- echo 'var nominatim_results = ' . json_encode([$aPlace], JSON_PRETTY_PRINT) . ';';
- ?>
- </script>
- <?php include(CONST_BasePath.'/lib/template/includes/html-footer.php'); ?>
+ echo 'var nominatim_results = ' . json_encode([$aPlace], JSON_PRETTY_PRINT) . ';';
+ ?>
+ </script>
+ <?php include(CONST_BasePath.'/lib/template/includes/html-footer.php'); ?>
</body>
</html>
if (isset($aPlace['place_id'])) $aFilteredPlaces['place_id'] = $aPlace['place_id'];
$aFilteredPlaces['licence'] = "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright";
$sOSMType = ($aPlace['osm_type'] == 'N'?'node':($aPlace['osm_type'] == 'W'?'way':($aPlace['osm_type'] == 'R'?'relation':'')));
- if ($sOSMType)
- {
- $aFilteredPlaces['osm_type'] = $sOSMType;
- $aFilteredPlaces['osm_id'] = $aPlace['osm_id'];
- }
- if (isset($aPlace['lat'])) $aFilteredPlaces['lat'] = $aPlace['lat'];
- if (isset($aPlace['lon'])) $aFilteredPlaces['lon'] = $aPlace['lon'];
+ if ($sOSMType)
+ {
+ $aFilteredPlaces['osm_type'] = $sOSMType;
+ $aFilteredPlaces['osm_id'] = $aPlace['osm_id'];
+ }
+ if (isset($aPlace['lat'])) $aFilteredPlaces['lat'] = $aPlace['lat'];
+ if (isset($aPlace['lon'])) $aFilteredPlaces['lon'] = $aPlace['lon'];
$aFilteredPlaces['display_name'] = $aPlace['langaddress'];
if (isset($aPlace['aAddress'])) $aFilteredPlaces['address'] = $aPlace['aAddress'];
if (isset($aPlace['sExtraTags'])) $aFilteredPlaces['extratags'] = $aPlace['sExtraTags'];
if (isset($aPlace['sNameDetails'])) $aFilteredPlaces['namedetails'] = $aPlace['sNameDetails'];
+
+ if (isset($aPlace['aBoundingBox']))
+ {
+ $aFilteredPlaces['boundingbox'] = $aPlace['aBoundingBox'];
+
+ if (isset($aPlace['aPolyPoints']) && $bAsPoints)
+ {
+ $aFilteredPlaces['polygonpoints'] = $aPlace['aPolyPoints'];
+ }
+ }
+
+ if (isset($aPlace['asgeojson']))
+ {
+ $aFilteredPlaces['geojson'] = json_decode($aPlace['asgeojson']);
+ }
+
+ if (isset($aPlace['assvg']))
+ {
+ $aFilteredPlaces['svg'] = $aPlace['assvg'];
+ }
+
+ if (isset($aPlace['astext']))
+ {
+ $aFilteredPlaces['geotext'] = $aPlace['astext'];
+ }
+
+ if (isset($aPlace['askml']))
+ {
+ $aFilteredPlaces['geokml'] = $aPlace['askml'];
+ }
+
+
}
javascript_renderData($aFilteredPlaces);
if ($aPlace['place_id']) $aFilteredPlaces['place_id'] = $aPlace['place_id'];
$aFilteredPlaces['licence'] = "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright";
$sOSMType = ($aPlace['osm_type'] == 'N'?'node':($aPlace['osm_type'] == 'W'?'way':($aPlace['osm_type'] == 'R'?'relation':'')));
- if ($sOSMType)
- {
- $aFilteredPlaces['osm_type'] = $sOSMType;
- $aFilteredPlaces['osm_id'] = $aPlace['osm_id'];
- }
+ if ($sOSMType)
+ {
+ $aFilteredPlaces['osm_type'] = $sOSMType;
+ $aFilteredPlaces['osm_id'] = $aPlace['osm_id'];
+ }
if (isset($aPlace['lat'])) $aFilteredPlaces['lat'] = $aPlace['lat'];
if (isset($aPlace['lon'])) $aFilteredPlaces['lon'] = $aPlace['lon'];
if (isset($aPlace['aAddress'])) $aFilteredPlaces['address'] = $aPlace['aAddress'];
if (isset($aPlace['sExtraTags'])) $aFilteredPlaces['extratags'] = $aPlace['sExtraTags'];
if (isset($aPlace['sNameDetails'])) $aFilteredPlaces['namedetails'] = $aPlace['sNameDetails'];
+
+ if (isset($aPlace['aBoundingBox']))
+ {
+ $aFilteredPlaces['boundingbox'] = $aPlace['aBoundingBox'];
+
+ if (isset($aPlace['aPolyPoints']) && $bAsPoints)
+ {
+ $aFilteredPlaces['polygonpoints'] = $aPlace['aPolyPoints'];
+ }
+ }
+
+ if (isset($aPlace['asgeojson']))
+ {
+ $aFilteredPlaces['geojson'] = json_decode($aPlace['asgeojson']);
+ }
+
+ if (isset($aPlace['assvg']))
+ {
+ $aFilteredPlaces['svg'] = $aPlace['assvg'];
+ }
+
+ if (isset($aPlace['astext']))
+ {
+ $aFilteredPlaces['geotext'] = $aPlace['astext'];
+ }
+
+ if (isset($aPlace['askml']))
+ {
+ $aFilteredPlaces['geokml'] = $aPlace['askml'];
+ }
+
}
javascript_renderData($aFilteredPlaces);
if ($aPlace['ref']) echo ' ref="'.htmlspecialchars($aPlace['ref']).'"';
if (isset($aPlace['lat'])) echo ' lat="'.htmlspecialchars($aPlace['lat']).'"';
if (isset($aPlace['lon'])) echo ' lon="'.htmlspecialchars($aPlace['lon']).'"';
+ if (isset($aPlace['aBoundingBox']))
+ {
+ echo ' boundingbox="';
+ echo join(',', $aPlace['aBoundingBox']);
+ echo '"';
+
+ if ($bAsPoints && isset($aPlace['aPolyPoints']))
+ {
+ echo ' polygonpoints=\'';
+ echo json_encode($aPlace['aPolyPoints']);
+ echo '\'';
+ }
+ }
+
+ if (isset($aPlace['asgeojson']))
+ {
+ echo ' geojson=\'';
+ echo $aPlace['asgeojson'];
+ echo '\'';
+ }
+
+ if (isset($aPlace['assvg']))
+ {
+ echo ' geosvg=\'';
+ echo $aPlace['assvg'];
+ echo '\'';
+ }
+
+ if (isset($aPlace['astext']))
+ {
+ echo ' geotext=\'';
+ echo $aPlace['astext'];
+ echo '\'';
+ }
echo ">".htmlspecialchars($aPlace['langaddress'])."</result>";
if (isset($aPlace['aAddress']))
}
echo "</namedetails>";
}
+
+ if (isset($aPlace['askml']))
+ {
+ echo "\n<geokml>";
+ echo $aPlace['askml'];
+ echo "</geokml>";
+ }
+
}
echo "</reversegeocode>";
echo "</tr>\n";
}
+ function _one_keyword_row($keyword_token,$word_id){
+ echo "<tr>\n";
+ echo '<td>';
+ // mark partial tokens (those starting with a space) with a star for readability
+ echo ($keyword_token[0]==' '?'*':'');
+ echo $keyword_token;
+ if (isset($word_id))
+ {
+ echo '</td><td>word id: '.$word_id;
+ }
+ echo "</td></tr>\n";
+ }
+
?>
headline('Name Keywords');
foreach($aPlaceSearchNameKeywords as $aRow)
{
- echo '<div>'.$aRow['word_token']."</div>\n";
+ _one_keyword_row($aRow['word_token'], $aRow['word_id']);
}
}
headline('Address Keywords');
foreach($aPlaceSearchAddressKeywords as $aRow)
{
- echo '<div>'.($aRow['word_token'][0]==' '?'*':'').$aRow['word_token'].'('.$aRow['word_id'].')'."</div>\n";
+ _one_keyword_row($aRow['word_token'], $aRow['word_id']);
}
}
<script type="text/javascript">
<?php
- $aNominatimMapInit = [
- 'tile_url' => $sTileURL,
- 'tile_attribution' => $sTileAttribution
- ];
- echo 'var nominatim_map_init = ' . json_encode($aNominatimMapInit, JSON_PRETTY_PRINT) . ';';
+ $aNominatimMapInit = [
+ 'tile_url' => $sTileURL,
+ 'tile_attribution' => $sTileAttribution
+ ];
+ echo 'var nominatim_map_init = ' . json_encode($aNominatimMapInit, JSON_PRETTY_PRINT) . ';';
- $aPlace = [
- 'outlinestring' => $aPointDetails['outlinestring'],
- 'lon' => $aPointDetails['lon'],
- 'lat' => $aPointDetails['lat'],
- ];
- echo 'var nominatim_result = ' . json_encode($aPlace, JSON_PRETTY_PRINT) . ';';
+ $aPlace = [
+ 'outlinestring' => $aPointDetails['outlinestring'],
+ 'lon' => $aPointDetails['lon'],
+ 'lat' => $aPointDetails['lat'],
+ ];
+ echo 'var nominatim_result = ' . json_encode($aPlace, JSON_PRETTY_PRINT) . ';';
- ?>
+ ?>
</script>
<footer>
- <p class="disclaimer">
- Addresses and postcodes are approximate
- </p>
- <p class="copyright">
- © <a href="http://osm.org/copyright">OpenStreetMap</a> contributors
- </p>
+ <p class="disclaimer">
+ Addresses and postcodes are approximate
+ </p>
+ <p class="copyright">
+ © <a href="http://osm.org/copyright">OpenStreetMap</a> contributors
+ </p>
</footer>
<script src="js/jquery.min.js"></script>
- <header class="container-fluid">
- <div class="row">
- <div class="col-xs-4">
- <div class="brand">
- <a href="<?php echo CONST_Website_BaseURL;?>">
- <img alt="logo" src="images/osm_logo.120px.png" width="30" height="30"/>
- <h1>Nominatim</h1>
- </a>
- </div>
- </div>
- <div id="last-updated" class="col-xs-4 text-center">
- <?php if ($sDataDate){ ?>
- Data last updated:
- <br>
- <?php echo $sDataDate; ?>
- <?php } ?>
- </div>
- <div class="col-xs-4 text-right">
- <div class="btn-group">
- <button class="dropdown-toggle btn btn-sm btn-default" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
- About & Help <span class="caret"></span>
- </button>
- <ul class="dropdown-menu dropdown-menu-right">
- <li><a href="http://wiki.openstreetmap.org/wiki/Nominatim" target="_blank">Documentation</a></li>
- <li><a href="http://wiki.openstreetmap.org/wiki/Nominatim/FAQ" target="_blank">FAQ</a></li>
- <li role="separator" class="divider"></li>
- <li><a href="#" class="" data-toggle="modal" data-target="#report-modal">Report problem with results</a></li>
- </ul>
- </div>
- </div>
- </div>
- </header>
+ <header class="container-fluid">
+ <div class="row">
+ <div class="col-xs-4">
+ <div class="brand">
+ <a href="<?php echo CONST_Website_BaseURL;?>">
+ <img alt="logo" src="images/osm_logo.120px.png" width="30" height="30"/>
+ <h1>Nominatim</h1>
+ </a>
+ </div>
+ </div>
+ <div id="last-updated" class="col-xs-4 text-center">
+ <?php if (isset($sDataDate)){ ?>
+ Data last updated:
+ <br>
+ <?php echo $sDataDate; ?>
+ <?php } ?>
+ </div>
+ <div class="col-xs-4 text-right">
+ <div class="btn-group">
+ <button class="dropdown-toggle btn btn-sm btn-default" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
+ About & Help <span class="caret"></span>
+ </button>
+ <ul class="dropdown-menu dropdown-menu-right">
+ <li><a href="http://wiki.openstreetmap.org/wiki/Nominatim" target="_blank">Documentation</a></li>
+ <li><a href="http://wiki.openstreetmap.org/wiki/Nominatim/FAQ" target="_blank">FAQ</a></li>
+ <li role="separator" class="divider"></li>
+ <li><a href="#" class="" data-toggle="modal" data-target="#report-modal">Report problem with results</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </header>
- <div class="modal fade" id="report-modal">
- <div class="modal-dialog">
- <div class="modal-content">
- <div class="modal-header">
- <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
- <h4 class="modal-title">Report a problem</h4>
- </div>
- <div class="modal-body">
- <?php include(CONST_BasePath.'/lib/template/includes/report-errors.php'); ?>
- </div>
- <div class="modal-footer">
- <button type="button" class="btn btn-default" data-dismiss="modal">OK</button>
- </div>
- </div>
- </div>
- </div>
+ <div class="modal fade" id="report-modal">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
+ <h4 class="modal-title">Report a problem</h4>
+ </div>
+ <div class="modal-body">
+ <?php include(CONST_BasePath.'/lib/template/includes/report-errors.php'); ?>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" data-dismiss="modal">OK</button>
+ </div>
+ </div>
+ </div>
+ </div>
foreach($aSearchResults as $iResNum => $aPointDetails)
{
$aPlace = array(
- 'place_id'=>$aPointDetails['place_id'],
- );
+ 'place_id'=>$aPointDetails['place_id'],
+ );
$sOSMType = ($aPointDetails['osm_type'] == 'N'?'node':($aPointDetails['osm_type'] == 'W'?'way':($aPointDetails['osm_type'] == 'R'?'relation':'')));
if ($sOSMType)
$aPlace['osm_id'] = $aPointDetails['osm_id'];
}
- if (isset($aPointDetails['aBoundingBox']))
- {
+ if (isset($aPointDetails['aBoundingBox']))
+ {
$aPlace['boundingbox'] = array(
$aPointDetails['aBoundingBox'][0],
$aPointDetails['aBoundingBox'][1],
{
$aPlace['polygonpoints'] = $aPointDetails['aPolyPoints'];
}
- }
+ }
if (isset($aPointDetails['zoom']))
{
if (isset($aPointDetails['address']) && sizeof($aPointDetails['address'])>0)
{
$aPlace['address'] = $aPointDetails['address'];
- }
+ }
- if (isset($aPointDetails['asgeojson']))
- {
+ if (isset($aPointDetails['asgeojson']))
+ {
$aPlace['geojson'] = json_decode($aPointDetails['asgeojson']);
- }
+ }
- if (isset($aPointDetails['assvg']))
- {
+ if (isset($aPointDetails['assvg']))
+ {
$aPlace['svg'] = $aPointDetails['assvg'];
- }
+ }
- if (isset($aPointDetails['astext']))
- {
- $aPlace['geotext'] = $aPointDetails['astext'];
- }
+ if (isset($aPointDetails['astext']))
+ {
+ $aPlace['geotext'] = $aPointDetails['astext'];
+ }
- if (isset($aPointDetails['askml']))
- {
- $aPlace['geokml'] = $aPointDetails['askml'];
- }
+ if (isset($aPointDetails['askml']))
+ {
+ $aPlace['geokml'] = $aPointDetails['askml'];
+ }
$aFilteredPlaces[] = $aPlace;
}
$aPlace['osm_id'] = $aPointDetails['osm_id'];
}
- if (isset($aPointDetails['aBoundingBox']))
- {
- $aPlace['boundingbox'] = array(
- $aPointDetails['aBoundingBox'][0],
- $aPointDetails['aBoundingBox'][1],
- $aPointDetails['aBoundingBox'][2],
- $aPointDetails['aBoundingBox'][3]);
+ if (isset($aPointDetails['aBoundingBox']))
+ {
+ $aPlace['boundingbox'] = $aPointDetails['aBoundingBox'];
if (isset($aPointDetails['aPolyPoints']) && $bShowPolygons)
{
$aPlace['polygonpoints'] = $aPointDetails['aPolyPoints'];
}
- }
+ }
if (isset($aPointDetails['zoom']))
{
if (isset($aPointDetails['address']))
{
$aPlace['address'] = $aPointDetails['address'];
- }
-
- if (isset($aPointDetails['asgeojson']))
- {
- $aPlace['geojson'] = json_decode($aPointDetails['asgeojson']);
- }
-
- if (isset($aPointDetails['assvg']))
- {
- $aPlace['svg'] = $aPointDetails['assvg'];
- }
-
- if (isset($aPointDetails['astext']))
- {
- $aPlace['geotext'] = $aPointDetails['astext'];
- }
+ }
+
+ if (isset($aPointDetails['asgeojson']))
+ {
+ $aPlace['geojson'] = json_decode($aPointDetails['asgeojson']);
+ }
+
+ if (isset($aPointDetails['assvg']))
+ {
+ $aPlace['svg'] = $aPointDetails['assvg'];
+ }
+
+ if (isset($aPointDetails['astext']))
+ {
+ $aPlace['geotext'] = $aPointDetails['astext'];
+ }
if (isset($aPointDetails['askml']))
{
$aPlace['osm_id'] = $aPointDetails['osm_id'];
}
- if (isset($aPointDetails['aBoundingBox']))
- {
- $aPlace['boundingbox'] = array(
- $aPointDetails['aBoundingBox'][0],
- $aPointDetails['aBoundingBox'][1],
- $aPointDetails['aBoundingBox'][2],
- $aPointDetails['aBoundingBox'][3]);
+ if (isset($aPointDetails['aBoundingBox']))
+ {
+ $aPlace['boundingbox'] = $aPointDetails['aBoundingBox'];
if (isset($aPointDetails['aPolyPoints']) && $bShowPolygons)
{
$aPlace['polygonpoints'] = $aPointDetails['aPolyPoints'];
}
- }
+ }
if (isset($aPointDetails['zoom']))
{
if (isset($aPointDetails['address']) && sizeof($aPointDetails['address'])>0)
{
$aPlace['address'] = $aPointDetails['address'];
- }
+ }
- if (isset($aPointDetails['asgeojson']))
- {
+ if (isset($aPointDetails['asgeojson']))
+ {
$aPlace['geojson'] = json_decode($aPointDetails['asgeojson']);
- }
+ }
- if (isset($aPointDetails['assvg']))
- {
+ if (isset($aPointDetails['assvg']))
+ {
$aPlace['svg'] = $aPointDetails['assvg'];
- }
+ }
- if (isset($aPointDetails['astext']))
- {
- $aPlace['geotext'] = $aPointDetails['astext'];
- }
+ if (isset($aPointDetails['astext']))
+ {
+ $aPlace['geotext'] = $aPointDetails['astext'];
+ }
- if (isset($aPointDetails['askml']))
- {
- $aPlace['geokml'] = $aPointDetails['askml'];
- }
+ if (isset($aPointDetails['askml']))
+ {
+ $aPlace['geokml'] = $aPointDetails['askml'];
+ }
if (isset($aPointDetails['sExtraTags'])) $aPlace['extratags'] = $aPointDetails['sExtraTags'];
if (isset($aPointDetails['sNameDetails'])) $aPlace['namedetails'] = $aPointDetails['sNameDetails'];
if (isset($aResult['aBoundingBox']))
{
echo ' boundingbox="';
- echo $aResult['aBoundingBox'][0];
- echo ','.$aResult['aBoundingBox'][1];
- echo ','.$aResult['aBoundingBox'][2];
- echo ','.$aResult['aBoundingBox'][3];
+ echo join(',',$aResult['aBoundingBox']);
echo '"';
if ($bShowPolygons && isset($aResult['aPolyPoints']))
# class/type combinations to exclude
$aTagsBlacklist = array(
- 'boundary' => array('administrative'),
- 'place' => array('house', 'houses'),
+ 'boundary' => array('administrative'),
+ 'place' => array('house', 'houses'),
);
# If a class is in the white list then all types will
# be ignored except the ones given in the list.
# Also use this list to exclude an entire class from
# special phrases.
$aTagsWhitelist = array(
- 'highway' => array('bus_stop', 'rest_area', 'raceway'),
- 'building' => array(),
+ 'highway' => array('bus_stop', 'rest_area', 'raceway'),
+ 'building' => array(),
);
}
+ public function test_getClassTypesWithImportance()
+ {
+ $aClasses = getClassTypesWithImportance();
+
+ $this->assertGreaterThan(
+ 200,
+ count($aClasses)
+ );
+
+ $this->assertEquals(
+ array(
+ 'label' => "Country",
+ 'frequency' => 0,
+ 'icon' => "poi_boundary_administrative",
+ 'defzoom' => 6,
+ 'defdiameter' => 15,
+ 'importance' => 3
+ ),
+ $aClasses['place:country']
+ );
+ }
+
+
+ public function test_getResultDiameter()
+ {
+ $aResult = array();
+ $this->assertEquals(
+ 0.0001,
+ getResultDiameter($aResult)
+ );
+
+ $aResult = array('class' => 'place', 'type' => 'country');
+ $this->assertEquals(
+ 15,
+ getResultDiameter($aResult)
+ );
+
+ $aResult = array('class' => 'boundary', 'type' => 'administrative', 'admin_level' => 6);
+ $this->assertEquals(
+ 0.32,
+ getResultDiameter($aResult)
+ );
+ }
+
+
public function test_addQuotes()
{
// FIXME: not quoting existing quote signs is probably a bug
65536,
count( getWordSets(array_fill( 0, 18, 'a'),0) )
);
+ }
+ // you might say we're creating a circle
+ public function test_createPointsAroundCenter()
+ {
+ $aPoints = createPointsAroundCenter(0, 0, 2);
+ $this->assertEquals(
+ 101,
+ count($aPoints)
+ );
+ $this->assertEquals(
+ array(
+ ['', 0, 2],
+ ['', 0.12558103905863, 1.9960534568565],
+ ['', 0.25066646712861, 1.984229402629]
+ ),
+ array_splice($aPoints, 0, 3)
+ );
}
+ public function test_geometryText2Points()
+ {
+ $fRadius = 1;
+ // invalid value
+ $this->assertEquals(
+ NULL,
+ geometryText2Points('', $fRadius)
+ );
+
+ // POINT
+ $aPoints = geometryText2Points('POINT(10 20)', $fRadius);
+ $this->assertEquals(
+ 101,
+ count($aPoints)
+ );
+ $this->assertEquals(
+ array(
+ [10, 21],
+ [10.062790519529, 20.998026728428],
+ [10.125333233564, 20.992114701314]
+ ),
+ array_splice($aPoints, 0,3)
+ );
+
+ // POLYGON
+ $this->assertEquals(
+ array(
+ ['30', '10'],
+ ['40', '40'],
+ ['20', '40'],
+ ['10', '20'],
+ ['30', '10']
+ ),
+ geometryText2Points('POLYGON((30 10, 40 40, 20 40, 10 20, 30 10))', $fRadius)
+ );
+
+ // MULTIPOLYGON
+ $this->assertEquals(
+ array(
+ ['30', '20'], // first polygon only
+ ['45', '40'],
+ ['10', '40'],
+ ['30', '20'],
+ ),
+ geometryText2Points('MULTIPOLYGON(((30 20, 45 40, 10 40, 30 20)),((15 5, 40 10, 10 20, 5 10, 15 5)))', $fRadius)
+ );
+ }
}
| ID | country
| 0 | Deutschland
+
+ Scenario: Boundingbox is returned
+ Given the request parameters
+ | format | zoom
+ | xml | 4
+ When looking up coordinates 53.9788769,13.0830313
+ And results contain valid boundingboxes
+
+
@Tiger
Scenario: TIGER house number
Given the request parameters
| xml
| json
| jsonv2
+
+
+ Scenario Outline: Reverse Geocoding contains TEXT geometry
+ Given the request parameters
+ | polygon_text
+ | 1
+ When looking up <format> coordinates 48.86093,2.2978
+ Then result 0 has attributes <response_attribute>
+
+ Examples:
+ | format | response_attribute
+ | xml | geotext
+ | json | geotext
+ | jsonv2 | geotext
+
+ Scenario Outline: Reverse Geocoding contains polygon-as-points geometry
+ Given the request parameters
+ | polygon
+ | 1
+ When looking up <format> coordinates 48.86093,2.2978
+ Then result 0 has not attributes <response_attribute>
+
+ Examples:
+ | format | response_attribute
+ | xml | polygonpoints
+ | json | polygonpoints
+ | jsonv2 | polygonpoints
+
+
+
+ Scenario Outline: Reverse Geocoding contains SVG geometry
+ Given the request parameters
+ | polygon_svg
+ | 1
+ When looking up <format> coordinates 48.86093,2.2978
+ Then result 0 has attributes <response_attribute>
+
+ Examples:
+ | format | response_attribute
+ | xml | geosvg
+ | json | svg
+ | jsonv2 | svg
+
+
+ Scenario Outline: Reverse Geocoding contains KML geometry
+ Given the request parameters
+ | polygon_kml
+ | 1
+ When looking up <format> coordinates 48.86093,2.2978
+ Then result 0 has attributes <response_attribute>
+
+ Examples:
+ | format | response_attribute
+ | xml | geokml
+ | json | geokml
+ | jsonv2 | geokml
+
+
+ Scenario Outline: Reverse Geocoding contains GEOJSON geometry
+ Given the request parameters
+ | polygon_geojson
+ | 1
+ When looking up <format> coordinates 48.86093,2.2978
+ Then result 0 has attributes <response_attribute>
+
+ Examples:
+ | format | response_attribute
+ | xml | geojson
+ | json | geojson
+ | jsonv2 | geojson
+
+
| -79.34 | 23.5
| 0.23 | -178.555
+ Scenario Outline: Testing different parameters
+ Given the request parameters
+ | <parameter>
+ | <value>
+ When sending search query "Manchester"
+ Then the result is valid html
+ Given the request parameters
+ | <parameter>
+ | <value>
+ When sending html search query "Manchester"
+ Then the result is valid html
+ Given the request parameters
+ | <parameter>
+ | <value>
+ When sending xml search query "Manchester"
+ Then the result is valid xml
+ Given the request parameters
+ | <parameter>
+ | <value>
+ When sending json search query "Manchester"
+ Then the result is valid json
+ Given the request parameters
+ | <parameter>
+ | <value>
+ When sending jsonv2 search query "Manchester"
+ Then the result is valid json
+
+ Examples:
+ | parameter | value
+ | polygon | 1
+ | polygon | 0
+ | polygon_text | 1
+ | polygon_text | 0
+ | polygon_kml | 1
+ | polygon_kml | 0
+ | polygon_geojson | 1
+ | polygon_geojson | 0
+ | polygon_svg | 1
+ | polygon_svg | 0
+
+
+
+
Scenario Outline: Wrapping of legal jsonp requests
Given the request parameters
| json_callback
And result 0 has attributes lat,lon,display_name
And result 0 has attributes class,type,importance,icon
And result 0 has not attributes address
+ And results contain valid boundingboxes
Scenario: Simple JSON search
When sending json search query "Vaduz"
And result 0 has attributes osm_type,osm_id,boundingbox
And result 0 has attributes lat,lon,display_name,importance
And result 0 has not attributes address
+ And results contain valid boundingboxes
Scenario: JSON search with addressdetails
When sending json search query "Montevideo" with address
| xml
| json
| jsonv2
+
+
+ Scenario Outline: Search result with contains TEXT geometry
+ Given the request parameters
+ | polygon_text
+ | 1
+ When sending <format> search query "switzerland"
+ Then result 0 has attributes <response_attribute>
+
+ Examples:
+ | format | response_attribute
+ | xml | geotext
+ | json | geotext
+ | jsonv2 | geotext
+
+ Scenario Outline: Search result contains polygon-as-points geometry
+ Given the request parameters
+ | polygon
+ | 1
+ When sending <format> search query "switzerland"
+ Then result 0 has attributes <response_attribute>
+
+ Examples:
+ | format | response_attribute
+ | xml | polygonpoints
+ | json | polygonpoints
+ | jsonv2 | polygonpoints
+
+
+
+ Scenario Outline: Search result contains SVG geometry
+ Given the request parameters
+ | polygon_svg
+ | 1
+ When sending <format> search query "switzerland"
+ Then result 0 has attributes <response_attribute>
+
+ Examples:
+ | format | response_attribute
+ | xml | geosvg
+ | json | svg
+ | jsonv2 | svg
+
+
+ Scenario Outline: Search result contains KML geometry
+ Given the request parameters
+ | polygon_kml
+ | 1
+ When sending <format> search query "switzerland"
+ Then result 0 has attributes <response_attribute>
+
+ Examples:
+ | format | response_attribute
+ | xml | geokml
+ | json | geokml
+ | jsonv2 | geokml
+
+
+ Scenario Outline: Search result contains GEOJSON geometry
+ Given the request parameters
+ | polygon_geojson
+ | 1
+ When sending <format> search query "switzerland"
+ Then result 0 has attributes <response_attribute>
+
+ Examples:
+ | format | response_attribute
+ | xml | geojson
+ | json | geojson
+ | jsonv2 | geojson
attrs = dict(tag.attributes.items())
assert_in('desc', attrs)
world.results[0]['namedetails'][attrs['desc']] = tag.firstChild.nodeValue.strip()
+ elif node.nodeName == "geokml":
+ world.results[0]['geokml'] = node
elif node.nodeName == "#text":
pass
else:
m = re.match("%s$" % (v,), curres[k])
assert_is_not_none(m, msg="field %s does not match: %s$ != %s." % (k, v, curres[k]))
+@step(u'results contain valid boundingboxes$')
+def api_result_address_contains(step):
+ step.given('the result is valid')
+ for curres in world.results:
+ bb = curres['boundingbox']
+ if world.response_format == 'json':
+ bb = ','.join(bb)
+ m = re.match('^(-?\d+\.\d+),(-?\d+\.\d+),(-?\d+\.\d+),(-?\d+\.\d+)$', bb)
+ assert_is_not_none(m, msg="invalid boundingbox: %s." % (curres['boundingbox']))
@step(u'result addresses contain$')
def api_result_address_contains(step):
--- /dev/null
+#!/bin/bash
+
+# This script sets up a Nominatim installation on a CentOS 7 box.
+#
+# For more detailed CentOS installation instructions see also
+# http://wiki.openstreetmap.org/wiki/Nominatim/Installation_on_CentOS
+
+## Part 1: System preparation
+
+## During 'vagrant provision' this script runs as root and the current
+## directory is '/root'
+USERNAME=vagrant
+
+yum update -y
+yum install -y epel-release
+
+yum install -y postgresql-server postgresql-contrib postgresql-devel postgis postgis-utils \
+ make automake gcc gcc-c++ libtool policycoreutils-python \
+ php-pgsql php php-pear php-pear-DB libpqxx-devel proj-epsg \
+ bzip2-devel proj-devel geos-devel libxml2-devel boost-devel \
+ expat-devel zlib-devel
+
+# Create a cluster and start up postgresql.
+postgresql-setup initdb
+systemctl enable postgresql
+systemctl start postgresql
+
+# We leave postgresql in its default configuration here. This is only
+# suitable for small extracts.
+
+# Create the necessary postgres users.
+sudo -u postgres createuser -s vagrant
+sudo -u postgres createuser apache
+
+# Create the website directory.
+mkdir -m 755 /var/www/html/nominatim
+chown vagrant /var/www/html/nominatim
+
+# Set up the necessary rights on SELinux.
+semanage fcontext -a -t httpd_sys_content_t "/home/vagrant/Nominatim/(website|lib|settings)(/.*)?"
+semanage fcontext -a -t lib_t "/home/vagrant/Nominatim/module/nominatim.so"
+semanage port -a -t http_port_t -p tcp 8089
+restorecon -R -v /home/vagrant/Nominatim
+
+# Configure apache site.
+echo '
+Listen 8089
+<VirtualHost *:8089>
+ # DirectoryIndex index.html
+ # ErrorDocument 403 /index.html
+
+ DocumentRoot "/var/www/html/"
+
+ <Directory "/var/www/html/nominatim/">
+ Options FollowSymLinks MultiViews
+ AddType text/html .php
+ </Directory>
+</VirtualHost>
+' | sudo tee /etc/httpd/conf.d/nominatim.conf > /dev/null
+
+# Restart apache to enable the site configuration.
+systemctl enable httpd
+systemctl restart httpd
+
+## Part 2: Nominatim installaion
+
+# now ideally login as $USERNAME and continue
+cd /home/$USERNAME
+
+# If the Nominatim source is not being shared with the host, check out source.
+if [ ! -d "Nominatim" ]; then
+ yum install -y git
+ sudo -u $USERNAME git clone --recursive https://github.com/twain47/Nominatim.git
+fi
+
+# Configure and compile the source.
+cd Nominatim
+sudo -u $USERNAME ./autogen.sh
+sudo -u $USERNAME ./configure
+sudo -u $USERNAME make
+
+# Make sure that postgres has access to the nominatim library.
+chmod +x /home/$USERNAME
+chmod +x ./
+chmod +x ./module
+
+# Create customized settings suitable for this VM installation.
+LOCALSETTINGS_FILE='settings/local.php'
+if [[ -e "$LOCALSETTINGS_FILE" ]]; then
+ echo "$LOCALSETTINGS_FILE already exist, writing to settings/local-vagrant.php instead."
+ LOCALSETTINGS_FILE='settings/local-vagrant.php'
+fi
+
+IP=localhost
+echo "<?php
+ // General settings
+ @define('CONST_Database_DSN', 'pgsql://@/nominatim');
+ // Paths
+ @define('CONST_Postgresql_Version', '9.2');
+ @define('CONST_Postgis_Version', '2.0');
+ @define('CONST_Database_Web_User', 'apache');
+ // Website settings
+ @define('CONST_Website_BaseURL', 'http://$IP:8089/nominatim/');
+" > $LOCALSETTINGS_FILE
+
+# Install the web interface.
+sudo -u $USERNAME ./utils/setup.php --create-website /var/www/html/nominatim
#!/bin/bash
+# This script sets up a Nominatim installation on a Ubuntu box.
+#
+# For more detailed installation instructions see also
+# http://wiki.openstreetmap.org/wiki/Nominatim/Installation
+
+## Part 1: System preparation
## During 'vagrant provision' this script runs as root and the current
## directory is '/root'
###
sudo apt-get install -y libgeos-c1 libgeos++-dev libxml2-dev
+## Part 2: Nominatim installaion
+
# now ideally login as $USERNAME and continue
-su $USERNAME -l
-cd /home/vagrant
+cd /home/$USERNAME
+# If the Nominatim source is not being shared with the host, check out source.
if [ ! -d "Nominatim" ]; then
sudo apt-get install -y git
- git clone --recursive https://github.com/twain47/Nominatim.git
+ sudo -u $USERNAME git clone --recursive https://github.com/twain47/Nominatim.git
fi
cd Nominatim
-./autogen.sh
-./configure
-make
+sudo -u $USERNAME ./autogen.sh
+sudo -u $USERNAME ./configure
+sudo -u $USERNAME make
chmod +x ./
chmod +x ./module
' | sudo tee /etc/apache2/sites-enabled/nominatim.conf > /dev/null
-sudo apache2ctl graceful
+apache2ctl graceful
-sudo mkdir -m 755 /var/www/nominatim
-sudo chown $USERNAME /var/www/nominatim
-./utils/setup.php --threads 1 --create-website /var/www/nominatim
+mkdir -m 755 /var/www/nominatim
+chown $USERNAME /var/www/nominatim
+sudo -u $USERNAME ./utils/setup.php --create-website /var/www/nominatim
# if you get 'permission denied for relation word', then try
## Test suite (Python)
## https://github.com/twain47/Nominatim/tree/master/tests
##
-sudo apt-get install -y python-dev python-pip python-Levenshtein python-shapely \
+apt-get install -y python-dev python-pip python-Levenshtein python-shapely \
python-psycopg2 tidy python-nose python-tidylib
-sudo pip install lettuce==0.2.18 six==1.7 haversine
+pip install lettuce==0.2.18 six==1.7 haversine
## Test suite (PHP)
## https://github.com/twain47/Nominatim/tree/master/tests-php
-sudo apt-get install -y phpunit
+apt-get install -y phpunit
<?php
- require_once(dirname(dirname(__FILE__)).'/lib/init-website.php');
- require_once(CONST_BasePath.'/lib/log.php');
+ require_once(dirname(dirname(__FILE__)).'/lib/init-website.php');
+ require_once(CONST_BasePath.'/lib/log.php');
$sOutputFormat = 'html';
ini_set('memory_limit', '200M');
<!DOCTYPE html>
<html>
<head>
- <meta charset="utf-8"/>
- <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
-
- <title>Nominatim Deleted Data</title>
-
- <meta name="description" content="List of OSM data that has been deleted" lang="en-US" />
+ <meta charset="utf-8"/>
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
+
+ <title>Nominatim Deleted Data</title>
+
+ <meta name="description" content="List of OSM data that has been deleted" lang="en-US" />
</head>
{
switch($sCol)
{
- case 'osm_id':
- $sOSMType = ($aRow['osm_type'] == 'N'?'node':($aRow['osm_type'] == 'W'?'way':($aRow['osm_type'] == 'R'?'relation':'')));
- echo '<td><a href="http://www.openstreetmap.org/browse/'.$sOSMType.'/'.$sVal.'" target="_new">'.$sVal.'</a></td>';
- break;
- case 'place_id':
- echo '<td><a href="'.CONST_Website_BaseURL.'details?place_id='.$sVal.'">'.$sVal.'</a></td>';
- break;
- default:
- echo "<td>".($sVal?$sVal:' ')."</td>";
- break;
+ case 'osm_id':
+ $sOSMType = ($aRow['osm_type'] == 'N'?'node':($aRow['osm_type'] == 'W'?'way':($aRow['osm_type'] == 'R'?'relation':'')));
+ echo '<td><a href="http://www.openstreetmap.org/browse/'.$sOSMType.'/'.$sVal.'" target="_new">'.$sVal.'</a></td>';
+ break;
+ case 'place_id':
+ echo '<td><a href="'.CONST_Website_BaseURL.'details?place_id='.$sVal.'">'.$sVal.'</a></td>';
+ break;
+ default:
+ echo "<td>".($sVal?$sVal:' ')."</td>";
+ break;
}
}
echo "</tr>";
logEnd($oDB, $hLog, 1);
- $sTileURL = CONST_Map_Tile_URL;
- $sTileAttribution = CONST_Map_Tile_Attribution;
+ if ($sOutputFormat=='html')
+ {
+ $sDataDate = $oDB->getOne("select TO_CHAR(lastimportdate - '2 minutes'::interval,'YYYY/MM/DD HH24:MI')||' GMT' from import_status limit 1");
+ $sTileURL = CONST_Map_Tile_URL;
+ $sTileAttribution = CONST_Map_Tile_Attribution;
+ }
+
include(CONST_BasePath.'/lib/template/details-'.$sOutputFormat.'.php');
$aBreadcrums[] = array('placeId'=>$aPlace['place_id'], 'osmType'=>$aPlace['osm_type'], 'osmId'=>$aPlace['osm_id'], 'localName'=>$aPlace['localname']);
$sPlaceUrl = 'hierarchy.php?place_id='.$aPlace['place_id'];
$sOSMType = ($aPlace['osm_type'] == 'N'?'node':($aPlace['osm_type'] == 'W'?'way':($aPlace['osm_type'] == 'R'?'relation':'')));
- $sOSMUrl = 'http://www.openstreetmap.org/browse/'.$sOSMType.'/'.$aPlace['osm_id'];
+ $sOSMUrl = 'http://www.openstreetmap.org/browse/'.$sOSMType.'/'.$aPlace['osm_id'];
if ($sOutputFormat == 'html') if ($i) echo " > ";
if ($sOutputFormat == 'html') echo '<a href="'.$sPlaceUrl.'">'.$aPlace['localname'].'</a> (<a href="'.$sOSMUrl.'">osm</a>)';
}
$sSQL .= " order by rank_address asc,rank_search asc,localname,class, type,housenumber";
$aParentOfLines = $oDB->getAll($sSQL);
- if (sizeof($aParentOfLines))
- {
- echo '<h2>Parent Of:</h2>';
+ if (sizeof($aParentOfLines))
+ {
+ echo '<h2>Parent Of:</h2>';
$aClassType = getClassTypesWithImportance();
- $aGroupedAddressLines = array();
- foreach($aParentOfLines as $aAddressLine)
- {
+ $aGroupedAddressLines = array();
+ foreach($aParentOfLines as $aAddressLine)
+ {
if (isset($aClassType[$aAddressLine['class'].':'.$aAddressLine['type'].':'.$aAddressLine['admin_level']]['label'])
- && $aClassType[$aAddressLine['class'].':'.$aAddressLine['type'].':'.$aAddressLine['admin_level']]['label'])
- {
- $aAddressLine['label'] = $aClassType[$aAddressLine['class'].':'.$aAddressLine['type'].':'.$aAddressLine['admin_level']]['label'];
- }
+ && $aClassType[$aAddressLine['class'].':'.$aAddressLine['type'].':'.$aAddressLine['admin_level']]['label'])
+ {
+ $aAddressLine['label'] = $aClassType[$aAddressLine['class'].':'.$aAddressLine['type'].':'.$aAddressLine['admin_level']]['label'];
+ }
elseif (isset($aClassType[$aAddressLine['class'].':'.$aAddressLine['type']]['label'])
- && $aClassType[$aAddressLine['class'].':'.$aAddressLine['type']]['label'])
- {
- $aAddressLine['label'] = $aClassType[$aAddressLine['class'].':'.$aAddressLine['type']]['label'];
- }
+ && $aClassType[$aAddressLine['class'].':'.$aAddressLine['type']]['label'])
+ {
+ $aAddressLine['label'] = $aClassType[$aAddressLine['class'].':'.$aAddressLine['type']]['label'];
+ }
else $aAddressLine['label'] = ucwords($aAddressLine['type']);
- if (!isset($aGroupedAddressLines[$aAddressLine['label']])) $aGroupedAddressLines[$aAddressLine['label']] = array();
- $aGroupedAddressLines[$aAddressLine['label']][] = $aAddressLine;
- }
- foreach($aGroupedAddressLines as $sGroupHeading => $aParentOfLines)
- {
- echo "<h3>$sGroupHeading</h3>";
- foreach($aParentOfLines as $aAddressLine)
- {
- $aAddressLine['localname'] = $aAddressLine['localname']?$aAddressLine['localname']:$aAddressLine['housenumber'];
- $sOSMType = ($aAddressLine['osm_type'] == 'N'?'node':($aAddressLine['osm_type'] == 'W'?'way':($aAddressLine['osm_type'] == 'R'?'relation':'')));
-
- echo '<div class="line">';
- echo '<span class="name">'.(trim($aAddressLine['localname'])?$aAddressLine['localname']:'<span class="noname">No Name</span>').'</span>';
- echo ' (';
- echo '<span class="area">'.($aAddressLine['isarea']=='t'?'Polygon':'Point').'</span>';
- if ($sOSMType) echo ', <span class="osm"><span class="label"></span>'.$sOSMType.' <a href="http://www.openstreetmap.org/browse/'.$sOSMType.'/'.$aAddressLine['osm_id'].'">'.$aAddressLine['osm_id'].'</a></span>';
- echo ', <a href="hierarchy.php?place_id='.$aAddressLine['place_id'].'">GOTO</a>';
- echo ', '.$aAddressLine['area'];
- echo ')';
- echo '</div>';
- }
- }
- if (sizeof($aParentOfLines) >= 500) {
- echo '<p>There are more child objects which are not shown.</p>';
- }
- echo '</div>';
- }
+ if (!isset($aGroupedAddressLines[$aAddressLine['label']])) $aGroupedAddressLines[$aAddressLine['label']] = array();
+ $aGroupedAddressLines[$aAddressLine['label']][] = $aAddressLine;
+ }
+ foreach($aGroupedAddressLines as $sGroupHeading => $aParentOfLines)
+ {
+ echo "<h3>$sGroupHeading</h3>";
+ foreach($aParentOfLines as $aAddressLine)
+ {
+ $aAddressLine['localname'] = $aAddressLine['localname']?$aAddressLine['localname']:$aAddressLine['housenumber'];
+ $sOSMType = ($aAddressLine['osm_type'] == 'N'?'node':($aAddressLine['osm_type'] == 'W'?'way':($aAddressLine['osm_type'] == 'R'?'relation':'')));
+
+ echo '<div class="line">';
+ echo '<span class="name">'.(trim($aAddressLine['localname'])?$aAddressLine['localname']:'<span class="noname">No Name</span>').'</span>';
+ echo ' (';
+ echo '<span class="area">'.($aAddressLine['isarea']=='t'?'Polygon':'Point').'</span>';
+ if ($sOSMType) echo ', <span class="osm"><span class="label"></span>'.$sOSMType.' <a href="http://www.openstreetmap.org/browse/'.$sOSMType.'/'.$aAddressLine['osm_id'].'">'.$aAddressLine['osm_id'].'</a></span>';
+ echo ', <a href="hierarchy.php?place_id='.$aAddressLine['place_id'].'">GOTO</a>';
+ echo ', '.$aAddressLine['area'];
+ echo ')';
+ echo '</div>';
+ }
+ }
+ if (sizeof($aParentOfLines) >= 500) {
+ echo '<p>There are more child objects which are not shown.</p>';
+ }
+ echo '</div>';
+ }
exit;
var bounds = [[result.aBoundingBox[0]*1,result.aBoundingBox[2]*1], [result.aBoundingBox[1]*1,result.aBoundingBox[3]*1]];
map.fitBounds(bounds);
- if (result.astext && result.astext.match(/POLY/) ){
+ if (result.astext && result.astext.match(/(POLY)|(LINE)/) ){
var layer = omnivore.wkt.parse(result.astext);
layerGroup.addLayer(layer);
}
<!DOCTYPE html>
<html>
<head>
- <meta charset="utf-8"/>
- <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
-
- <title>Nominatim Broken Polygon Data</title>
-
- <meta name="description" content="List of broken OSM polygon data by date" lang="en-US" />
+ <meta charset="utf-8"/>
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
+
+ <title>Nominatim Broken Polygon Data</title>
+
+ <meta name="description" content="List of broken OSM polygon data by date" lang="en-US" />
</head>
require_once(CONST_BasePath.'/lib/PlaceLookup.php');
require_once(CONST_BasePath.'/lib/ReverseGeocode.php');
+ $bAsPoints = false;
+ $bAsGeoJSON = (boolean)isset($_GET['polygon_geojson']) && $_GET['polygon_geojson'];
+ $bAsKML = (boolean)isset($_GET['polygon_kml']) && $_GET['polygon_kml'];
+ $bAsSVG = (boolean)isset($_GET['polygon_svg']) && $_GET['polygon_svg'];
+ $bAsText = (boolean)isset($_GET['polygon_text']) && $_GET['polygon_text'];
+ if ( ( ($bAsGeoJSON?1:0)
+ + ($bAsKML?1:0)
+ + ($bAsSVG?1:0)
+ + ($bAsText?1:0)
+ + ($bAsPoints?1:0)
+ ) > CONST_PolygonOutput_MaximumTypes)
+ {
+ if (CONST_PolygonOutput_MaximumTypes)
+ {
+ userError("Select only ".CONST_PolygonOutput_MaximumTypes." polgyon output option");
+ }
+ else
+ {
+ userError("Polygon output is disabled");
+ }
+ exit;
+ }
+
+
+ // Polygon simplification threshold (optional)
+ $fThreshold = 0.0;
+ if (isset($_GET['polygon_threshold'])) $fThreshold = (float)$_GET['polygon_threshold'];
+
+
$oDB =& getDB();
ini_set('memory_limit', '200M');
$oPlaceLookup->setIncludeNameDetails(getParamBool('namedetails', false));
$aPlace = $oPlaceLookup->lookupPlace($aLookup);
+
+ $oPlaceLookup->setIncludePolygonAsPoints($bAsPoints);
+ $oPlaceLookup->setIncludePolygonAsText($bAsText);
+ $oPlaceLookup->setIncludePolygonAsGeoJSON($bAsGeoJSON);
+ $oPlaceLookup->setIncludePolygonAsKML($bAsKML);
+ $oPlaceLookup->setIncludePolygonAsSVG($bAsSVG);
+ $oPlaceLookup->setPolygonSimplificationThreshold($fThreshold);
+
+ $fRadius = $fDiameter = getResultDiameter($aPlace);
+ $aOutlineResult = $oPlaceLookup->getOutlines($aPlace['place_id'],$aPlace['lon'],$aPlace['lat'],$fRadius);
+
+ $aPlace = array_merge($aPlace, $aOutlineResult);
}
else
{
exit;
}
- $sTileURL = CONST_Map_Tile_URL;
- $sTileAttribution = CONST_Map_Tile_Attribution;
+ if ($sOutputFormat=='html')
+ {
+ $sDataDate = $oDB->getOne("select TO_CHAR(lastimportdate - '2 minutes'::interval,'YYYY/MM/DD HH24:MI')||' GMT' from import_status limit 1");
+ $sTileURL = CONST_Map_Tile_URL;
+ $sTileAttribution = CONST_Map_Tile_Attribution;
+ }
include(CONST_BasePath.'/lib/template/address-'.$sOutputFormat.'.php');
$fLat = CONST_Default_Lat;
$fLon = CONST_Default_Lon;
$iZoom = CONST_Default_Zoom;
- $sTileURL = CONST_Map_Tile_URL;
- $sTileAttribution = CONST_Map_Tile_Attribution;
$oGeocode =& new Geocode($oDB);
{
if (!(isset($_GET['q']) && $_GET['q']) && isset($_SERVER['PATH_INFO']) && $_SERVER['PATH_INFO'][0] == '/')
{
- $sQuery = substr(rawurldecode($_SERVER['PATH_INFO']), 1);
+ $sQuery = substr(rawurldecode($_SERVER['PATH_INFO']), 1);
- // reverse order of '/' separated string
- $aPhrases = explode('/', $sQuery);
- $aPhrases = array_reverse($aPhrases);
- $sQuery = join(', ',$aPhrases);
- $oGeocode->setQuery($sQuery);
+ // reverse order of '/' separated string
+ $aPhrases = explode('/', $sQuery);
+ $aPhrases = array_reverse($aPhrases);
+ $sQuery = join(', ',$aPhrases);
+ $oGeocode->setQuery($sQuery);
}
else
{
- $oGeocode->setQueryFromParams($_GET);
+ $oGeocode->setQueryFromParams($_GET);
}
}
$aSearchResults = $oGeocode->lookup();
if ($aSearchResults === false) $aSearchResults = array();
- $sDataDate = $oDB->getOne("select TO_CHAR(lastimportdate - '2 minutes'::interval,'YYYY/MM/DD HH24:MI')||' GMT' from import_status limit 1");
-
+ if ($sOutputFormat=='html')
+ {
+ $sDataDate = $oDB->getOne("select TO_CHAR(lastimportdate - '2 minutes'::interval,'YYYY/MM/DD HH24:MI')||' GMT' from import_status limit 1");
+ $sTileURL = CONST_Map_Tile_URL;
+ $sTileAttribution = CONST_Map_Tile_Attribution;
+ }
logEnd($oDB, $hLog, sizeof($aSearchResults));
$bAsText = $oGeocode->getIncludePolygonAsText();