mirror of
https://github.com/osm-search/Nominatim.git
synced 2026-02-14 01:47:57 +00:00
Merge pull request #812 from lonvia/search-as-a-class
Refactoring Search arrays
This commit is contained in:
942
lib/Geocode.php
942
lib/Geocode.php
File diff suppressed because it is too large
Load Diff
@@ -1,158 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
/**
|
||||
* A geographic point with a search radius.
|
||||
*/
|
||||
class NearPoint
|
||||
{
|
||||
private $fLat;
|
||||
private $fLon;
|
||||
private $fRadius;
|
||||
|
||||
private $sSQL;
|
||||
|
||||
|
||||
public function __construct($lat, $lon, $radius = 0.1)
|
||||
{
|
||||
$this->fLat = (float)$lat;
|
||||
$this->fLon = (float)$lon;
|
||||
$this->fRadius = (float)$radius;
|
||||
$this->sSQL = 'ST_SetSRID(ST_Point('.$this->fLon.','.$this->fLat.'),4326)';
|
||||
}
|
||||
|
||||
public function lat()
|
||||
{
|
||||
return $this->fLat;
|
||||
}
|
||||
|
||||
public function lon()
|
||||
{
|
||||
return $this->fLon;
|
||||
}
|
||||
|
||||
public function radius()
|
||||
{
|
||||
return $this->fRadius;
|
||||
}
|
||||
|
||||
public function distanceSQL($sObj)
|
||||
{
|
||||
return 'ST_Distance('.$this->sSQL.", $sObj)";
|
||||
}
|
||||
|
||||
public function withinSQL($sObj)
|
||||
{
|
||||
return sprintf('ST_DWithin(%s, %s, %F)', $sObj, $this->sSQL, $this->fRadius);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the coordinates are valid WSG84 coordinates.
|
||||
*
|
||||
* @return bool True if the coordinates are correctly bounded.
|
||||
*/
|
||||
public function isValid()
|
||||
{
|
||||
return ($this->fLat <= 90.1
|
||||
&& $this->fLat >= -90.1
|
||||
&& $this->fLon <= 180.1
|
||||
&& $this->fLon >= -180.1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a coordinate point from a query string.
|
||||
*
|
||||
* If a coordinate is found an array of a new NearPoint and the
|
||||
* remaining query is returned or false otherwise.
|
||||
*
|
||||
* @param string $sQuery Query to scan.
|
||||
*
|
||||
* @return array|false If a coordinate was found, an array with
|
||||
* `pt` as the NearPoint coordinates and `query`
|
||||
* with the remaining query string. False otherwiese.
|
||||
*/
|
||||
public static function extractFromQuery($sQuery)
|
||||
{
|
||||
// Do we have anything that looks like a lat/lon pair?
|
||||
// returns array(lat,lon,query_with_lat_lon_removed)
|
||||
// or null
|
||||
$sFound = null;
|
||||
$fQueryLat = null;
|
||||
$fQueryLon = null;
|
||||
|
||||
if (preg_match('/\\s*([NS])[ ]+([0-9]+[0-9.]*)[° ]+([0-9.]+)?[′\']*[, ]+([EW])[ ]+([0-9]+)[° ]+([0-9]+[0-9.]*)[′\']*\\s*/', $sQuery, $aData)) {
|
||||
/* 1 2 3 4 5 6
|
||||
* degrees decimal minutes
|
||||
* N 40 26.767, W 79 58.933
|
||||
* N 40°26.767′, W 79°58.933′
|
||||
*/
|
||||
$sFound = $aData[0];
|
||||
$fQueryLat = ($aData[1]=='N'?1:-1) * ($aData[2] + $aData[3]/60);
|
||||
$fQueryLon = ($aData[4]=='E'?1:-1) * ($aData[5] + $aData[6]/60);
|
||||
} elseif (preg_match('/\\s*([0-9]+)[° ]+([0-9]+[0-9.]*)?[′\']*[ ]+([NS])[, ]+([0-9]+)[° ]+([0-9]+[0-9.]*)?[′\' ]+([EW])\\s*/', $sQuery, $aData)) {
|
||||
/* 1 2 3 4 5 6
|
||||
* degrees decimal minutes
|
||||
* 40 26.767 N, 79 58.933 W
|
||||
* 40° 26.767′ N 79° 58.933′ W
|
||||
*/
|
||||
$sFound = $aData[0];
|
||||
$fQueryLat = ($aData[3]=='N'?1:-1) * ($aData[1] + $aData[2]/60);
|
||||
$fQueryLon = ($aData[6]=='E'?1:-1) * ($aData[4] + $aData[5]/60);
|
||||
} elseif (preg_match('/\\s*([NS])[ ]([0-9]+)[° ]+([0-9]+)[′\' ]+([0-9]+)[″"]*[, ]+([EW])[ ]([0-9]+)[° ]+([0-9]+)[′\' ]+([0-9]+)[″"]*\\s*/', $sQuery, $aData)) {
|
||||
/* 1 2 3 4 5 6 7 8
|
||||
* degrees decimal seconds
|
||||
* N 40 26 46 W 79 58 56
|
||||
* N 40° 26′ 46″, W 79° 58′ 56″
|
||||
*/
|
||||
$sFound = $aData[0];
|
||||
$fQueryLat = ($aData[1]=='N'?1:-1) * ($aData[2] + $aData[3]/60 + $aData[4]/3600);
|
||||
$fQueryLon = ($aData[5]=='E'?1:-1) * ($aData[6] + $aData[7]/60 + $aData[8]/3600);
|
||||
} elseif (preg_match('/\\s*([0-9]+)[° ]+([0-9]+)[′\' ]+([0-9]+)[″" ]+([NS])[, ]+([0-9]+)[° ]+([0-9]+)[′\' ]+([0-9]+)[″" ]+([EW])\\s*/', $sQuery, $aData)) {
|
||||
/* 1 2 3 4 5 6 7 8
|
||||
* degrees decimal seconds
|
||||
* 40 26 46 N 79 58 56 W
|
||||
* 40° 26′ 46″ N, 79° 58′ 56″ W
|
||||
*/
|
||||
$sFound = $aData[0];
|
||||
$fQueryLat = ($aData[4]=='N'?1:-1) * ($aData[1] + $aData[2]/60 + $aData[3]/3600);
|
||||
$fQueryLon = ($aData[8]=='E'?1:-1) * ($aData[5] + $aData[6]/60 + $aData[7]/3600);
|
||||
} elseif (preg_match('/\\s*([NS])[ ]([0-9]+[0-9]*\\.[0-9]+)[°]*[, ]+([EW])[ ]([0-9]+[0-9]*\\.[0-9]+)[°]*\\s*/', $sQuery, $aData)) {
|
||||
/* 1 2 3 4
|
||||
* degrees decimal
|
||||
* N 40.446° W 79.982°
|
||||
*/
|
||||
$sFound = $aData[0];
|
||||
$fQueryLat = ($aData[1]=='N'?1:-1) * ($aData[2]);
|
||||
$fQueryLon = ($aData[3]=='E'?1:-1) * ($aData[4]);
|
||||
} elseif (preg_match('/\\s*([0-9]+[0-9]*\\.[0-9]+)[° ]+([NS])[, ]+([0-9]+[0-9]*\\.[0-9]+)[° ]+([EW])\\s*/', $sQuery, $aData)) {
|
||||
/* 1 2 3 4
|
||||
* degrees decimal
|
||||
* 40.446° N 79.982° W
|
||||
*/
|
||||
$sFound = $aData[0];
|
||||
$fQueryLat = ($aData[2]=='N'?1:-1) * ($aData[1]);
|
||||
$fQueryLon = ($aData[4]=='E'?1:-1) * ($aData[3]);
|
||||
} elseif (preg_match('/(\\s*\\[|^\\s*|\\s*)(-?[0-9]+[0-9]*\\.[0-9]+)[, ]+(-?[0-9]+[0-9]*\\.[0-9]+)(\\]\\s*|\\s*$|\\s*)/', $sQuery, $aData)) {
|
||||
/* 1 2 3 4
|
||||
* degrees decimal
|
||||
* 12.34, 56.78
|
||||
* 12.34 56.78
|
||||
* [12.456,-78.90]
|
||||
*/
|
||||
$sFound = $aData[0];
|
||||
$fQueryLat = $aData[2];
|
||||
$fQueryLon = $aData[3];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
$oPt = new NearPoint($fQueryLat, $fQueryLon);
|
||||
|
||||
if (!$oPt->isValid()) return false;
|
||||
|
||||
$sQuery = trim(str_replace($sFound, ' ', $sQuery));
|
||||
|
||||
return array('pt' => $oPt, 'query' => $sQuery);
|
||||
}
|
||||
}
|
||||
@@ -66,15 +66,22 @@ class ReverseGeocode
|
||||
);
|
||||
}
|
||||
|
||||
public function lookup($fLat, $fLon, $bDoInterpolation = true)
|
||||
{
|
||||
return $this->lookupPoint(
|
||||
'ST_SetSRID(ST_Point('.$fLon.','.$fLat.'),4326)',
|
||||
$bDoInterpolation
|
||||
);
|
||||
}
|
||||
|
||||
/* lookup()
|
||||
* returns { place_id =>, type => '(osm|tiger)' }
|
||||
* fails if no place was found
|
||||
*/
|
||||
|
||||
|
||||
public function lookup($fLat, $fLon, $bDoInterpolation = true)
|
||||
public function lookupPoint($sPointSQL, $bDoInterpolation = true)
|
||||
{
|
||||
$sPointSQL = 'ST_SetSRID(ST_Point('.$fLon.','.$fLat.'),4326)';
|
||||
$iMaxRank = $this->iMaxRank;
|
||||
|
||||
// Find the nearest point
|
||||
|
||||
270
lib/SearchContext.php
Normal file
270
lib/SearchContext.php
Normal file
@@ -0,0 +1,270 @@
|
||||
<?php
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
require_once(CONST_BasePath.'/lib/lib.php');
|
||||
|
||||
|
||||
/**
|
||||
* Collection of search constraints that are independent of the
|
||||
* actual interpretation of the search query.
|
||||
*
|
||||
* The search context is shared between all SearchDescriptions. This
|
||||
* object mainly serves as context provider for the database queries.
|
||||
* Therefore most data is directly cached as SQL statements.
|
||||
*/
|
||||
class SearchContext
|
||||
{
|
||||
/// Search radius around a given Near reference point.
|
||||
private $fNearRadius = false;
|
||||
/// True if search must be restricted to viewbox only.
|
||||
public $bViewboxBounded = false;
|
||||
|
||||
/// Reference point for search (as SQL).
|
||||
public $sqlNear = '';
|
||||
/// Viewbox selected for search (as SQL).
|
||||
public $sqlViewboxSmall = '';
|
||||
/// Viewbox with a larger buffer around (as SQL).
|
||||
public $sqlViewboxLarge = '';
|
||||
/// Reference along a route (as SQL).
|
||||
public $sqlViewboxCentre = '';
|
||||
/// List of countries to restrict search to (as SQL).
|
||||
public $sqlCountryList = '';
|
||||
/// List of place IDs to exclude (as SQL).
|
||||
private $sqlExcludeList = '';
|
||||
|
||||
|
||||
/**
|
||||
* Check if a reference point is defined.
|
||||
*
|
||||
* @return bool True if a reference point is defined.
|
||||
*/
|
||||
public function hasNearPoint()
|
||||
{
|
||||
return $this->fNearRadius !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get radius around reference point.
|
||||
*
|
||||
* @return float Search radius around refernce point.
|
||||
*/
|
||||
public function nearRadius()
|
||||
{
|
||||
return $this->fNearRadius;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set search reference point in WGS84.
|
||||
*
|
||||
* If set, then only places around this point will be taken into account.
|
||||
*
|
||||
* @param float $fLat Latitude of point.
|
||||
* @param float $fLon Longitude of point.
|
||||
* @param float $fRadius Search radius around point.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setNearPoint($fLat, $fLon, $fRadius = 0.1)
|
||||
{
|
||||
$this->fNearRadius = $fRadius;
|
||||
$this->sqlNear = 'ST_SetSRID(ST_Point('.$fLon.','.$fLat.'),4326)';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the search is geographically restricted.
|
||||
*
|
||||
* Searches are restricted if a reference point is given or if
|
||||
* a bounded viewbox is set.
|
||||
*
|
||||
* @return bool True, if the search is geographically bounded.
|
||||
*/
|
||||
public function isBoundedSearch()
|
||||
{
|
||||
return $this->hasNearPoint() || ($this->sqlViewboxSmall && $this->bViewboxBounded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set rectangular viewbox.
|
||||
*
|
||||
* The viewbox may be bounded which means that no search results
|
||||
* must be outside the viewbox.
|
||||
*
|
||||
* @param float[4] $aViewBox Coordinates of the viewbox.
|
||||
* @param bool $bBounded True if the viewbox is bounded.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setViewboxFromBox(&$aViewBox, $bBounded)
|
||||
{
|
||||
$this->bViewboxBounded = $bBounded;
|
||||
$this->sqlViewboxCentre = '';
|
||||
|
||||
$this->sqlViewboxSmall = sprintf(
|
||||
'ST_SetSRID(ST_MakeBox2D(ST_Point(%F,%F),ST_Point(%F,%F)),4326)',
|
||||
$aViewBox[0],
|
||||
$aViewBox[1],
|
||||
$aViewBox[2],
|
||||
$aViewBox[3]
|
||||
);
|
||||
|
||||
$fHeight = $aViewBox[0] - $aViewBox[2];
|
||||
$fWidth = $aViewBox[1] - $aViewBox[3];
|
||||
|
||||
$this->sqlViewboxLarge = sprintf(
|
||||
'ST_SetSRID(ST_MakeBox2D(ST_Point(%F,%F),ST_Point(%F,%F)),4326)',
|
||||
max($aViewBox[0], $aViewBox[2]) + $fHeight,
|
||||
max($aViewBox[1], $aViewBox[3]) + $fWidth,
|
||||
min($aViewBox[0], $aViewBox[2]) - $fHeight,
|
||||
min($aViewBox[1], $aViewBox[3]) - $fWidth
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set viewbox along a route.
|
||||
*
|
||||
* The viewbox may be bounded which means that no search results
|
||||
* must be outside the viewbox.
|
||||
*
|
||||
* @param object $oDB DB connection to use for computing the box.
|
||||
* @param string[] $aRoutePoints List of x,y coordinates along a route.
|
||||
* @param float $fRouteWidth Buffer around the route to use.
|
||||
* @param bool $bBounded True if the viewbox bounded.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setViewboxFromRoute(&$oDB, $aRoutePoints, $fRouteWidth, $bBounded)
|
||||
{
|
||||
$this->bViewboxBounded = $bBounded;
|
||||
$this->sqlViewboxCentre = "ST_SetSRID('LINESTRING(";
|
||||
$sSep = '';
|
||||
foreach ($aRoutePoints as $aPoint) {
|
||||
$fPoint = (float)$aPoint;
|
||||
$this->sqlViewboxCentre .= $sSep.$fPoint;
|
||||
$sSep = ($sSep == ' ') ? ',' : ' ';
|
||||
}
|
||||
$this->sqlViewboxCentre .= ")'::geometry,4326)";
|
||||
|
||||
$sSQL = 'ST_BUFFER('.$this->sqlViewboxCentre.','.($fRouteWidth/69).')';
|
||||
$sGeom = chksql($oDB->getOne("select ".$sSQL), "Could not get small viewbox");
|
||||
$this->sqlViewboxSmall = "'".$sGeom."'::geometry";
|
||||
|
||||
$sSQL = 'ST_BUFFER('.$this->sqlViewboxCentre.','.($fRouteWidth/30).')';
|
||||
$sGeom = chksql($oDB->getOne("select ".$sSQL), "Could not get large viewbox");
|
||||
$this->sqlViewboxLarge = "'".$sGeom."'::geometry";
|
||||
}
|
||||
|
||||
/**
|
||||
* Set list of excluded place IDs.
|
||||
*
|
||||
* @param integer[] $aExcluded List of IDs.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setExcludeList($aExcluded)
|
||||
{
|
||||
$this->sqlExcludeList = ' not in ('.join(',', $aExcluded).')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set list of countries to restrict search to.
|
||||
*
|
||||
* @param string[] $aCountries List of two-letter lower-case country codes.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setCountryList($aCountries)
|
||||
{
|
||||
$this->sqlCountryList = '('.join(',', array_map('addQuotes', $aCountries)).')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a reference point from a query string.
|
||||
*
|
||||
* @param string $sQuery Query to scan.
|
||||
*
|
||||
* @return string The remaining query string.
|
||||
*/
|
||||
public function setNearPointFromQuery($sQuery)
|
||||
{
|
||||
$aResult = parseLatLon($sQuery);
|
||||
|
||||
if ($aResult !== false
|
||||
&& $aResult[1] <= 90.1
|
||||
&& $aResult[1] >= -90.1
|
||||
&& $aResult[2] <= 180.1
|
||||
&& $aResult[2] >= -180.1
|
||||
) {
|
||||
$this->setNearPoint($aResult[1], $aResult[2]);
|
||||
$sQuery = trim(str_replace($aResult[0], ' ', $sQuery));
|
||||
}
|
||||
|
||||
return $sQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an SQL snipped for computing the distance from the reference point.
|
||||
*
|
||||
* @param string $sObj SQL variable name to compute the distance from.
|
||||
*
|
||||
* @return string An SQL string.
|
||||
*/
|
||||
public function distanceSQL($sObj)
|
||||
{
|
||||
return 'ST_Distance('.$this->sqlNear.", $sObj)";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an SQL snipped for checking if something is within range of the
|
||||
* reference point.
|
||||
*
|
||||
* @param string $sObj SQL variable name to compute if it is within range.
|
||||
*
|
||||
* @return string An SQL string.
|
||||
*/
|
||||
public function withinSQL($sObj)
|
||||
{
|
||||
return sprintf('ST_DWithin(%s, %s, %F)', $sObj, $this->sqlNear, $this->fNearRadius);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an SQL snipped of the importance factor of the viewbox.
|
||||
*
|
||||
* The importance factor is computed by checking if an object is within
|
||||
* the viewbox and/or the extended version of the viewbox.
|
||||
*
|
||||
* @param string $sObj SQL variable name of object to weight the importance
|
||||
*
|
||||
* @return string SQL snipped of the factor with a leading multiply sign.
|
||||
*/
|
||||
public function viewboxImportanceSQL($sObj)
|
||||
{
|
||||
$sSQL = '';
|
||||
|
||||
if ($this->sqlViewboxSmall) {
|
||||
$sSQL = " * CASE WHEN ST_Contains($this->sqlViewboxSmall, $sObj) THEN 1 ELSE 0.5 END";
|
||||
}
|
||||
if ($this->sqlViewboxLarge) {
|
||||
$sSQL = " * CASE WHEN ST_Contains($this->sqlViewboxLarge, $sObj) THEN 1 ELSE 0.5 END";
|
||||
}
|
||||
|
||||
return $sSQL;
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL snipped checking if a place ID should be excluded.
|
||||
*
|
||||
* @param string $sVariable SQL variable name of place ID to check,
|
||||
* potentially prefixed with more SQL.
|
||||
*
|
||||
* @return string SQL snippet.
|
||||
*/
|
||||
public function excludeSQL($sVariable)
|
||||
{
|
||||
if ($this->sqlExcludeList) {
|
||||
return $sVariable.$this->sqlExcludeList;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
1020
lib/SearchDescription.php
Normal file
1020
lib/SearchDescription.php
Normal file
File diff suppressed because it is too large
Load Diff
44
lib/SpecialSearchOperator.php
Normal file
44
lib/SpecialSearchOperator.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
/**
|
||||
* Operators describing special searches.
|
||||
*/
|
||||
abstract class Operator
|
||||
{
|
||||
/// No operator selected.
|
||||
const NONE = 0;
|
||||
/// Search for POI of the given type.
|
||||
const TYPE = 1;
|
||||
/// Search for POIs near the given place.
|
||||
const NEAR = 2;
|
||||
/// Search for POIS in the given place.
|
||||
const IN = 3;
|
||||
/// Search for POIS named as given.
|
||||
const NAME = 4;
|
||||
/// Search for postcodes.
|
||||
const POSTCODE = 5;
|
||||
|
||||
private static $aConstantNames = null;
|
||||
|
||||
|
||||
public static function toString($iOperator)
|
||||
{
|
||||
if ($iOperator == Operator::NONE) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (Operator::$aConstantNames === null) {
|
||||
$oReflector = new \ReflectionClass('Nominatim\Operator');
|
||||
$aConstants = $oReflector->getConstants();
|
||||
|
||||
Operator::$aConstantNames = array();
|
||||
foreach ($aConstants as $sName => $iValue) {
|
||||
Operator::$aConstantNames[$iValue] = $sName;
|
||||
}
|
||||
}
|
||||
|
||||
return Operator::$aConstantNames[$iOperator];
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,11 @@ function getDBQuoted($s)
|
||||
return "'".pg_escape_string($s)."'";
|
||||
}
|
||||
|
||||
function getArraySQL($a)
|
||||
{
|
||||
return 'ARRAY['.join(',', $a).']';
|
||||
}
|
||||
|
||||
function getPostgresVersion(&$oDB)
|
||||
{
|
||||
$sVersionString = $oDB->getOne('select version()');
|
||||
|
||||
145
lib/lib.php
145
lib/lib.php
@@ -51,14 +51,6 @@ function getDatabaseDate(&$oDB)
|
||||
}
|
||||
|
||||
|
||||
function bySearchRank($a, $b)
|
||||
{
|
||||
if ($a['iSearchRank'] == $b['iSearchRank'])
|
||||
return strlen($a['sOperator']) + strlen($a['sHouseNumber']) - strlen($b['sOperator']) - strlen($b['sHouseNumber']);
|
||||
return ($a['iSearchRank'] < $b['iSearchRank']?-1:1);
|
||||
}
|
||||
|
||||
|
||||
function byImportance($a, $b)
|
||||
{
|
||||
if ($a['importance'] != $b['importance'])
|
||||
@@ -489,71 +481,19 @@ function _debugDumpGroupedSearches($aData, $aTokens)
|
||||
foreach ($aTokens as $sToken => $aWords) {
|
||||
if ($aWords) {
|
||||
foreach ($aWords as $aToken) {
|
||||
$aWordsIDs[$aToken['word_id']] = $sToken.'('.$aToken['word_id'].')';
|
||||
$aWordsIDs[$aToken['word_id']] =
|
||||
'#'.$sToken.'('.$aToken['word_id'].')#';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
echo "<table border=\"1\">";
|
||||
echo "<tr><th>rank</th><th>Name Tokens</th><th>Name Not</th>";
|
||||
echo "<th>Address Tokens</th><th>Address Not</th><th>country</th>";
|
||||
echo "<th>operator</th><th>class</th><th>type</th><th>postcode</th><th>house#</th>";
|
||||
echo "<th>Lat</th><th>Lon</th><th>Radius</th></tr>";
|
||||
echo "<th>Address Tokens</th><th>Address Not</th><th>country</th><th>operator</th>";
|
||||
echo "<th>class</th><th>type</th><th>postcode</th><th>housenumber</th></tr>";
|
||||
foreach ($aData as $iRank => $aRankedSet) {
|
||||
foreach ($aRankedSet as $aRow) {
|
||||
echo "<tr>";
|
||||
echo "<td>$iRank</td>";
|
||||
|
||||
echo "<td>";
|
||||
$sSep = '';
|
||||
foreach ($aRow['aName'] as $iWordID) {
|
||||
echo $sSep.'#'.$aWordsIDs[$iWordID].'#';
|
||||
$sSep = ', ';
|
||||
}
|
||||
echo "</td>";
|
||||
|
||||
echo "<td>";
|
||||
$sSep = '';
|
||||
foreach ($aRow['aNameNonSearch'] as $iWordID) {
|
||||
echo $sSep.'#'.$aWordsIDs[$iWordID].'#';
|
||||
$sSep = ', ';
|
||||
}
|
||||
echo "</td>";
|
||||
|
||||
echo "<td>";
|
||||
$sSep = '';
|
||||
foreach ($aRow['aAddress'] as $iWordID) {
|
||||
echo $sSep.'#'.$aWordsIDs[$iWordID].'#';
|
||||
$sSep = ', ';
|
||||
}
|
||||
echo "</td>";
|
||||
|
||||
echo "<td>";
|
||||
$sSep = '';
|
||||
foreach ($aRow['aAddressNonSearch'] as $iWordID) {
|
||||
echo $sSep.'#'.$aWordsIDs[$iWordID].'#';
|
||||
$sSep = ', ';
|
||||
}
|
||||
echo "</td>";
|
||||
|
||||
echo "<td>".$aRow['sCountryCode']."</td>";
|
||||
|
||||
echo "<td>".$aRow['sOperator']."</td>";
|
||||
echo "<td>".$aRow['sClass']."</td>";
|
||||
echo "<td>".$aRow['sType']."</td>";
|
||||
|
||||
echo "<td>".$aRow['sPostcode']."</td>";
|
||||
echo "<td>".$aRow['sHouseNumber']."</td>";
|
||||
|
||||
if ($aRow['oNear']) {
|
||||
echo "<td>".$aRow['oNear']->lat()."</td>";
|
||||
echo "<td>".$aRow['oNear']->lon()."</td>";
|
||||
echo "<td>".$aRow['oNear']->radius()."</td>";
|
||||
} else {
|
||||
echo "<td></td><td></td><td></td>";
|
||||
}
|
||||
|
||||
echo "</tr>";
|
||||
$aRow->dumpAsHtmlTableRow($aWordsIDs);
|
||||
}
|
||||
}
|
||||
echo "</table>";
|
||||
@@ -605,6 +545,81 @@ function addQuotes($s)
|
||||
return "'".$s."'";
|
||||
}
|
||||
|
||||
function parseLatLon($sQuery)
|
||||
{
|
||||
$sFound = null;
|
||||
$fQueryLat = null;
|
||||
$fQueryLon = null;
|
||||
|
||||
if (preg_match('/\\s*([NS])[ ]+([0-9]+[0-9.]*)[° ]+([0-9.]+)?[′\']*[, ]+([EW])[ ]+([0-9]+)[° ]+([0-9]+[0-9.]*)[′\']*\\s*/', $sQuery, $aData)) {
|
||||
/* 1 2 3 4 5 6
|
||||
* degrees decimal minutes
|
||||
* N 40 26.767, W 79 58.933
|
||||
* N 40°26.767′, W 79°58.933′
|
||||
*/
|
||||
$sFound = $aData[0];
|
||||
$fQueryLat = ($aData[1]=='N'?1:-1) * ($aData[2] + $aData[3]/60);
|
||||
$fQueryLon = ($aData[4]=='E'?1:-1) * ($aData[5] + $aData[6]/60);
|
||||
} elseif (preg_match('/\\s*([0-9]+)[° ]+([0-9]+[0-9.]*)?[′\']*[ ]+([NS])[, ]+([0-9]+)[° ]+([0-9]+[0-9.]*)?[′\' ]+([EW])\\s*/', $sQuery, $aData)) {
|
||||
/* 1 2 3 4 5 6
|
||||
* degrees decimal minutes
|
||||
* 40 26.767 N, 79 58.933 W
|
||||
* 40° 26.767′ N 79° 58.933′ W
|
||||
*/
|
||||
$sFound = $aData[0];
|
||||
$fQueryLat = ($aData[3]=='N'?1:-1) * ($aData[1] + $aData[2]/60);
|
||||
$fQueryLon = ($aData[6]=='E'?1:-1) * ($aData[4] + $aData[5]/60);
|
||||
} elseif (preg_match('/\\s*([NS])[ ]([0-9]+)[° ]+([0-9]+)[′\' ]+([0-9]+)[″"]*[, ]+([EW])[ ]([0-9]+)[° ]+([0-9]+)[′\' ]+([0-9]+)[″"]*\\s*/', $sQuery, $aData)) {
|
||||
/* 1 2 3 4 5 6 7 8
|
||||
* degrees decimal seconds
|
||||
* N 40 26 46 W 79 58 56
|
||||
* N 40° 26′ 46″, W 79° 58′ 56″
|
||||
*/
|
||||
$sFound = $aData[0];
|
||||
$fQueryLat = ($aData[1]=='N'?1:-1) * ($aData[2] + $aData[3]/60 + $aData[4]/3600);
|
||||
$fQueryLon = ($aData[5]=='E'?1:-1) * ($aData[6] + $aData[7]/60 + $aData[8]/3600);
|
||||
} elseif (preg_match('/\\s*([0-9]+)[° ]+([0-9]+)[′\' ]+([0-9]+)[″" ]+([NS])[, ]+([0-9]+)[° ]+([0-9]+)[′\' ]+([0-9]+)[″" ]+([EW])\\s*/', $sQuery, $aData)) {
|
||||
/* 1 2 3 4 5 6 7 8
|
||||
* degrees decimal seconds
|
||||
* 40 26 46 N 79 58 56 W
|
||||
* 40° 26′ 46″ N, 79° 58′ 56″ W
|
||||
*/
|
||||
$sFound = $aData[0];
|
||||
$fQueryLat = ($aData[4]=='N'?1:-1) * ($aData[1] + $aData[2]/60 + $aData[3]/3600);
|
||||
$fQueryLon = ($aData[8]=='E'?1:-1) * ($aData[5] + $aData[6]/60 + $aData[7]/3600);
|
||||
} elseif (preg_match('/\\s*([NS])[ ]([0-9]+[0-9]*\\.[0-9]+)[°]*[, ]+([EW])[ ]([0-9]+[0-9]*\\.[0-9]+)[°]*\\s*/', $sQuery, $aData)) {
|
||||
/* 1 2 3 4
|
||||
* degrees decimal
|
||||
* N 40.446° W 79.982°
|
||||
*/
|
||||
$sFound = $aData[0];
|
||||
$fQueryLat = ($aData[1]=='N'?1:-1) * ($aData[2]);
|
||||
$fQueryLon = ($aData[3]=='E'?1:-1) * ($aData[4]);
|
||||
} elseif (preg_match('/\\s*([0-9]+[0-9]*\\.[0-9]+)[° ]+([NS])[, ]+([0-9]+[0-9]*\\.[0-9]+)[° ]+([EW])\\s*/', $sQuery, $aData)) {
|
||||
/* 1 2 3 4
|
||||
* degrees decimal
|
||||
* 40.446° N 79.982° W
|
||||
*/
|
||||
$sFound = $aData[0];
|
||||
$fQueryLat = ($aData[2]=='N'?1:-1) * ($aData[1]);
|
||||
$fQueryLon = ($aData[4]=='E'?1:-1) * ($aData[3]);
|
||||
} elseif (preg_match('/(\\s*\\[|^\\s*|\\s*)(-?[0-9]+[0-9]*\\.[0-9]+)[, ]+(-?[0-9]+[0-9]*\\.[0-9]+)(\\]\\s*|\\s*$|\\s*)/', $sQuery, $aData)) {
|
||||
/* 1 2 3 4
|
||||
* degrees decimal
|
||||
* 12.34, 56.78
|
||||
* 12.34 56.78
|
||||
* [12.456,-78.90]
|
||||
*/
|
||||
$sFound = $aData[0];
|
||||
$fQueryLat = $aData[2];
|
||||
$fQueryLon = $aData[3];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return array($sFound, $fQueryLat, $fQueryLon);
|
||||
}
|
||||
|
||||
|
||||
function geometryText2Points($geometry_as_text, $fRadius)
|
||||
{
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
|
||||
<rule ref="Generic.Files.LineLength">
|
||||
<properties>
|
||||
<property name="lineLimit" value="199"/>
|
||||
<property name="absoluteLineLimit" value="199"/>
|
||||
<property name="lineLimit" value="194"/>
|
||||
<property name="absoluteLineLimit" value="194"/>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
require '../../lib/NearPoint.php';
|
||||
|
||||
class NearPointTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
}
|
||||
|
||||
public function testExtractFromQuery()
|
||||
{
|
||||
// no coordinates expected
|
||||
$this->assertFalse(NearPoint::extractFromQuery(''));
|
||||
$this->assertFalse(NearPoint::extractFromQuery('abc'));
|
||||
$this->assertFalse(NearPoint::extractFromQuery('12 34'));
|
||||
$this->assertFalse(NearPoint::extractFromQuery('200.1 89.9')); // because latitude > 180
|
||||
|
||||
// coordinates expected
|
||||
$this->assertNotNull(NearPoint::extractFromQuery('0.0 -0.0'));
|
||||
|
||||
$aRes = NearPoint::extractFromQuery(' abc 12.456 -78.90 def ');
|
||||
$this->assertEquals($aRes['pt']->lat(), 12.456);
|
||||
$this->assertEquals($aRes['pt']->lon(), -78.90);
|
||||
$this->assertEquals($aRes['pt']->radius(), 0.1);
|
||||
$this->assertEquals($aRes['query'], 'abc def');
|
||||
|
||||
$aRes = NearPoint::extractFromQuery(' [12.456,-78.90] ');
|
||||
$this->assertEquals($aRes['pt']->lat(), 12.456);
|
||||
$this->assertEquals($aRes['pt']->lon(), -78.90);
|
||||
$this->assertEquals($aRes['pt']->radius(), 0.1);
|
||||
$this->assertEquals($aRes['query'], '');
|
||||
|
||||
$aRes = NearPoint::extractFromQuery(' -12.456,-78.90 ');
|
||||
$this->assertEquals($aRes['pt']->lat(), -12.456);
|
||||
$this->assertEquals($aRes['pt']->lon(), -78.90);
|
||||
|
||||
// http://en.wikipedia.org/wiki/Geographic_coordinate_conversion
|
||||
// these all represent the same location
|
||||
$aQueries = array(
|
||||
'40 26.767 N 79 58.933 W',
|
||||
'40° 26.767′ N 79° 58.933′ W',
|
||||
"40° 26.767' N 79° 58.933' W",
|
||||
'N 40 26.767, W 79 58.933',
|
||||
'N 40°26.767′, W 79°58.933′',
|
||||
"N 40°26.767', W 79°58.933'",
|
||||
|
||||
'40 26 46 N 79 58 56 W',
|
||||
'40° 26′ 46″ N 79° 58′ 56″ W',
|
||||
'N 40 26 46 W 79 58 56',
|
||||
'N 40° 26′ 46″, W 79° 58′ 56″',
|
||||
'N 40° 26\' 46", W 79° 58\' 56"',
|
||||
|
||||
'40.446 -79.982',
|
||||
'40.446,-79.982',
|
||||
'40.446° N 79.982° W',
|
||||
'N 40.446° W 79.982°',
|
||||
|
||||
'[40.446 -79.982]',
|
||||
' 40.446 , -79.982 ',
|
||||
);
|
||||
|
||||
|
||||
foreach ($aQueries as $sQuery) {
|
||||
$aRes = NearPoint::extractFromQuery($sQuery);
|
||||
$this->assertEquals(40.446, $aRes['pt']->lat(), 'degrees decimal ' . $sQuery, 0.01);
|
||||
$this->assertEquals(-79.982, $aRes['pt']->lon(), 'degrees decimal ' . $sQuery, 0.01);
|
||||
$this->assertEquals('', $aRes['query']);
|
||||
}
|
||||
}
|
||||
|
||||
public function testWithinSQL()
|
||||
{
|
||||
$np = new NearPoint(0.1, 23, 1);
|
||||
|
||||
$this->assertEquals(
|
||||
'ST_DWithin(foo, ST_SetSRID(ST_Point(23,0.1),4326), 1.000000)',
|
||||
$np->withinSQL('foo')
|
||||
);
|
||||
}
|
||||
|
||||
public function testDistanceSQL()
|
||||
{
|
||||
$np = new NearPoint(0.1, 23, 1);
|
||||
|
||||
$this->assertEquals(
|
||||
'ST_Distance(ST_SetSRID(ST_Point(23,0.1),4326), foo)',
|
||||
$np->distanceSQL('foo')
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
require '../../lib/lib.php';
|
||||
require_once '../../lib/lib.php';
|
||||
|
||||
class NominatimTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
@@ -203,4 +203,63 @@ class NominatimTest extends \PHPUnit_Framework_TestCase
|
||||
geometryText2Points('MULTIPOLYGON(((30 20, 45 40, 10 40, 30 20)),((15 5, 40 10, 10 20, 5 10, 15 5)))', $fRadius)
|
||||
);
|
||||
}
|
||||
|
||||
public function testParseLatLon()
|
||||
{
|
||||
// no coordinates expected
|
||||
$this->assertFalse(parseLatLon(''));
|
||||
$this->assertFalse(parseLatLon('abc'));
|
||||
$this->assertFalse(parseLatLon('12 34'));
|
||||
|
||||
// coordinates expected
|
||||
$this->assertNotNull(parseLatLon('0.0 -0.0'));
|
||||
|
||||
$aRes = parseLatLon(' abc 12.456 -78.90 def ');
|
||||
$this->assertEquals($aRes[1], 12.456);
|
||||
$this->assertEquals($aRes[2], -78.90);
|
||||
$this->assertEquals($aRes[0], ' 12.456 -78.90 ');
|
||||
|
||||
$aRes = parseLatLon(' [12.456,-78.90] ');
|
||||
$this->assertEquals($aRes[1], 12.456);
|
||||
$this->assertEquals($aRes[2], -78.90);
|
||||
$this->assertEquals($aRes[0], ' [12.456,-78.90] ');
|
||||
|
||||
$aRes = parseLatLon(' -12.456,-78.90 ');
|
||||
$this->assertEquals($aRes[1], -12.456);
|
||||
$this->assertEquals($aRes[2], -78.90);
|
||||
$this->assertEquals($aRes[0], ' -12.456,-78.90 ');
|
||||
|
||||
// http://en.wikipedia.org/wiki/Geographic_coordinate_conversion
|
||||
// these all represent the same location
|
||||
$aQueries = array(
|
||||
'40 26.767 N 79 58.933 W',
|
||||
'40° 26.767′ N 79° 58.933′ W',
|
||||
"40° 26.767' N 79° 58.933' W",
|
||||
'N 40 26.767, W 79 58.933',
|
||||
'N 40°26.767′, W 79°58.933′',
|
||||
"N 40°26.767', W 79°58.933'",
|
||||
|
||||
'40 26 46 N 79 58 56 W',
|
||||
'40° 26′ 46″ N 79° 58′ 56″ W',
|
||||
'N 40 26 46 W 79 58 56',
|
||||
'N 40° 26′ 46″, W 79° 58′ 56″',
|
||||
'N 40° 26\' 46", W 79° 58\' 56"',
|
||||
|
||||
'40.446 -79.982',
|
||||
'40.446,-79.982',
|
||||
'40.446° N 79.982° W',
|
||||
'N 40.446° W 79.982°',
|
||||
|
||||
'[40.446 -79.982]',
|
||||
' 40.446 , -79.982 ',
|
||||
);
|
||||
|
||||
|
||||
foreach ($aQueries as $sQuery) {
|
||||
$aRes = parseLatLon($sQuery);
|
||||
$this->assertEquals(40.446, $aRes[1], 'degrees decimal ' . $sQuery, 0.01);
|
||||
$this->assertEquals(-79.982, $aRes[2], 'degrees decimal ' . $sQuery, 0.01);
|
||||
$this->assertEquals($sQuery, $aRes[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
52
test/php/Nominatim/SearchContextTest.php
Normal file
52
test/php/Nominatim/SearchContextTest.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
@define('CONST_BasePath', '../../');
|
||||
|
||||
require_once '../../lib/SearchContext.php';
|
||||
|
||||
class SearchContextTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
private $oCtx;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->oCtx = new SearchContext();
|
||||
}
|
||||
|
||||
public function testHasNearPoint()
|
||||
{
|
||||
$this->assertFalse($this->oCtx->hasNearPoint());
|
||||
$this->oCtx->setNearPoint(0, 0);
|
||||
$this->assertTrue($this->oCtx->hasNearPoint());
|
||||
}
|
||||
|
||||
public function testNearRadius()
|
||||
{
|
||||
$this->oCtx->setNearPoint(1, 1);
|
||||
$this->assertEquals(0.1, $this->oCtx->nearRadius());
|
||||
$this->oCtx->setNearPoint(1, 1, 0.338);
|
||||
$this->assertEquals(0.338, $this->oCtx->nearRadius());
|
||||
}
|
||||
|
||||
public function testWithinSQL()
|
||||
{
|
||||
$this->oCtx->setNearPoint(0.1, 23, 1);
|
||||
|
||||
$this->assertEquals(
|
||||
'ST_DWithin(foo, ST_SetSRID(ST_Point(23,0.1),4326), 1.000000)',
|
||||
$this->oCtx->withinSQL('foo')
|
||||
);
|
||||
}
|
||||
|
||||
public function testDistanceSQL()
|
||||
{
|
||||
$this->oCtx->setNearPoint(0.1, 23, 1);
|
||||
|
||||
$this->assertEquals(
|
||||
'ST_Distance(ST_SetSRID(ST_Point(23,0.1),4326), foo)',
|
||||
$this->oCtx->distanceSQL('foo')
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -540,7 +540,6 @@ if ($aCMDResult['calculate-postcodes'] || $aCMDResult['all']) {
|
||||
$sSQL .= " FROM us_postcode WHERE postcode NOT IN";
|
||||
$sSQL .= " (SELECT postcode FROM location_postcode";
|
||||
$sSQL .= " WHERE country_code = 'us')";
|
||||
|
||||
} else {
|
||||
$sSQL .= "TRUNCATE TABLE us_postcode";
|
||||
}
|
||||
|
||||
@@ -77,8 +77,7 @@ if ($aResult['init-updates']) {
|
||||
if ($sDatabaseDate === false) {
|
||||
fail("Cannot determine date of database.");
|
||||
}
|
||||
$sWindBack = strftime('%Y-%m-%dT%H:%M:%SZ',
|
||||
strtotime($sDatabaseDate) - (3*60*60));
|
||||
$sWindBack = strftime('%Y-%m-%dT%H:%M:%SZ', strtotime($sDatabaseDate) - (3*60*60));
|
||||
|
||||
// get the appropriate state id
|
||||
$aOutput = 0;
|
||||
@@ -288,7 +287,7 @@ if ($aResult['import-osmosis'] || $aResult['import-osmosis-all']) {
|
||||
if ($iResult == 3) {
|
||||
echo 'No new updates. Sleeping for '.CONST_Replication_Recheck_Interval." sec.\n";
|
||||
sleep(CONST_Replication_Recheck_Interval);
|
||||
} else if ($iResult != 0) {
|
||||
} elseif ($iResult != 0) {
|
||||
echo 'ERROR: updates failed.';
|
||||
exit($iResult);
|
||||
} else {
|
||||
@@ -325,7 +324,11 @@ if ($aResult['import-osmosis'] || $aResult['import-osmosis-all']) {
|
||||
|
||||
// write the update logs
|
||||
$iFileSize = filesize($sImportFile);
|
||||
$sSQL = "INSERT INTO import_osmosis_log (batchend, batchseq, batchsize, starttime, endtime, event) values ('$sBatchEnd',$iEndSequence,$iFileSize,'".date('Y-m-d H:i:s', $fCMDStartTime)."','".date('Y-m-d H:i:s')."','import')";
|
||||
$sSQL = 'INSERT INTO import_osmosis_log';
|
||||
$sSQL .= '(batchend, batchseq, batchsize, starttime, endtime, event)';
|
||||
$sSQL .= " values ('$sBatchEnd',$iEndSequence,$iFileSize,'";
|
||||
$sSQL .= date('Y-m-d H:i:s', $fCMDStartTime)."','";
|
||||
$sSQL .= date('Y-m-d H:i:s')."','import')";
|
||||
var_Dump($sSQL);
|
||||
chksql($oDB->query($sSQL));
|
||||
|
||||
@@ -348,7 +351,11 @@ if ($aResult['import-osmosis'] || $aResult['import-osmosis-all']) {
|
||||
exit($iErrorLevel);
|
||||
}
|
||||
|
||||
$sSQL = "INSERT INTO import_osmosis_log (batchend, batchseq, batchsize, starttime, endtime, event) values ('$sBatchEnd',$iEndSequence,$iFileSize,'".date('Y-m-d H:i:s', $fCMDStartTime)."','".date('Y-m-d H:i:s')."','index')";
|
||||
$sSQL = 'INSERT INTO import_osmosis_log';
|
||||
$sSQL .= '(batchend, batchseq, batchsize, starttime, endtime, event)';
|
||||
$sSQL .= " values ('$sBatchEnd',$iEndSequence,$iFileSize,'";
|
||||
$sSQL .= date('Y-m-d H:i:s', $fCMDStartTime)."','";
|
||||
$sSQL .= date('Y-m-d H:i:s')."','index')";
|
||||
var_Dump($sSQL);
|
||||
$oDB->query($sSQL);
|
||||
echo date('Y-m-d H:i:s')." Completed index step for $sBatchEnd in ".round((time()-$fCMDStartTime)/60, 2)." minutes\n";
|
||||
@@ -362,4 +369,3 @@ if ($aResult['import-osmosis'] || $aResult['import-osmosis-all']) {
|
||||
if (!$aResult['import-osmosis-all']) exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user