]> git.openstreetmap.org Git - nominatim.git/commitdiff
Merge remote-tracking branch 'upstream/master'
authorSarah Hoffmann <lonvia@denofr.de>
Sun, 19 Mar 2017 22:06:06 +0000 (23:06 +0100)
committerSarah Hoffmann <lonvia@denofr.de>
Sun, 19 Mar 2017 22:06:06 +0000 (23:06 +0100)
1  2 
CMakeLists.txt
lib/Geocode.php
lib/lib.php
sql/functions.sql

diff --combined CMakeLists.txt
index 89624069160887ab2cfc67e793a24bfc999063b1,79cc7d19755365a5e6a8f684a804418d3042e1bb..8d533cc8ae08bf40a32b4bcadaa4d53fc6c23016
@@@ -34,6 -34,12 +34,12 @@@ add_definitions(-DNOMINATIM_VERSION="${
  
  set(BUILD_TESTS off CACHE BOOL "Build test suite" FORCE)
  set(WITH_LUA off CACHE BOOL "Build with lua support" FORCE)
+ if (NOT EXISTS "${CMAKE_SOURCE_DIR}/osm2pgsql/CMakeLists.txt")
+     message(FATAL_ERROR "The osm2pgsql directory is empty.\
+     Did you forget to check out Nominatim recursively?\
+     \nTry updating submodules with: git submodules update --init")
+ endif()
  add_subdirectory(osm2pgsql)
  
  find_package(Threads REQUIRED)
@@@ -86,14 -92,6 +92,14 @@@ set(CUSTOMFILE
      website/reverse.php
      website/search.php
      website/status.php
 +    website/403.html
 +    website/509.html
 +    website/crossdomain.xml
 +    website/favicon.ico
 +    website/last_update.php
 +    website/nominatim.xml
 +    website/robots.txt
 +    website/taginfo.json
      utils/blocks.php
      utils/country_languages.php
      utils/imports.php
diff --combined lib/Geocode.php
index 537f179c6982bea2ab0dd82f5020f1497e2340f2,3726f3379600675a00196020f7d18d7e37741c3f..62e7a7cfed120da8735b509740cf78f3339d50be
@@@ -2,6 -2,7 +2,7 @@@
  
  namespace Nominatim;
  
+ require_once(CONST_BasePath.'/lib/NearPoint.php');
  require_once(CONST_BasePath.'/lib/PlaceLookup.php');
  require_once(CONST_BasePath.'/lib/ReverseGeocode.php');
  
@@@ -24,7 -25,7 +25,7 @@@ class Geocod
  
      protected $aExcludePlaceIDs = array();
      protected $bDeDupe = true;
 -    protected $bReverseInPlan = false;
 +    protected $bReverseInPlan = true;
  
      protected $iLimit = 20;
      protected $iFinalLimit = 10;
@@@ -32,7 -33,6 +33,6 @@@
      protected $bFallback = false;
  
      protected $aCountryCodes = false;
-     protected $aNearPoint = false;
  
      protected $bBoundedSearch = false;
      protected $aViewBox = false;
          );
      }
  
-     public function setNearPoint($aNearPoint, $fRadiusDeg = 0.1)
-     {
-         $this->aNearPoint = array((float)$aNearPoint[0], (float)$aNearPoint[1], (float)$fRadiusDeg);
-     }
      public function setQuery($sQueryString)
      {
          $this->sQuery = $sQueryString;
                                          if ($aSearch['iSearchRank'] < $this->iMaxRank) $aNewWordsetSearches[] = $aSearch;
                                      }
                                  } elseif (isset($aSearchTerm['lat']) && $aSearchTerm['lat'] !== '' && $aSearchTerm['lat'] !== null) {
-                                     if ($aSearch['fLat'] === '') {
-                                         $aSearch['fLat'] = $aSearchTerm['lat'];
-                                         $aSearch['fLon'] = $aSearchTerm['lon'];
-                                         $aSearch['fRadius'] = $aSearchTerm['radius'];
+                                     if ($aSearch['oNear'] === false) {
+                                         $aSearch['oNear'] = new NearPoint(
+                                             $aSearchTerm['lat'],
+                                             $aSearchTerm['lon'],
+                                             $aSearchTerm['radius']
+                                         );
                                          if ($aSearch['iSearchRank'] < $this->iMaxRank) $aNewWordsetSearches[] = $aSearch;
                                      }
                                  } elseif ($sPhraseType == 'postalcode') {
          }
  
          // Do we have anything that looks like a lat/lon pair?
-         if ($aLooksLike = looksLikeLatLonPair($sQuery)) {
-             $this->setNearPoint(array($aLooksLike['lat'], $aLooksLike['lon']));
+         $oNearPoint = false;
+         if ($aLooksLike = NearPoint::extractFromQuery($sQuery)) {
+             $oNearPoint = $aLooksLike['pt'];
              $sQuery = $aLooksLike['query'];
          }
  
                             'sClass' => '',
                             'sType' => '',
                             'sHouseNumber' => '',
-                            'fLat' => '',
-                            'fLon' => '',
-                            'fRadius' => ''
+                            'oNear' => $oNearPoint
                            )
                           );
  
-             // Do we have a radius search?
-             $sNearPointSQL = false;
-             if ($this->aNearPoint) {
-                 $sNearPointSQL = "ST_SetSRID(ST_Point(".(float)$this->aNearPoint[1].",".(float)$this->aNearPoint[0]."),4326)";
-                 $aSearches[0]['fLat'] = (float)$this->aNearPoint[0];
-                 $aSearches[0]['fLon'] = (float)$this->aNearPoint[1];
-                 $aSearches[0]['fRadius'] = (float)$this->aNearPoint[2];
-             }
              // Any 'special' terms in the search?
              $bSpecialTerms = false;
              preg_match_all('/\\[(.*)=(.*)\\]/', $sQuery, $aSpecialTermsRaw, PREG_SET_ORDER);
                      if (CONST_Debug) _debugDumpGroupedSearches(array($iGroupedRank => array($aSearch)), $aValidTokens);
  
                      // No location term?
-                     if (!sizeof($aSearch['aName']) && !sizeof($aSearch['aAddress']) && !$aSearch['fLon']) {
+                     if (!sizeof($aSearch['aName']) && !sizeof($aSearch['aAddress']) && !$aSearch['oNear']) {
                          if ($aSearch['sCountryCode'] && !$aSearch['sClass'] && !$aSearch['sHouseNumber']) {
                              // Just looking for a country by code - look it up
                              if (4 >= $this->iMinAddressRank && 4 <= $this->iMaxAddressRank) {
                                  $aPlaceIDs = array();
                              }
                          } else {
-                             if (!$bBoundingBoxSearch && !$aSearch['fLon']) continue;
+                             if (!$bBoundingBoxSearch && !$aSearch['oNear']) continue;
                              if (!$aSearch['sClass']) continue;
  
                              $sSQL = "SELECT COUNT(*) FROM pg_tables WHERE tablename = 'place_classtype_".$aSearch['sClass']."_".$aSearch['sType']."'";
                                  $aPlaceIDs = chksql($this->oDB->getCol($sSQL));
                              }
                          }
-                     } elseif ($aSearch['fLon'] && !sizeof($aSearch['aName']) && !sizeof($aSearch['aAddress']) && !$aSearch['sClass']) {
+                     } elseif ($aSearch['oNear'] && !sizeof($aSearch['aName']) && !sizeof($aSearch['aAddress']) && !$aSearch['sClass']) {
                          // If a coordinate is given, the search must either
                          // be for a name or a special search. Ignore everythin else.
                          $aPlaceIDs = array();
                          // TODO: filter out the pointless search terms (2 letter name tokens and less)
                          // they might be right - but they are just too darned expensive to run
                          if (sizeof($aSearch['aName'])) $aTerms[] = "name_vector @> ARRAY[".join($aSearch['aName'], ",")."]";
 -                        if (sizeof($aSearch['aNameNonSearch'])) $aTerms[] = "array_cat(name_vector,ARRAY[]::integer[]) @> ARRAY[".join($aSearch['aNameNonSearch'], ",")."]";
 +                        //if (sizeof($aSearch['aNameNonSearch'])) $aTerms[] = "array_cat(name_vector,ARRAY[]::integer[]) @> ARRAY[".join($aSearch['aNameNonSearch'], ",")."]";
                          if (sizeof($aSearch['aAddress']) && $aSearch['aName'] != $aSearch['aAddress']) {
                              // For infrequent name terms disable index usage for address
                              if (CONST_Search_NameOnlySearchFrequencyThreshold
                                  && sizeof($aSearch['aName']) == 1
                                  && $aWordFrequencyScores[$aSearch['aName'][reset($aSearch['aName'])]] < CONST_Search_NameOnlySearchFrequencyThreshold
                              ) {
 -                                $aTerms[] = "array_cat(nameaddress_vector,ARRAY[]::integer[]) @> ARRAY[".join(array_merge($aSearch['aAddress'], $aSearch['aAddressNonSearch']), ",")."]";
 +                                //$aTerms[] = "array_cat(nameaddress_vector,ARRAY[]::integer[]) @> ARRAY[".join(array_merge($aSearch['aAddress'], $aSearch['aAddressNonSearch']), ",")."]";
 +                                $aTerms[] = "array_cat(nameaddress_vector,ARRAY[]::integer[]) @> ARRAY[".join($aSearch['aAddress'],",")."]";
                              } else {
                                  $aTerms[] = "nameaddress_vector @> ARRAY[".join($aSearch['aAddress'], ",")."]";
 -                                if (sizeof($aSearch['aAddressNonSearch'])) {
 +                                /*if (sizeof($aSearch['aAddressNonSearch'])) {
                                      $aTerms[] = "array_cat(nameaddress_vector,ARRAY[]::integer[]) @> ARRAY[".join($aSearch['aAddressNonSearch'], ",")."]";
 -                                }
 +                                }*/
                              }
                          }
                          if ($aSearch['sCountryCode']) $aTerms[] = "country_code = '".pg_escape_string($aSearch['sCountryCode'])."'";
                                  $aTerms[] = "address_rank <= ".$this->iMaxAddressRank;
                              }
                          }
-                         if ($aSearch['fLon'] && $aSearch['fLat']) {
-                             $aTerms[] = sprintf(
-                                 'ST_DWithin(centroid, ST_SetSRID(ST_Point(%F,%F),4326), %F)',
-                                 $aSearch['fLon'],
-                                 $aSearch['fLat'],
-                                 $aSearch['fRadius']
-                             );
+                         if ($aSearch['oNear']) {
+                             $aTerms[] = $aSearch['oNear']->withinSQL('centroid');
  
-                             $aOrder[] = "ST_Distance(centroid, ST_SetSRID(ST_Point(".$aSearch['fLon'].",".$aSearch['fLat']."),4326)) ASC";
+                             $aOrder[] = $aSearch['oNear']->distanceSQL('centroid');
                          }
                          if (sizeof($this->aExcludePlaceIDs)) {
                              $aTerms[] = "place_id not in (".join(',', $this->aExcludePlaceIDs).")";
                          }
  
                          if ($bBoundingBoxSearch) $aTerms[] = "centroid && $this->sViewboxSmallSQL";
-                         if ($sNearPointSQL) $aOrder[] = "ST_Distance($sNearPointSQL, centroid) ASC";
+                         if ($oNearPoint) {
+                             $aOrder[] = $oNearPoint->distanceSQL('centroid');
+                         }
  
                          if ($aSearch['sHouseNumber']) {
                              $sImportanceSQL = '- abs(26 - address_rank) + 3';
                                          $fRange = 0.05;
  
                                          $sOrderBySQL = '';
-                                         if ($sNearPointSQL) $sOrderBySQL = "ST_Distance($sNearPointSQL, l.centroid)";
-                                         elseif ($sPlaceIDs) $sOrderBySQL = "ST_Distance(l.centroid, f.geometry)";
-                                         elseif ($sPlaceGeom) $sOrderBysSQL = "ST_Distance(st_centroid('".$sPlaceGeom."'), l.centroid)";
+                                         if ($oNearPoint) {
+                                             $sOrderBySQL = $oNearPoint->distanceSQL('l.centroid');
+                                         } elseif ($sPlaceIDs) {
+                                             $sOrderBySQL = "ST_Distance(l.centroid, f.geometry)";
+                                         } elseif ($sPlaceGeom) {
+                                             $sOrderBysSQL = "ST_Distance(st_centroid('".$sPlaceGeom."'), l.centroid)";
+                                         }
  
                                          $sSQL = "select distinct l.place_id".($sOrderBySQL?','.$sOrderBySQL:'')." from place_classtype_".$aSearch['sClass']."_".$aSearch['sType']." as l";
                                          if ($sCountryCodesSQL) $sSQL .= " join placex as lp using (place_id)";
                                          if (CONST_Debug) var_dump($sSQL);
                                          $aClassPlaceIDs = array_merge($aClassPlaceIDs, chksql($this->oDB->getCol($sSQL)));
                                      } else {
-                                         if (isset($aSearch['fRadius']) && $aSearch['fRadius']) $fRange = $aSearch['fRadius'];
+                                         if ($aSearch['oNear']) {
+                                             $fRange = $aSearch['oNear']->radius();
+                                         }
  
                                          $sOrderBySQL = '';
-                                         if ($sNearPointSQL) $sOrderBySQL = "ST_Distance($sNearPointSQL, l.geometry)";
-                                         else $sOrderBySQL = "ST_Distance(l.geometry, f.geometry)";
+                                         if ($oNearPoint) {
+                                             $sOrderBySQL = $oNearPoint->distanceSQL('l.geometry');
+                                         } else {
+                                             $sOrderBySQL = "ST_Distance(l.geometry, f.geometry)";
+                                         }
  
                                          $sSQL = "SELECT distinct l.place_id".($sOrderBysSQL?','.$sOrderBysSQL:'');
                                          $sSQL .= " FROM placex as l, placex as f ";
              $oReverse->setZoom(18);
  
              $aLookup = $oReverse->lookup(
-                 (float)$this->aNearPoint[0],
-                 (float)$this->aNearPoint[1],
+                 $oNearPoint->lat(),
+                 $oNearPoint->lon(),
                  false
              );
  
diff --combined lib/lib.php
index f020a8b2b8ac81b0005de42cc4438043b72d221b,a535191879c3733329a2f528c3fd37f4931bd038..a0f67ed80f4b455e3c021aa27dc6eed7bdc1b00e
@@@ -599,89 -599,6 +599,6 @@@ function addQuotes($s
      return "'".$s."'";
  }
  
- function validLatLon($fLat, $fLon)
- {
-     return ($fLat <= 90.1 && $fLat >= -90.1 && $fLon <= 180.1 && $fLon >= -180.1);
- }
- function looksLikeLatLonPair($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('/\\b([NS])[ ]+([0-9]+[0-9.]*)[° ]+([0-9.]+)?[′\']*[, ]+([EW])[ ]+([0-9]+)[° ]+([0-9]+[0-9.]*)[′\']*?\\b/', $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('/\\b([0-9]+)[° ]+([0-9]+[0-9.]*)?[′\']*[ ]+([NS])[, ]+([0-9]+)[° ]+([0-9]+[0-9.]*)?[′\' ]+([EW])\\b/', $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('/\\b([NS])[ ]([0-9]+)[° ]+([0-9]+)[′\' ]+([0-9]+)[″"]*[, ]+([EW])[ ]([0-9]+)[° ]+([0-9]+)[′\' ]+([0-9]+)[″"]*\\b/', $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('/\\b([0-9]+)[° ]+([0-9]+)[′\' ]+([0-9]+)[″" ]+([NS])[, ]+([0-9]+)[° ]+([0-9]+)[′\' ]+([0-9]+)[″" ]+([EW])\\b/', $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('/\\b([NS])[ ]([0-9]+[0-9]*\\.[0-9]+)[°]*[, ]+([EW])[ ]([0-9]+[0-9]*\\.[0-9]+)[°]*\\b/', $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('/\\b([0-9]+[0-9]*\\.[0-9]+)[° ]+([NS])[, ]+([0-9]+[0-9]*\\.[0-9]+)[° ]+([EW])\\b/', $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('/(\\[|^|\\b)(-?[0-9]+[0-9]*\\.[0-9]+)[, ]+(-?[0-9]+[0-9]*\\.[0-9]+)(\\]|$|\\b)/', $sQuery, $aData)) {
-         /*                 1          2                             3                        4
-          * degrees decimal
-          * 12.34, 56.78
-          * [12.456,-78.90]
-          */
-         $sFound    = $aData[0];
-         $fQueryLat = $aData[2];
-         $fQueryLon = $aData[3];
-     }
-     if (!validLatLon($fQueryLat, $fQueryLon)) return;
-     $sQuery = trim(str_replace($sFound, ' ', $sQuery));
-     return array('lat' => $fQueryLat, 'lon' => $fQueryLon, 'query' => $sQuery);
- }
  
  function geometryText2Points($geometry_as_text, $fRadius)
  {
          //
          preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/', $aMatch[1], $aPolyPoints, PREG_SET_ORDER);
          //
 -    } elseif (preg_match('#MULTIPOLYGON\\(\\(\\(([- 0-9.,]+)#', $geometry_as_text, $aMatch)) {
 +/*    } elseif (preg_match('#MULTIPOLYGON\\(\\(\\(([- 0-9.,]+)#', $geometry_as_text, $aMatch)) {
          //
          preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/', $aMatch[1], $aPolyPoints, PREG_SET_ORDER);
 -        //
 +        */
      } elseif (preg_match('#POINT\\((-?[0-9.]+) (-?[0-9.]+)\\)#', $geometry_as_text, $aMatch)) {
          //
          $aPolyPoints = createPointsAroundCenter($aMatch[1], $aMatch[2], $fRadius);
diff --combined sql/functions.sql
index dc2597107582f257fca266a982a175b9ef3f048c,be67cf011d7481c2d0d3158c1906f9db22af009c..f8ec472a0d6464ad94e64e9a0ae955ad726dbdf0
@@@ -1679,7 -1679,12 +1679,12 @@@ BEGI
    -- added ourself as address already
    address_havelevel[NEW.rank_address] := true;
    -- RAISE WARNING '  getNearFeatures(%,''%'',%,''%'')',NEW.partition, place_centroid, search_maxrank, isin_tokens;
-   FOR location IN SELECT * from getNearFeatures(NEW.partition, place_centroid, search_maxrank, isin_tokens) LOOP
+   FOR location IN
+     SELECT * from getNearFeatures(NEW.partition,
+                                   CASE WHEN NEW.rank_search >= 26 THEN NEW.geometry
+                                   ELSE place_centroid END,
+                                   search_maxrank, isin_tokens)
+   LOOP
  
  --RAISE WARNING '  AREA: %',location;
  
@@@ -2417,7 -2422,7 +2422,7 @@@ BEGI
        CASE WHEN class = 'place' and type = 'postcode' THEN hstore('name', postcode) ELSE name END as name,
        CASE WHEN extratags ? 'place' THEN 'place' ELSE class END as class,
        CASE WHEN extratags ? 'place' THEN extratags->'place' ELSE type END as type,
 -      admin_level, fromarea, isaddress,
 +      admin_level, fromarea, isaddress and linked_place_id is NULL as isaddress,
        CASE WHEN address_place_id = for_place_id AND rank_address = 0 THEN 100 WHEN rank_address = 11 THEN 5 ELSE rank_address END as rank_address,
        distance,calculated_country_code,postcode
        from place_addressline join placex on (address_place_id = placex.place_id)