]> git.openstreetmap.org Git - nominatim.git/blob - lib/SearchContext.php
7552ae992a9df85882bf046f2e1be4587694df51
[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
26     public function hasNearPoint()
27     {
28         return $this->fNearRadius !== false;
29     }
30
31     public function nearRadius()
32     {
33         return $this->fNearRadius;
34     }
35
36     public function setNearPoint($fLat, $fLon, $fRadius = 0.1)
37     {
38         $this->fNearRadius = $fRadius;
39         $this->sqlNear = 'ST_SetSRID(ST_Point('.$fLon.','.$fLat.'),4326)';
40     }
41
42     public function isBoundedSearch()
43     {
44         return $this->hasNearPoint() || ($this->sqlViewboxSmall && $this->bViewboxBounded);
45
46     }
47
48     public function setViewboxFromBox(&$aViewBox, $bBounded)
49     {
50         $this->bViewboxBounded = $bBounded;
51         $this->sqlViewboxCentre = '';
52
53         $this->sqlViewboxSmall = sprintf(
54             'ST_SetSRID(ST_MakeBox2D(ST_Point(%F,%F),ST_Point(%F,%F)),4326)',
55             $aViewBox[0],
56             $aViewBox[1],
57             $aViewBox[2],
58             $aViewBox[3]
59         );
60
61         $fHeight = $aViewBox[0] - $aViewBox[2];
62         $fWidth = $aViewBox[1] - $aViewBox[3];
63
64         $this->sqlViewboxLarge = sprintf(
65             'ST_SetSRID(ST_MakeBox2D(ST_Point(%F,%F),ST_Point(%F,%F)),4326)',
66             max($aViewBox[0], $aViewBox[2]) + $fHeight,
67             max($aViewBox[1], $aViewBox[3]) + $fWidth,
68             min($aViewBox[0], $aViewBox[2]) - $fHeight,
69             min($aViewBox[1], $aViewBox[3]) - $fWidth
70         );
71     }
72
73     public function setViewboxFromRoute(&$oDB, $aRoutePoints, $fRouteWidth, $bBounded)
74     {
75         $this->bViewboxBounded = $bBounded;
76         $this->sqlViewboxCentre = "ST_SetSRID('LINESTRING(";
77         $sSep = '';
78         foreach ($aRoutePoints as $aPoint) {
79             $fPoint = (float)$aPoint;
80             $this->sqlViewboxCentre .= $sSep.$fPoint;
81             $sSep = ($sSep == ' ') ? ',' : ' ';
82         }
83         $this->sqlViewboxCentre .= ")'::geometry,4326)";
84
85         $sSQL = 'ST_BUFFER('.$this->sqlViewboxCentre.','.($fRouteWidth/69).')';
86         $sGeom = chksql($oDB->getOne("select ".$sSQL), "Could not get small viewbox");
87         $this->sqlViewboxSmall = "'".$sGeom."'::geometry";
88
89         $sSQL = 'ST_BUFFER('.$this->sqlViewboxCentre.','.($fRouteWidth/30).')';
90         $sGeom = chksql($oDB->getOne("select ".$sSQL), "Could not get large viewbox");
91         $this->sqlViewboxLarge = "'".$sGeom."'::geometry";
92     }
93
94     /**
95      * Extract a coordinate point from a query string.
96      *
97      * @param string $sQuery Query to scan.
98      *
99      * @return The remaining query string.
100      */
101     public function setNearPointFromQuery($sQuery)
102     {
103         $aResult = parseLatLon($sQuery);
104
105         if ($aResult !== false
106             && $aResult[1] <= 90.1
107             && $aResult[1] >= -90.1
108             && $aResult[2] <= 180.1
109             && $aResult[2] >= -180.1
110         ) {
111             $this->setNearPoint($aResult[1], $aResult[2]);
112             $sQuery = trim(str_replace($aResult[0], ' ', $sQuery));
113         }
114
115         return $sQuery;
116     }
117
118     public function distanceSQL($sObj)
119     {
120         return 'ST_Distance('.$this->sqlNear.", $sObj)";
121     }
122
123     public function withinSQL($sObj)
124     {
125         return sprintf('ST_DWithin(%s, %s, %F)', $sObj, $this->sqlNear, $this->fNearRadius);
126     }
127
128     public function viewboxImportanceSQL($sObj)
129     {
130         $sSQL = '';
131
132         if ($this->sqlViewboxSmall) {
133             $sSQL = " * CASE WHEN ST_Contains($this->sqlViewboxSmall, $sObj) THEN 1 ELSE 0.5 END";
134         }
135         if ($this->sqlViewboxLarge) {
136             $sSQL = " * CASE WHEN ST_Contains($this->sqlViewboxLarge, $sObj) THEN 1 ELSE 0.5 END";
137         }
138
139         return $sSQL;
140     }
141 }