]> git.openstreetmap.org Git - nominatim.git/blob - lib/SearchContext.php
9bab8658ac8a9b24a86cfc85cef81d83c3cd0f8b
[nominatim.git] / lib / SearchContext.php
1 <?php
2
3 namespace Nominatim;
4
5 require_once(CONST_BasePath.'/lib/lib.php');
6
7
8 /**
9  * Collection of 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     /// Search radius around a given Near reference point.
19     private $fNearRadius = false;
20     /// True if search must be restricted to viewbox only.
21     public $bViewboxBounded = false;
22
23     /// Reference point for search (as SQL).
24     public $sqlNear = '';
25     /// Viewbox selected for search (as SQL).
26     public $sqlViewboxSmall = '';
27     /// Viewbox with a larger buffer around (as SQL).
28     public $sqlViewboxLarge = '';
29     /// Reference along a route (as SQL).
30     public $sqlViewboxCentre = '';
31     /// List of countries to restrict search to (as SQL).
32     public $sqlCountryList = '';
33     /// List of place IDs to exclude (as SQL).
34     private $sqlExcludeList = '';
35
36
37     public function hasNearPoint()
38     {
39         return $this->fNearRadius !== false;
40     }
41
42     public function nearRadius()
43     {
44         return $this->fNearRadius;
45     }
46
47     public function setNearPoint($fLat, $fLon, $fRadius = 0.1)
48     {
49         $this->fNearRadius = $fRadius;
50         $this->sqlNear = 'ST_SetSRID(ST_Point('.$fLon.','.$fLat.'),4326)';
51     }
52
53     public function isBoundedSearch()
54     {
55         return $this->hasNearPoint() || ($this->sqlViewboxSmall && $this->bViewboxBounded);
56     }
57
58     public function setViewboxFromBox(&$aViewBox, $bBounded)
59     {
60         $this->bViewboxBounded = $bBounded;
61         $this->sqlViewboxCentre = '';
62
63         $this->sqlViewboxSmall = sprintf(
64             'ST_SetSRID(ST_MakeBox2D(ST_Point(%F,%F),ST_Point(%F,%F)),4326)',
65             $aViewBox[0],
66             $aViewBox[1],
67             $aViewBox[2],
68             $aViewBox[3]
69         );
70
71         $fHeight = $aViewBox[0] - $aViewBox[2];
72         $fWidth = $aViewBox[1] - $aViewBox[3];
73
74         $this->sqlViewboxLarge = sprintf(
75             'ST_SetSRID(ST_MakeBox2D(ST_Point(%F,%F),ST_Point(%F,%F)),4326)',
76             max($aViewBox[0], $aViewBox[2]) + $fHeight,
77             max($aViewBox[1], $aViewBox[3]) + $fWidth,
78             min($aViewBox[0], $aViewBox[2]) - $fHeight,
79             min($aViewBox[1], $aViewBox[3]) - $fWidth
80         );
81     }
82
83     public function setViewboxFromRoute(&$oDB, $aRoutePoints, $fRouteWidth, $bBounded)
84     {
85         $this->bViewboxBounded = $bBounded;
86         $this->sqlViewboxCentre = "ST_SetSRID('LINESTRING(";
87         $sSep = '';
88         foreach ($aRoutePoints as $aPoint) {
89             $fPoint = (float)$aPoint;
90             $this->sqlViewboxCentre .= $sSep.$fPoint;
91             $sSep = ($sSep == ' ') ? ',' : ' ';
92         }
93         $this->sqlViewboxCentre .= ")'::geometry,4326)";
94
95         $sSQL = 'ST_BUFFER('.$this->sqlViewboxCentre.','.($fRouteWidth/69).')';
96         $sGeom = chksql($oDB->getOne("select ".$sSQL), "Could not get small viewbox");
97         $this->sqlViewboxSmall = "'".$sGeom."'::geometry";
98
99         $sSQL = 'ST_BUFFER('.$this->sqlViewboxCentre.','.($fRouteWidth/30).')';
100         $sGeom = chksql($oDB->getOne("select ".$sSQL), "Could not get large viewbox");
101         $this->sqlViewboxLarge = "'".$sGeom."'::geometry";
102     }
103
104     public function setExcludeList($aExcluded)
105     {
106         $this->sqlExcludeList = ' not in ('.join(',', $aExcluded).')';
107     }
108
109     public function setCountryList($aCountries)
110     {
111         $this->sqlCountryList = '('.join(',', array_map('addQuotes', $aCountries)).')';
112     }
113
114     /**
115      * Extract a coordinate point from a query string.
116      *
117      * @param string $sQuery Query to scan.
118      *
119      * @return The remaining query string.
120      */
121     public function setNearPointFromQuery($sQuery)
122     {
123         $aResult = parseLatLon($sQuery);
124
125         if ($aResult !== false
126             && $aResult[1] <= 90.1
127             && $aResult[1] >= -90.1
128             && $aResult[2] <= 180.1
129             && $aResult[2] >= -180.1
130         ) {
131             $this->setNearPoint($aResult[1], $aResult[2]);
132             $sQuery = trim(str_replace($aResult[0], ' ', $sQuery));
133         }
134
135         return $sQuery;
136     }
137
138     public function distanceSQL($sObj)
139     {
140         return 'ST_Distance('.$this->sqlNear.", $sObj)";
141     }
142
143     public function withinSQL($sObj)
144     {
145         return sprintf('ST_DWithin(%s, %s, %F)', $sObj, $this->sqlNear, $this->fNearRadius);
146     }
147
148     public function viewboxImportanceSQL($sObj)
149     {
150         $sSQL = '';
151
152         if ($this->sqlViewboxSmall) {
153             $sSQL = " * CASE WHEN ST_Contains($this->sqlViewboxSmall, $sObj) THEN 1 ELSE 0.5 END";
154         }
155         if ($this->sqlViewboxLarge) {
156             $sSQL = " * CASE WHEN ST_Contains($this->sqlViewboxLarge, $sObj) THEN 1 ELSE 0.5 END";
157         }
158
159         return $sSQL;
160     }
161
162     public function excludeSQL($sVariable)
163     {
164         if ($this->sqlExcludeList) {
165             return $sVariable.$this->sqlExcludeList;
166         }
167
168         return '';
169     }
170 }