]> git.openstreetmap.org Git - nominatim.git/commitdiff
Merge branch 'customPHP1' of https://github.com/ThomasBarris/Nominatim into ThomasBar...
authorSarah Hoffmann <lonvia@denofr.de>
Thu, 23 Aug 2018 18:41:44 +0000 (20:41 +0200)
committerSarah Hoffmann <lonvia@denofr.de>
Thu, 23 Aug 2018 18:41:44 +0000 (20:41 +0200)
14 files changed:
docs/api/Details.md [new file with mode: 0644]
docs/api/Overview.md
docs/api/Reverse.md
docs/api/Search.md
docs/mkdocs.yml
lib/DebugHtml.php
lib/ReverseGeocode.php
lib/cmd.php
lib/template/details-html.php
lib/template/details-json.php
test/bdd/api/details/params.feature
test/bdd/api/reverse/queries.feature
test/bdd/api/search/simple.feature
test/bdd/steps/queries.py

diff --git a/docs/api/Details.md b/docs/api/Details.md
new file mode 100644 (file)
index 0000000..66b5240
--- /dev/null
@@ -0,0 +1,146 @@
+# Place details
+
+Lookup details about a single place by id. The default output is HTML for debugging search logic and results.
+
+**The details page (including JSON output) exists for debugging only and must not be downloaded automatically**, see [Nominatim Usage Policy](https://operations.osmfoundation.org/policies/nominatim/).
+
+
+## Parameters
+
+The details API supports the following two request formats:
+
+```
+  https://nominatim.openstreetmap.org/details?osmtype=[N|W|R]&osmid=<value>
+```
+
+Both parameters are required, the type is one of node(N), way(W) or relation(R).
+
+Or
+
+```
+  https://nominatim.openstreetmap.org/details?placeid=<value>
+```
+
+Placeids are assigned sequentially during Nominatim data import. The id for a place is different between Nominatim installation (servers) and changes when data gets reimported. Therefore it can't be used as permanent id and shouldn't be used in bug reports.
+
+
+Additional optional parameters are explained below.
+
+### Output format
+
+* `format=[html|json]`
+
+See [Place Output Formats](Output.md) for details on each format. (Default: html)
+
+* `json_callback=<string>`
+
+Wrap json output in a callback function (JSONP) i.e. `<string>(<json>)`.
+Only has an effect for JSON output formats.
+
+* `pretty=[0|1]`
+
+For JSON output will add indentation to make it more human-readable. (Default: 0)
+
+
+### Output details
+
+* `addressdetails=[0|1]`
+
+Include a breakdown of the address into elements. (Default for JSON: 0, for HTML: 1)
+
+* `keywords=[0|1]`
+
+Include a list of name keywords and address keywords (word ids). (Default: 0)
+
+* `linkedplaces=[0|1]`
+
+Include details of places higher in the address hierarchy. E.g. for a street this is usually the city, state, postal code, country. (Default: 1)
+
+* `hierarchy=[0|1]`
+
+Include details of places lower in the address hierarchy. E.g. for a city this usually a list of streets, suburbs, rivers. (Default for JSON: 0, for HTML: 1)
+
+* `group_hierarchy=[0|1]`
+
+For JSON output will group the places by type. (Default: 0)
+
+* `polygon_geojson=[0|1]`
+
+Include geometry of result. (Default for JSON: 0, for HTML: 1)
+
+### Language of results
+
+* `accept-language=<browser language string>`
+
+Preferred language order for showing result, overrides the value
+specified in the "Accept-Language" HTTP header.
+Either use a standard RFC2616 accept-language string or a simple
+comma-separated list of language codes.
+
+
+## Examples
+
+##### HTML
+
+[https://nominatim.openstreetmap.org/details.php?osmtype=W&osmid=38210407](https://nominatim.openstreetmap.org/details.php?osmtype=W&osmid=38210407)
+
+##### JSON
+
+[https://nominatim.openstreetmap.org/details.php?osmtype=W&osmid=38210407&format=json](https://nominatim.openstreetmap.org/details.php?osmtype=W&osmid=38210407&format=json)
+
+
+```json
+{
+  "place_id": 85993608,
+  "parent_place_id": 72765313,
+  "osm_type": "W",
+  "osm_id": 38210407,
+  "category": "place",
+  "type": "square",
+  "admin_level": "15",
+  "localname": "Pariser Platz",
+  "names": {
+    "name": "Pariser Platz",
+    "name:be": "Парыжская плошча",
+    "name:de": "Pariser Platz",
+    "name:es": "Plaza de París",
+    "name:he": "פאריזר פלאץ",
+    "name:ko": "파리저 광장",
+    "name:la": "Forum Parisinum",
+    "name:ru": "Парижская площадь",
+    "name:uk": "Паризька площа",
+    "name:zh": "巴黎廣場"
+  },
+  "addresstags": {
+    "postcode": "10117"
+  },
+  "housenumber": null,
+  "calculated_postcode": "10117",
+  "country_code": "de",
+  "indexed_date": "2018-08-18T17:02:45+00:00",
+  "importance": 0.339401620591472,
+  "calculated_importance": 0.339401620591472,
+  "extratags": {
+    "wikidata": "Q156716",
+    "wikipedia": "de:Pariser Platz"
+  },
+  "calculated_wikipedia": "de:Pariser_Platz",
+  "rank_address": 30,
+  "rank_search": 30,
+  "isarea": true,
+  "centroid": {
+    "type": "Point",
+    "coordinates": [
+      13.3786822618517,
+      52.5163654
+    ]
+  },
+  "geometry": {
+    "type": "Point",
+    "coordinates": [
+      13.3786822618517,
+      52.5163654
+    ]
+  }
+}
+```
index 8bf14c43942ee3027a9d1a6bc6750a6355fed8b7..7e8220591779abc820233fdfc4ae777ce75c7be4 100644 (file)
@@ -1,14 +1,14 @@
 ### Nominatim API
 
-Nominatim indexes named (or numbered) features with the OSM data set and a subset of other unnamed features (pubs, hotels, churches, etc).
+Nominatim indexes named (or numbered) features within the OpenStreetMap (OSM) dataset and a subset of other unnamed features (pubs, hotels, churches, etc).
 
 Its API has the following endpoints for querying the data:
 
  * __[/search](Search.md)__ - search OSM objects by name or type
  * __[/reverse](Reverse.md)__ - search OSM object by their location
- * __[/lookup](Lookup.md)__ - look up address details for OSM objects by thier ID
+ * __[/lookup](Lookup.md)__ - look up address details for OSM objects by their ID
  * __/status__ - query the status of the server
  * __/deletable__ - list objects that have been deleted in OSM but are held
                     back in Nominatim in case the deletion was accidental
  * __/polygons__ - list of broken polygons detected by Nominatim
- * __/details__ - show internal details for an object (for debugging only)
+ * __[/details](Details.md)__ - show internal details for an object (for debugging only)
index ae368e1c500f2c49003ec7970540024aa4eb78f7..22e0133160d5dce90275c20fa103dbd1a65d5a7a 100644 (file)
@@ -34,7 +34,7 @@ See [Place Output Formats](Output.md) for details on each format. (Default: html
 
 * `json_callback=<string>`
 
-Wrap json output in a callback function (JSONP) i.e. `<string>(<json>)`.
+Wrap json output in a callback function ([JSONP](https://en.wikipedia.org/wiki/JSONP)) i.e. `<string>(<json>)`.
 Only has an effect for JSON output formats.
 
 ### Output details
@@ -69,7 +69,7 @@ comma-separated list of language codes.
 
 * `zoom=[0-18]`
 
-Level of detail required for the address. This is a number that corresponds
+Level of detail required for the address. Default: 18. This is a number that corresponds
 roughly to the zoom level used in map frameworks like Leaflet.js, Openlayers etc.
 In terms of address details the zoom levels are as follows:
 
index ab7023790eea2242e65313445ce465a2d85e778b..4b9d773c485dd4869b430b593a9b85487adf6ddb 100644 (file)
@@ -5,10 +5,9 @@ Nominatim supports structured as well as free-form search queries.
 
 The search query may also contain
 [special phrases](https://wiki.openstreetmap.org/wiki/Nominatim/Special_Phrases)
-which are tranlated into specific OpenStreetMap(OSM) tags (e.g. Pub => amenity=pub).
-Note that this only limits the items to be found. It is not suited to return complete
-lists of OSM objects of a specific type.
-Use [Overpass API](https://overpass-api.de/) for that.
+which are translated into specific OpenStreetMap (OSM) tags (e.g. Pub => `amenity=pub`).
+Note that this only limits the items to be found, it's not suited to return complete
+lists of OSM objects of a specific type. For those use [Overpass API](https://overpass-api.de/).
 
 ## Parameters
 
@@ -30,22 +29,20 @@ In this form, the query may be given through two different sets of parameters:
 * `q=<query>`
 
     Free-form query string to search for.
-    Free-form queries are processed first left to right and then right to
-    left if that fails. So you may search for
+    Free-form queries are processed first left-to-right and then right-to-left if that fails. So you may search for
     [pilkington avenue, birmingham](//nominatim.openstreetmap.org/search?q=pilkington+avenue,birmingham) as well as for
     [birmingham, pilkington avenue](//nominatim.openstreetmap.org/search?q=birmingham,+pilkington+avenue).
-    Commas are optional, but improve performance by reducing the complexity
-    of the search.
+    Commas are optional, but improve performance by reducing the complexity of the search.
 
 
 * `street=<housenumber> <streetname>`
-  `city=<city>`
-  `county=<county>`
-  `state=<state>`
-  `country=<country>`
-  `postalcode=<postalcode>`
+* `city=<city>`
+* `county=<county>`
+* `state=<state>`
+* `country=<country>`
+* `postalcode=<postalcode>`
 
-    Alternative query string format for structured requests.
+    Alternative query string format split into several parameters for structured requests.
     Structured requests are faster but are less robust against alternative
     OSM tagging schemas. **Do not combine with** `q=<query>` **parameter**.
 
@@ -59,7 +56,7 @@ See [Place Output Formats](Output.md) for details on each format. (Default: html
 
 * `json_callback=<string>`
 
-Wrap json output in a callback function (JSONP) i.e. `<string>(<json>)`.
+Wrap json output in a callback function ([JSONP](https://en.wikipedia.org/wiki/JSONP)) i.e. `<string>(<json>)`.
 Only has an effect for JSON output formats.
 
 ### Output details
@@ -86,7 +83,7 @@ language variants, references, operator and brand. (Default: 0)
 * `accept-language=<browser language string>`
 
 Preferred language order for showing search results, overrides the value
-specified in the "Accept-Language" HTTP header.
+specified in the ["Accept-Language" HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language).
 Either use a standard RFC2616 accept-language string or a simple
 comma-separated list of language codes.
 
@@ -109,7 +106,7 @@ the search to return other, less accurate, matches (if possible).
 
 * `limit=<integer>`
 
-Limit the number of returned results. (Default: 10)
+Limit the number of returned results. (Default: 10, Maximum: 50)
 
 
 * `viewbox=<x1>,<y1>,<x2>,<y2>`
@@ -121,9 +118,9 @@ are accepted in any order as long as they span a real box.
 * `bounded=[0|1]`
 
 When a viewbox is given, restrict the result to items contained with that
-viewbox (see above). When `viewbox` and `bounded` are given, an amenity
+viewbox (see above). When `viewbox` and `bounded=1` are given, an amenity
 only search is allowed. In this case, give the special keyword for the
-amenity in squaer brackets, e.g. `[pub]`. (Default: 0)
+amenity in square brackets, e.g. `[pub]`. (Default: 0)
 
 
 ### Polygon output
index 87d6536378a90d8f6a5a240c84d8b756153e164c..7c3cd89537681dde9b01faa747a88d2d5284a65b 100644 (file)
@@ -10,6 +10,7 @@ pages:
         - 'Search': 'api/Search.md'
         - 'Reverse': 'api/Reverse.md'
         - 'Address Lookup': 'api/Lookup.md'
+        - 'Details' : 'api/Details.md'
         - 'Place Output Formats': 'api/Output.md'
         - 'FAQ': 'api/Faq.md'
     - 'Administration Guide':
index a600fae58124edc6a441ad587bcbcf2e4652d67a..98da8794055c644e23fbb90ffdbbc6d3d5b45f8e 100644 (file)
@@ -155,6 +155,8 @@ class Debug
             }
         } elseif (is_object($mVar) && method_exists($mVar, 'debugInfo')) {
             Debug::outputVar($mVar->debugInfo(), $sPreNL);
+        } elseif (is_a($mVar, 'stdClass')) {
+            Debug::outputVar(json_decode(json_encode($mVar), true), $sPreNL);
         } else {
             Debug::outputSimpleVar($mVar);
         }
index 681403a19eff902d389fb8feba18e61b5b489a8d..820ca3855b178ef4365201ce5db9481f159d223b 100644 (file)
@@ -47,13 +47,12 @@ class ReverseGeocode
     /**
      * Find the closest interpolation with the given search diameter.
      *
-     * @param string  $sPointSQL      Reverse geocoding point as SQL
-     * @param float   $fSearchDiam    Search diameter
-     * @param integer $iParentPlaceID Id of parent object
+     * @param string $sPointSQL   Reverse geocoding point as SQL
+     * @param float  $fSearchDiam Search diameter
      *
      * @return Record of the interpolation or null.
      */
-    protected function lookupInterpolation($sPointSQL, $fSearchDiam, $iParentPlaceID = null)
+    protected function lookupInterpolation($sPointSQL, $fSearchDiam)
     {
         $sSQL = 'SELECT place_id, parent_place_id, 30 as rank_search,';
         $sSQL .= '  ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fraction,';
@@ -62,9 +61,6 @@ class ReverseGeocode
         $sSQL .= ' FROM location_property_osmline';
         $sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', linegeo, '.$fSearchDiam.')';
         $sSQL .= ' and indexed_status = 0 and startnumber is not NULL ';
-        if (isset($iParentPlaceID)) {
-            $sSQL .= ' and parent_place_id = '.$iParentPlaceID;
-        }
         $sSQL .= ' ORDER BY distance ASC limit 1';
 
         return chksql(
@@ -73,62 +69,59 @@ class ReverseGeocode
         );
     }
 
-    protected function polygonFunctions($sPointSQL, $iMaxRank)
+    protected function lookupLargeArea($sPointSQL, $iMaxRank)
     {
-        // starts the nopolygonFound function if no polygon is found with the lookupPolygon function
         $oResult = null;
 
-        $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank);
-        if ($aPlace) {
-            $oResult = new Result($aPlace['place_id']);
-        // if no polygon which contains the searchpoint is found,
-        // the noPolygonFound function searches in the country_osm_grid table for a polygon
-        } elseif (!$aPlace && $iMaxRank > 4) {
-            $aPlace = $this->noPolygonFound($sPointSQL, $iMaxRank);
+        if ($iMaxRank > 4) {
+            $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank);
             if ($aPlace) {
-                $oResult = new Result($aPlace['place_id']);
+                return new Result($aPlace['place_id']);
             }
         }
-        return $oResult;
+
+        // If no polygon which contains the searchpoint is found,
+        // searches in the country_osm_grid table for a polygon.
+        return  $this->lookupInCountry($sPointSQL, $iMaxRank);
     }
 
-    protected function noPolygonFound($sPointSQL, $iMaxRank)
+    protected function lookupInCountry($sPointSQL, $iMaxRank)
     {
         // searches for polygon in table country_osm_grid which contains the searchpoint
         // and searches for the nearest place node to the searchpoint in this polygon
         $sSQL = 'SELECT country_code FROM country_osm_grid';
-        $sSQL .= ' WHERE ST_CONTAINS (geometry, '.$sPointSQL.') limit 1';
+        $sSQL .= ' WHERE ST_CONTAINS(geometry, '.$sPointSQL.') LIMIT 1';
 
-        $aPoly = chksql(
-            $this->oDB->getRow($sSQL),
-            'Could not determine polygon containing the point.'
+        $sCountryCode = chksql(
+            $this->oDB->getOne($sSQL),
+            'Could not determine country polygon containing the point.'
         );
-        if ($aPoly) {
-            $sCountryCode = $aPoly['country_code'];
-
-            // look for place nodes with the given country code
-            $sSQL = 'SELECT place_id FROM';
-            $sSQL .= ' (SELECT place_id, rank_search,';
-            $sSQL .= '         ST_distance('.$sPointSQL.', geometry) as distance';
-            $sSQL .= ' FROM placex';
-            $sSQL .= ' WHERE osm_type = \'N\'';
-            $sSQL .= ' AND country_code = \''.$sCountryCode.'\'';
-            $sSQL .= ' AND rank_search between 5 and ' .min(25, $iMaxRank);
-            $sSQL .= ' AND class = \'place\' AND type != \'postcode\'';
-            $sSQL .= ' AND name IS NOT NULL ';
-            $sSQL .= ' and indexed_status = 0 and linked_place_id is null';
-            $sSQL .= ' AND ST_DWithin('.$sPointSQL.', geometry, 1.8)) p ';
-            $sSQL .= 'WHERE distance <= reverse_place_diameter(rank_search)';
-            $sSQL .= ' ORDER BY rank_search DESC, distance ASC';
-            $sSQL .= ' LIMIT 1';
+        if ($sCountryCode) {
+            if ($iMaxRank > 4) {
+                // look for place nodes with the given country code
+                $sSQL = 'SELECT place_id FROM';
+                $sSQL .= ' (SELECT place_id, rank_search,';
+                $sSQL .= '         ST_distance('.$sPointSQL.', geometry) as distance';
+                $sSQL .= ' FROM placex';
+                $sSQL .= ' WHERE osm_type = \'N\'';
+                $sSQL .= ' AND country_code = \''.$sCountryCode.'\'';
+                $sSQL .= ' AND rank_search between 5 and ' .min(25, $iMaxRank);
+                $sSQL .= ' AND class = \'place\' AND type != \'postcode\'';
+                $sSQL .= ' AND name IS NOT NULL ';
+                $sSQL .= ' and indexed_status = 0 and linked_place_id is null';
+                $sSQL .= ' AND ST_DWithin('.$sPointSQL.', geometry, 1.8)) p ';
+                $sSQL .= 'WHERE distance <= reverse_place_diameter(rank_search)';
+                $sSQL .= ' ORDER BY rank_search DESC, distance ASC';
+                $sSQL .= ' LIMIT 1';
 
-            if (CONST_Debug) var_dump($sSQL);
-            $aPlacNode = chksql(
-                $this->oDB->getRow($sSQL),
-                'Could not determine place node.'
-            );
-            if ($aPlacNode) {
-                return $aPlacNode;
+                if (CONST_Debug) var_dump($sSQL);
+                $aPlace = chksql(
+                    $this->oDB->getRow($sSQL),
+                    'Could not determine place node.'
+                );
+                if ($aPlace) {
+                    return new Result($aPlace['place_id']);
+                }
             }
 
             // still nothing, then return the country object
@@ -137,24 +130,36 @@ class ReverseGeocode
             $sSQL .= ' WHERE country_code = \''.$sCountryCode.'\'';
             $sSQL .= ' AND rank_search = 4 AND rank_address = 4';
             $sSQL .= ' AND class in (\'boundary\',  \'place\')';
+            $sSQL .= ' AND linked_place_id is null';
             $sSQL .= ' ORDER BY distance ASC';
 
             if (CONST_Debug) var_dump($sSQL);
-            $aPlacNode = chksql(
+            $aPlace = chksql(
                 $this->oDB->getRow($sSQL),
                 'Could not determine place node.'
             );
-            if ($aPlacNode) {
-                return $aPlacNode;
+            if ($aPlace) {
+                return new Result($aPlace['place_id']);
             }
         }
+
+        return null;
     }
 
+    /**
+     * Search for areas or nodes for areas or nodes between state and suburb level.
+     *
+     * @param string $sPointSQL Search point as SQL string.
+     * @param int    $iMaxRank  Maximum address rank of the feature.
+     *
+     * @return Record of the found feature or null.
+     *
+     * Searches first for polygon that contains the search point.
+     * If such a polygon is found, place nodes with a higher rank are
+     * searched inside the polygon.
+     */
     protected function lookupPolygon($sPointSQL, $iMaxRank)
     {
-        // searches for polygon where the searchpoint is within
-        // if a polygon is found, placenodes with a higher rank are searched inside the polygon
-
         // polygon search begins at suburb-level
         if ($iMaxRank > 25) $iMaxRank = 25;
         // no polygon search over country-level
@@ -241,8 +246,6 @@ class ReverseGeocode
         $fSearchDiam = 0.006;
         $oResult = null;
         $aPlace = null;
-        $fMaxAreaDistance = 1;
-        $bIsTigerStreet = false;
 
         // for POI or street level
         if ($iMaxRank >= 26) {
@@ -271,28 +274,40 @@ class ReverseGeocode
                 'Could not determine closest place.'
             );
 
+            if (CONST_Debug) var_dump($aPlace);
             if ($aPlace) {
-                $iDistance = $aPlace['distance'];
                 $iPlaceID = $aPlace['place_id'];
                 $oResult = new Result($iPlaceID);
+                $iRankAddress = $aPlace['rank_address'];
                 $iParentPlaceID = $aPlace['parent_place_id'];
+            }
 
-                if ($bDoInterpolation && $iMaxRank >= 30) {
-                    if ($aPlace['rank_address'] <=27) {
-                        $iDistance = 0.001;
-                    }
-                    $aHouse = $this->lookupInterpolation($sPointSQL, $iDistance);
+            if ($bDoInterpolation && $iMaxRank >= 30) {
+                $fDistance = $fSearchDiam;
+                if ($aPlace) {
+                    // We can't reliably go from the closest street to an
+                    // interpolation line because the closest interpolation
+                    // may have a different street segments as a parent.
+                    // Therefore allow an interpolation line to take precendence
+                    // even when the street is closer.
+                    $fDistance = $iRankAddress < 28 ? 0.001 : $aPlace['distance'];
+                }
 
-                    if ($aHouse) {
-                        $oResult = new Result($aHouse['place_id'], Result::TABLE_OSMLINE);
-                        $oResult->iHouseNumber = closestHouseNumber($aHouse);
-                    }
+                $aHouse = $this->lookupInterpolation($sPointSQL, $fDistance);
+
+                if ($aHouse) {
+                    $oResult = new Result($aHouse['place_id'], Result::TABLE_OSMLINE);
+                    $oResult->iHouseNumber = closestHouseNumber($aHouse);
+                    $aPlace = $aHouse;
+                    $iRankAddress = 30;
                 }
+            }
 
+            if ($aPlace) {
                 // if street and maxrank > streetlevel
-                if (($aPlace['rank_address'] <=27)&& $iMaxRank > 27) {
+                if ($iRankAddress <= 27 && $iMaxRank > 27) {
                     // find the closest object (up to a certain radius) of which the street is a parent of
-                    $sSQL = ' select place_id,parent_place_id,rank_address,country_code,';
+                    $sSQL = ' select place_id,';
                     $sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance';
                     $sSQL .= ' FROM ';
                     $sSQL .= ' placex';
@@ -310,31 +325,23 @@ class ReverseGeocode
                         'Could not determine closest place.'
                     );
                     if ($aStreet) {
-                        $iDistance = $aStreet['distance'];
-                        $iPlaceID = $aStreet['place_id'];
-                        $oResult = new Result($iPlaceID);
-                        $iParentPlaceID = $aStreet['parent_place_id'];
-
-                        if ($bDoInterpolation && $iMaxRank >= 30) {
-                            $aHouse = $this->lookupInterpolation($sPointSQL, $iDistance, $iParentPlaceID);
-
-                            if ($aHouse) {
-                                $oResult = new Result($aHouse['place_id'], Result::TABLE_OSMLINE);
-                                $oResult->iHouseNumber = closestHouseNumber($aHouse);
-                            }
-                        }
+                        if (CONST_Debug) var_dump($aStreet);
+                        $oResult = new Result($aStreet['place_id']);
                     }
                 }
 
                   // In the US we can check TIGER data for nearest housenumber
-                if (CONST_Use_US_Tiger_Data && $aPlace['country_code'] == 'us' && $this->iMaxRank >= 28) {
-                    $fSearchDiam = $aPlace['rank_address'] > 28 ? $aPlace['distance'] : 0.001;
+                if (CONST_Use_US_Tiger_Data
+                    && $iRankAddress <= 27
+                    && $aPlace['country_code'] == 'us'
+                    && $this->iMaxRank >= 28
+                ) {
                     $sSQL = 'SELECT place_id,parent_place_id,30 as rank_search,';
                     $sSQL .= 'ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fraction,';
                     $sSQL .= 'ST_distance('.$sPointSQL.', linegeo) as distance,';
                     $sSQL .= 'startnumber,endnumber,interpolationtype';
                     $sSQL .= ' FROM location_property_tiger WHERE parent_place_id = '.$oResult->iId;
-                    $sSQL .= ' AND ST_DWithin('.$sPointSQL.', linegeo, '.$fSearchDiam.')';
+                    $sSQL .= ' AND ST_DWithin('.$sPointSQL.', linegeo, 0.001)';
                     $sSQL .= ' ORDER BY distance ASC limit 1';
                     if (CONST_Debug) var_dump($sSQL);
                     $aPlaceTiger = chksql(
@@ -343,18 +350,17 @@ class ReverseGeocode
                     );
                     if ($aPlaceTiger) {
                         if (CONST_Debug) var_dump('found Tiger housenumber', $aPlaceTiger);
-                        $aPlace = $aPlaceTiger;
-                        $oResult = new Result($aPlace['place_id'], Result::TABLE_TIGER);
+                        $oResult = new Result($aPlaceTiger['place_id'], Result::TABLE_TIGER);
                         $oResult->iHouseNumber = closestHouseNumber($aPlaceTiger);
                     }
                 }
-            // if no POI or street is found ...
             } else {
-                $oResult = $this->PolygonFunctions($sPointSQL, $iMaxRank);
+                // if no POI or street is found ...
+                $oResult = $this->lookupLargeArea($sPointSQL, 25);
             }
-            // lower than street level ($iMaxRank < 26 )
         } else {
-            $oResult = $this->PolygonFunctions($sPointSQL, $iMaxRank);
+            // lower than street level ($iMaxRank < 26 )
+            $oResult = $this->lookupLargeArea($sPointSQL, $iMaxRank);
         }
         return $oResult;
     }
index 9ec290d1c4243f5158217ab2da6392c0595848bf..9efe5653b735ca45dd12a62da471d824436dc4ee 100644 (file)
@@ -203,7 +203,8 @@ function runWithEnv($sCmd, $aEnv)
     $aFDs = array(
              0 => array('pipe', 'r'),
              1 => STDOUT,
-             2 => STDERR);
+             2 => STDERR
+            );
     $aPipes = null;
     $hProc = @proc_open($sCmd, $aFDs, $aPipes, null, $aEnv);
     if (!is_resource($hProc)) {
index 4d5ccb87c60c23c1b35e1f22b27e869e14219ac8..01583e5f789499a27a28dbdb4d9e3048c72b761e 100644 (file)
@@ -46,8 +46,7 @@
     function hash_to_subtable($aAssociatedList)
     {
         $sHTML = '';
-        foreach($aAssociatedList as $sKey => $sValue)
-        {
+        foreach ($aAssociatedList as $sKey => $sValue) {
             $sHTML = $sHTML.' <div class="line"><span class="name">'.$sValue.'</span> ('.$sKey.')</div>'."\n";
         }
         return $sHTML;
                 <tbody>
 
                 <?php
-
-                    foreach($aAddressLines as $aAddressLine)
-                    {   
+                    foreach ($aAddressLines as $aAddressLine) {
                         _one_row($aAddressLine);
                     }
                 ?>
-    
 
 
 <?php
     if ($aLinkedLines)
     {
         headline('Linked Places');
-        foreach($aLinkedLines as $aAddressLine)
-        {   
+        foreach ($aLinkedLines as $aAddressLine) {
             _one_row($aAddressLine);
         }
     }
 
-
-
     if ($bIncludeKeywords)
     {
         headline('Name Keywords');
-        foreach($aPlaceSearchNameKeywords as $aRow)
-        {
-            _one_keyword_row($aRow['word_token'], $aRow['word_id']);
+        if ($aPlaceSearchNameKeywords) {
+            foreach ($aPlaceSearchNameKeywords as $aRow) {
+                _one_keyword_row($aRow['word_token'], $aRow['word_id']);
+            }
         }
 
         headline('Address Keywords');
-        foreach($aPlaceSearchAddressKeywords as $aRow)
-        {
-            _one_keyword_row($aRow['word_token'], $aRow['word_id']);
+        if ($aPlaceSearchAddressKeywords) {
+            foreach ($aPlaceSearchAddressKeywords as $aRow) {
+                _one_keyword_row($aRow['word_token'], $aRow['word_id']);
+            }
         }
     }
-    
+
     if (!empty($aHierarchyLines))
     {
         headline('Parent Of');
 
         $aGroupedAddressLines = array();
-        foreach($aHierarchyLines as $aAddressLine)
-        {
+        foreach ($aHierarchyLines as $aAddressLine) {
             if ($aAddressLine['type'] == 'yes') $sType = $aAddressLine['class'];
             else $sType = $aAddressLine['type'];
 
                 $aGroupedAddressLines[$sType] = array();
             $aGroupedAddressLines[$sType][] = $aAddressLine;
         }
-        foreach($aGroupedAddressLines as $sGroupHeading => $aHierarchyLines)
-        {
+        foreach ($aGroupedAddressLines as $sGroupHeading => $aHierarchyLines) {
             $sGroupHeading = ucwords($sGroupHeading);
             headline3($sGroupHeading);
 
-            foreach($aHierarchyLines as $aAddressLine)
-            {
+            foreach ($aHierarchyLines as $aAddressLine) {
                 _one_row($aAddressLine);
             }
         }
                 'lon' => $aPointDetails['lon'],
                 'lat' => $aPointDetails['lat'],
         );
-        echo 'var nominatim_result = ' . json_encode($aPlace, JSON_PRETTY_PRINT) . ';'; 
+        echo 'var nominatim_result = ' . json_encode($aPlace, JSON_PRETTY_PRINT) . ';';
 
 
     ?>
index 9b4237c70720331a82b20160f2570c1b7bc3c0df..06554aba68f2143c6a24b46ce9cdb39e9cfc3362 100644 (file)
@@ -26,7 +26,9 @@ $aPlaceDetails['calculated_importance'] = (float) $aPointDetails['calculated_imp
 
 $aPlaceDetails['extratags'] = $aPointDetails['aExtraTags'];
 $aPlaceDetails['calculated_wikipedia'] = $aPointDetails['wikipedia'];
-$aPlaceDetails['icon'] = CONST_Website_BaseURL.'images/mapicons/'.$aPointDetails['icon'].'.n.32.png';
+if ($aPointDetails['icon']) {
+    $aPlaceDetails['icon'] = CONST_Website_BaseURL.'images/mapicons/'.$aPointDetails['icon'].'.n.32.png';
+}
 
 $aPlaceDetails['rank_address'] = (int) $aPointDetails['rank_address'];
 $aPlaceDetails['rank_search'] = (int) $aPointDetails['rank_search'];
index a0b990ebc14cd90123fc111f13211f0f326d56f0..3c9286ed285acedc3c2c847a04db89a0662889bf 100644 (file)
@@ -41,3 +41,16 @@ Feature: Object details
             | linkedplaces |
             | 1 |
         Then the result is valid json
+
+    Scenario Outline: HTML Details with keywords
+        When sending html details query for <osmid>
+            | keywords |
+            | 1 |
+        Then the result is valid html
+
+    Examples:
+            | osmid |
+            | W78099902 |
+            | N3121929846 |
+
+
index e06b1775fa2d69306833f11630229d0073c9e0f0..88f3bccbc34756e3b7b8284a541d14d323012864 100644 (file)
@@ -59,3 +59,35 @@ Feature: Reverse geocoding
         Then results contain
          | display_name |
          | Tacuarembó, Uruguay |
+
+    Scenario Outline: Zoom levels below 5 result in country
+        When sending jsonv2 reverse coordinates -33.28,-56.29
+         | zoom |
+         | <zoom> |
+        Then results contain
+         | display_name |
+         | Uruguay |
+
+    Examples:
+         | zoom |
+         | 0    |
+         | 1    |
+         | 2    |
+         | 3    |
+         | 4    |
+
+    Scenario: When on a street, the closest interpolation is shown
+        When sending jsonv2 reverse coordinates -33.2309430210215,-54.38126470020989
+         | zoom |
+         | 18 |
+        Then results contain
+         | display_name |
+         | 1429, Andrés Areguati, Treinta y Tres, 33000, Uruguay |
+
+    Scenario: When on a street with zoom 18, the closest housenumber is returned
+        When sending jsonv2 reverse coordinates 53.551826690895226,9.885258475318201
+         | zoom |
+         | 18 |
+        Then result addresses contain
+         | house_number |
+         | 33 |
index 5cd80a83de36f77dbd7fe643f0262bd0780c49b2..ca441258784c2fde1f468883d77f768fb833b145 100644 (file)
@@ -233,6 +233,17 @@ Feature: Simple Tests
         When sending xml search query "Vaduz"
           | countrycodes |
           | pl,1,,invalid,undefined,%3Cb%3E,bo,, |
-       Then result header contains
+        Then result header contains
           | attr     | value |
           | more_url | .*&countrycodes=pl%2Cbo&.* |
+
+    Scenario Outline: Search with debug prints valid HTML
+        When sending html search query "<query>"
+          | extratags | addressdetails | namedetails | debug |
+          | 1         | 1              | 1           | 1     |
+        Then the result is valid html
+
+        Examples:
+          | query |
+          | 10, Alvierweg, 9490, Vaduz |
+          | Hamburg |
index fd13dd13b0f348c58dd725a6ff892b499e569de6..df34b5cc0696fc17d156a5500fb4047cb03b5b8f 100644 (file)
@@ -122,13 +122,17 @@ class SearchResponse(GenericResponse):
                                         options={'char-encoding' : 'utf8'})
         #eq_(len(errors), 0 , "Errors found in HTML document:\n%s" % errors)
 
+        self.result = []
         b = content.find('nominatim_results =')
         e = content.find('</script>')
-        content = content[b:e]
-        b = content.find('[')
-        e = content.rfind(']')
-
-        self.result = json.JSONDecoder(object_pairs_hook=OrderedDict).decode(content[b:e+1])
+        if b >= 0 and e >= 0:
+            content = content[b:e]
+
+            b = content.find('[')
+            e = content.rfind(']')
+            if b >= 0 and e >= 0:
+                self.result = json.JSONDecoder(object_pairs_hook=OrderedDict)\
+                                  .decode(content[b:e+1])
 
     def parse_xml(self):
         et = ET.fromstring(self.page)