diff --git a/lib/Geocode.php b/lib/Geocode.php
index a6ff279c..cf7dfbe6 100644
--- a/lib/Geocode.php
+++ b/lib/Geocode.php
@@ -1,4 +1,6 @@
$aResult)
{
// Default
- $fDiameter = 0.0001;
+ $fDiameter = getResultDiameter($aResult);
- if (isset($aClassType[$aResult['class'].':'.$aResult['type'].':'.$aResult['admin_level']]['defdiameter'])
- && $aClassType[$aResult['class'].':'.$aResult['type'].':'.$aResult['admin_level']]['defdiameter'])
+ $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);
+
+ $aOutlineResult = $oPlaceLookup->getOutlines($aResult['place_id'], $aResult['lon'], $aResult['lat'], $fDiameter/2);
+ foreach($aOutlineResult as $k => $v)
{
- $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;
- }
-
- $aPointPolygon = $this->oDB->getRow($sSQL);
- if (PEAR::IsError($aPointPolygon))
- {
- failInternalError("Could not get outline.", $sSQL, $aPointPolygon);
- }
-
- 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)
- {
- $aPolyPoints[] = geometryText2Points($aPointPolygon['astext'],$fRadius);
-
- // Output data suitable for display (points and a bounding box)
- if (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']);
- }
+ $aResult[$k] = $v;
}
if ($aResult['extra_place'] == 'city')
@@ -1724,32 +1659,6 @@
$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'])
diff --git a/lib/PlaceLookup.php b/lib/PlaceLookup.php
index c5129fee..04e45d5a 100644
--- a/lib/PlaceLookup.php
+++ b/lib/PlaceLookup.php
@@ -15,6 +15,14 @@
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;
@@ -46,6 +54,48 @@
}
}
+
+ 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;
@@ -219,5 +269,110 @@
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;
+ }
}
?>
diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php
index e40ce6cc..d9652764 100644
--- a/lib/ReverseGeocode.php
+++ b/lib/ReverseGeocode.php
@@ -9,6 +9,14 @@
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;
@@ -58,6 +66,48 @@
$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)';
@@ -86,7 +136,8 @@
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)';
@@ -152,7 +203,11 @@
{
$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))
{
@@ -165,7 +220,8 @@
}
return array('place_id' => $iPlaceID,
- 'type' => $bPlaceIsTiger ? 'tiger' : 'osm');
+ 'type' => $bPlaceIsTiger ? 'tiger' : 'osm');
}
+
}
?>
diff --git a/lib/lib.php b/lib/lib.php
index e81d85be..51bf7ebb 100644
--- a/lib/lib.php
+++ b/lib/lib.php
@@ -673,6 +673,31 @@
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)
{
@@ -1024,27 +1049,47 @@
}
-
- function geometryText2Points($geometry_as_text,$fRadius)
+ function geometryText2Points($geometry_as_text, $fRadius)
{
$aPolyPoints = NULL;
- if (preg_match('#POLYGON\\(\\(([- 0-9.,]+)#',$geometry_as_text,$aMatch))
+ if (preg_match('#POLYGON\\(\\(([- 0-9.,]+)#', $geometry_as_text, $aMatch))
{
- preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/',$aMatch[1],$aPolyPoints,PREG_SET_ORDER);
+ preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/', $aMatch[1], $aPolyPoints, PREG_SET_ORDER);
}
- elseif (preg_match('#MULTIPOLYGON\\(\\(\\(([- 0-9.,]+)#',$geometry_as_text,$aMatch))
+ elseif (preg_match('#LINESTRING\\(([- 0-9.,]+)#', $geometry_as_text, $aMatch))
{
- preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/',$aMatch[1],$aPolyPoints,PREG_SET_ORDER);
+ 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))
+ 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('',$aMatch[1]+($fRadius*sin($f)),$aMatch[2]+($fRadius*cos($f)));
+ $aPolyPoints[] = array('', $fLon+($fRadius*sin($f)), $fLat+($fRadius*cos($f)) );
}
- }
- return $aPolyPoints;
+ return $aPolyPoints;
}
diff --git a/lib/template/address-json.php b/lib/template/address-json.php
index d1edaf0d..6fd101bb 100644
--- a/lib/template/address-json.php
+++ b/lib/template/address-json.php
@@ -24,6 +24,38 @@
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);
diff --git a/lib/template/address-jsonv2.php b/lib/template/address-jsonv2.php
index 40c5c56d..89403875 100644
--- a/lib/template/address-jsonv2.php
+++ b/lib/template/address-jsonv2.php
@@ -36,6 +36,37 @@
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);
diff --git a/lib/template/address-xml.php b/lib/template/address-xml.php
index 39d9a147..109e66a1 100644
--- a/lib/template/address-xml.php
+++ b/lib/template/address-xml.php
@@ -27,6 +27,40 @@
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'])."";
if (isset($aPlace['aAddress']))
@@ -63,6 +97,14 @@
}
echo "";
}
+
+ if (isset($aPlace['askml']))
+ {
+ echo "\n";
+ echo $aPlace['askml'];
+ echo "";
+ }
+
}
echo "";
diff --git a/lib/template/search-json.php b/lib/template/search-json.php
index 5f29fdfb..06859919 100644
--- a/lib/template/search-json.php
+++ b/lib/template/search-json.php
@@ -18,11 +18,7 @@
if (isset($aPointDetails['aBoundingBox']))
{
- $aPlace['boundingbox'] = array(
- $aPointDetails['aBoundingBox'][0],
- $aPointDetails['aBoundingBox'][1],
- $aPointDetails['aBoundingBox'][2],
- $aPointDetails['aBoundingBox'][3]);
+ $aPlace['boundingbox'] = $aPointDetails['aBoundingBox'][0];
if (isset($aPointDetails['aPolyPoints']) && $bShowPolygons)
{
diff --git a/lib/template/search-jsonv2.php b/lib/template/search-jsonv2.php
index 66098d30..773cfd96 100644
--- a/lib/template/search-jsonv2.php
+++ b/lib/template/search-jsonv2.php
@@ -16,11 +16,7 @@
if (isset($aPointDetails['aBoundingBox']))
{
- $aPlace['boundingbox'] = array(
- $aPointDetails['aBoundingBox'][0],
- $aPointDetails['aBoundingBox'][1],
- $aPointDetails['aBoundingBox'][2],
- $aPointDetails['aBoundingBox'][3]);
+ $aPlace['boundingbox'] = $aPointDetails['aBoundingBox'];
if (isset($aPointDetails['aPolyPoints']) && $bShowPolygons)
{
diff --git a/lib/template/search-xml.php b/lib/template/search-xml.php
index b61ff22f..6a382ebf 100644
--- a/lib/template/search-xml.php
+++ b/lib/template/search-xml.php
@@ -36,10 +36,7 @@
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']))
diff --git a/tests-php/Nominatim/NominatimTest.php b/tests-php/Nominatim/NominatimTest.php
index 129fa012..d50a8da4 100644
--- a/tests-php/Nominatim/NominatimTest.php
+++ b/tests-php/Nominatim/NominatimTest.php
@@ -12,6 +12,51 @@ class NominatimTest extends \PHPUnit_Framework_TestCase
}
+ 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
@@ -142,36 +187,48 @@ class NominatimTest extends \PHPUnit_Framework_TestCase
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(
+ [10, 21],
+ [10.062790519529, 20.998026728428],
+ [10.125333233564, 20.992114701314]
),
array_splice($aPoints, 0,3)
);
@@ -179,35 +236,25 @@ class NominatimTest extends \PHPUnit_Framework_TestCase
// POLYGON
$this->assertEquals(
array(
- ['30 10', '30', '10'],
- ['40 40', '40', '40'],
- ['20 40', '20', '40'],
- ['10 20', '10', '20'],
- ['30 10', '30', '10']
+ ['30', '10'],
+ ['40', '40'],
+ ['20', '40'],
+ ['10', '20'],
+ ['30', '10']
),
geometryText2Points('POLYGON((30 10, 40 40, 20 40, 10 20, 30 10))', $fRadius)
);
// MULTIPOLYGON
- // only the first polygon is used
$this->assertEquals(
array(
- ['30 20', '30', '20'],
- ['45 40', '45', '40'],
- ['10 40', '10', '40'],
- ['30 20', '30', '20'],
-
- // ['15 5' , '15', '5' ],
- // ['45 10', '45', '10'],
- // ['10 20', '10', '20'],
- // ['5 10' , '5' , '10'],
- // ['15 5' , '15', '5' ]
+ ['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)
);
-
-
}
-
}
diff --git a/tests/features/api/reverse.feature b/tests/features/api/reverse.feature
index fa636acf..4d0c5549 100644
--- a/tests/features/api/reverse.feature
+++ b/tests/features/api/reverse.feature
@@ -61,3 +61,75 @@ Feature: Reverse geocoding
| xml
| json
| jsonv2
+
+
+ Scenario Outline: Reverse Geocoding contains TEXT geometry
+ Given the request parameters
+ | polygon_text
+ | 1
+ When looking up coordinates 48.86093,2.2978
+ Then result 0 has attributes
+
+ 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 coordinates 48.86093,2.2978
+ Then result 0 has not attributes
+
+ 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 coordinates 48.86093,2.2978
+ Then result 0 has attributes
+
+ 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 coordinates 48.86093,2.2978
+ Then result 0 has attributes
+
+ 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 coordinates 48.86093,2.2978
+ Then result 0 has attributes
+
+ Examples:
+ | format | response_attribute
+ | xml | geojson
+ | json | geojson
+ | jsonv2 | geojson
+
+
diff --git a/tests/features/api/reverse_simple.feature b/tests/features/api/reverse_simple.feature
index 8621ec65..5d79fd4b 100644
--- a/tests/features/api/reverse_simple.feature
+++ b/tests/features/api/reverse_simple.feature
@@ -17,6 +17,49 @@ Feature: Simple Reverse Tests
| -79.34 | 23.5
| 0.23 | -178.555
+ Scenario Outline: Testing different parameters
+ Given the request parameters
+ |
+ |
+ When sending search query "Manchester"
+ Then the result is valid html
+ Given the request parameters
+ |
+ |
+ When sending html search query "Manchester"
+ Then the result is valid html
+ Given the request parameters
+ |
+ |
+ When sending xml search query "Manchester"
+ Then the result is valid xml
+ Given the request parameters
+ |
+ |
+ When sending json search query "Manchester"
+ Then the result is valid json
+ Given the request parameters
+ |
+ |
+ 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
diff --git a/tests/features/api/search_params.feature b/tests/features/api/search_params.feature
index 7099c72f..fa0e63b7 100644
--- a/tests/features/api/search_params.feature
+++ b/tests/features/api/search_params.feature
@@ -230,3 +230,73 @@ Feature: Search queries
| xml
| json
| jsonv2
+
+
+ Scenario Outline: Search result with contains TEXT geometry
+ Given the request parameters
+ | polygon_text
+ | 1
+ When sending search query "switzerland"
+ Then result 0 has attributes
+
+ 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 search query "switzerland"
+ Then result 0 has attributes
+
+ 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 search query "switzerland"
+ Then result 0 has attributes
+
+ 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 search query "switzerland"
+ Then result 0 has attributes
+
+ 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 search query "switzerland"
+ Then result 0 has attributes
+
+ Examples:
+ | format | response_attribute
+ | xml | geojson
+ | json | geojson
+ | jsonv2 | geojson
diff --git a/tests/steps/api_result.py b/tests/steps/api_result.py
index 4910c157..5e1bcc90 100644
--- a/tests/steps/api_result.py
+++ b/tests/steps/api_result.py
@@ -98,6 +98,8 @@ def _parse_xml():
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:
diff --git a/website/reverse.php b/website/reverse.php
index f760dc09..ca823d3c 100755
--- a/website/reverse.php
+++ b/website/reverse.php
@@ -18,6 +18,36 @@
}
}
+
+ $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');
@@ -63,6 +93,22 @@
$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);
+
+ foreach($aOutlineResult as $k => $v)
+ {
+ $aPlace[$k] = $v;
+ }
+
}
else
{