Merge pull request #812 from lonvia/search-as-a-class

Refactoring Search arrays
This commit is contained in:
Sarah Hoffmann
2017-10-10 21:08:11 +02:00
committed by GitHub
14 changed files with 1719 additions and 1107 deletions

File diff suppressed because it is too large Load Diff

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View 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];
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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