]> git.openstreetmap.org Git - nominatim.git/blob - lib/SearchContext.php
f5eab95ac5d8d7dd4e5d8ce59903f0a6c240d67d
[nominatim.git] / lib / SearchContext.php
1 <?php
2
3 namespace Nominatim;
4
5 require_once(CONST_BasePath.'/lib/lib.php');
6
7
8 /**
9  * Collects search constraints that are independent of the
10  * actual interpretation of the search query.
11  *
12  * The search context is shared between all SearchDescriptions. This
13  * object mainly serves as context provider for the database queries.
14  * Therefore most data is directly cached as SQL statements.
15  */
16 class SearchContext
17 {
18     private $fNearRadius = false;
19     public $bViewboxBounded = false;
20
21     public $sqlNear = '';
22     public $sqlViewboxSmall = '';
23     public $sqlViewboxLarge = '';
24     public $sqlViewboxCentre = '';
25     public $sqlCountryList = '';
26     private $sqlExcludeList = '';
27
28     public function hasNearPoint()
29     {
30         return $this->fNearRadius !== false;
31     }
32
33     public function nearRadius()
34     {
35         return $this->fNearRadius;
36     }
37
38     public function setNearPoint($fLat, $fLon, $fRadius = 0.1)
39     {
40         $this->fNearRadius = $fRadius;
41         $this->sqlNear = 'ST_SetSRID(ST_Point('.$fLon.','.$fLat.'),4326)';
42     }
43
44     public function isBoundedSearch()
45     {
46         return $this->hasNearPoint() || ($this->sqlViewboxSmall && $this->bViewboxBounded);
47
48     }
49
50     public function setViewboxFromBox(&$aViewBox, $bBounded)
51     {
52         $this->bViewboxBounded = $bBounded;
53         $this->sqlViewboxCentre = '';
54
55         $this->sqlViewboxSmall = sprintf(
56             'ST_SetSRID(ST_MakeBox2D(ST_Point(%F,%F),ST_Point(%F,%F)),4326)',
57             $aViewBox[0],
58             $aViewBox[1],
59             $aViewBox[2],
60             $aViewBox[3]
61         );
62
63         $fHeight = $aViewBox[0] - $aViewBox[2];
64         $fWidth = $aViewBox[1] - $aViewBox[3];
65
66         $this->sqlViewboxLarge = sprintf(
67             'ST_SetSRID(ST_MakeBox2D(ST_Point(%F,%F),ST_Point(%F,%F)),4326)',
68             max($aViewBox[0], $aViewBox[2]) + $fHeight,
69             max($aViewBox[1], $aViewBox[3]) + $fWidth,
70             min($aViewBox[0], $aViewBox[2]) - $fHeight,
71             min($aViewBox[1], $aViewBox[3]) - $fWidth
72         );
73     }
74
75     public function setViewboxFromRoute(&$oDB, $aRoutePoints, $fRouteWidth, $bBounded)
76     {
77         $this->bViewboxBounded = $bBounded;
78         $this->sqlViewboxCentre = "ST_SetSRID('LINESTRING(";
79         $sSep = '';
80         foreach ($aRoutePoints as $aPoint) {
81             $fPoint = (float)$aPoint;
82             $this->sqlViewboxCentre .= $sSep.$fPoint;
83             $sSep = ($sSep == ' ') ? ',' : ' ';
84         }
85         $this->sqlViewboxCentre .= ")'::geometry,4326)";
86
87         $sSQL = 'ST_BUFFER('.$this->sqlViewboxCentre.','.($fRouteWidth/69).')';
88         $sGeom = chksql($oDB->getOne("select ".$sSQL), "Could not get small viewbox");
89         $this->sqlViewboxSmall = "'".$sGeom."'::geometry";
90
91         $sSQL = 'ST_BUFFER('.$this->sqlViewboxCentre.','.($fRouteWidth/30).')';
92         $sGeom = chksql($oDB->getOne("select ".$sSQL), "Could not get large viewbox");
93         $this->sqlViewboxLarge = "'".$sGeom."'::geometry";
94     }
95
96     public function setExcludeList($aExcluded)
97     {
98         $this->sqlExcludeList = ' not in ('.join(',', $aExcluded).')';
99     }
100
101     public function setCountryList($aCountries)
102     {
103         $this->sqlCountryList = '('.join(',', array_map('addQuotes', $aCountries)).')';
104     }
105
106     /**
107      * Extract a coordinate point from a query string.
108      *
109      * @param string $sQuery Query to scan.
110      *
111      * @return The remaining query string.
112      */
113     public function setNearPointFromQuery($sQuery)
114     {
115         $aResult = parseLatLon($sQuery);
116
117         if ($aResult !== false
118             && $aResult[1] <= 90.1
119             && $aResult[1] >= -90.1
120             && $aResult[2] <= 180.1
121             && $aResult[2] >= -180.1
122         ) {
123             $this->setNearPoint($aResult[1], $aResult[2]);
124             $sQuery = trim(str_replace($aResult[0], ' ', $sQuery));
125         }
126
127         return $sQuery;
128     }
129
130     public function distanceSQL($sObj)
131     {
132         return 'ST_Distance('.$this->sqlNear.", $sObj)";
133     }
134
135     public function withinSQL($sObj)
136     {
137         return sprintf('ST_DWithin(%s, %s, %F)', $sObj, $this->sqlNear, $this->fNearRadius);
138     }
139
140     public function viewboxImportanceSQL($sObj)
141     {
142         $sSQL = '';
143
144         if ($this->sqlViewboxSmall) {
145             $sSQL = " * CASE WHEN ST_Contains($this->sqlViewboxSmall, $sObj) THEN 1 ELSE 0.5 END";
146         }
147         if ($this->sqlViewboxLarge) {
148             $sSQL = " * CASE WHEN ST_Contains($this->sqlViewboxLarge, $sObj) THEN 1 ELSE 0.5 END";
149         }
150
151         return $sSQL;
152     }
153
154     public function excludeSQL($sVariable)
155     {
156         if ($this->sqlExcludeList) {
157             return $sVariable.$this->sqlExcludeList;
158         }
159
160         return '';
161     }
162 }