Reverse geocode include geometry

This commit is contained in:
Marc Tobias Metten
2016-03-04 20:29:09 +01:00
parent d3ff9600b5
commit 991bd0004a
16 changed files with 699 additions and 160 deletions

View File

@@ -1,4 +1,6 @@
<?php
require_once(CONST_BasePath.'/lib/PlaceLookup.php');
class Geocode
{
protected $oDB;
@@ -1634,87 +1636,20 @@
foreach($aSearchResults as $iResNum => $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'])

View File

@@ -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;
}
}
?>

View File

@@ -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');
}
}
?>

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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'])."</result>";
if (isset($aPlace['aAddress']))
@@ -63,6 +97,14 @@
}
echo "</namedetails>";
}
if (isset($aPlace['askml']))
{
echo "\n<geokml>";
echo $aPlace['askml'];
echo "</geokml>";
}
}
echo "</reversegeocode>";

View File

@@ -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)
{

View File

@@ -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)
{

View File

@@ -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']))

View File

@@ -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)
);
}
}

View File

@@ -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 <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

View File

@@ -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
| <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

View File

@@ -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 <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

View File

@@ -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:

View File

@@ -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
{