Kurt Roeckx
Rodolphe QuiƩdeville
Marc Tobias Metten
+
+Reverse geocoding using Tiger data feature made possible with support from Guru Labs
-2.0.1
+ * reverse geocoding looking includes looking up Tiger data
- * delete outdated entries from location_area_country
- * remove remaining uses of INTEGER, to allow node ids larger than 2^31
+
+2.4
+
+ * drop support for postgres 8.4
+ * rewrite address interpolation
+ * switch to C++ version of osm2pgsql and rewrite tag filtering
+ * support for bridge:name and tunnel:name, man_made, junction
+ * drop way-node index (reduces database size by about 15%)
+ * add support for configuring tablespaces and webserver user
+ * better evaluation of search queries in right-to-left notation
+ * improve house number search for streets with many duplicate entries
+ * code cleanup (remove unused functions and tables)
+
+2.3
+
+ * further improve ordering of results
+ * support for more lat/lon formats in search-as-reverse
+ * fix handling of GB postcodes
+ * new functional test suite
+ * support for waterway relations
+ * inherit postcodes from street to poi
+ * fix housenumber normalisation to find non-latin house numbers
+ * take viewbox into account for ordering of results
+ * pois may now inherit address tags from surrounding buildings
+ * improve what objects may participate in an address
+ * clean up handled class/type combinations to current OSM usage
+ * lots of bug fixes
+
+2.2
+
+ * correct database rights for www-data
+ * add timestamps for update output
+ * load postgis via extension for postgis >= 2.0
+ * remove non-admin boundaries from addresses
+ * further improve ordering of results with same importance
+ * merge addr:postcode tags into object addresses
+ * include rank and importance in reverse geocode output
+ * replace ST_Line_Interpolate_Point with ST_LineInterpolatePoint
+ (for postgis >= 2.1)
+ * update osm2pgsql to latest version
+ * properly detect changes of admin_level
+ * remove landuses when name is removed
+ * smaller fixes
2.1
* refactoring of front-end PHP code
* lots of smaller bug fixes
-2.2
-
- * correct database rights for www-data
- * add timestamps for update output
- * load postgis via extension for postgis >= 2.0
- * remove non-admin boundaries from addresses
- * further improve ordering of results with same importance
- * merge addr:postcode tags into object addresses
- * include rank and importance in reverse geocode output
- * replace ST_Line_Interpolate_Point with ST_LineInterpolatePoint
- (for postgis >= 2.1)
- * update osm2pgsql to latest version
- * properly detect changes of admin_level
- * remove landuses when name is removed
- * smaller fixes
-
-2.3
+2.0.1
- * further improve ordering of results
- * support for more lat/lon formats in search-as-reverse
- * fix handling of GB postcodes
- * new functional test suite
- * support for waterway relations
- * inherit postcodes from street to poi
- * fix housenumber normalisation to find non-latin house numbers
- * take viewbox into account for ordering of results
- * pois may now inherit address tags from surrounding buildings
- * improve what objects may participate in an address
- * clean up handled class/type combinations to current OSM usage
- * lots of bug fixes
+ * delete outdated entries from location_area_country
+ * remove remaining uses of INTEGER, to allow node ids larger than 2^31
-AC_INIT(Nominatim,2.4)
+AC_INIT(Nominatim,2.5)
if git rev-parse HEAD 2>/dev/null >/dev/null; then
AC_SUBST([PACKAGE_VERSION], [$PACKAGE_VERSION-git-`git rev-parse --short HEAD`])
fi
protected $bIncludePolygonAsGeoJSON = false;
protected $bIncludePolygonAsKML = false;
protected $bIncludePolygonAsSVG = false;
+ protected $fPolygonSimplificationThreshold = 0.0;
protected $aExcludePlaceIDs = array();
protected $bDeDupe = true;
$this->bIncludePolygonAsSVG = $b;
}
+ function setPolygonSimplificationThreshold($f)
+ {
+ $this->fPolygonSimplificationThreshold = $f;
+ }
+
function setDeDupe($bDeDupe = true)
{
$this->bDeDupe = (bool)$bDeDupe;
else $aSearch['sOperator'] = 'near'; // near = in for the moment
if (strlen($aSearchTerm['operator']) == 0) $aSearch['iSearchRank'] += 1;
- // Do we have a shortcut id?
- if ($aSearch['sOperator'] == 'name')
- {
- $sSQL = "select get_tagpair('".$aSearch['sClass']."', '".$aSearch['sType']."')";
- if ($iAmenityID = $this->oDB->getOne($sSQL))
- {
- $aValidTokens[$aSearch['sClass'].':'.$aSearch['sType']] = array('word_id' => $iAmenityID);
- $aSearch['aName'][$iAmenityID] = $iAmenityID;
- $aSearch['sClass'] = '';
- $aSearch['sType'] = '';
- }
- }
if ($aSearch['iSearchRank'] < $this->iMaxRank) $aNewWordsetSearches[] = $aSearch;
}
}
if (!$this->sQuery && !$this->aStructuredQuery) return false;
$sLanguagePrefArraySQL = "ARRAY[".join(',',array_map("getDBQuoted",$this->aLangPrefOrder))."]";
-
$sCountryCodesSQL = false;
if ($this->aCountryCodes && sizeof($this->aCountryCodes))
{
if ($this->bIncludePolygonAsKML) $sSQL .= ",ST_AsKML(geometry) as askml";
if ($this->bIncludePolygonAsSVG) $sSQL .= ",ST_AsSVG(geometry) as assvg";
if ($this->bIncludePolygonAsText || $this->bIncludePolygonAsPoints) $sSQL .= ",ST_AsText(geometry) as astext";
- $sSQL .= " from placex where place_id = ".$aResult['place_id'];
+ $sFrom = " from placex where place_id = ".$aResult['place_id'];
+ if ($this->fPolygonSimplificationThreshold > 0)
+ {
+ $sSQL .= " from (select place_id,centroid,ST_SimplifyPreserveTopology(geometry,".$this->fPolygonSimplificationThreshold.") as geometry".$sFrom.") as plx";
+ }
+ else
+ {
+ $sSQL .= $sFrom;
+ }
+
$aPointPolygon = $this->oDB->getRow($sSQL);
if (PEAR::IsError($aPointPolygon))
{
protected $iPlaceID;
+ protected $bIsTiger = false;
+
protected $aLangPrefOrder = array();
protected $bAddressDetails = false;
$this->iPlaceID = $this->oDB->getOne($sSQL);
}
+ function setIsTiger($b = false)
+ {
+ $this->bIsTiger = $b;
+ }
+
function lookup()
{
if (!$this->iPlaceID) return null;
$sSQL .= " (case when centroid is null then st_y(st_centroid(geometry)) else st_y(centroid) end) as lat,";
$sSQL .= " (case when centroid is null then st_x(st_centroid(geometry)) else st_x(centroid) end) as lon";
$sSQL .= " from placex where place_id = ".(int)$this->iPlaceID;
+
+
+ if ($this->bIsTiger)
+ {
+ $sSQL = "select place_id,partition, 'T' as osm_type, place_id as osm_id, 'place' as class, 'house' as type, null as admin_level, housenumber, null as street, null as isin, postcode,";
+ $sSQL .= " 'us' as country_code, null as extratags, parent_place_id, null as linked_place_id, 30 as rank_address, 30 as rank_search,";
+ $sSQL .= " coalesce(null,0.75-(30::float/40)) as importance, null as indexed_status, null as indexed_date, null as wikipedia, 'us' as calculated_country_code, ";
+ $sSQL .= " get_address_by_language(place_id, $sLanguagePrefArraySQL) as langaddress,";
+ $sSQL .= " null as placename,";
+ $sSQL .= " null as ref,";
+ $sSQL .= " st_y(centroid) as lat,";
+ $sSQL .= " st_x(centroid) as lon";
+ $sSQL .= " from location_property_tiger where place_id = ".(int)$this->iPlaceID;
+ }
+
$aPlace = $this->oDB->getRow($sSQL);
+
if (PEAR::IsError($aPlace))
{
failInternalError("Could not lookup place.", $sSQL, $aPlace);
}
+
if (!$aPlace['place_id']) return null;
if ($this->bAddressDetails)
$aPlace['aAddress'] = $aAddress;
}
+
$aClassType = getClassTypes();
$sAddressType = '';
$sClassType = $aPlace['class'].':'.$aPlace['type'].':'.$aPlace['admin_level'];
{
$sPointSQL = 'ST_SetSRID(ST_Point('.$this->fLon.','.$this->fLat.'),4326)';
$iMaxRank = $this->iMaxRank;
+ $iMaxRank_orig = $this->iMaxRank;
// Find the nearest point
$fSearchDiam = 0.0004;
$iPlaceID = null;
$aArea = false;
$fMaxAreaDistance = 1;
+ $bIsInUnitedStates = false;
+ $bPlaceIsTiger = false;
while(!$iPlaceID && $fSearchDiam < $fMaxAreaDistance)
{
$fSearchDiam = $fSearchDiam * 2;
if ($fSearchDiam > 0.008 && $iMaxRank > 22) $iMaxRank = 22;
if ($fSearchDiam > 0.001 && $iMaxRank > 26) $iMaxRank = 26;
- $sSQL = 'select place_id,parent_place_id,rank_search from placex';
+ $sSQL = 'select place_id,parent_place_id,rank_search,calculated_country_code from placex';
$sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, '.$fSearchDiam.')';
$sSQL .= ' and rank_search != 28 and rank_search >= '.$iMaxRank;
$sSQL .= ' and (name is not null or housenumber is not null)';
}
$iPlaceID = $aPlace['place_id'];
$iParentPlaceID = $aPlace['parent_place_id'];
+ $bIsInUnitedStates = ($aPlace['calculated_country_code'] == 'us');
+ }
+
+ // Only street found? If it's in the US we can check TIGER data for nearest housenumber
+ if ($bIsInUnitedStates && $iMaxRank_orig >= 28 && $iPlaceID && ($aPlace['rank_search'] == 26 || $aPlace['rank_search'] == 27 ))
+ {
+ $fSearchDiam = 0.001;
+ $sSQL = 'SELECT place_id,parent_place_id,30 as rank_search ';
+ if (CONST_Debug) { $sSQL .= ', housenumber, ST_distance('.$sPointSQL.', centroid) as distance, st_y(centroid) as lat, st_x(centroid) as lon'; }
+ $sSQL .= ' FROM location_property_tiger WHERE parent_place_id = '.$iPlaceID;
+ $sSQL .= ' AND ST_DWithin('.$sPointSQL.', centroid, '.$fSearchDiam.')';
+ $sSQL .= ' ORDER BY ST_distance('.$sPointSQL.', centroid) ASC limit 1';
+
+
+ // print all house numbers in the parent (street)
+ if (CONST_Debug)
+ {
+ $sSQL = preg_replace('/limit 1/', 'limit 100', $sSQL);
+ var_dump($sSQL);
+
+ $aAllHouses = $this->oDB->getAll($sSQL);
+ foreach($aAllHouses as $i)
+ {
+ echo $i['housenumber'] . ' | ' . $i['distance'] * 1000 . ' | ' . $i['lat'] . ' | ' . $i['lon']. ' | '. "<br>\n";
+ }
+ }
+
+ $aPlaceTiger = $this->oDB->getRow($sSQL);
+ if (PEAR::IsError($aPlace))
+ {
+ failInternalError("Could not determine closest Tiger place.", $sSQL, $aPlaceTiger);
+ }
+ if ($aPlaceTiger)
+ {
+ if (CONST_Debug) var_dump('found Tiger place', $aPlaceTiger);
+ $bPlaceIsTiger = true;
+ $aPlace = $aPlaceTiger;
+ $iPlaceID = $aPlaceTiger['place_id'];
+ $iParentPlaceID = $aPlaceTiger['parent_place_id']; // the street
+ }
}
// The point we found might be too small - use the address to find what it is a child of
if ($iPlaceID && $iMaxRank < 28)
{
- if ($aPlace['rank_search'] > 28 && $iParentPlaceID)
+ if ($aPlace['rank_search'] > 28 && $iParentPlaceID && !$bPlaceIsTiger)
{
$iPlaceID = $iParentPlaceID;
}
$oPlaceLookup->setLanguagePreference($this->aLangPrefOrder);
$oPlaceLookup->setIncludeAddressDetails($this->bAddressDetails);
$oPlaceLookup->setPlaceId($iPlaceID);
+ $oPlaceLookup->setIsTiger($bPlaceIsTiger);
return $oPlaceLookup->lookup();
}
@define('CONST_Limit_Reindexing', true);
// Software versions
- @define('CONST_Postgresql_Version', '9.1'); // values: 9.0, 9.1, 9.2
- @define('CONST_Postgis_Version', '1.5'); // values: 1.5, 2.0
+ @define('CONST_Postgresql_Version', '9.3'); // values: 9.0, ... , 9.4
+ @define('CONST_Postgis_Version', '2.1'); // values: 1.5, 2.0, 2.1
// Paths
@define('CONST_Path_Postgresql_Contrib', '/usr/share/postgresql/'.CONST_Postgresql_Version.'/contrib');
| ID | country
| 0 | Deutschland
+ @Tiger
+ Scenario: TIGER house number
+ Given the request parameters
+ | addressdetails
+ | 1
+ When looking up coordinates 40.6863624710666,-112.060005720023
+ And exactly 1 result is returned
+ And result addresses contain
+ | ID | house_number | road | postcode | country_code
+ | 0 | 7094 | Kings Estate Drive | 84128 | us
+ And result 0 has not attributes osm_id,osm_type
+
+
+ @Tiger
+ Scenario: No TIGER house number for zoom < 18
+ Given the request parameters
+ | addressdetails | zoom
+ | 1 | 17
+ When looking up coordinates 40.6863624710666,-112.060005720023
+ And exactly 1 result is returned
+ And result addresses contain
+ | ID | road | postcode | country_code
+ | 0 | Kings Estate Drive | 84128 | us
+ And result 0 has attributes osm_id,osm_type
+
Then results contain
| ID | display_name
| 0 | Illinois.*
+
+ Scenario: Search with class-type feature
+ When sending jsonv2 search query "Hotel California"
+ Then results contain
+ | place_rank
+ | 30
Then results contain
| ID | display_name
| 0 | Everest.*
+
+ Scenario Outline: Search with polygon threshold (json)
+ Given the request parameters
+ | polygon_geojson | polygon_threshold
+ | 1 | <th>
+ When sending json search query "switzerland"
+ Then at least 1 result is returned
+ And result 0 has attributes geojson
+
+ Examples:
+ | th
+ | -1
+ | 0.0
+ | 0.5
+ | 999
+ | nan
+
+ Scenario Outline: Search with polygon threshold (xml)
+ Given the request parameters
+ | polygon_geojson | polygon_threshold
+ | 1 | <th>
+ When sending xml search query "switzerland"
+ Then at least 1 result is returned
+ And result 0 has attributes geojson
+
+ Examples:
+ | th
+ | -1
+ | 0.0
+ | 0.5
+ | 999
+ | nan
$oGeocode->setIncludePolygonAsSVG($bAsSVG);
}
+ // Polygon simplification threshold (optional)
+ $fThreshold = 0.0;
+ if (isset($_GET['polygon_threshold'])) $fThreshold = (float)$_GET['polygon_threshold'];
+ $oGeocode->setPolygonSimplificationThreshold($fThreshold);
+
$oGeocode->loadParamArray($_GET);
if (CONST_Search_BatchMode && isset($_GET['batch']))